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 .contact import ContactCommands
from .device import DeviceCommands from .device import DeviceCommands
from .messaging import MessagingCommands from .messaging import MessagingCommands
from .control_data import ControlDataCommandHandler
class CommandHandler( class CommandHandler(
DeviceCommands, ContactCommands, MessagingCommands, BinaryCommandHandler DeviceCommands,
ContactCommands,
MessagingCommands,
BinaryCommandHandler,
ControlDataCommandHandler
): ):
pass 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" PATH_RESPONSE = "path_response"
PRIVATE_KEY = "private_key" PRIVATE_KEY = "private_key"
DISABLED = "disabled" DISABLED = "disabled"
CONTROL_DATA = "control_data"
DISCOVER_RESPONSE = "discover_response"
# Command response types # Command response types
OK = "command_ok" OK = "command_ok"

View File

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

View File

@@ -4,7 +4,7 @@ import time
import io import io
from typing import Any, Dict from typing import Any, Dict
from .events import Event, EventType, EventDispatcher 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 .parsing import lpp_parse, lpp_parse_mma, parse_acl, parse_status
from cayennelpp import LppFrame, LppData from cayennelpp import LppFrame, LppData
from meshcore.lpp_json_encoder import lpp_json_encoder from meshcore.lpp_json_encoder import lpp_json_encoder
@@ -331,8 +331,8 @@ class MessageReader:
elif packet_type_value == PacketType.RAW_DATA.value: elif packet_type_value == PacketType.RAW_DATA.value:
res = {} res = {}
res["SNR"] = dbuf.read(1)[0] / 4 res["SNR"] = int.from_bytes(dbuf.read(1), byteorder="little", signed=True) / 4
res["RSSI"] = dbuf.read(1)[0] res["RSSI"] = int.from_bytes(dbuf.read(1), byteorder="little", signed=True)
res["payload"] = dbuf.read(4).hex() res["payload"] = dbuf.read(4).hex()
logger.debug("Received raw data") logger.debug("Received raw data")
print(res) print(res)
@@ -593,6 +593,43 @@ class MessageReader:
res = {"reason": "private_key_export_disabled"} res = {"reason": "private_key_export_disabled"}
await self.dispatcher.dispatch(Event(EventType.DISABLED, res)) 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: else:
logger.debug(f"Unhandled data received {data}") logger.debug(f"Unhandled data received {data}")
logger.debug(f"Unhandled packet type: {packet_type_value}") logger.debug(f"Unhandled packet type: {packet_type_value}")