meshcore 2.2.20__tar.gz → 2.2.22__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 (68) hide show
  1. {meshcore-2.2.20 → meshcore-2.2.22}/PKG-INFO +1 -1
  2. {meshcore-2.2.20 → meshcore-2.2.22}/pyproject.toml +1 -1
  3. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/reader.py +21 -10
  4. {meshcore-2.2.20 → meshcore-2.2.22}/.github/python-test.yml +0 -0
  5. {meshcore-2.2.20 → meshcore-2.2.22}/.gitignore +0 -0
  6. {meshcore-2.2.20 → meshcore-2.2.22}/LICENSE +0 -0
  7. {meshcore-2.2.20 → meshcore-2.2.22}/README.md +0 -0
  8. {meshcore-2.2.20 → meshcore-2.2.22}/examples/.pubsub_example.py.swp +0 -0
  9. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_chat.py +0 -0
  10. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_pin_pairing_example.py +0 -0
  11. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_private_key_export.py +0 -0
  12. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_sign_example.py +0 -0
  13. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_stats.py +0 -0
  14. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_t1000_chan_msg.py +0 -0
  15. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_t1000_custom_vars.py +0 -0
  16. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_t1000_infos.py +0 -0
  17. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_t1000_msg.py +0 -0
  18. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_t1000_msg_retries.py +0 -0
  19. {meshcore-2.2.20 → meshcore-2.2.22}/examples/ble_t1000_set_cv.py +0 -0
  20. {meshcore-2.2.20 → meshcore-2.2.22}/examples/chan_recv_with_path.py +0 -0
  21. {meshcore-2.2.20 → meshcore-2.2.22}/examples/connection_events_example.py +0 -0
  22. {meshcore-2.2.20 → meshcore-2.2.22}/examples/mepo_mc_gps.py +0 -0
  23. {meshcore-2.2.20 → meshcore-2.2.22}/examples/pubsub_example.py +0 -0
  24. {meshcore-2.2.20 → meshcore-2.2.22}/examples/rf_packet_monitor.py +0 -0
  25. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_battery_monitor.py +0 -0
  26. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_channel_manager.py +0 -0
  27. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_chat.py +0 -0
  28. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_contacts.py +0 -0
  29. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_infos.py +0 -0
  30. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_meshcore_ollama.py +0 -0
  31. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_msg.py +0 -0
  32. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_pingbot.py +0 -0
  33. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_repeater_status.py +0 -0
  34. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_repeater_telemetry.py +0 -0
  35. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_rss_bot.py +0 -0
  36. {meshcore-2.2.20 → meshcore-2.2.22}/examples/serial_trace.py +0 -0
  37. {meshcore-2.2.20 → meshcore-2.2.22}/examples/tcp_chat.py +0 -0
  38. {meshcore-2.2.20 → meshcore-2.2.22}/examples/tcp_login_status.py +0 -0
  39. {meshcore-2.2.20 → meshcore-2.2.22}/examples/tcp_mchome_contacts.py +0 -0
  40. {meshcore-2.2.20 → meshcore-2.2.22}/examples/tcp_mchome_infos.py +0 -0
  41. {meshcore-2.2.20 → meshcore-2.2.22}/examples/tcp_mchome_msg.py +0 -0
  42. {meshcore-2.2.20 → meshcore-2.2.22}/examples/tcp_mchome_readmsgs.py +0 -0
  43. {meshcore-2.2.20 → meshcore-2.2.22}/pytest.ini +0 -0
  44. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/__init__.py +0 -0
  45. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/ble_cx.py +0 -0
  46. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/commands/__init__.py +0 -0
  47. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/commands/base.py +0 -0
  48. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/commands/binary.py +0 -0
  49. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/commands/contact.py +0 -0
  50. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/commands/control_data.py +0 -0
  51. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/commands/device.py +0 -0
  52. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/commands/messaging.py +0 -0
  53. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/connection_manager.py +0 -0
  54. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/events.py +0 -0
  55. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/lpp_json_encoder.py +0 -0
  56. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/meshcore.py +0 -0
  57. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/packets.py +0 -0
  58. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/parsing.py +0 -0
  59. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/serial_cx.py +0 -0
  60. {meshcore-2.2.20 → meshcore-2.2.22}/src/meshcore/tcp_cx.py +0 -0
  61. {meshcore-2.2.20 → meshcore-2.2.22}/tests/README.md +0 -0
  62. {meshcore-2.2.20 → meshcore-2.2.22}/tests/test_ble_connection.py +0 -0
  63. {meshcore-2.2.20 → meshcore-2.2.22}/tests/test_ble_pin_pairing.py +0 -0
  64. {meshcore-2.2.20 → meshcore-2.2.22}/tests/test_meshcore_ble_pin.py +0 -0
  65. {meshcore-2.2.20 → meshcore-2.2.22}/tests/unit/test_commands.py +0 -0
  66. {meshcore-2.2.20 → meshcore-2.2.22}/tests/unit/test_events.py +0 -0
  67. {meshcore-2.2.20 → meshcore-2.2.22}/tests/unit/test_private_key_export.py +0 -0
  68. {meshcore-2.2.20 → meshcore-2.2.22}/tests/unit/test_reader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcore
