fix: v3 payload byte 1 layout — 10-bit sensor data, button on bit 2

Sens'it Discovery v3 byte 1 layout per official spec:
  bits 7-3: mode
  bit 2   : special / button alert
  bits 1-0: MSB (2 bits) of sensor data

Previous decoder had button on bit 0 and used only bit 2 as data MSB
(9-bit values). Real payloads confirmed 10-bit: e.g. b609a861 was
decoded as -4°C but correctly resolves to 28°C with the fixed layout.

Fixes applied consistently to all v3 modes:
- Temperature: 10-bit temp with formula (raw - 200) / 8
- Light: 10-bit brightness with formula raw / 96
- Door/Vibration/Magnet: 2-bit status from bits 1-0

Existing DB entries re-decoded in place.
This commit is contained in:
2026-07-06 19:32:46 +02:00
parent 139deb5467
commit 026ec0620d
+13 -8
View File
@@ -18,8 +18,13 @@ V3_MODES = {
def _decode_v3(b0: int, b1: int, b2: int, b3: int) -> dict: def _decode_v3(b0: int, b1: int, b2: int, b3: int) -> dict:
# byte 1 layout per Sens'it Discovery v3 spec:
# bits 7-3: mode
# bit 2 : special / button alert
# bits 1-0: 2 MSB bits of sensor data (giving 10-bit values with b2)
battery_raw = (b0 >> 3) & 0x1F battery_raw = (b0 >> 3) & 0x1F
mode = (b1 >> 3) & 0x1F mode = (b1 >> 3) & 0x1F
data_msb = b1 & 0x03
result = { result = {
"format": "sensit_v3", "format": "sensit_v3",
"battery": round(battery_raw * 0.05 + 2.7, 2), "battery": round(battery_raw * 0.05 + 2.7, 2),
@@ -27,24 +32,24 @@ def _decode_v3(b0: int, b1: int, b2: int, b3: int) -> dict:
"reserved_ok": True, "reserved_ok": True,
"mode": V3_MODES.get(mode, f"Unknown ({mode})"), "mode": V3_MODES.get(mode, f"Unknown ({mode})"),
"mode_id": mode, "mode_id": mode,
"button_alert": bool(b1 & 0x01), "button_alert": bool((b1 >> 2) & 0x01),
} }
if mode == 1: # Temperature + Humidity if mode == 1: # Temperature + Humidity (10-bit temp)
temp_raw = (((b1 >> 2) & 0x01) << 8) | b2 temp_raw = (data_msb << 8) | b2
result["temperature_c"] = round((temp_raw - 200) / 8, 2) result["temperature_c"] = round((temp_raw - 200) / 8, 2)
result["humidity_pct"] = round(b3 / 2, 1) result["humidity_pct"] = round(b3 / 2, 1)
elif mode == 2: # Light elif mode == 2: # Light (10-bit brightness)
brightness_raw = (((b1 >> 2) & 0x01) << 8) | b2 brightness_raw = (data_msb << 8) | b2
result["brightness_lux"] = round(brightness_raw / 96, 2) result["brightness_lux"] = round(brightness_raw / 96, 2)
elif mode == 3: elif mode == 3:
result["door_status"] = {0: "closed", 1: "opened", 2: "opening_alert", 3: "closing_alert"}.get((b1 >> 1) & 0x03, "unknown") result["door_status"] = {0: "closed", 1: "opened", 2: "opening_alert", 3: "closing_alert"}.get(data_msb, "unknown")
result["event_count"] = (b2 << 8) | b3 result["event_count"] = (b2 << 8) | b3
elif mode == 4: elif mode == 4:
result["vibration_status"] = {0: "no_vibration", 1: "vibration_detected"}.get((b1 >> 1) & 0x03, "unknown") result["vibration_status"] = {0: "no_vibration", 1: "vibration_detected"}.get(data_msb, "unknown")
result["event_count"] = (b2 << 8) | b3 result["event_count"] = (b2 << 8) | b3
elif mode == 5: elif mode == 5:
result["magnet_status"] = {0: "no_magnet", 1: "magnet_detected"}.get((b1 >> 1) & 0x03, "unknown") result["magnet_status"] = {0: "no_magnet", 1: "magnet_detected"}.get(data_msb, "unknown")
result["event_count"] = (b2 << 8) | b3 result["event_count"] = (b2 << 8) | b3
return result return result