diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index 48ba802..8c6efbf 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -252,6 +252,10 @@ def onConnected(interface): closeNow = True interface.getNode(args.dest).reboot() + if args.shutdown: + closeNow = True + interface.getNode(args.dest).shutdown() + if args.sendtext: closeNow = True channelIndex = 0 @@ -803,6 +807,9 @@ def initParser(): parser.add_argument( "--reboot", help="Tell the destination node to reboot", action="store_true") + parser.add_argument( + "--shutdown", help="Tell the destination node to shutdown", action="store_true") + parser.add_argument( "--reply", help="Reply to received messages", action="store_true") diff --git a/meshtastic/node.py b/meshtastic/node.py index a08523a..5eb6532 100644 --- a/meshtastic/node.py +++ b/meshtastic/node.py @@ -285,6 +285,14 @@ class Node: return self._sendAdmin(p) + def shutdown(self, secs: int = 10): + """Tell the node to shutdown.""" + p = admin_pb2.AdminMessage() + p.shutdown_seconds = secs + logging.info(f"Telling node to shutdown in {secs} seconds") + + return self._sendAdmin(p) + def _fixupChannels(self): """Fixup indexes and add disabled channels as needed""" diff --git a/meshtastic/tests/test_main.py b/meshtastic/tests/test_main.py index 21e9fe5..52b3ad7 100644 --- a/meshtastic/tests/test_main.py +++ b/meshtastic/tests/test_main.py @@ -478,6 +478,30 @@ def test_main_reboot(capsys): mo.assert_called() +@pytest.mark.unit +@pytest.mark.usefixtures("reset_globals") +def test_main_shutdown(capsys): + """Test --shutdown""" + sys.argv = ['', '--shutdown'] + Globals.getInstance().set_args(sys.argv) + + mocked_node = MagicMock(autospec=Node) + def mock_shutdown(): + print('inside mocked shutdown') + mocked_node.shutdown.side_effect = mock_shutdown + + iface = MagicMock(autospec=SerialInterface) + iface.getNode.return_value = mocked_node + + with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo: + main() + out, err = capsys.readouterr() + assert re.search(r'Connected to radio', out, re.MULTILINE) + assert re.search(r'inside mocked shutdown', out, re.MULTILINE) + assert err == '' + mo.assert_called() + + @pytest.mark.unit @pytest.mark.usefixtures("reset_globals") def test_main_sendtext(capsys):