3
- Version: 2.2.20
3
+ Version: 2.2.22
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.2.20"
7
+ version = "2.2.22"
8
8
  authors = [
9
9
  { name="Florent de Lamotte", email="florent@frizoncorrea.fr" },
10
10
  { name="Alex Wolden", email="awolden@gmail.com" },
@@ -29,7 +29,7 @@ class MessageReader:
29
29
  # Track pending binary requests by tag for proper response parsing
30
30
  self.pending_binary_requests: Dict[str, Dict[str, Any]] = {} # tag -> {request_type, expires_at}
31
31
 
32
- self.channels = [{} for _ in range(20)] # keep our own copy of channels, 20 elements by default
32
+ self.channels = [{} for _ in range(40)] # keep our own copy of channels, 40 elements by default
33
33
  self.decrypt_channels = True
34
34
  self.channels_log = [] # stores the channel msg events
35
35
 
@@ -219,12 +219,12 @@ class MessageReader:
219
219
  res["channel_idx"] = dbuf.read(1)[0]
220
220
  res["path_len"] = dbuf.read(1)[0]
221
221
  res["txt_type"] = dbuf.read(1)[0]
222
- res["sender_timestamp"] = int.from_bytes(dbuf.read(4), byteorder="little")
222
+ res["sender_timestamp"] = int.from_bytes(dbuf.read(4), byteorder="little", signed=False)
223
223
  text = dbuf.read().strip(b"\0")
224
224
  res["text"] = text.decode("utf-8", "ignore")
225
225
 
226
226
  # search for text in log_channels
227
- txt_hash = int.from_bytes(SHA256.new(text).digest()[0:4], "little", signed=False)
227
+ txt_hash = int.from_bytes(SHA256.new(res["sender_timestamp"].to_bytes(4, "little", signed=False)+text).digest()[0:4], "little", signed=False)
228
228
  if self.decrypt_channels:
229
229
  logged = next((l for l in reversed(self.channels_log) if 'msg_hash' in l and l['msg_hash'] == txt_hash), None)
230
230
  if not logged is None:
@@ -232,6 +232,7 @@ class MessageReader:
232
232
  res["RSSI"] = logged["rssi"]
233
233
  res["SNR"] = logged["snr"]
234
234
  res["recv_time"] = logged["recv_time"]
235
+ res["attempt"] = logged["attempt"]
235
236
 
236
237
  attributes = {
237
238
  "channel_idx": res["channel_idx"],
@@ -250,12 +251,12 @@ class MessageReader:
250
251
  res["channel_idx"] = dbuf.read(1)[0]
251
252
  res["path_len"] = dbuf.read(1)[0]
252
253
  res["txt_type"] = dbuf.read(1)[0]
253
- res["sender_timestamp"] = int.from_bytes(dbuf.read(4), byteorder="little")
254
+ res["sender_timestamp"] = int.from_bytes(dbuf.read(4), byteorder="little", signed=False)
254
255
  text = dbuf.read()
255
256
  res["text"] = text.decode("utf-8", "ignore")
256
257
 
257
258
  # search for text in log_channels
258
- txt_hash = int.from_bytes(SHA256.new(text).digest()[0:4], "little", signed=False)
259
+ txt_hash = int.from_bytes(SHA256.new(res["sender_timestamp"].to_bytes(4, "little", signed=False)+text).digest()[0:4], "little", signed=False)
259
260
  res["txt_hash"] = txt_hash
260
261
  logged = next((l for l in reversed(self.channels_log) if 'msg_hash' in l and l['msg_hash'] == txt_hash), None)
261
262
 
@@ -264,6 +265,7 @@ class MessageReader:
264
265
  res["path"] = logged["path"]
265
266
  res["RSSI"] = logged["rssi"]
266
267
  res["recv_time"] = logged["recv_time"]
268
+ res["attempt"] = logged["attempt"]
267
269
 
268
270
  attributes = {
269
271
  "channel_idx": res["channel_idx"],
@@ -428,9 +430,8 @@ class MessageReader:
428
430
  idx = dbuf.read(1)[0]
429
431
  res["channel_idx"] = idx
430
432
 
431
- if idx >= len(self.channels):
432
- self.channels = self.channels.extend(
433
- [{} for _ in range(idx - len(self.channels) + 1)])
433
+ if len(self.channels) <= idx:
434
+ self.channels.extend([{} for _ in range(1 + idx - len(self.channels))])
434
435
 
435
436
  # Channel name is null-terminated, so find the first null byte
436
437
  name_bytes = dbuf.read(32)
@@ -653,14 +654,24 @@ class MessageReader:
653
654
  # not found: decrypt the text and hash it
654
655
  aes_key = channel["channel_secret"]
655
656
  cipher = AES.new(aes_key, AES.MODE_ECB)
656
- message = cipher.decrypt(msg)[5:].strip(b"\0")
657
- msg_hash = int.from_bytes(SHA256.new(message).digest()[0:4], "little", signed=False)
657
+ uncrypted = cipher.decrypt(msg)
658
+ timestamp = int.from_bytes(uncrypted[0:4], "little", signed=False)
659
+ attempt = uncrypted[4] & 3
660
+ txt_type = int.from_bytes(uncrypted[4:4], "little", signed=False) >> 2
661
+ message = uncrypted[5:].strip(b"\0")
662
+ msg_hash = int.from_bytes(SHA256.new(timestamp.to_bytes(4, "little", signed=False) + message).digest()[0:4], "little", signed=False)
658
663
  log_data["message"] = message.decode("utf-8", "ignore")
659
664
  log_data["msg_hash"] = msg_hash
665
+ log_data["sender_timestamp"] = timestamp
666
+ log_data["attempt"] = attempt
667
+ log_data["txt_type"] = txt_type
660
668
  else:
661
669
  # found: copy
662
670
  log_data["message"] = logged["message"]
663
671
  log_data["msg_hash"] = logged["msg_hash"]
672
+ log_data["sender_timestamp"] = logged["sender_timestamp"]
673
+ log_data["attempt"] = logged["attempt"]
674
+ log_data["txt_type"] = logged["txt_type"]
664
675
 
665
676
  self.channels_log.append(log_data)
666
677
  if len(self.channels_log) > 100:
File without changes
File without changes
File without changes
File without changes
File without changes