BirdMenu is a macOS menu bar app for compatible Bluetooth Low Energy thermometer/hygrometer sensors.
It listens for the device's BLE advertisements and shows the communication state, temperature, and humidity in the menu bar. The detail menu also shows battery level, RSSI, and the last update time.
When multiple compatible sensors are detected, BirdMenu keeps the latest reading for each device. The menu bar shows the average temperature and humidity by default, and the menu lets you switch the display to a specific sensor.
Compatibility testing has been performed with the INKBIRD ITH-11-B sensor. BirdMenu is an independent utility and is not affiliated with or endorsed by INKBIRD.
The menu includes Fetch Sensor History. It connects to the selected compatible sensor and tries the history-read command pattern observed from related BLE hygrometers:
- subscribe to notify characteristics on service
0000fff0-0000-1000-8000-00805f9b34fb - write one-byte read commands to
0000fff8-0000-1000-8000-00805f9b34fb - never write to the history-delete characteristic
0000fff9-0000-1000-8000-00805f9b34fb
Some tested sensors do not expose fff8; observed devices expose fff3, fff4, fff5, fff6, fff7, and an additional 5833ff01-9b8b-5191-6142-22a4536ef123 service. In that case BirdMenu saves a read-only GATT snapshot: it discovers all services, reads all readable characteristics, subscribes to notify characteristics, and does not write unknown history commands.
Fetched data is saved under ~/Documents/BirdMenu Logs/. The app always writes a raw JSON dump. If the packet layout can be decoded confidently, it also writes history.csv.
Use Settings to generate a graph for a specific local date. BirdMenu scans the saved history.csv files that still exist under ~/Documents/BirdMenu Logs/, combines records for the selected date, and writes history_yyyymmdd.png to the logs folder.
For observed sensors, the companion-app command sequence appears to return records that have not yet been synced rather than the full retained memory every time. In practice this means repeated fetches may produce only the new records since the previous successful sync. Keep the raw JSON files if you need to audit or re-decode the captured BLE packets later.
This feature is intentionally conservative because the offline history protocol is not publicly documented and is not implemented by inkbird-ble.
Enable Debug Logging from the menu to write received BLE data to macOS Unified Logging. The app logs decoded temperature/humidity/battery/RSSI values, raw advertisement bytes, and history-fetch GATT packets.
View recent logs with:
log show --style compact --last 10m --predicate 'subsystem == "st.rio.birdmenu"'For live logs:
log stream --style compact --predicate 'subsystem == "st.rio.birdmenu"'The tested sensor's offline history protocol is not exposed through fff8 on observed units. To identify the real sync command, capture an Android Bluetooth HCI snoop log while the companion app syncs offline data, then run:
node Tools/analyze-btsnoop.js /path/to/btsnoop_hci.log
node Tools/analyze-btsnoop.js --summary /path/to/btsnoop_hci.log
node Tools/analyze-btsnoop.js --plan /path/to/btsnoop_hci.log
node Tools/analyze-btsnoop.js --json /path/to/btsnoop_hci.log > trace.jsonThe tool extracts ATT writes, notifications, and indications, including traffic around fff0 and 5833ff01-9b8b-5191-6142-22a4536ef123. The output is intended to identify the characteristic and command bytes used by the official app for offline history sync.
--plan prints non-CCCD write candidates in the order they appeared, with the response characteristic and sample notification payloads. The JSON output also includes candidateCommandPlan, which is the safest starting point for implementing a replay only after the trace clearly shows the official app's history-sync command.
Typical Android capture flow:
- Enable Developer options on the Android phone.
- Enable
Bluetooth HCI snoop log. - Force stop the companion app, then reopen it.
- Connect to the sensor and wait until the app finishes syncing offline data.
- Export the bug report or retrieve
btsnoop_hci.logfrom the phone.
The useful lines are usually non-CCCD write_request or write_command entries followed by notification or indication packets within a few seconds.
Apple PacketLogger captures from a real iPhone or iPad can also be passed to the same tool. The analyzer reports PacketLogger metadata, interesting advertisements, and whether ATT connection traffic is present. A capture that only contains LE advertising reports is not enough for offline history implementation; it must include the official app's BLE connection writes and notifications during a history sync.
make runThe app bundle is generated at build/BirdMenu.app.
On first launch, macOS may ask for Bluetooth permission. Allow it so the app can receive BLE advertisements.
The advertisement parsing follows the tested sensor behavior documented by inkbird-ble:
- service UUID:
0000fff0-0000-1000-8000-00805f9b34fb - manufacturer id:
9289 - 18-byte advertisement payload
- temperature/humidity: bytes
[6..<10], little-endian signed temperature and unsigned humidity, both in tenths - battery: byte
[10]
The app drops impossible humidity values above 100% and battery values above 100%, matching the corruption guards used by inkbird-ble.
BirdMenu does not collect, transmit, sell, share, or track personal data. Bluetooth readings and history exports are processed locally on your Mac.
See Privacy Policy (English) and プライバシーポリシー (日本語).
The BLE parsing logic is based on the MIT-licensed inkbird-ble project.
The history-fetch command sequence is informed by public reverse-engineering notes for related BLE hygrometers.
BirdMenu is released under the MIT License. See LICENSE.
