From a9034e440ea99886e892541712f2dfd9b1964a92 Mon Sep 17 00:00:00 2001 From: rencsaridogan Date: Mon, 29 Jun 2026 10:36:31 +0200 Subject: [PATCH 1/3] fix: derive device MAC from BLE local name on EU/NA v2 API OMRON's EU/NA v2 init-user response does not include a `macAddress` field for registered devices, so `get_registered_devices` dropped every device via the "skip device without MAC address" guard, leaving the device list empty even when the account had active devices. OMRON encodes the MAC in the BLE local name (e.g. `blesmart_0001020828ffb210aaa4` -> `28:FF:B2:10:AA:A4`), the same value the Bluetooth scanner derives. Fall back to that local name, then to `deviceSerialID` via `serial_to_mac`, before skipping. The derivation matches `omramin.omron_ble_scan`, so the resulting MAC is consistent with BLE discovery and manual `add --macaddr`. Co-Authored-By: Claude Opus 4.8 --- omronconnect.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/omronconnect.py b/omronconnect.py index e084cf1..1eab46f 100644 --- a/omronconnect.py +++ b/omronconnect.py @@ -278,6 +278,17 @@ def serial_to_mac(serial: str) -> str: return ":".join(values[5:2:-1] + values[2::-1]) +def ble_local_name_to_mac(local_name: str) -> str: + # e.g. blesmart_0001020828ffb210aaa4 to 28:FF:B2:10:AA:A4 + # OMRON encodes the MAC as the last 12 hex chars of the BLE local name. + # Mirrors the BLE-scan derivation in omramin.omron_ble_scan. + name = (local_name or "").strip() + mac_hex = name[-12:].upper() + if len(mac_hex) != 12 or not all(c in "0123456789ABCDEF" for c in mac_hex): + return "" + return ":".join(mac_hex[i : i + 2] for i in range(0, 12, 2)) + + def convert_weight_to_kg(weight: T.Union[int, float], unit: int) -> float: if unit == WeightUnit.G: return weight / 1000 @@ -833,6 +844,14 @@ def get_registered_devices(self, days: T.Optional[int] = 30) -> T.Optional[list[ continue macAddress = attrs.get("macAddress", "").strip() + if not macAddress: + # EU/NA v2 responses omit macAddress; OMRON encodes the MAC in the + # BLE local name (blesmart_<...>) and falls back to deviceSerialID. + macAddress = ble_local_name_to_mac(attrs.get("deviceLocalName", "")) + if not macAddress: + serial = attrs.get("deviceSerialID", "") + if serial: + macAddress = serial_to_mac(serial) if not macAddress: L.debug(f"Skipping device without MAC address: {attrs.get('name', 'unknown')}") continue From b91d0fcb4123b72cb23fed4df2e610cddff6e670 Mon Sep 17 00:00:00 2001 From: rencsaridogan Date: Sun, 26 Jul 2026 11:50:43 +0200 Subject: [PATCH 2/3] docs: note EU/NA device discovery fix + troubleshooting Add a CHANGELOG entry for the macAddress-derivation fix and a README troubleshooting subsection for the "omron list shows no devices" symptom (region mismatch, not-yet-synced, and the --debug inspection tip). Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 11 +++++++++++ README.md | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a1290d..95b8379 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## Unreleased + +### Fixes + +- **EU/NA device discovery**: `omron list` and setup device discovery no longer + return an empty list on the EU/NA v2 API. That API omits the `macAddress` + field, so every device was dropped by the "skip device without MAC address" + guard. The MAC is now derived from the BLE local name (e.g. + `blesmart_…` → `28:FF:B2:10:AA:A4`), then from `deviceSerialID`, matching the + value produced by Bluetooth discovery and manual `add --macaddr`. + ## v0.3.0 - **Garmin auth rewritten**: Migrated to garminconnect>=0.3.0 due to Garmin SSO/OAuth changes; replaces garth-based authentication. Re-login required. diff --git a/README.md b/README.md index f880d6e..1b29b36 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,23 @@ OMRAMIN_GARMIN_DEBUG=1 omramin sync # Garmin API only --- +### Troubleshooting + +**`omron list` shows no devices, but the device is in the OMRON app** + +- **Region mismatch**: the device only appears on the OMRON regional server your + country code maps to. Make sure the country you logged in with matches your + OMRON account's region. Some countries (e.g. `TR`) map to an offline region + with no cloud API. +- **Not synced to the cloud yet**: open the OMRON Connect phone app so it uploads + the latest measurements — `omramin` reads what's on OMRON's servers, not what is + only on the device over Bluetooth. +- **Inspect the raw response**: `omramin --debug omron list` logs the full + `init-user` response (credentials redacted) so you can see the returned + `deviceList`. + +--- + ## Commands | Command | Description | From f39fff1f6edbe3ac59999e57f103d4e389a7d4e4 Mon Sep 17 00:00:00 2001 From: rencsaridogan Date: Sun, 26 Jul 2026 12:00:30 +0200 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20address=20review=20=E2=80=94=20norma?= =?UTF-8?q?lize=20MAC=20case,=20guard=20BLE=20name,=20fix=20v2=20log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ble_local_name_to_mac: require a BLESMART_ prefix so an unrelated deviceLocalName that merely ends in 12 hex chars can't yield a bogus MAC. - get_registered_devices: uppercase the resolved MAC so every discovery path (API macAddress, BLE local name, serial fallback) produces the same string for a device, avoiding case-sensitive mismatches on dedup/lookup. - Fix the v2 unknown-category warning to log the inferred deviceModel instead of device.get('deviceModel'), which was always None in the v2 loop (deviceModel lives under attributes). Co-Authored-By: Claude Opus 4.8 --- omronconnect.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/omronconnect.py b/omronconnect.py index 1eab46f..b7eaf98 100644 --- a/omronconnect.py +++ b/omronconnect.py @@ -283,6 +283,10 @@ def ble_local_name_to_mac(local_name: str) -> str: # OMRON encodes the MAC as the last 12 hex chars of the BLE local name. # Mirrors the BLE-scan derivation in omramin.omron_ble_scan. name = (local_name or "").strip() + # Only OMRON BLE local names carry the MAC this way; guard against deriving a + # bogus MAC from an unrelated name that happens to end in 12 hex chars. + if not name.upper().startswith("BLESMART_"): + return "" mac_hex = name[-12:].upper() if len(mac_hex) != 12 or not all(c in "0123456789ABCDEF" for c in mac_hex): return "" @@ -855,6 +859,9 @@ def get_registered_devices(self, days: T.Optional[int] = 30) -> T.Optional[list[ if not macAddress: L.debug(f"Skipping device without MAC address: {attrs.get('name', 'unknown')}") continue + # Normalize case so every discovery path (API macAddress, BLE local + # name, serial fallback) yields the same string for a given device. + macAddress = macAddress.upper() category = None deviceCategory = attrs.get("deviceCategory") @@ -874,7 +881,7 @@ def get_registered_devices(self, days: T.Optional[int] = 30) -> T.Optional[list[ continue else: - L.warning(f"Device with unknown category {device.get('deviceModel')}") + L.warning(f"Device with unknown category {deviceModel}") # Create OmronDevice deviceModel = attrs.get("deviceModel", attrs.get("identifier", "Unknown"))