Node API Reference¶
This section documents the node management classes and functions in pyMC_Core.
MeshNode¶
pymc_core.node.node.MeshNode
¶
MeshNode(radio, local_identity, config=None, *, contacts=None, channel_db=None, logger=None, event_service=None)
Represents a node in a mesh network for radio communication.
Manages radio communication, message routing, and protocol handling within a mesh network. Provides high-level APIs for sending messages, telemetry requests, and commands to other nodes and repeaters.
The node integrates with various components like contact storage, channel databases, and event services for comprehensive mesh functionality.
Initialise a mesh network node instance.
Sets up the node's core components including radio interface, identity management, and communication handlers.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
radio
|
Optional[Any]
|
Radio hardware interface for transmission/reception. |
required |
local_identity
|
LocalIdentity
|
Node's cryptographic identity for secure communication. |
required |
config
|
Optional[dict]
|
Optional configuration dictionary with node settings. |
None
|
contacts
|
Optional[Any]
|
Optional contact storage for managing known nodes. |
None
|
channel_db
|
Optional[Any]
|
Optional channel database for group communication. |
None
|
logger
|
Optional[Logger]
|
Optional logger instance; defaults to module logger. |
None
|
event_service
|
Optional[Any]
|
Optional event service for broadcasting mesh events. |
None
|
send_group_text
async
¶
Broadcast a text message to all members of a group.
Sends a group datagram that will be received by all nodes configured for the specified group. Group messages are fire-and-forget with no acknowledgements expected.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
group_name
|
str
|
Name of the group to broadcast to. |
required |
message
|
str
|
Text content to broadcast. |
required |
Returns:
Name | Type | Description |
---|---|---|
dict
|
Dictionary with transmission results and signal metrics. |
|
Note |
dict
|
Group messages don't wait for acknowledgements. |
send_login
async
¶
Authenticate with a repeater node.
Sends login credentials to a repeater and waits for authentication response. Successful login may grant administrative privileges.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
repeater_name
|
str
|
Name of the repeater to authenticate with. |
required |
password
|
str
|
Authentication password for the repeater. |
required |
Returns:
Type | Description |
---|---|
dict
|
Dictionary with login results including success status, |
dict
|
admin privileges, and keep-alive intervals. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If repeater contact not found. |
send_logout
async
¶
Terminate authentication session with a repeater.
Sends a logout command to end the current session with a repeater. This should be called when finished with repeater operations.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
repeater_name
|
str
|
Name of the repeater to logout from. |
required |
Returns:
Type | Description |
---|---|
dict
|
Dictionary with logout results and performance metrics. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If repeater contact not found. |
send_protocol_request
async
¶
Send a protocol-specific request to a repeater.
Transmits a custom protocol request with optional data payload and waits for the repeater's response.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
repeater_name
|
str
|
Name of the repeater to send request to. |
required |
protocol_code
|
int
|
Protocol operation code (0-255). |
required |
data
|
bytes
|
Optional binary data payload for the request. |
b''
|
Returns:
Type | Description |
---|---|
dict
|
Dictionary with protocol response, parsed data, and timing metrics. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If repeater contact or protocol handler not found. |
send_repeater_command
async
¶
Send a text-based command to a repeater and await response.
Transmits a command string to a repeater using the text message protocol and waits for a response. Useful for administrative operations and status queries.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
repeater_name
|
str
|
Name of the repeater to send command to. |
required |
command
|
str
|
Command string to execute on the repeater. |
required |
parameters
|
Optional[str]
|
Optional parameters for the command. |
None
|
Returns:
Type | Description |
---|---|
dict
|
Dictionary with command results, response text, and timing data. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If repeater contact not found. |
send_status_request
async
¶
Request status information from a repeater.
Queries a repeater for its current operational status and configuration. This is a convenience method that uses the text command interface.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
repeater_name
|
str
|
Name of the repeater to query. |
required |
Returns:
Type | Description |
---|---|
dict
|
Dictionary with status information and response metrics. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If repeater contact not found. |
send_telemetry_request
async
¶
send_telemetry_request(contact_name, want_base=True, want_location=True, want_environment=True, timeout=10.0)
Request telemetry data from a contact node.
Sends a telemetry request and waits for the target node to respond with requested sensor data including base metrics, location, and environmental readings.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
contact_name
|
str
|
Name of the contact to query. |
required |
want_base
|
bool
|
Include basic telemetry metrics in request. |
True
|
want_location
|
bool
|
Include GPS/location data in request. |
True
|
want_environment
|
bool
|
Include environmental sensors in request. |
True
|
timeout
|
float
|
Maximum time to wait for response in seconds. |
10.0
|
Returns:
Type | Description |
---|---|
dict
|
Dictionary with request results, telemetry data, and performance |
dict
|
metrics including round-trip time. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If contact not found or protocol handler unavailable. |
send_text
async
¶
Send a text message to a specified contact.
Transmits a text message to another node in the mesh network, with optional routing and retry configuration.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
contact_name
|
str
|
Name of the target contact in the contact book. |
required |
message
|
str
|
Text content to send. |
required |
attempt
|
int
|
Message attempt number for retry logic (default: 1). |
1
|
message_type
|
str
|
Routing type - "direct" or other supported types. |
'direct'
|
out_path
|
Optional[list]
|
Optional list of intermediate nodes for routing. |
None
|
Returns:
Type | Description |
---|---|
dict
|
Dictionary containing transmission results including success status, |
dict
|
signal strength metrics (SNR/RSSI), and routing information. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If the specified contact is not found. |
send_trace_packet
async
¶
Send a diagnostic trace packet for network analysis.
Transmits a trace packet to analyse routing paths and network performance. Always expects a response with trace data, signal metrics, and routing information.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
contact_name
|
str
|
Name of the target contact for tracing. |
required |
tag
|
int
|
Unique identifier for this trace operation. |
required |
auth_code
|
int
|
Authentication code for the trace request. |
required |
flags
|
int
|
Optional flags to modify trace behaviour. |
0
|
path
|
Optional[list]
|
Optional custom routing path for the trace. |
None
|
timeout
|
float
|
Maximum time to wait for trace response. |
5.0
|
Returns:
Type | Description |
---|---|
dict
|
Dictionary with trace results, routing data, and signal metrics. |
Raises:
Type | Description |
---|---|
RuntimeError
|
If contact not found or trace handler unavailable. |
set_event_service
¶
Set the event service for broadcasting mesh events.
start
async
¶
Start the mesh node and begin processing radio communications.
Initialises the radio interface and dispatcher, then enters the main event loop for handling incoming/outgoing messages. This method blocks until the node is stopped.
Note
This is an asynchronous operation that runs indefinitely until cancelled or the node is stopped.
stop
¶
Stop the mesh node and clean up associated services.
Terminates radio communications and shuts down all active handlers. This method is synchronous and should be called to gracefully shut down the node.
Event System¶
pymc_core.node.events
¶
Mesh event system - event service and event definitions
EventService
¶
Generic event broadcasting service for the mesh library. Allows multiple subscribers to listen for different types of events.
EventSubscriber
¶
Bases: ABC
Abstract base class for event subscribers.
handle_event
abstractmethod
async
¶
Handle an event with the given type and data.
MeshEvents
¶
Standard mesh event types for the mesh library.
Packet Handlers¶
Base Handler¶
pymc_core.node.handlers.base
¶
ACK Handler¶
pymc_core.node.handlers.ack
¶
AckHandler
¶
Bases: BaseHandler
ACK handler that processes all ACK variants: 1. Discrete ACK packets (payload type 1) 2. Bundled ACKs in PATH packets 3. Encrypted ACK responses (20-byte PATH packets)
process_discrete_ack
async
¶
Process a discrete ACK packet and return the CRC if valid.
process_path_ack_variants
async
¶
Process PATH packets that may contain ACKs in different forms. Returns CRC if ACK found, None otherwise.
set_ack_received_callback
¶
Set callback to notify dispatcher when ACK is received.
set_dispatcher
¶
Set dispatcher reference for contact lookup and waiting ACKs.
Advert Handler¶
pymc_core.node.handlers.advert
¶
Text Handler¶
pymc_core.node.handlers.text
¶
TextMessageHandler
¶
Bases: BaseHandler
set_command_response_callback
¶
Set callback function for command responses.
Group Text Handler¶
pymc_core.node.handlers.group_text
¶
GroupTextHandler
¶
GroupTextHandler(local_identity, contacts, log_fn, send_packet_fn, channel_db=None, event_service=None, our_node_name=None)
Bases: BaseHandler
__call__
async
¶
Handle incoming group text messages according to the specification.
Login Response Handler¶
pymc_core.node.handlers.login_response
¶
AnonReqResponseHandler
¶
LoginResponseHandler
¶
Bases: BaseHandler
Handles PAYLOAD_TYPE_RESPONSE packets for login authentication responses.
Expected response format from C++ server: - timestamp (4 bytes): Server response timestamp - response_code (1 byte): RESP_SERVER_LOGIN_OK (0x80) for success - keep_alive_interval (1 byte): Recommended keep-alive interval (secs / 16) - is_admin (1 byte): 1 if admin, 0 if guest - reserved (1 byte): Reserved for future use - random_blob (4 bytes): Random data for packet uniqueness
set_login_callback
¶
Set callback to notify when login response is received.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
callback
|
Callable[[bool, dict], None]
|
Function that accepts (success: bool, response_data: dict) |
required |
set_protocol_response_handler
¶
Set protocol response handler for forwarding telemetry responses.
store_login_password
¶
Store password for response decryption by destination hash.
Path Handler¶
pymc_core.node.handlers.path
¶
Path packet handler for mesh network routing.
PathHandler
¶
Handler for PATH packets (payload type 0x08) - "Returned path" packets.
According to the official documentation, PATH packets are used for returning responses through the mesh network along discovered routing paths.
Official Packet Structure: - Header [1B]: Route type (0-1) + Payload type (2-5) + Version (6-7) - Path Length [1B]: Length of the path field - Path [up to 64B]: Routing path data (if applicable) - Payload [up to 184B]: The actual data being transmitted
For PATH packets, the payload typically contains: - [1B] dest_hash: Destination node hash - [1B] src_hash: Source node hash - [2B] MAC: Message Authentication Code (for payload version 0x00) - [NB] encrypted_data: Contains ACK or other response data
Protocol Response Handler¶
pymc_core.node.handlers.protocol_response
¶
Protocol response handler for mesh network protocol requests.
Handles responses to protocol requests (like stats, config, etc.) that come back as PATH packets with encrypted payloads.
ProtocolResponseHandler
¶
Handler for protocol responses that come back as encrypted PATH packets.
This handler specifically deals with responses to protocol requests like: - Protocol 0x01: Get repeater stats - Protocol 0x02: Get configuration - etc.
Trace Handler¶
pymc_core.node.handlers.trace
¶
Trace packet handler for mesh network diagnostics.
Handles trace packets that contain SNR and routing information for network diagnostics and analysis.
TraceHandler
¶
Handler for trace packets (payload type 0x09).
Trace packets are used for network diagnostics and routing analysis. They contain tag, auth_code, flags, and trace path information with SNR data.
def __init__(self):
"""Initialize the packet dispatcher."""
def register_handler(
self,
packet_type: PacketType,
handler: Callable[[Packet], Awaitable[None]]
) -> None:
"""Register a handler for a specific packet type."""
def unregister_handler(self, packet_type: PacketType) -> None:
"""Remove handler for a packet type."""
async def dispatch_packet(self, packet: Packet) -> None:
"""Dispatch packet to registered handler."""
def get_registered_types(self) -> List[PacketType]:
"""Get list of registered packet types."""
```
Event System¶
python
class EventEmitter:
"""Simple event emission system for node events."""
def on(self, event: str, callback: Callable) -> None:
"""Register event callback."""
def off(self, event: str, callback: Callable) -> None:
"""Remove event callback."""
def emit(self, event: str, *args, **kwargs) -> None:
"""Emit an event to all registered callbacks."""
Node Events¶
The mesh node emits the following events:
packet_received
: When a packet is receivedpacket_sent
: When a packet is successfully sentnode_discovered
: When a new node is discoverednode_lost
: When a node becomes unreachablenetwork_error
: When a network error occurs
# Example event handling
node = MeshNode(radio, identity)
@node.on('packet_received')
async def handle_packet(packet: Packet):
print(f"Received packet from {packet.source.hex()[:8]}")
@node.on('node_discovered')
async def handle_discovery(node_id: bytes):
print(f"Discovered node {node_id.hex()[:8]}")
Packet Handlers¶
ACK Handler¶
class AckHandler:
"""Handles acknowledgment packets."""
def __init__(self, node: MeshNode):
"""Initialize ACK handler."""
async def handle_ack(self, packet: Packet) -> None:
"""Process incoming ACK packet."""
Advert Handler¶
class AdvertHandler:
"""Handles node advertisement packets."""
def __init__(self, node: MeshNode):
"""Initialize advert handler."""
async def handle_advert(self, packet: Packet) -> None:
"""Process incoming advertisement."""
def get_known_nodes(self) -> List[bytes]:
"""Get list of known node IDs."""
Text Handler¶
class TextHandler:
"""Handles text message packets."""
def __init__(self, node: MeshNode):
"""Initialize text handler."""
async def handle_text(self, packet: Packet) -> None:
"""Process incoming text message."""
async def send_text(
self,
destination: bytes,
message: str
) -> None:
"""Send a text message to destination."""
Group Text Handler¶
class GroupTextHandler:
"""Handles group text message packets."""
def __init__(self, node: MeshNode):
"""Initialize group text handler."""
async def handle_group_text(self, packet: Packet) -> None:
"""Process incoming group message."""
async def send_group_text(
self,
group_id: bytes,
message: str
) -> None:
"""Send message to group."""
def create_group(self, group_name: str) -> bytes:
"""Create a new message group."""
Node Configuration¶
@dataclass
class NodeConfig:
"""Configuration options for mesh nodes."""
max_hops: int = 16
packet_timeout: float = 30.0
ack_timeout: float = 5.0
retransmit_attempts: int = 3
broadcast_interval: float = 60.0
keep_alive_interval: float = 300.0
Node Statistics¶
@dataclass
class NodeStats:
"""Runtime statistics for a mesh node."""
packets_sent: int = 0
packets_received: int = 0
packets_forwarded: int = 0
acks_sent: int = 0
acks_received: int = 0
retransmits: int = 0
known_nodes: int = 0
uptime: float = 0.0
def reset(self) -> None:
"""Reset all statistics to zero."""
Error Handling¶
class NodeError(Exception):
"""Base exception for node-related errors."""
pass
class NetworkTimeoutError(NodeError):
"""Raised when network operations timeout."""
pass
class InvalidPacketError(NodeError):
"""Raised when an invalid packet is received."""
pass
class RadioError(NodeError):
"""Raised when radio hardware errors occur."""
pass