control codes support: node_discover_req

This commit is contained in:
Florent 2025-11-06 22:32:53 +01:00
parent 057051c8c3
commit d3c9c8d984
5 changed files with 99 additions and 4 deletions

View file

@ -7,10 +7,15 @@ from .binary import BinaryCommandHandler
from .contact import ContactCommands
from .device import DeviceCommands
from .messaging import MessagingCommands
from .control_data import ControlDataCommandHandler
class CommandHandler(
DeviceCommands, ContactCommands, MessagingCommands, BinaryCommandHandler
DeviceCommands,
ContactCommands,
MessagingCommands,
BinaryCommandHandler,
ControlDataCommandHandler
):
pass

View file

@ -0,0 +1,45 @@
import logging
import random
from .base import CommandHandlerBase
from ..events import EventType, Event
from ..packets import ControlType, PacketType
logger = logging.getLogger("meshcore")
class ControlDataCommandHandler(CommandHandlerBase):
"""Helper functions to handle binary requests through binary commands"""
async def send_control_data (self, control_type: ControlType, payload: bytes) -> Event:
data = bytearray([PacketType.SEND_CONTROL_DATA.value])
data.extend(control_type.value.to_bytes(1, "little", signed = False))
data.extend(payload)
result = await self.send(data, [EventType.OK, EventType.ERROR])
return result
async def send_node_discover_req (
self,
filter: int,
tag: int=None,
since: int=None
) -> Event:
if tag is None:
tag = random.randint(1, 0xFFFFFFFF)
data = bytearray()
data.extend(filter.to_bytes(1, "little", signed=False))
data.extend(tag.to_bytes(4, "little"))
if not since is None:
data.extend(since.to_bytes(4, "little", signed=False))
logger.debug(f"sending node discover req {data.hex()}")
res = await self.send_control_data(ControlType.NODE_DISCOVER_REQ, data)
if res is None:
return None
else:
res.payload["tag"] = tag
return res

View file

@ -44,6 +44,8 @@ class EventType(Enum):
PATH_RESPONSE = "path_response"
PRIVATE_KEY = "private_key"
DISABLED = "disabled"
CONTROL_DATA = "control_data"
DISCOVER_RESPONSE = "discover_response"
# Command response types
OK = "command_ok"

View file

@ -7,6 +7,10 @@ class BinaryReqType(Enum):
MMA = 0x04
ACL = 0x05
class ControlType(Enum):
NODE_DISCOVER_REQ = 0x80
NODE_DISCOVER_RESP = 0x90
# Packet prefixes for the protocol
class PacketType(Enum):
OK = 0
@ -35,6 +39,7 @@ class PacketType(Enum):
FACTORY_RESET = 51
PATH_DISCOVERY = 52
SET_FLOOD_SCOPE = 54
SEND_CONTROL_DATA = 55
# Push notifications
ADVERTISEMENT = 0x80
@ -51,3 +56,4 @@ class PacketType(Enum):
TELEMETRY_RESPONSE = 0x8B
BINARY_RESPONSE = 0x8C
PATH_DISCOVERY_RESPONSE = 0x8D
CONTROL_DATA = 0x8E

View file

@ -4,7 +4,7 @@ import time
import io
from typing import Any, Dict
from .events import Event, EventType, EventDispatcher
from .packets import BinaryReqType, PacketType
from .packets import BinaryReqType, PacketType, ControlType
from .parsing import lpp_parse, lpp_parse_mma, parse_acl, parse_status
from cayennelpp import LppFrame, LppData
from meshcore.lpp_json_encoder import lpp_json_encoder
@ -331,8 +331,8 @@ class MessageReader:
elif packet_type_value == PacketType.RAW_DATA.value:
res = {}
res["SNR"] = dbuf.read(1)[0] / 4
res["RSSI"] = dbuf.read(1)[0]
res["SNR"] = int.from_bytes(dbuf.read(1), byteorder="little", signed=True) / 4
res["RSSI"] = int.from_bytes(dbuf.read(1), byteorder="little", signed=True)
res["payload"] = dbuf.read(4).hex()
logger.debug("Received raw data")
print(res)
@ -593,6 +593,43 @@ class MessageReader:
res = {"reason": "private_key_export_disabled"}
await self.dispatcher.dispatch(Event(EventType.DISABLED, res))
elif packet_type_value == PacketType.CONTROL_DATA.value:
logger.debug("Received control data packet")
res={}
res["SNR"] = int.from_bytes(dbuf.read(1), byteorder="little", signed=True) / 4
res["RSSI"] = int.from_bytes(dbuf.read(1), byteorder="little", signed=True)
res["path_len"] = dbuf.read(1)[0]
payload = dbuf.read()
payload_type = payload[0]
res["payload_type"] = payload_type
res["payload"] = payload
attributes = {"payload_type": payload_type}
await self.dispatcher.dispatch(
Event(EventType.CONTROL_DATA, res, attributes)
)
# decode NODE_DISCOVER_RESP
if payload_type & 0xF0 == ControlType.NODE_DISCOVER_RESP.value:
pbuf = io.BytesIO(payload[1:])
ndr = dict(res)
del ndr["payload_type"]
del ndr["payload"]
ndr["node_type"] = payload_type & 0x0F
ndr["SNR_in"] = int.from_bytes(pbuf.read(1), byteorder="little", signed=True)/4
ndr["tag"] = pbuf.read(4).hex()
ndr["pubkey"] = pbuf.read(32).hex()
attributes = {
"node_type" : ndr["node_type"],
"tag" : ndr["tag"],
"pubkey" : ndr["pubkey"],
}
await self.dispatcher.dispatch(
Event(EventType.DISCOVER_RESPONSE, ndr, attributes)
)
else:
logger.debug(f"Unhandled data received {data}")
logger.debug(f"Unhandled packet type: {packet_type_value}")