Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic load timeout #78

Merged
merged 9 commits into from
Jun 5, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name="python-velbus",
version="2.1.3",
version="2.1.4",
url="https://github.com/thomasdelaet/python-velbus",
license="MIT",
author="Thomas Delaet",
Expand Down
29 changes: 26 additions & 3 deletions velbus/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def module_loaded():
self._load_finished = True
callback()

def timeout_expired():
def final_timeout_expired():
if not self._load_finished:
modules_not_loaded = []
for module in self._modules:
Expand All @@ -170,10 +170,33 @@ def timeout_expired():
del self._modules[module]
callback()

# 180 second timeout for loading modules
self.load_timeout = threading.Timer(360, timeout_expired).start()
def first_retry():
if not self._load_finished:
# First load failed, do 2nd retry for failed modules
_missing_modules = 0
for module in self._modules:
if not self._modules[module].loaded:
self.logger.warning(
"Failed to load module "
+ str(self._modules[module].get_module_name())
+ " at address "
+ str(self._modules[module].get_module_address())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (81 > 79 characters)

+ ", retry initiated."
)
# Trigger load without callback
self._modules[module].load(None)
_missing_modules += 1
# Set final timeout
threading.Timer(
(_missing_modules * 10) + 1, final_timeout_expired
).start()

# Set first timeout (10 second for each module to load) to trigger a retry
threading.Timer((len(self._modules) * 10) + 1, first_retry).start()

for module in self._modules:
self._modules[module].load(module_loaded)
time.sleep(1) # Throttle loading modules

for address in range(0, 256):
message = ModuleTypeRequestMessage(address)
Expand Down
43 changes: 31 additions & 12 deletions velbus/module.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
:author: Thomas Delaet <[email protected]>
"""
import datetime
import string
import struct
from velbus.messages.read_data_from_memory import ReadDataFromMemoryMessage
Expand Down Expand Up @@ -39,7 +40,9 @@ def __init__(self, module_type, module_name, module_address, controller):

self._loaded_callbacks = []
self.loaded = False
self._loading_triggered = False

self._last_channel_name_msg = datetime.datetime.utcnow()
self._controller = controller
self._controller.subscribe(self.on_message)

Expand Down Expand Up @@ -148,18 +151,33 @@ def load(self, callback):
"""
Retrieve names of channels
"""
if not self._is_submodule():
# load the data from memory ( the stuff that we need)
self._load_memory()
# load the module status
self._request_module_status()
if not self._is_submodule():
# load the channel names
self._request_channel_name()
if callback:
self._loaded_callbacks.append(callback)
# load the module specific stuff
self._load()
if not self.loaded:
if not self._loading_triggered:
self._loading_triggered = True
if not self._is_submodule():
# load the data from memory ( the stuff that we need)
self._load_memory()
# load the module status
self._request_module_status()
if not self._is_submodule():
# load the channel names
self._request_channel_name()
# load the module specific stuff
self._load()
else:
# Request channel names if last received
if (
not self._is_submodule()
and not self._name_messages_complete()
and self._last_channel_name_msg
< datetime.datetime.utcnow() - datetime.timedelta(seconds=10)
):
self._request_channel_name()
if callback:
self._loaded_callbacks.append(callback)
else:
if callback:
callback()

def loading_in_progress(self):
return not self._name_messages_complete()
Expand All @@ -185,6 +203,7 @@ def _name_count_needed(self):
return self.number_of_channels() * 3

def _process_channel_name_message(self, part, message):
self._last_channel_name_msg = datetime.datetime.utcnow()
channel = message.channel
if self._is_submodule():
channel = channel - (self.number_of_channels() * self.sub_module)
Expand Down