casambi-bt-revamped 0.3.12.dev11__tar.gz → 0.3.12.dev12__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 (31) hide show
  1. {casambi_bt_revamped-0.3.12.dev11/src/casambi_bt_revamped.egg-info → casambi_bt_revamped-0.3.12.dev12}/PKG-INFO +1 -1
  2. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/setup.cfg +1 -1
  3. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_client.py +66 -7
  4. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_version.py +1 -1
  5. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12/src/casambi_bt_revamped.egg-info}/PKG-INFO +1 -1
  6. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/LICENSE +0 -0
  7. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/README.md +0 -0
  8. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/pyproject.toml +0 -0
  9. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/__init__.py +0 -0
  10. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_cache.py +0 -0
  11. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_casambi.py +0 -0
  12. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_classic_crypto.py +0 -0
  13. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_constants.py +0 -0
  14. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_discover.py +0 -0
  15. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_encryption.py +0 -0
  16. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_invocation.py +0 -0
  17. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_keystore.py +0 -0
  18. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_network.py +0 -0
  19. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_operation.py +0 -0
  20. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_switch_events.py +0 -0
  21. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/_unit.py +0 -0
  22. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/errors.py +0 -0
  23. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/CasambiBt/py.typed +0 -0
  24. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/casambi_bt_revamped.egg-info/SOURCES.txt +0 -0
  25. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/casambi_bt_revamped.egg-info/dependency_links.txt +0 -0
  26. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/casambi_bt_revamped.egg-info/requires.txt +0 -0
  27. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/src/casambi_bt_revamped.egg-info/top_level.txt +0 -0
  28. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/tests/test_classic_protocol.py +0 -0
  29. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/tests/test_legacy_protocol_handling.py +0 -0
  30. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/tests/test_switch_event_logs.py +0 -0
  31. {casambi_bt_revamped-0.3.12.dev11 → casambi_bt_revamped-0.3.12.dev12}/tests/test_unit_state_logs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: casambi-bt-revamped
3
- Version: 0.3.12.dev11
3
+ Version: 0.3.12.dev12
4
4
  Summary: Forked Casambi Bluetooth client library with switch event support, use original if no special need. https://github.com/lkempf/casambi-bt
5
5
  Home-page: https://github.com/rankjie/casambi-bt
6
6
  Author: rankjie
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = casambi-bt-revamped
3
- version = 0.3.12.dev11
3
+ version = 0.3.12.dev12
4
4
  author = rankjie
5
5
  author_email = rankjie@gmail.com
6
6
  description = Forked Casambi Bluetooth client library with switch event support, use original if no special need. https://github.com/lkempf/casambi-bt
@@ -438,6 +438,7 @@ class CasambiClient:
438
438
  self._network.classicManagerKey() is not None,
439
439
  getattr(self._network, "isManager", lambda: False)(),
440
440
  )
441
+ await self._classicEnumerateAndSubscribeGatt(notify_kwargs)
441
442
  _log_probe_summary("CLASSIC", classic_variant="ca52_legacy")
442
443
  # Emit a warning if we never see Classic RX frames; this is a common failure mode.
443
444
  self._classicNoRxTask = asyncio.create_task(self._classic_no_rx_watchdog(30.0))
@@ -593,6 +594,7 @@ class CasambiClient:
593
594
  self._network.classicManagerKey() is not None,
594
595
  getattr(self._network, "isManager", lambda: False)(),
595
596
  )
597
+ await self._classicEnumerateAndSubscribeGatt(notify_kwargs)
596
598
  _log_probe_summary("CLASSIC", classic_variant="auth_uuid_conformant")
597
599
  self._classicNoRxTask = asyncio.create_task(self._classic_no_rx_watchdog(30.0))
598
600
  return
@@ -1223,6 +1225,58 @@ class CasambiClient:
1223
1225
  len(pkt),
1224
1226
  )
1225
1227
 
