This commit is contained in:
David Rice
2026-06-17 14:41:43 +02:00
parent fdbbc98088
commit 1aa81e6758
7 changed files with 146 additions and 41 deletions

View File

@@ -1,6 +0,0 @@
timestamp,freq_hz,vol,duration_s,avg_db,min_db,max_db,samples
2026-06-16T16:44:31,250,0.2,3.0,56.6,56.3,56.8,7
2026-06-16T16:44:34,500,0.2,3.0,56.0,56.0,56.1,6
2026-06-16T16:44:38,1000,0.2,3.0,57.3,56.2,58.1,6
2026-06-16T16:44:41,2000,0.2,3.0,61.8,58.6,64.4,5
2026-06-16T16:44:45,4000,0.2,3.0,63.1,61.1,65.2,6
1 timestamp freq_hz vol duration_s avg_db min_db max_db samples
2 2026-06-16T16:44:31 250 0.2 3.0 56.6 56.3 56.8 7
3 2026-06-16T16:44:34 500 0.2 3.0 56.0 56.0 56.1 6
4 2026-06-16T16:44:38 1000 0.2 3.0 57.3 56.2 58.1 6
5 2026-06-16T16:44:41 2000 0.2 3.0 61.8 58.6 64.4 5
6 2026-06-16T16:44:45 4000 0.2 3.0 63.1 61.1 65.2 6

View File

@@ -1 +0,0 @@
timestamp,freq_hz,vol,duration_s,avg_db,min_db,max_db,samples
1 timestamp freq_hz vol duration_s avg_db min_db max_db samples

View File

@@ -1 +0,0 @@
timestamp,freq_hz,vol,duration_s,avg_db,min_db,max_db,samples
1 timestamp freq_hz vol duration_s avg_db min_db max_db samples

View File

@@ -1,23 +0,0 @@
timestamp,freq_hz,vol,duration_s,avg_db,min_db,max_db,samples
2026-06-16T17:10:21,100,0.0,5.0,0.0,0.0,0.0,0
2026-06-16T17:10:27,100,0.1,5.0,0.0,0.0,0.0,0
2026-06-16T17:10:33,100,0.2,5.0,0.0,0.0,0.0,0
2026-06-16T17:10:38,100,0.3,5.0,0.0,0.0,0.0,0
2026-06-16T17:10:44,100,0.4,5.0,0.0,0.0,0.0,0
2026-06-16T17:10:49,100,0.5,5.0,0.0,0.0,0.0,0
2026-06-16T17:10:55,100,0.6,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:00,100,0.7,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:06,100,0.8,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:11,100,0.9,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:17,100,1.0,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:22,250,0.0,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:28,250,0.1,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:33,250,0.2,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:39,250,0.3,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:45,250,0.4,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:50,250,0.5,5.0,0.0,0.0,0.0,0
2026-06-16T17:11:56,250,0.6,5.0,0.0,0.0,0.0,0
2026-06-16T17:12:01,250,0.7,5.0,0.0,0.0,0.0,0
2026-06-16T17:12:07,250,0.8,5.0,0.0,0.0,0.0,0
2026-06-16T17:12:12,250,0.9,5.0,0.0,0.0,0.0,0
2026-06-16T17:12:18,250,1.0,5.0,0.0,0.0,0.0,0
1 timestamp freq_hz vol duration_s avg_db min_db max_db samples
2 2026-06-16T17:10:21 100 0.0 5.0 0.0 0.0 0.0 0
3 2026-06-16T17:10:27 100 0.1 5.0 0.0 0.0 0.0 0
4 2026-06-16T17:10:33 100 0.2 5.0 0.0 0.0 0.0 0
5 2026-06-16T17:10:38 100 0.3 5.0 0.0 0.0 0.0 0
6 2026-06-16T17:10:44 100 0.4 5.0 0.0 0.0 0.0 0
7 2026-06-16T17:10:49 100 0.5 5.0 0.0 0.0 0.0 0
8 2026-06-16T17:10:55 100 0.6 5.0 0.0 0.0 0.0 0
9 2026-06-16T17:11:00 100 0.7 5.0 0.0 0.0 0.0 0
10 2026-06-16T17:11:06 100 0.8 5.0 0.0 0.0 0.0 0
11 2026-06-16T17:11:11 100 0.9 5.0 0.0 0.0 0.0 0
12 2026-06-16T17:11:17 100 1.0 5.0 0.0 0.0 0.0 0
13 2026-06-16T17:11:22 250 0.0 5.0 0.0 0.0 0.0 0
14 2026-06-16T17:11:28 250 0.1 5.0 0.0 0.0 0.0 0
15 2026-06-16T17:11:33 250 0.2 5.0 0.0 0.0 0.0 0
16 2026-06-16T17:11:39 250 0.3 5.0 0.0 0.0 0.0 0
17 2026-06-16T17:11:45 250 0.4 5.0 0.0 0.0 0.0 0
18 2026-06-16T17:11:50 250 0.5 5.0 0.0 0.0 0.0 0
19 2026-06-16T17:11:56 250 0.6 5.0 0.0 0.0 0.0 0
20 2026-06-16T17:12:01 250 0.7 5.0 0.0 0.0 0.0 0
21 2026-06-16T17:12:07 250 0.8 5.0 0.0 0.0 0.0 0
22 2026-06-16T17:12:12 250 0.9 5.0 0.0 0.0 0.0 0
23 2026-06-16T17:12:18 250 1.0 5.0 0.0 0.0 0.0 0

