diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index ee869e9b..bce45e35 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -339,16 +339,31 @@ def onConnected(interface): # can include lat/long/alt etc: latitude = 37.5, longitude = -122.1 interface.getNode(args.dest, False, **getNode_kwargs).setFixedPosition(lat, lon, alt) - if args.set_owner or args.set_owner_short: + if args.set_owner or args.set_owner_short or args.set_is_unmessageable or args.set_is_unmessagable: closeNow = True waitForAckNak = True if args.set_owner and args.set_owner_short: print(f"Setting device owner to {args.set_owner} and short name to {args.set_owner_short}") elif args.set_owner: print(f"Setting device owner to {args.set_owner}") - else: # short name only + elif args.set_owner_short and not args.set_owner: print(f"Setting device owner short to {args.set_owner_short}") - interface.getNode(args.dest, False, **getNode_kwargs).setOwner(long_name=args.set_owner, short_name=args.set_owner_short) + unmessageable = ( + args.set_is_unmessageable + if args.set_is_unmessageable is not None + else args.set_is_unmessagable + ) + set_is_unmessagable = ( + meshtastic.util.fromStr(unmessageable) + if isinstance(unmessageable, str) + else unmessageable + ) + if set_is_unmessagable is not None: + print(f"Setting device owner is_unmessageable to {set_is_unmessagable}") + interface.getNode( + args.dest, False, **getNode_kwargs).setOwner(long_name=args.set_owner, + short_name=args.set_owner_short, is_unmessagable=set_is_unmessagable + ) # TODO: add to export-config and configure if args.set_canned_message: @@ -1540,6 +1555,13 @@ def addConfigArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser: "--set-ham", help="Set licensed Ham ID and turn off encryption", action="store" ) + group.add_argument( + "--set-is-unmessageable", help="Set if a node is messageable or not", action="store" + ) + + group.add_argument( + "--set-is-unmessagable", help="Set if a node is messageable or not", action="store" +) group.add_argument( "--ch-set-url", "--seturl", help="Set all channels and set LoRa config from a supplied URL", diff --git a/meshtastic/node.py b/meshtastic/node.py index e54963c1..90eeba40 100644 --- a/meshtastic/node.py +++ b/meshtastic/node.py @@ -298,7 +298,7 @@ def _getAdminChannelIndex(self): return c.index return 0 - def setOwner(self, long_name: Optional[str]=None, short_name: Optional[str]=None, is_licensed: bool=False): + def setOwner(self, long_name: Optional[str]=None, short_name: Optional[str]=None, is_licensed: bool=False, is_unmessagable: Optional[bool]=None): """Set device owner name""" logging.debug(f"in setOwner nodeNum:{self.nodeNum}") self.ensureSessionKey() @@ -315,11 +315,14 @@ def setOwner(self, long_name: Optional[str]=None, short_name: Optional[str]=None short_name = short_name[:nChars] print(f"Maximum is 4 characters, truncated to {short_name}") p.set_owner.short_name = short_name + if is_unmessagable is not None: + p.set_owner.is_unmessagable = is_unmessagable # Note: These debug lines are used in unit tests logging.debug(f"p.set_owner.long_name:{p.set_owner.long_name}:") logging.debug(f"p.set_owner.short_name:{p.set_owner.short_name}:") logging.debug(f"p.set_owner.is_licensed:{p.set_owner.is_licensed}") + logging.debug(f"p.set_owner.is_unmessagable:{p.set_owner.is_unmessagable}:") # If sending to a remote node, wait for ACK/NAK if self == self.iface.localNode: onResponse = None diff --git a/meshtastic/tests/test_main.py b/meshtastic/tests/test_main.py index 8b70a4e8..39bd599b 100644 --- a/meshtastic/tests/test_main.py +++ b/meshtastic/tests/test_main.py @@ -454,6 +454,37 @@ def test_main_set_owner_short_to_bob(capsys): assert err == "" mo.assert_called() +@pytest.mark.unit +@pytest.mark.usefixtures("reset_mt_config") +def test_main_set_is_unmessageable_to_true(capsys): + """Test --set-is-unmessageable true""" + sys.argv = ["", "--set-is-unmessageable", "true"] + mt_config.args = sys.argv + + iface = MagicMock(autospec=SerialInterface) + 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"Setting device owner is_unmessageable to True", out, re.MULTILINE) + assert err == "" + mo.assert_called() + +@pytest.mark.unit +@pytest.mark.usefixtures("reset_mt_config") +def test_main_set_is_unmessagable_to_true(capsys): + """Test --set-is-unmessagable true""" + sys.argv = ["", "--set-is-unmessagable", "true"] + mt_config.args = sys.argv + + iface = MagicMock(autospec=SerialInterface) + 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"Setting device owner is_unmessageable to True", out, re.MULTILINE) + assert err == "" + mo.assert_called() @pytest.mark.unit @pytest.mark.usefixtures("reset_mt_config")