ESPHome-Apple-Watch-detection
ESPHome-Apple-Watch-detection copied to clipboard
Detect all watches, or just one watch?
Hello, I have been using this successfully to detect my apple watch (series 5) for some time now. I recently tested to see if it picked up my wife's watch (series 3) by walking out of range of the ESP32 while my wife was in range and found that did not detect it. Shouldn't it have detected my wife's watch as well? My config is below.
scan_parameters:
interval: 1.2s
window: 500ms
active: false
on_ble_advertise:
- then:
# Look for manufacturer data of form: 4c00 10 05 YY 98 XXXXXX
# Where YY can be 01..0F or 20..2F; and XXXXXX is ignored
- lambda: |-
optional<int16_t> best_rssi = nullopt;
for (auto data : x.get_manufacturer_datas()) {
// Guard against non-Apple datagrams, or those that are too small.
if (data.data.size() < 4 || data.uuid.to_string() != "0x004C" || data.data[0] != 0x10 || data.data[1] < 5) {
continue;
}
const int16_t rssi = x.get_rssi();
const uint8_t status_flags = data.data[2] >> 4; // High nibble
const uint8_t data_flags = data.data[3];
if (data_flags == 0x98) { // Match unlocked Apple Watches
if (status_flags == 0 || status_flags == 2) {
best_rssi = max(rssi, best_rssi.value_or(rssi));
ESP_LOGD("ble_adv", "Found Apple Watch (mac %s) rssi %i", x.address_str().c_str(), rssi);
} else {
ESP_LOGD("ble_adv", "Possible Apple Watch? (mac %s) rssi %i, unrecognised status/action flags %#04x", x.address_str().c_str(), rssi, data.data[2]);
}
}
}
if (best_rssi) {
id(apple_watch_rssi).publish_state(*best_rssi);
}
sensor:
- platform: template
id: apple_watch_rssi
name: "$yourname Apple Watch $roomname RSSI"
device_class: signal_strength
unit_of_measurement: dBm
accuracy_decimals: 0
filters:
- exponential_moving_average:
alpha: 0.3
send_every: 1
on_value:
then:
- lambda: |-
if (id(apple_watch_rssi).state > $rssi_present) {
id(room_presence_debounce).publish_state(1);
} else if (id(apple_watch_rssi).state < $rssi_not_present) {
id(room_presence_debounce).publish_state(0);
}
- script.execute: presence_timeout # Publish 0 if no rssi received
- platform: template
id: room_presence_debounce
filters:
- sliding_window_moving_average:
window_size: 3
send_every: 1
- platform: homeassistant
name: HA RSSI Present Value
entity_id: input_number.office_rssi_present_value
id: harssi_present
- platform: homeassistant
name: HA RSSI Not Present Value
entity_id: input_number.office_rssi_not_present
id: harssi_not_present
binary_sensor:
- platform: status
name: "Office BLE Tracker Status"
- platform: template
id: room_presence
name: "$yourname $roomname presence"
device_class: occupancy
lambda: |-
if (id(room_presence_debounce).state > 0.99) {
return true;
} else if (id(room_presence_debounce).state < 0.01) {
return false;
} else {
return id(room_presence).state;
}
script:
# Publish event every 30 seconds when no rssi received
id: presence_timeout
mode: restart
then:
- delay: 30s
- lambda: |-
id(room_presence_debounce).publish_state(0);
- script.execute: presence_timeout
Hi. Yes, the code should detect any Apple watch that is in range, whether Series 3 or 5.
Two things to try:
- Is the Series 3 watch unlocked?
- Could you post some logs from when your Series 5 watch goes out of range and only the Series 3 is in range? Could help surface the issue.
Very good project, but unfortunately, the AppleWatch firmware sold in China is not universal.
Whether the watch is unlocked or locked, the Data flags are 0x18.
Hi @neroxps - If you want to detect a Watch where the data flag is 0x18, have a look at line 60 in the yaml file. Change
if (data_flags == 0x98) {
to
if (data_flags == 0x98 || data_flags == 0x18) {
If this doesn't work, please send your full yaml, your watch series, and verbose debug log. Verbose logging can be set
logger:
level: VERY_VERBOSE
Hi @dcgrove - I wanted to check if you still needed help diagnosing this issue?