diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index efba7a21..abf8afe4 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -454,6 +454,16 @@ def onConnected(interface): waitForAckNak = True interface.getNode(args.dest, False, **getNode_kwargs).removeFavorite(args.remove_favorite_node) + if args.set_ignored_node: + closeNow = True + waitForAckNak = True + interface.getNode(args.dest, False, **getNode_kwargs).setIgnored(args.set_ignored_node) + + if args.remove_ignored_node: + closeNow = True + waitForAckNak = True + interface.getNode(args.dest, False, **getNode_kwargs).removeIgnored(args.remove_ignored_node) + if args.reset_nodedb: closeNow = True waitForAckNak = True @@ -1722,6 +1732,16 @@ def addRemoteAdminArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPars help="Tell the destination node to set the specified node to be un-favorited on the NodeDB on the device, by number or ID", metavar="!xxxxxxxx" ) + group.add_argument( + "--set-ignored-node", + help="Tell the destination node to set the specified node to be ignored on the NodeDB on the devicein its DB, by number or ID", + metavar="!xxxxxxxx" + ) + group.add_argument( + "--remove-ignored-node", + help="Tell the destination node to set the specified node to be un-ignored on the NodeDB on the device, by number or ID", + metavar="!xxxxxxxx" + ) group.add_argument( "--reset-nodedb", help="Tell the destination node to clear its list of nodes", diff --git a/meshtastic/node.py b/meshtastic/node.py index edba1ae7..9e65e27e 100644 --- a/meshtastic/node.py +++ b/meshtastic/node.py @@ -704,6 +704,42 @@ def removeFavorite(self, nodeId: Union[int, str]): onResponse = self.onAckNak return self._sendAdmin(p, onResponse=onResponse) + def setIgnored(self, nodeId: Union[int, str]): + """Tell the node to set the specified node ID to be ignored on the NodeDB on the device""" + self.ensureSessionKey() + if isinstance(nodeId, str): + if nodeId.startswith("!"): + nodeId = int(nodeId[1:], 16) + else: + nodeId = int(nodeId) + + p = admin_pb2.AdminMessage() + p.set_ignored_node = nodeId + + if self == self.iface.localNode: + onResponse = None + else: + onResponse = self.onAckNak + return self._sendAdmin(p, onResponse=onResponse) + + def removeIgnored(self, nodeId: Union[int, str]): + """Tell the node to set the specified node ID to be un-ignored on the NodeDB on the device""" + self.ensureSessionKey() + if isinstance(nodeId, str): + if nodeId.startswith("!"): + nodeId = int(nodeId[1:], 16) + else: + nodeId = int(nodeId) + + p = admin_pb2.AdminMessage() + p.remove_ignored_node = nodeId + + if self == self.iface.localNode: + onResponse = None + else: + onResponse = self.onAckNak + return self._sendAdmin(p, onResponse=onResponse) + def resetNodeDb(self): """Tell the node to reset its list of nodes.""" self.ensureSessionKey() diff --git a/meshtastic/tests/test_main.py b/meshtastic/tests/test_main.py index f01a67f8..30f3154a 100644 --- a/meshtastic/tests/test_main.py +++ b/meshtastic/tests/test_main.py @@ -2683,3 +2683,33 @@ def test_remove_favorite_node(): main() mocked_node.removeFavorite.assert_called_once_with("!12345678") + +@pytest.mark.unit +@pytest.mark.usefixtures("reset_mt_config") +def test_set_ignored_node(): + """Test --set-ignored-node node""" + sys.argv = ["", "--set-ignored-node", "!12345678"] + mt_config.args = sys.argv + mocked_node = MagicMock(autospec=Node) + iface = MagicMock(autospec=SerialInterface) + iface.getNode.return_value = mocked_node + with patch("meshtastic.serial_interface.SerialInterface", return_value=iface): + main() + + mocked_node.setIgnored.assert_called_once_with("!12345678") + + +@pytest.mark.unit +@pytest.mark.usefixtures("reset_mt_config") +def test_remove_ignored_node(): + """Test --remove-ignored-node node""" + sys.argv = ["", "--remove-ignored-node", "!12345678"] + mt_config.args = sys.argv + mocked_node = MagicMock(autospec=Node) + iface = MagicMock(autospec=SerialInterface) + iface.getNode.return_value = mocked_node + mocked_node.iface = iface + with patch("meshtastic.serial_interface.SerialInterface", return_value=iface): + main() + + mocked_node.removeIgnored.assert_called_once_with("!12345678") diff --git a/meshtastic/tests/test_node.py b/meshtastic/tests/test_node.py index 0a7ad099..a7fcfd3b 100644 --- a/meshtastic/tests/test_node.py +++ b/meshtastic/tests/test_node.py @@ -1453,6 +1453,33 @@ def test_remove_favorite(favorite): iface.sendData.assert_called_once() +@pytest.mark.unit +@pytest.mark.parametrize("ignored", ["!1dec0ded", 502009325]) +def test_set_ignored(ignored): + """Test setFavorite""" + iface = MagicMock(autospec=SerialInterface) + node = Node(iface, 12345678) + amesg = admin_pb2.AdminMessage() + with patch("meshtastic.admin_pb2.AdminMessage", return_value=amesg): + node.setIgnored(ignored) + assert amesg.set_ignored_node == 502009325 + iface.sendData.assert_called_once() + + +@pytest.mark.unit +@pytest.mark.parametrize("ignored", ["!1dec0ded", 502009325]) +def test_remove_ignored(ignored): + """Test setFavorite""" + iface = MagicMock(autospec=SerialInterface) + node = Node(iface, 12345678) + amesg = admin_pb2.AdminMessage() + with patch("meshtastic.admin_pb2.AdminMessage", return_value=amesg): + node.removeIgnored(ignored) + + assert amesg.remove_ignored_node == 502009325 + iface.sendData.assert_called_once() + + # TODO # @pytest.mark.unitslow # def test_waitForConfig():