meshcore 2.3.10__tar.gz → 2.3.12__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.10 → meshcore-2.3.12}/PKG-INFO +1 -1
- {meshcore-2.3.10 → meshcore-2.3.12}/pyproject.toml +1 -1
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/device.py +5 -2
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/messaging.py +16 -17
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/meshcore.py +18 -3
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/serial_cx.py +5 -3
- {meshcore-2.3.10 → meshcore-2.3.12}/.github/funding.yml +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/.github/python-test.yml +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/.gitignore +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/LICENSE +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/README.md +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/.pubsub_example.py.swp +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_chat.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_pin_pairing_example.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_private_key_export.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_sign_example.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_stats.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_chan_msg.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_custom_vars.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_infos.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_msg.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_msg_retries.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_set_cv.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/chan_recv_with_path.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/connection_events_example.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/mepo_mc_gps.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/pubsub_example.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/rf_packet_monitor.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_battery_monitor.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_channel_manager.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_chat.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_contacts.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_infos.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_meshcore_ollama.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_msg.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_pingbot.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_repeater_status.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_repeater_telemetry.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_rss_bot.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_trace.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_chat.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_login_status.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_mchome_contacts.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_mchome_infos.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_mchome_msg.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_mchome_readmsgs.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/pytest.ini +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/__init__.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/ble_cx.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/__init__.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/base.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/binary.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/contact.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/control_data.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/connection_manager.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/events.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/lpp_json_encoder.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/meshcore_parser.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/packets.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/parsing.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/reader.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/tcp_cx.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/README.md +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/test_ble_connection.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/test_ble_pin_pairing.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/test_meshcore_ble_pin.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_asyncio_lifecycle.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_ble_reconnect_cleanup.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_commands.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_connection_manager.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_error_handling.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_events.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_lpp_parsing.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_parse_status.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_path_discovery_response.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_private_key_export.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_protocol_surface_gaps.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_reader.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_rxlog_keyerror_regression.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_serial_connection.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_standalone_fixes.py +0 -0
- {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_transport_symmetry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: meshcore
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.12
|
|
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
|
|
@@ -11,10 +11,13 @@ logger = logging.getLogger("meshcore")
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class DeviceCommands(CommandHandlerBase):
|
|
14
|
-
async def send_appstart(self) -> Event:
|
|
14
|
+
async def send_appstart(self, timeout=None) -> Event:
|
|
15
15
|
logger.debug("Sending appstart command")
|
|
16
16
|
b1 = bytearray(b"\x01\x03 mccli")
|
|
17
|
-
|
|
17
|
+
if timeout is None:
|
|
18
|
+
return await self.send(b1, [EventType.SELF_INFO, EventType.ERROR])
|
|
19
|
+
else:
|
|
20
|
+
return await self.send(b1, [EventType.SELF_INFO, EventType.ERROR], timeout=timeout)
|
|
18
21
|
|
|
19
22
|
async def send_device_query(self) -> Event:
|
|
20
23
|
logger.debug("Sending device query command")
|
|
@@ -114,31 +114,29 @@ class MessagingCommands(CommandHandlerBase):
|
|
|
114
114
|
max_attempts=3, max_flood_attempts=2, flood_after=2, timeout=0, min_timeout=0
|
|
115
115
|
) -> Event:
|
|
116
116
|
|
|
117
|
+
# try to get a 32 bytes key (for flood reset), fallback to 6
|
|
117
118
|
try:
|
|
118
119
|
dst_bytes = _validate_destination(dst, prefix_length=32)
|
|
119
|
-
# with 32 bytes we can reset to flood
|
|
120
120
|
except ValueError:
|
|
121
|
-
# but if we can't, we'll assume we're flood
|
|
122
121
|
dst_bytes = _validate_destination(dst, prefix_length=6)
|
|
123
122
|
contact = self._get_contact_by_prefix(dst_bytes.hex())
|
|
123
|
+
if not contact is None and len(dst_bytes) < 32 :
|
|
124
|
+
# if we have a contact then we can get full key
|
|
125
|
+
dst_bytes = _validate_destination(contact, prefix_length=32)
|
|
124
126
|
|
|
125
127
|
attempts = 0
|
|
126
128
|
flood_attempts = 0
|
|
127
|
-
|
|
128
|
-
flood = contact["out_path_len"] == -1
|
|
129
|
-
if len(dst_bytes) < 32:
|
|
130
|
-
# if we have a contact, then we can get a 32 bytes key !
|
|
131
|
-
dst_bytes = _validate_destination(contact, prefix_length=32)
|
|
132
|
-
else:
|
|
133
|
-
# we can't know if we're flood without fetching all contacts
|
|
134
|
-
# if we have a full key (meaning we can reset path) consider direct
|
|
135
|
-
# else consider flood
|
|
136
|
-
flood = len(dst_bytes) < 32
|
|
137
|
-
logger.info(f"send_msg_with_retry: can't determine if flood, assume {flood}")
|
|
129
|
+
flood = False # by default consider we sent direct (will be overriden after send)
|
|
138
130
|
res = None
|
|
139
131
|
while attempts < max_attempts and res is None \
|
|
140
132
|
and (not flood or flood_attempts < max_flood_attempts):
|
|
141
|
-
if attempts == flood_after and not flood: # change path to flood
|
|
133
|
+
if attempts == flood_after and not flood : # change path to flood
|
|
134
|
+
if len(dst_bytes) < 32: # can only reset with full key
|
|
135
|
+
logger.info("Don't have full key, retreiving contacts so we can reset path")
|
|
136
|
+
await self.get_contacts()
|
|
137
|
+
contact = self._get_contact_by_prefix(dst_bytes.hex())
|
|
138
|
+
if not contact is None:
|
|
139
|
+
dst_bytes = _validate_destination(contact, prefix_length=32)
|
|
142
140
|
logger.info("Resetting path")
|
|
143
141
|
rp_res = await self.reset_path(dst_bytes)
|
|
144
142
|
if rp_res.type == EventType.ERROR:
|
|
@@ -160,12 +158,13 @@ class MessagingCommands(CommandHandlerBase):
|
|
|
160
158
|
flood_attempts += 1
|
|
161
159
|
continue
|
|
162
160
|
|
|
161
|
+
flood = result.payload["type"] == 1 # we can sync flood flag from result ...
|
|
163
162
|
exp_ack = result.payload["expected_ack"].hex()
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
atimeout = result.payload["suggested_timeout"] / 1000 * 1.2 if timeout==0 else timeout
|
|
164
|
+
atimeout = atimeout if atimeout > min_timeout else min_timeout
|
|
166
165
|
res = await self.dispatcher.wait_for_event(EventType.ACK,
|
|
167
166
|
attribute_filters={"code": exp_ack},
|
|
168
|
-
timeout=
|
|
167
|
+
timeout=atimeout)
|
|
169
168
|
|
|
170
169
|
attempts = attempts + 1
|
|
171
170
|
if flood :
|
|
@@ -118,9 +118,11 @@ class MeshCore:
|
|
|
118
118
|
auto_reconnect: bool = False,
|
|
119
119
|
max_reconnect_attempts: int = 3,
|
|
120
120
|
cx_dly: float = 0.1,
|
|
121
|
+
rts = False,
|
|
122
|
+
dtr = True
|
|
121
123
|
) -> "MeshCore":
|
|
122
124
|
"""Create and connect a MeshCore instance using serial connection"""
|
|
123
|
-
connection = SerialConnection(port, baudrate, cx_dly=cx_dly)
|
|
125
|
+
connection = SerialConnection(port, baudrate, cx_dly=cx_dly, rts=rts, dtr=dtr)
|
|
124
126
|
|
|
125
127
|
mc = cls(
|
|
126
128
|
connection,
|
|
@@ -131,6 +133,19 @@ class MeshCore:
|
|
|
131
133
|
max_reconnect_attempts=max_reconnect_attempts,
|
|
132
134
|
)
|
|
133
135
|
res = await mc.connect()
|
|
136
|
+
if res is None:
|
|
137
|
+
logger.info("No response from meshcore node, trying to invert dtr")
|
|
138
|
+
await mc.disconnect()
|
|
139
|
+
connection = SerialConnection(port, baudrate, cx_dly=cx_dly, rts=rts, dtr=not dtr)
|
|
140
|
+
mc = cls(
|
|
141
|
+
connection,
|
|
142
|
+
debug=debug,
|
|
143
|
+
only_error=only_error,
|
|
144
|
+
default_timeout=default_timeout,
|
|
145
|
+
auto_reconnect=auto_reconnect,
|
|
146
|
+
max_reconnect_attempts=max_reconnect_attempts,
|
|
147
|
+
)
|
|
148
|
+
res = await mc.connect()
|
|
134
149
|
if res is None:
|
|
135
150
|
logger.error("No response from meshcore node, disconnecting")
|
|
136
151
|
logger.error("Are you sure your node is a serial companion ?")
|
|
@@ -188,7 +203,7 @@ class MeshCore:
|
|
|
188
203
|
to initialize the session. MeshCore.connect() does this on the initial
|
|
189
204
|
connection; this callback ensures it also happens on reconnects (F02).
|
|
190
205
|
"""
|
|
191
|
-
await self.commands.send_appstart()
|
|
206
|
+
await self.commands.send_appstart(timeout=2)
|
|
192
207
|
|
|
193
208
|
async def connect(self):
|
|
194
209
|
await self.dispatcher.start()
|
|
@@ -196,7 +211,7 @@ class MeshCore:
|
|
|
196
211
|
if result is None:
|
|
197
212
|
await self.dispatcher.stop()
|
|
198
213
|
raise ConnectionError("Failed to connect to device")
|
|
199
|
-
res = await self.commands.send_appstart()
|
|
214
|
+
res = await self.commands.send_appstart(timeout=2)
|
|
200
215
|
if res is None or res.type == EventType.ERROR:
|
|
201
216
|
return None
|
|
202
217
|
return res
|
|
@@ -11,7 +11,7 @@ logger = logging.getLogger("meshcore")
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class SerialConnection:
|
|
14
|
-
def __init__(self, port, baudrate, cx_dly=0.2):
|
|
14
|
+
def __init__(self, port, baudrate, cx_dly=0.2, rts=False, dtr=True):
|
|
15
15
|
self.port = port
|
|
16
16
|
self.baudrate = baudrate
|
|
17
17
|
self.transport = None
|
|
@@ -21,6 +21,8 @@ class SerialConnection:
|
|
|
21
21
|
self.cx_dly = cx_dly
|
|
22
22
|
self._connected_event = asyncio.Event()
|
|
23
23
|
self._background_tasks: set[asyncio.Task] = set()
|
|
24
|
+
self.rts = rts
|
|
25
|
+
self.dtr = dtr
|
|
24
26
|
|
|
25
27
|
self.frame_expected_size = 0
|
|
26
28
|
self.inframe = b""
|
|
@@ -41,8 +43,8 @@ class SerialConnection:
|
|
|
41
43
|
self.cx.transport = transport
|
|
42
44
|
logger.debug('port opened')
|
|
43
45
|
if isinstance(transport, serial_asyncio.SerialTransport) and transport.serial:
|
|
44
|
-
transport.serial.dtr =
|
|
45
|
-
transport.serial.rts =
|
|
46
|
+
transport.serial.dtr = self.cx.dtr # DTR should be deasserted on heltec_v2 to avoid serial-open reset/handshake issues
|
|
47
|
+
transport.serial.rts = self.cx.rts
|
|
46
48
|
self.cx._connected_event.set()
|
|
47
49
|
|
|
48
50
|
def data_received(self, data):
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|