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.
Files changed (82) hide show
  1. {meshcore-2.3.10 → meshcore-2.3.12}/PKG-INFO +1 -1
  2. {meshcore-2.3.10 → meshcore-2.3.12}/pyproject.toml +1 -1
  3. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/device.py +5 -2
  4. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/messaging.py +16 -17
  5. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/meshcore.py +18 -3
  6. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/serial_cx.py +5 -3
  7. {meshcore-2.3.10 → meshcore-2.3.12}/.github/funding.yml +0 -0
  8. {meshcore-2.3.10 → meshcore-2.3.12}/.github/python-test.yml +0 -0
  9. {meshcore-2.3.10 → meshcore-2.3.12}/.gitignore +0 -0
  10. {meshcore-2.3.10 → meshcore-2.3.12}/LICENSE +0 -0
  11. {meshcore-2.3.10 → meshcore-2.3.12}/README.md +0 -0
  12. {meshcore-2.3.10 → meshcore-2.3.12}/examples/.pubsub_example.py.swp +0 -0
  13. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_chat.py +0 -0
  14. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_pin_pairing_example.py +0 -0
  15. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_private_key_export.py +0 -0
  16. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_sign_example.py +0 -0
  17. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_stats.py +0 -0
  18. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_chan_msg.py +0 -0
  19. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_custom_vars.py +0 -0
  20. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_infos.py +0 -0
  21. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_msg.py +0 -0
  22. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_msg_retries.py +0 -0
  23. {meshcore-2.3.10 → meshcore-2.3.12}/examples/ble_t1000_set_cv.py +0 -0
  24. {meshcore-2.3.10 → meshcore-2.3.12}/examples/chan_recv_with_path.py +0 -0
  25. {meshcore-2.3.10 → meshcore-2.3.12}/examples/connection_events_example.py +0 -0
  26. {meshcore-2.3.10 → meshcore-2.3.12}/examples/mepo_mc_gps.py +0 -0
  27. {meshcore-2.3.10 → meshcore-2.3.12}/examples/pubsub_example.py +0 -0
  28. {meshcore-2.3.10 → meshcore-2.3.12}/examples/rf_packet_monitor.py +0 -0
  29. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_battery_monitor.py +0 -0
  30. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_channel_manager.py +0 -0
  31. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_chat.py +0 -0
  32. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_contacts.py +0 -0
  33. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_infos.py +0 -0
  34. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_meshcore_ollama.py +0 -0
  35. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_msg.py +0 -0
  36. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_pingbot.py +0 -0
  37. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_repeater_status.py +0 -0
  38. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_repeater_telemetry.py +0 -0
  39. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_rss_bot.py +0 -0
  40. {meshcore-2.3.10 → meshcore-2.3.12}/examples/serial_trace.py +0 -0
  41. {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_chat.py +0 -0
  42. {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_login_status.py +0 -0
  43. {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_mchome_contacts.py +0 -0
  44. {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_mchome_infos.py +0 -0
  45. {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_mchome_msg.py +0 -0
  46. {meshcore-2.3.10 → meshcore-2.3.12}/examples/tcp_mchome_readmsgs.py +0 -0
  47. {meshcore-2.3.10 → meshcore-2.3.12}/pytest.ini +0 -0
  48. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/__init__.py +0 -0
  49. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/ble_cx.py +0 -0
  50. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/__init__.py +0 -0
  51. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/base.py +0 -0
  52. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/binary.py +0 -0
  53. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/contact.py +0 -0
  54. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/commands/control_data.py +0 -0
  55. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/connection_manager.py +0 -0
  56. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/events.py +0 -0
  57. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/lpp_json_encoder.py +0 -0
  58. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/meshcore_parser.py +0 -0
  59. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/packets.py +0 -0
  60. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/parsing.py +0 -0
  61. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/reader.py +0 -0
  62. {meshcore-2.3.10 → meshcore-2.3.12}/src/meshcore/tcp_cx.py +0 -0
  63. {meshcore-2.3.10 → meshcore-2.3.12}/tests/README.md +0 -0
  64. {meshcore-2.3.10 → meshcore-2.3.12}/tests/test_ble_connection.py +0 -0
  65. {meshcore-2.3.10 → meshcore-2.3.12}/tests/test_ble_pin_pairing.py +0 -0
  66. {meshcore-2.3.10 → meshcore-2.3.12}/tests/test_meshcore_ble_pin.py +0 -0
  67. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_asyncio_lifecycle.py +0 -0
  68. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_ble_reconnect_cleanup.py +0 -0
  69. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_commands.py +0 -0
  70. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_connection_manager.py +0 -0
  71. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_error_handling.py +0 -0
  72. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_events.py +0 -0
  73. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_lpp_parsing.py +0 -0
  74. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_parse_status.py +0 -0
  75. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_path_discovery_response.py +0 -0
  76. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_private_key_export.py +0 -0
  77. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_protocol_surface_gaps.py +0 -0
  78. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_reader.py +0 -0
  79. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_rxlog_keyerror_regression.py +0 -0
  80. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_serial_connection.py +0 -0
  81. {meshcore-2.3.10 → meshcore-2.3.12}/tests/unit/test_standalone_fixes.py +0 -0
  82. {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.10
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "meshcore"
7
- version = "2.3.10"
7
+ version = "2.3.12"
8
8
  authors = [
9
9
  { name="Florent de Lamotte", email="florent@frizoncorrea.fr" },
10
10
  { name="Alex Wolden", email="awolden@gmail.com" },
@@ -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
- return await self.send(b1, [EventType.SELF_INFO, EventType.ERROR])
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
- if not contact is None :
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
- timeout = result.payload["suggested_timeout"] / 1000 * 1.2 if timeout==0 else timeout
165
- timeout = timeout if timeout > min_timeout else min_timeout
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=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 = False # Deassert DTR to avoid serial-open reset/handshake issues
45
- transport.serial.rts = False # You can manipulate Serial object via transport
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