Skip to content

Commit

Permalink
Introducing UI update lock. (#186)
Browse files Browse the repository at this point in the history
* Introducing UI update lock.

* Using actual threading Lock.

* Fix import order.

* Using lock as a context manager (with).

* Add logging for the lock.

* Avoid calling UI update fn from the polling thread when it's already running.

* Minor: comments.

* Update octoprint_octorelay/__init__.py

* test_input_polling__locked.

* Asserting the released lock in test_update_ui.
  • Loading branch information
RobinTail authored Aug 26, 2023
1 parent 996f9ce commit e6b1aeb
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 0 deletions.
5 changes: 5 additions & 0 deletions octoprint_octorelay/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def __init__(self):
self.polling_timer = None
self.tasks = [] # of Task
self.model = { index: {} for index in RELAY_INDEXES }
self.ui_update_lock = None

def get_settings_version(self):
return SETTINGS_VERSION
Expand Down Expand Up @@ -263,6 +264,7 @@ def reducer(agg, task):
)

def update_ui(self):
self.ui_update_lock = True # issue 186
self._logger.debug("Updating the UI")
settings = self._settings.get([], merged=True) # expensive
upcoming = self.get_upcoming_tasks(filter(
Expand Down Expand Up @@ -290,6 +292,7 @@ def update_ui(self):
"deadline": int(upcoming[index].deadline * 1000) # ms for JS
}
}
self.ui_update_lock = None # issue 186, once model is updated, the lock can be released
self._logger.debug(f"The UI feed: {self.model}")
self._plugin_manager.send_plugin_message(self._identifier, self.model)

Expand All @@ -315,6 +318,8 @@ def get_update_information(self):
# Polling thread
def input_polling(self):
# self._logger.debug("input_polling") # in case your log file is too small
if self.ui_update_lock:
return # issue 186, avoid the update during the another one
for index in RELAY_INDEXES:
active = self.model[index]["active"]
model_state = self.model[index]["relay_state"] # bool since v3.1
Expand Down
10 changes: 10 additions & 0 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,15 @@ def test_input_polling(self):
self.plugin_instance.update_ui.assert_called_with()
self.plugin_instance._logger.debug.assert_called_with("relay: r3 has changed its pin state")

def test_input_polling__locked(self):
# Should return immediately when the UI update is locked
self.plugin_instance.ui_update_lock = True
self.plugin_instance.update_ui = Mock()
relayConstructorMock.reset_mock()
self.plugin_instance.input_polling()
self.plugin_instance.update_ui.assert_not_called()
relayConstructorMock.assert_not_called()

def test_update_ui(self):
# Should send message via plugin manager containing actual settings and the relay state
cases = [
Expand Down Expand Up @@ -501,6 +510,7 @@ def test_update_ui(self):
self.plugin_instance._plugin_manager.send_plugin_message.assert_called_with(
"MockedIdentifier", expected_model
)
self.assertIsNone(self.plugin_instance.ui_update_lock)

@patch("os.system")
def test_toggle_relay(self, system_mock):
Expand Down

0 comments on commit e6b1aeb

Please sign in to comment.