Skip to content

Commit

Permalink
Disconnecting from the printer before when turning its relay off (#207)
Browse files Browse the repository at this point in the history
* Draft: disconnecting from the printer before when turning its relay off.

* Fixing the tests.

* Testing is_printer_relay() method.

* Testing toggle_relay() method for the case of printer relay.

* Update tests/test_init.py

* Handling the case of double turned on the printer relay.
  • Loading branch information
RobinTail authored Sep 15, 2023
1 parent 4cdfe47 commit 21d7cea
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 3 deletions.
14 changes: 12 additions & 2 deletions octoprint_octorelay/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,9 @@ def on_event(self, event, payload):
self.handle_plugin_event(PRINTING_STOPPED)
elif hasattr(Events, "CONNECTIONS_AUTOREFRESHED"): # Requires OctoPrint 1.9+
if event == Events.CONNECTIONS_AUTOREFRESHED:
self._logger.debug("Connecting to the printer")
self._printer.connect()
if payload is not None and "ports" in payload and len(payload["ports"]) > 0:
self._logger.debug("Connecting to the printer")
self._printer.connect()
#elif event == Events.PRINT_CANCELLING:
# self.print_stopped()
#elif event == Events.PRINT_CANCELLED:
Expand Down Expand Up @@ -209,11 +210,20 @@ def handle_plugin_event(self, event, scope = None):
if needs_ui_update:
self.update_ui() # issue 190

def is_printer_relay(self, index) -> bool:
printer_relay = self._settings.get(["common", "printer"], merged=True) # expensive
return printer_relay is not None and printer_relay == index

def toggle_relay(self, index, target: Optional[bool] = None):
settings = self._settings.get([index], merged=True) # expensive
if not bool(settings["active"]):
self._logger.debug(f"Refusing to switch the relay {index} since it's disabled")
return
if target is not True and self.is_printer_relay(index):
self._logger.debug(f"{index} is the printer relay")
if self._printer.is_operational():
self._logger.debug(f"Disconnecting from the printer before turning {index} OFF")
self._printer.disconnect()
pin = int(settings["relay_pin"] or 0)
inverted = bool(settings["inverted_output"])
relay = Relay(pin, inverted)
Expand Down
48 changes: 47 additions & 1 deletion tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,9 +505,22 @@ def test_update_ui(self):
"MockedIdentifier", expected_model
)

def test_is_printer_relay(self):
# Should assert the equality of the common/printer value with the supplied argument
cases = [
{ "printer": "r4", "expected": True },
{ "printer": "r5", "expected": False },
{ "printer": None, "expected": False }
]
for case in cases:
self.plugin_instance._settings.get = Mock(return_value=case["printer"])
actual = self.plugin_instance.is_printer_relay("r4")
self.assertEqual(actual, case["expected"])

@patch("os.system")
def test_toggle_relay(self, system_mock):
# Should toggle the relay and execute a command matching its new state
self.plugin_instance.is_printer_relay = Mock(return_value=False)
cases = [
{ "target": True, "inverted": False, "expectedCommand": "CommandON" },
{ "target": True, "inverted": True, "expectedCommand": "CommandON" },
Expand Down Expand Up @@ -551,6 +564,33 @@ def test_toggle_relay__disabled(self):
self.plugin_instance.toggle_relay("r4", True)
relayMock.toggle.assert_not_called()

def test_toggle_relay__printer(self):
# Should disconnect from the printer when turning its relay off
cases = [
{ "target": None, "is_printer": True, "is_operational": True },
{ "target": False, "is_printer": True, "is_operational": True },
{ "target": True, "is_printer": True, "is_operational": True },
{ "target": False, "is_printer": True, "is_operational": False },
{ "target": False, "is_printer": False, "is_operational": True },
]
self.plugin_instance._settings.get = Mock(return_value={
"active": True,
"relay_pin": 17,
"inverted_output": False,
"cmd_on": None,
"cmd_off": None
})
relayMock.toggle = Mock(return_value=False)
for case in cases:
self.plugin_instance._printer.reset_mock()
self.plugin_instance.is_printer_relay = Mock(return_value=case["is_printer"])
self.plugin_instance._printer.is_operational = Mock(return_value=case["is_operational"])
self.plugin_instance.toggle_relay("r4", case["target"])
if case["target"] is not True and case["is_printer"] and case["is_operational"]:
self.plugin_instance._printer.disconnect.assert_called_with()
else:
self.plugin_instance._printer.disconnect.assert_not_called()

@patch("octoprint.plugin")
def test_on_settings_save(self, plugins_mock):
# Should call the SettingsPlugin event handler with own instance and supplied argument
Expand All @@ -568,33 +608,38 @@ def test_on_event(self):
cases = [
{
"event": Events.CLIENT_OPENED,
"payload": {"remoteAddress": "127.0.0.1"},
"expectedMethod": self.plugin_instance.update_ui,
"expectedParams": []
},
{
"event": Events.PRINT_STARTED,
"payload": {"name": "test.gcode"},
"expectedMethod": self.plugin_instance.handle_plugin_event,
"expectedParams": ["PRINTING_STARTED"]
},
{
"event": Events.PRINT_DONE,
"payload": {"name": "test.gcode"},
"expectedMethod": self.plugin_instance.handle_plugin_event,
"expectedParams": ["PRINTING_STOPPED"]
},
{
"event": Events.PRINT_FAILED,
"payload": {"name": "test.gcode"},
"expectedMethod": self.plugin_instance.handle_plugin_event,
"expectedParams": ["PRINTING_STOPPED"]
},
]
if hasattr(Events, "CONNECTIONS_AUTOREFRESHED"): # Requires OctoPrint 1.9+
cases.append({
"event": Events.CONNECTIONS_AUTOREFRESHED,
"payload": {"ports": ["/dev/ttyUSB0"]},
"expectedMethod": self.plugin_instance._printer.connect,
"expectedParams": []
})
for case in cases:
self.plugin_instance.on_event(case["event"], "MockedPayload")
self.plugin_instance.on_event(case["event"], case["payload"])
case["expectedMethod"].assert_called_with(*case["expectedParams"])

def test_on_after_startup(self):
Expand Down Expand Up @@ -814,6 +859,7 @@ def test_handle_get_status_command(self, jsonify_mock):
def test_handle_update_command(self, system_mock, jsonify_mock):
# Should toggle the relay state, execute command and update UI when having permission
self.plugin_instance.update_ui = Mock()
self.plugin_instance.is_printer_relay = Mock(return_value=False)
cases = [
{
"index": "r4",
Expand Down

0 comments on commit 21d7cea

Please sign in to comment.