1228
+ async def _classicEnumerateAndSubscribeGatt(
1229
+ self, notify_kwargs: dict[str, Any]
1230
+ ) -> None:
1231
+ """Enumerate all GATT characteristics and subscribe to any notifiable ones.
1232
+
1233
+ This discovers characteristics beyond the manually-probed CA51/CA52/CA53
1234
+ UUIDs and subscribes to any that support notify or indicate, which may be
1235
+ needed for receiving Classic state/config notifications.
1236
+ """
1237
+ try:
1238
+ total_chars = 0
1239
+ for svc in self._gattClient.services:
1240
+ for char in svc.characteristics:
1241
+ total_chars += 1
1242
+ char_uuid = str(char.uuid).lower()
1243
+ props = char.properties
1244
+ self._logger.warning(
1245
+ "[CASAMBI_CLASSIC_GATT_CHAR] uuid=%s props=%s handle=%d",
1246
+ char_uuid,
1247
+ props,
1248
+ char.handle,
1249
+ )
1250
+ if char_uuid not in self._classicNotifyCharUuids:
1251
+ if "notify" in props or "indicate" in props:
1252
+ try:
1253
+ await self._gattClient.start_notify(
1254
+ char.uuid,
1255
+ self._queueCallback,
1256
+ **notify_kwargs,
1257
+ )
1258
+ self._classicNotifyCharUuids.add(char_uuid)
1259
+ self._logger.warning(
1260
+ "[CASAMBI_CLASSIC_GATT_SUB] subscribed uuid=%s",
1261
+ char_uuid,
1262
+ )
1263
+ except Exception as e:
1264
+ self._logger.warning(
1265
+ "[CASAMBI_CLASSIC_GATT_SUB] failed uuid=%s err=%s",
1266
+ char_uuid,
1267
+ type(e).__name__,
1268
+ )
1269
+ self._logger.warning(
1270
+ "[CASAMBI_CLASSIC_GATT_ENUM] total_chars=%d subscribed_uuids=%s",
1271
+ total_chars,
1272
+ sorted(self._classicNotifyCharUuids),
1273
+ )
1274
+ except Exception as e:
1275
+ self._logger.warning(
1276
+ "[CASAMBI_CLASSIC_GATT_ENUM] services enumeration unavailable: %s",
1277
+ type(e).__name__,
1278
+ )
1279
+
1226
1280
  async def classicSendInit(self) -> None:
1227
1281
  """Send Classic post-connection initialization (time-sync).
1228
1282
 
@@ -1253,7 +1307,7 @@ class CasambiClient:
1253
1307
  # Build the time-sync payload.
1254
1308
  # Format: [10][year:2BE][month:1][day:1][hour:1][min:1][sec:1]
1255
1309
  # [tz_offset:2BE signed][dst_transition:4BE][dst_change:1]
1256
- # [timestamp1:4BE][timestamp2:4BE][zero:2][millis:3BE]
1310
+ # [timestamp1:3BE][timestamp2:3BE][zero:2][millis:3BE][extra:1]
1257
1311
  payload = bytearray()
1258
1312
  payload.append(10) # Classic time-sync command byte
1259
1313
  payload.extend(struct.pack(">H", now.year))
@@ -1266,16 +1320,21 @@ class CasambiClient:
1266
1320
  # DST transition data and change minutes (0 = no DST info).
1267
1321
  payload.extend(struct.pack(">I", 0))
1268
1322
  payload.append(0)
1269
- # Classic extra bytes: timestamps, zero short, millis.
1270
- # Start with zeros - refine after tester feedback if needed.
1271
- payload.extend(struct.pack(">I", 0)) # timestamp1
1272
- payload.extend(struct.pack(">I", 0)) # timestamp2
1273
- payload.extend(struct.pack(">H", 0)) # zero
1274
- # j() in Android is a 3-byte big-endian write.
1323
+ # Classic extra bytes: timestamps, zero short, millis, trailing byte.
1324
+ # Android AbstractC1717h.X() lines 323-328: j() = 3-byte big-endian write
1325
+ # (Q2.t.java:59-63), NOT 4-byte. Plus trailing writeByte(iK0 >> 24).
1326
+ ts1 = 0 # Q2.r.K0(network.V) — start with 0
1327
+ ts2 = 0 # Q2.r.K0(network.W) — start with 0
1328
+ for ts in (ts1, ts2):
1329
+ payload.append((ts >> 16) & 0xFF)
1330
+ payload.append((ts >> 8) & 0xFF)
1331
+ payload.append(ts & 0xFF)
1332
+ payload.extend(struct.pack(">H", 0)) # writeShort(0)
1275
1333
  millis_val = now.microsecond // 1000 * 1000
1276
1334
  payload.append((millis_val >> 16) & 0xFF)
1277
1335
  payload.append((millis_val >> 8) & 0xFF)
1278
1336
  payload.append(millis_val & 0xFF)
1337
+ payload.append((ts1 >> 24) & 0xFF) # writeByte(iK0 >> 24)
1279
1338
 
1280
1339
  self._logger.warning(
1281
1340
  "[CASAMBI_CLASSIC_INIT] sending time-sync len=%d hex=%s",
@@ -7,4 +7,4 @@ Avoid using importlib.metadata in hot paths by providing a static version string
7
7
  __all__ = ["__version__"]
8
8
 
9
9
  # NOTE: Must match `casambi-bt/setup.cfg` [metadata] version.
10
- __version__ = "0.3.12.dev10"
10
+ __version__ = "0.3.12.dev12"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: casambi-bt-revamped
3
- Version: 0.3.12.dev11
3
+ Version: 0.3.12.dev12
4
4
  Summary: Forked Casambi Bluetooth client library with switch event support, use original if no special need. https://github.com/lkempf/casambi-bt
5
5
  Home-page: https://github.com/rankjie/casambi-bt
6
6
  Author: rankjie