meshcore 2.3.8__tar.gz → 2.3.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {meshcore-2.3.8 → meshcore-2.3.9}/PKG-INFO +4 -2
- {meshcore-2.3.8 → meshcore-2.3.9}/README.md +2 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/pyproject.toml +1 -1
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/commands/device.py +17 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/commands/messaging.py +19 -10
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/events.py +1 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/packets.py +16 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/reader.py +5 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/.github/funding.yml +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/.github/python-test.yml +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/.gitignore +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/LICENSE +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/.pubsub_example.py.swp +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_chat.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_pin_pairing_example.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_private_key_export.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_sign_example.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_stats.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_t1000_chan_msg.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_t1000_custom_vars.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_t1000_infos.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_t1000_msg.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_t1000_msg_retries.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/ble_t1000_set_cv.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/chan_recv_with_path.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/connection_events_example.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/mepo_mc_gps.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/pubsub_example.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/rf_packet_monitor.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_battery_monitor.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_channel_manager.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_chat.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_contacts.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_infos.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_meshcore_ollama.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_msg.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_pingbot.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_repeater_status.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_repeater_telemetry.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_rss_bot.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/serial_trace.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/tcp_chat.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/tcp_login_status.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/tcp_mchome_contacts.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/tcp_mchome_infos.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/tcp_mchome_msg.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/examples/tcp_mchome_readmsgs.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/pytest.ini +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/__init__.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/ble_cx.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/commands/__init__.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/commands/base.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/commands/binary.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/commands/contact.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/commands/control_data.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/connection_manager.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/lpp_json_encoder.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/meshcore.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/meshcore_parser.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/parsing.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/serial_cx.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/src/meshcore/tcp_cx.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/README.md +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/test_ble_connection.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/test_ble_pin_pairing.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/test_meshcore_ble_pin.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_asyncio_lifecycle.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_commands.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_connection_manager.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_error_handling.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_events.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_lpp_parsing.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_parse_status.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_path_discovery_response.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_private_key_export.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_protocol_surface_gaps.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_reader.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_serial_connection.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_standalone_fixes.py +0 -0
- {meshcore-2.3.8 → meshcore-2.3.9}/tests/unit/test_transport_symmetry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: meshcore
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.9
|
|
4
4
|
Summary: Base classes for communicating with meshcore companion radios
|
|
5
5
|
Project-URL: Homepage, https://github.com/fdlamotte/meshcore_py
|
|
6
6
|
Project-URL: Issues, https://github.com/fdlamotte/meshcore_py/issues
|
|
@@ -541,6 +541,8 @@ All commands are async methods that return `Event` objects. Commands are organiz
|
|
|
541
541
|
| **Device Actions** ||||
|
|
542
542
|
| `send_advert(flood=False)` | `flood: bool` | `OK` | Send advertisement (optionally flood network) |
|
|
543
543
|
| `reboot()` | None | None | Reboot device (no response expected) |
|
|
544
|
+
| `run_cli_command()` | `cmd: str` | `CLI_REPLY/ERROR` | Send a cli command to device |
|
|
545
|
+
| `send_raw_packet()` | `data: str/bytes, priority=0` | `OK/ERROR` | Send a raw packet through device, can be an hex string or bytes |
|
|
544
546
|
| **Security** ||||
|
|
545
547
|
| `export_private_key()` | None | `PRIVATE_KEY/DISABLED` | Export device private key (requires PIN auth & enabled firmware) |
|
|
546
548
|
| `import_private_key(key)` | `key: bytes` | `OK` | Import private key to device |
|
|
@@ -518,6 +518,8 @@ All commands are async methods that return `Event` objects. Commands are organiz
|
|
|
518
518
|
| **Device Actions** ||||
|
|
519
519
|
| `send_advert(flood=False)` | `flood: bool` | `OK` | Send advertisement (optionally flood network) |
|
|
520
520
|
| `reboot()` | None | None | Reboot device (no response expected) |
|
|
521
|
+
| `run_cli_command()` | `cmd: str` | `CLI_REPLY/ERROR` | Send a cli command to device |
|
|
522
|
+
| `send_raw_packet()` | `data: str/bytes, priority=0` | `OK/ERROR` | Send a raw packet through device, can be an hex string or bytes |
|
|
521
523
|
| **Security** ||||
|
|
522
524
|
| `export_private_key()` | None | `PRIVATE_KEY/DISABLED` | Export device private key (requires PIN auth & enabled firmware) |
|
|
523
525
|
| `import_private_key(key)` | `key: bytes` | `OK` | Import private key to device |
|
|
@@ -20,6 +20,23 @@ class DeviceCommands(CommandHandlerBase):
|
|
|
20
20
|
logger.debug("Sending device query command")
|
|
21
21
|
return await self.send(b"\x16\x03", [EventType.DEVICE_INFO, EventType.ERROR])
|
|
22
22
|
|
|
23
|
+
async def run_cli_command(self, cmd: str) -> Event:
|
|
24
|
+
logger.debug(f"Sending cli command: {cmd}")
|
|
25
|
+
cmd_data = bytearray([CommandType.RUN_CLI_COMMAND.value])
|
|
26
|
+
cmd_data.extend(cmd.encode("utf-8"))
|
|
27
|
+
return await self.send(cmd_data, [EventType.CLI_REPLY, EventType.ERROR])
|
|
28
|
+
|
|
29
|
+
async def send_raw_packet(self, data, priority=0):
|
|
30
|
+
if isinstance(data, str): # got a string (assuming hex), change it to bytes
|
|
31
|
+
data=bytes.fromhex(data)
|
|
32
|
+
|
|
33
|
+
cmd_data = bytearray([CommandType.SEND_RAW_PACKET.value])
|
|
34
|
+
cmd_data.append(priority)
|
|
35
|
+
cmd_data.extend(data)
|
|
36
|
+
|
|
37
|
+
logger.debug(f"Sending raw packet {data.hex()}")
|
|
38
|
+
return await self.send(cmd_data, [EventType.OK, EventType.ERROR])
|
|
39
|
+
|
|
23
40
|
async def send_advert(self, flood: bool = False) -> Event:
|
|
24
41
|
logger.debug(f"Sending advertisement command (flood={flood})")
|
|
25
42
|
if flood:
|
|
@@ -4,7 +4,7 @@ from typing import Optional, Union
|
|
|
4
4
|
from hashlib import sha256
|
|
5
5
|
|
|
6
6
|
from ..events import Event, EventType
|
|
7
|
-
from ..packets import CommandType
|
|
7
|
+
from ..packets import CommandType, TxtType, AdvType
|
|
8
8
|
from .base import CommandHandlerBase, DestinationType, _validate_destination
|
|
9
9
|
|
|
10
10
|
logger = logging.getLogger("meshcore")
|
|
@@ -61,23 +61,32 @@ class MessagingCommands(CommandHandlerBase):
|
|
|
61
61
|
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])
|
|
62
62
|
|
|
63
63
|
async def send_cmd(
|
|
64
|
-
self, dst: DestinationType, cmd: str, timestamp: Optional[int] = None
|
|
64
|
+
self, dst: DestinationType, cmd: str, timestamp: Optional[int] = None,
|
|
65
|
+
dst_type = None # if None, will have to get a contact to know this
|
|
65
66
|
) -> Event:
|
|
66
67
|
dst_bytes = _validate_destination(dst)
|
|
67
68
|
logger.debug(f"Sending command to {dst_bytes.hex()}: {cmd}")
|
|
68
69
|
|
|
69
70
|
if timestamp is None:
|
|
70
71
|
import time
|
|
71
|
-
|
|
72
72
|
timestamp = int(time.time())
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
if dst_type is None:
|
|
75
|
+
dst_type = dst["type"]
|
|
76
|
+
else: # assume destination is a repeater
|
|
77
|
+
logger.warning("Can't determine destination type, please ensure contacts first or specify dst_type when calling `send_cmd`. Assuming it's a repeater.")
|
|
78
|
+
dst_type = AdvType.REPEATER.value
|
|
79
|
+
|
|
80
|
+
cmd_data = bytearray([CommandType.SEND_TXT_MSG.value])
|
|
81
|
+
if dst_type == AdvType.REPEATER.value :
|
|
82
|
+
cmd_data.append(TxtType.CLI_DATA.value)
|
|
83
|
+
else:
|
|
84
|
+
cmd_data.append(TxtType.CLI_CMD.value)
|
|
85
|
+
cmd_data.append(0) # first and only attempt
|
|
86
|
+
cmd_data.extend(timestamp.to_bytes(4, "little"))
|
|
87
|
+
cmd_data.extend(dst_bytes)
|
|
88
|
+
cmd_data.extend(cmd.encode("utf-8"))
|
|
89
|
+
return await self.send(cmd_data, [EventType.MSG_SENT, EventType.ERROR])
|
|
81
90
|
|
|
82
91
|
async def send_msg(
|
|
83
92
|
self, dst: DestinationType, msg: str, timestamp: Optional[int] = None,
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
|
+
class AdvType(Enum):
|
|
4
|
+
NONE = 0x00
|
|
5
|
+
CHAT = 0x01
|
|
6
|
+
REPEATER = 0x02
|
|
7
|
+
ROOM = 0x03
|
|
8
|
+
SENSOR = 0x04
|
|
9
|
+
|
|
10
|
+
class TxtType(Enum):
|
|
11
|
+
PLAIN = 0x00
|
|
12
|
+
CLI_DATA = 0x01
|
|
13
|
+
SIGNED_PLAIN = 0x02
|
|
14
|
+
CLI_CMD = 0x03
|
|
15
|
+
|
|
3
16
|
class AnonReqType(Enum):
|
|
4
17
|
REGIONS = 0x01
|
|
5
18
|
OWNER = 0x02
|
|
@@ -75,6 +88,8 @@ class CommandType(Enum):
|
|
|
75
88
|
SET_PATH_HASH_MODE = 61
|
|
76
89
|
SET_DEFAULT_FLOOD_SCOPE = 63
|
|
77
90
|
GET_DEFAULT_FLOOD_SCOPE = 64
|
|
91
|
+
SEND_RAW_PACKET = 65
|
|
92
|
+
RUN_CLI_COMMAND = 66
|
|
78
93
|
|
|
79
94
|
# Packet prefixes for the protocol
|
|
80
95
|
class PacketType(Enum):
|
|
@@ -107,6 +122,7 @@ class PacketType(Enum):
|
|
|
107
122
|
ALLOWED_REPEAT_FREQ = 26
|
|
108
123
|
CHANNEL_DATA_RECV = 27
|
|
109
124
|
DEFAULT_FLOOD_SCOPE = 28
|
|
125
|
+
CLI_REPLY = 29
|
|
110
126
|
|
|
111
127
|
# Push notifications
|
|
112
128
|
ADVERTISEMENT = 0x80
|
|
@@ -1052,6 +1052,11 @@ class MessageReader:
|
|
|
1052
1052
|
res = {"rx_delay": rx_delay, "airtime_factor": airtime_factor}
|
|
1053
1053
|
await self.dispatcher.dispatch(Event(EventType.TUNING_PARAMS, res))
|
|
1054
1054
|
|
|
1055
|
+
elif packet_type_value == PacketType.CLI_REPLY.value:
|
|
1056
|
+
res = {}
|
|
1057
|
+
res["text"] = data[1:].decode("utf-8", "ignore")
|
|
1058
|
+
await self.dispatcher.dispatch(Event(EventType.CLI_REPLY, res))
|
|
1059
|
+
|
|
1055
1060
|
else:
|
|
1056
1061
|
logger.debug(f"Unhandled data received {data}")
|
|
1057
1062
|
logger.debug(f"Unhandled packet type: {packet_type_value}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|