ESPHome-Apple-Watch-detection icon indicating copy to clipboard operation
ESPHome-Apple-Watch-detection copied to clipboard

Detect all watches, or just one watch?

Open dcgrove opened this issue 3 years ago • 4 comments

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

dcgrove avatar Nov 22 '21 21:11 dcgrove

Hi. Yes, the code should detect any Apple watch that is in range, whether Series 3 or 5.

Two things to try:

  1. Is the Series 3 watch unlocked?
  2. 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.

dalehumby avatar Nov 23 '21 06:11 dalehumby

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.

image

neroxps avatar Nov 27 '21 03:11 neroxps

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

dalehumby avatar Feb 15 '22 20:02 dalehumby

Hi @dcgrove - I wanted to check if you still needed help diagnosing this issue?

dalehumby avatar Feb 15 '22 20:02 dalehumby