Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect all watches, or just one watch? #9

Open
dcgrove opened this issue Nov 22, 2021 · 4 comments
Open

Detect all watches, or just one watch? #9

dcgrove opened this issue Nov 22, 2021 · 4 comments
Assignees
Labels
question Further information is requested

Comments

@dcgrove
Copy link
Contributor

dcgrove commented Nov 22, 2021

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

@dalehumby dalehumby self-assigned this Nov 23, 2021
@dalehumby
Copy link
Owner

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.

@neroxps
Copy link

neroxps commented Nov 27, 2021

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

@dalehumby
Copy link
Owner

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
Copy link
Owner

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

@dalehumby dalehumby added the question Further information is requested label Feb 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants