From 5a1b4fb855439a5ffa4f5998f54a79dc3951e37e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 3 Dec 2025 00:26:21 +0000 Subject: [PATCH] Fix device public key retrieval and add node-address config option - Use meshcore library's self_info property directly after connection instead of waiting for SELF_INFO event (which was already processed) - Add --node-address CLI option to override device public key/address - Support NODE_ADDRESS environment variable - Add node_address parameter to DeviceConfig and all related functions --- src/meshcore_hub/interface/cli.py | 34 ++++++++++++++++++ src/meshcore_hub/interface/device.py | 49 ++++++++++++++++---------- src/meshcore_hub/interface/receiver.py | 7 +++- src/meshcore_hub/interface/sender.py | 7 +++- 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/src/meshcore_hub/interface/cli.py b/src/meshcore_hub/interface/cli.py index ea9229b..8563b1b 100644 --- a/src/meshcore_hub/interface/cli.py +++ b/src/meshcore_hub/interface/cli.py @@ -45,6 +45,13 @@ def interface() -> None: envvar="MOCK_DEVICE", help="Use mock device for testing", ) +@click.option( + "--node-address", + type=str, + default=None, + envvar="NODE_ADDRESS", + help="Override for device public key/address (hex string)", +) @click.option( "--mqtt-host", type=str, @@ -92,6 +99,7 @@ def run( port: str, baud: int, mock: bool, + node_address: str | None, mqtt_host: str, mqtt_port: int, mqtt_username: str | None, @@ -119,6 +127,8 @@ def run( click.echo(f"Serial: {port} @ {baud} baud") click.echo(f"MQTT: {mqtt_host}:{mqtt_port} (prefix: {prefix})") click.echo(f"Mock device: {mock}") + if node_address: + click.echo(f"Node address: {node_address}") mode_upper = mode.upper() @@ -129,6 +139,7 @@ def run( port=port, baud=baud, mock=mock, + node_address=node_address, mqtt_host=mqtt_host, mqtt_port=mqtt_port, mqtt_username=mqtt_username, @@ -142,6 +153,7 @@ def run( port=port, baud=baud, mock=mock, + node_address=node_address, mqtt_host=mqtt_host, mqtt_port=mqtt_port, mqtt_username=mqtt_username, @@ -175,6 +187,13 @@ def run( envvar="MOCK_DEVICE", help="Use mock device for testing", ) +@click.option( + "--node-address", + type=str, + default=None, + envvar="NODE_ADDRESS", + help="Override for device public key/address (hex string)", +) @click.option( "--mqtt-host", type=str, @@ -214,6 +233,7 @@ def receiver( port: str, baud: int, mock: bool, + node_address: str | None, mqtt_host: str, mqtt_port: int, mqtt_username: str | None, @@ -230,11 +250,14 @@ def receiver( click.echo(f"Serial: {port} @ {baud} baud") click.echo(f"MQTT: {mqtt_host}:{mqtt_port} (prefix: {prefix})") click.echo(f"Mock device: {mock}") + if node_address: + click.echo(f"Node address: {node_address}") run_receiver( port=port, baud=baud, mock=mock, + node_address=node_address, mqtt_host=mqtt_host, mqtt_port=mqtt_port, mqtt_username=mqtt_username, @@ -265,6 +288,13 @@ def receiver( envvar="MOCK_DEVICE", help="Use mock device for testing", ) +@click.option( + "--node-address", + type=str, + default=None, + envvar="NODE_ADDRESS", + help="Override for device public key/address (hex string)", +) @click.option( "--mqtt-host", type=str, @@ -304,6 +334,7 @@ def sender( port: str, baud: int, mock: bool, + node_address: str | None, mqtt_host: str, mqtt_port: int, mqtt_username: str | None, @@ -320,11 +351,14 @@ def sender( click.echo(f"Serial: {port} @ {baud} baud") click.echo(f"MQTT: {mqtt_host}:{mqtt_port} (prefix: {prefix})") click.echo(f"Mock device: {mock}") + if node_address: + click.echo(f"Node address: {node_address}") run_sender( port=port, baud=baud, mock=mock, + node_address=node_address, mqtt_host=mqtt_host, mqtt_port=mqtt_port, mqtt_username=mqtt_username, diff --git a/src/meshcore_hub/interface/device.py b/src/meshcore_hub/interface/device.py index fc6f72a..b9e1731 100644 --- a/src/meshcore_hub/interface/device.py +++ b/src/meshcore_hub/interface/device.py @@ -38,6 +38,7 @@ class DeviceConfig: timeout: float = 1.0 reconnect_delay: float = 5.0 max_reconnect_attempts: int = 10 + node_address: Optional[str] = None # Override for device public key/address class BaseMeshCoreDevice(ABC): @@ -244,8 +245,8 @@ class MeshCoreDevice(BaseMeshCoreDevice): def connect(self) -> bool: """Connect to the MeshCore device.""" try: - from meshcore import MeshCore, SerialConnection - from meshcore import EventType as MCEventType + from meshcore import MeshCore + from meshcore.serial_cx import SerialConnection except ImportError: logger.error( "meshcore library not installed. " @@ -273,22 +274,30 @@ class MeshCoreDevice(BaseMeshCoreDevice): # Connect asynchronously self._loop.run_until_complete(self._mc.connect()) - # Get device info to retrieve public key - async def get_self_info(): - from meshcore import EventType as MCEventType - # Wait for SELF_INFO event - event = await self._mc.wait_for_event( - MCEventType.SELF_INFO, - timeout=5.0 - ) - if event: - return event.attributes.get("public_key") - return None - - self._public_key = self._loop.run_until_complete(get_self_info()) - - if not self._public_key: - logger.warning("Could not retrieve device public key") + # Get device public key from self_info property + # After connect(), the library internally processes SELF_INFO + # and stores it in the self_info property + if self.config.node_address: + # Use configured override + self._public_key = self.config.node_address + logger.info(f"Using configured node address: {self._public_key}") + else: + # Get from device self_info + self_info = self._mc.self_info + if self_info: + self._public_key = self_info.get("public_key") + if self._public_key: + logger.info(f"Retrieved device public key from self_info") + else: + logger.warning( + "Device self_info missing public_key field. " + "Use --node-address to configure manually." + ) + else: + logger.warning( + "Could not retrieve device self_info. " + "Use --node-address to configure manually." + ) self._connected = True logger.info(f"Connected to MeshCore device, public_key: {self._public_key}") @@ -480,6 +489,7 @@ def create_device( port: str = "/dev/ttyUSB0", baud: int = 115200, mock: bool = False, + node_address: Optional[str] = None, ) -> BaseMeshCoreDevice: """Create a MeshCore device instance. @@ -487,11 +497,12 @@ def create_device( port: Serial port path baud: Baud rate mock: Use mock device for testing + node_address: Optional override for device public key/address Returns: Device instance """ - config = DeviceConfig(port=port, baud=baud) + config = DeviceConfig(port=port, baud=baud, node_address=node_address) if mock: from meshcore_hub.interface.mock_device import MockMeshCoreDevice diff --git a/src/meshcore_hub/interface/receiver.py b/src/meshcore_hub/interface/receiver.py index 22ac6e0..ece9018 100644 --- a/src/meshcore_hub/interface/receiver.py +++ b/src/meshcore_hub/interface/receiver.py @@ -139,6 +139,7 @@ def create_receiver( port: str = "/dev/ttyUSB0", baud: int = 115200, mock: bool = False, + node_address: Optional[str] = None, mqtt_host: str = "localhost", mqtt_port: int = 1883, mqtt_username: Optional[str] = None, @@ -151,6 +152,7 @@ def create_receiver( port: Serial port path baud: Baud rate mock: Use mock device + node_address: Optional override for device public key/address mqtt_host: MQTT broker host mqtt_port: MQTT broker port mqtt_username: MQTT username @@ -161,7 +163,7 @@ def create_receiver( Configured Receiver instance """ # Create device - device = create_device(port=port, baud=baud, mock=mock) + device = create_device(port=port, baud=baud, mock=mock, node_address=node_address) # Create MQTT client mqtt_config = MQTTConfig( @@ -181,6 +183,7 @@ def run_receiver( port: str = "/dev/ttyUSB0", baud: int = 115200, mock: bool = False, + node_address: Optional[str] = None, mqtt_host: str = "localhost", mqtt_port: int = 1883, mqtt_username: Optional[str] = None, @@ -195,6 +198,7 @@ def run_receiver( port: Serial port path baud: Baud rate mock: Use mock device + node_address: Optional override for device public key/address mqtt_host: MQTT broker host mqtt_port: MQTT broker port mqtt_username: MQTT username @@ -205,6 +209,7 @@ def run_receiver( port=port, baud=baud, mock=mock, + node_address=node_address, mqtt_host=mqtt_host, mqtt_port=mqtt_port, mqtt_username=mqtt_username, diff --git a/src/meshcore_hub/interface/sender.py b/src/meshcore_hub/interface/sender.py index 6245687..5c08a1e 100644 --- a/src/meshcore_hub/interface/sender.py +++ b/src/meshcore_hub/interface/sender.py @@ -239,6 +239,7 @@ def create_sender( port: str = "/dev/ttyUSB0", baud: int = 115200, mock: bool = False, + node_address: Optional[str] = None, mqtt_host: str = "localhost", mqtt_port: int = 1883, mqtt_username: Optional[str] = None, @@ -251,6 +252,7 @@ def create_sender( port: Serial port path baud: Baud rate mock: Use mock device + node_address: Optional override for device public key/address mqtt_host: MQTT broker host mqtt_port: MQTT broker port mqtt_username: MQTT username @@ -261,7 +263,7 @@ def create_sender( Configured Sender instance """ # Create device - device = create_device(port=port, baud=baud, mock=mock) + device = create_device(port=port, baud=baud, mock=mock, node_address=node_address) # Create MQTT client mqtt_config = MQTTConfig( @@ -281,6 +283,7 @@ def run_sender( port: str = "/dev/ttyUSB0", baud: int = 115200, mock: bool = False, + node_address: Optional[str] = None, mqtt_host: str = "localhost", mqtt_port: int = 1883, mqtt_username: Optional[str] = None, @@ -295,6 +298,7 @@ def run_sender( port: Serial port path baud: Baud rate mock: Use mock device + node_address: Optional override for device public key/address mqtt_host: MQTT broker host mqtt_port: MQTT broker port mqtt_username: MQTT username @@ -305,6 +309,7 @@ def run_sender( port=port, baud=baud, mock=mock, + node_address=node_address, mqtt_host=mqtt_host, mqtt_port=mqtt_port, mqtt_username=mqtt_username,