View File

@@ -1,4 +0,0 @@
timestamp,freq_hz,vol,duration_s,avg_db,min_db,max_db,samples
2026-06-16T17:13:29,100,0.0,5.0,0.0,0.0,0.0,0
2026-06-16T17:13:34,100,0.1,5.0,0.0,0.0,0.0,0
2026-06-16T17:13:40,100,0.2,5.0,0.0,0.0,0.0,0
1 timestamp freq_hz vol duration_s avg_db min_db max_db samples
2 2026-06-16T17:13:29 100 0.0 5.0 0.0 0.0 0.0 0
3 2026-06-16T17:13:34 100 0.1 5.0 0.0 0.0 0.0 0
4 2026-06-16T17:13:40 100 0.2 5.0 0.0 0.0 0.0 0

119
ble_discover.py Normal file
View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""
ble_discover.py — BLE characteristic discovery + wake-up probe.
Connects to the RS-95-EM, subscribes to every NOTIFY characteristic,
then tries writing common "start measurement" byte sequences to every
WRITE characteristic, watching for any data after each write.
Run this while Meterbox is NOT connected, then compare with traffic
observed when Meterbox IS connected.
"""
import asyncio
from bleak import BleakClient
BLE_MAC = "B0:D2:78:5C:20:07"
WATCH_SEC = 2.0 # seconds to listen after each write attempt
# Common "start measurement" payloads seen on BLE meters
PROBE_PAYLOADS = [
# Confirmed from Meterbox logcat (MeterBleClass.java onWriteSuccess)
b'\xd5\xfc\x11\x0d',
# Short single-byte
b'\x01', b'\x02', b'\x00', b'\xff', b'\xa0', b'\xa5',
# Common 2-byte wake sequences
b'\xaa\x00', b'\xaa\x01', b'\xaa\x55', b'\xaa\xbb',
b'\xa5\x5a', b'\xab\xbc', b'\xd5\xf0',
# Common longer init sequences seen on BLE meters
b'\xaa\x55\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xaa\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xa5\x5a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
]
async def run():
print(f"Connecting to {BLE_MAC}")
async with BleakClient(BLE_MAC, timeout=15.0) as client:
print("Connected.\n")
# ── 1. Enumerate all characteristics ─────────────────────────────────
notify_chars = []
write_chars = []
for svc in client.services:
print(f"SVC {svc.uuid}{svc.description}")
for ch in svc.characteristics:
props = ', '.join(ch.properties)
print(f" CHAR {ch.uuid} [{props}]")
if 'notify' in ch.properties or 'indicate' in ch.properties:
notify_chars.append(ch)
if 'write' in ch.properties or 'write-without-response' in ch.properties:
write_chars.append(ch)
print()
# ── 2. Subscribe to every notify characteristic ───────────────────────
traffic = {} # uuid → list of bytearray
def make_handler(uuid):
def handler(sender, data):
traffic.setdefault(uuid, []).append(bytes(data))
print(f" [NOTIFY {uuid}] {data.hex(' ')}")
return handler
for ch in notify_chars:
try:
await client.start_notify(ch.uuid, make_handler(ch.uuid))
print(f"Subscribed to NOTIFY: {ch.uuid}")
except Exception as e:
print(f"Could not subscribe to {ch.uuid}: {e}")
print()
# ── 3. Listen passively first (maybe it sends on its own) ─────────────
print(f"Listening passively for {WATCH_SEC}s …")
await asyncio.sleep(WATCH_SEC)
active_passive = {k for k, v in traffic.items() if v}
if active_passive:
print(f"\nPassive traffic on: {active_passive}")
else:
print("No passive traffic — device needs a wake-up write.\n")
# ── 4. Try each payload on each writable characteristic ───────────────
for ch in write_chars:
for payload in PROBE_PAYLOADS:
before = {k: len(v) for k, v in traffic.items()}
try:
if 'write-without-response' in ch.properties:
await client.write_gatt_char(ch.uuid, payload, response=False)
else:
await client.write_gatt_char(ch.uuid, payload, response=True)
print(f"Wrote {payload.hex(' ')}{ch.uuid}", end='', flush=True)
except Exception as e:
print(f"Write {payload.hex(' ')}{ch.uuid} FAILED: {e}")
continue
await asyncio.sleep(WATCH_SEC)
after = {k: len(v) for k, v in traffic.items()}
new_traffic = {k for k, v in after.items() if v > before.get(k, 0)}
if new_traffic:
print(f"\n *** DATA on {new_traffic} after writing {payload.hex(' ')} to {ch.uuid} ***")
else:
print("no response.")
# ── 5. Summary ────────────────────────────────────────────────────────
print("\n── Summary ──────────────────────────────────────────")
for uuid, packets in traffic.items():
if packets:
print(f" {uuid}: {len(packets)} packets received")
print(f" First: {packets[0].hex(' ')}")
if len(packets) > 1:
print(f" Last: {packets[-1].hex(' ')}")
if not any(traffic.values()):
print(" No data received on any characteristic.")
if __name__ == '__main__':
asyncio.run(run())

View File

@@ -30,14 +30,16 @@ IMX8_IP = "10.32.34.103"
IMX8_URL = f"http://{IMX8_IP}:5000"
BLE_MAC = "B0:D2:78:5C:20:07"
BLE_CHAR = "0000fff2-0000-1000-8000-00805f9b34fb"
BLE_CHAR = "0000fff2-0000-1000-8000-00805f9b34fb"
BLE_WAKE_CHAR = "0000fff1-0000-1000-8000-00805f9b34fb"
BLE_WAKE_CMD = bytes([0xD5, 0xFC, 0x11, 0x0D]) # from Meterbox logcat
# ── Test sequence — edit as required ─────────────────────────────────────────
_FREQS = [100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000,
8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000]
TEST_STEPS = [
{"freq": freq, "vol": round(vol / 10, 1), "duration": 5.0}
{"freq": freq, "vol": round(vol / 10, 1), "duration": 10.0}
for freq in _FREQS
for vol in range(0, 11) # 0% → 100% in 10% steps
]
@@ -76,11 +78,26 @@ def _http_stop() -> dict:
# ── Main test runner ──────────────────────────────────────────────────────────
async def run_test():
readings: list[float] = []
_buf = bytearray()
def on_notify(_sender, data: bytearray):
db = _parse_db(data)
if db is not None:
readings.append(db)
nonlocal _buf
_buf.extend(data)
# reassemble: packets are always 11 bytes starting with D5 F0
while len(_buf) >= 11:
idx = bytes(_buf).find(b'\xd5\xf0')
if idx == -1:
_buf.clear()
break
if idx > 0:
del _buf[:idx] # discard garbage before header
if len(_buf) < 11:
break
packet = bytes(_buf[:11])
del _buf[:11]
db = _parse_db(packet)
if db is not None:
readings.append(db)
print(f"Connecting to BLE {BLE_MAC}")
async with BleakClient(BLE_MAC, timeout=15.0) as client:
@@ -91,8 +108,12 @@ async def run_test():
props = ','.join(ch.properties)
print(f" CHAR {ch.uuid} [{props}]")
# Wake-up sequence: write D5 FC 11 0D before subscribing (from Meterbox logcat)
await client.write_gatt_char(BLE_WAKE_CHAR, BLE_WAKE_CMD, response=True)
print(f"Wake-up sent: {BLE_WAKE_CMD.hex(' ')}")
await client.start_notify(BLE_CHAR, on_notify)
print(f"\nSubscribed to {BLE_CHAR}\n")
print(f"Subscribed to {BLE_CHAR}\n")
with CSV_FILE.open('w', newline='') as f:
writer = csv.writer(f)