dalehumby / ESPHome-Apple-Watch-detection

ESPHome BLE Apple Watch presence detection
MIT License
332 stars 17 forks source link

ESP32 Restarting #16

Closed jcastro closed 2 years ago

jcastro commented 2 years ago

Hi! Using esphome version 2022.1.4 with a Wemos D1 Mini ESP32 I'm getting restarts after about 5 minutes. Log

[20:59:11][D][sensor:125]: 'Jonatan Apple Watch Oficina RSSI': Sending state -58.53296 dBm with 0 decimals of accuracy
[20:59:11][D][sensor:125]: 'room_presence_debounce': Sending state 1.00000  with 1 decimals of accuracy
[20:59:11][D][script:020]: Script 'presence_timeout' restarting (mode: restart)
[20:59:12][D][text_sensor:067]: 'watch Uptime': Sending state '5m 59s'
[20:59:12][D][sensor:125]: 'watch Uptime': Sending state 358.57599 s with 0 decimals of accuracy
[20:59:12]abort() was called at PC 0x401e0653 on core 0
[20:59:12]
[20:59:12]ELF file SHA256: 0000000000000000
[20:59:12]
[20:59:12]Backtrace: 0x4008f980:0x3ffd5190 0x4008fbfd:0x3ffd51b0 0x401e0653:0x3ffd51d0 0x401e069a:0x3ffd51f0 0x401dffb5:0x3ffd5210 0x401e008c:0x3ffd5230 0x400d7fa5:0x3ffd5250 0x401366d1:0x3ffd5270 0x401317f2:0x3ffd5290 0x40090c72:0x3ffd52c0
WARNING Found stack trace! Trying to decode it
WARNING Decoded 0x4008f980: invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:715
WARNING Decoded 0x4008fbfd: abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:715
WARNING Decoded 0x401e0653: __cxxabiv1::__terminate(void (*)()) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_terminate.cc:112
WARNING Decoded 0x401e069a: std::terminate() at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_terminate.cc:112
WARNING Decoded 0x401dffb5: __cxa_allocate_exception at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_alloc.cc:313
WARNING Decoded 0x401e008c: operator new(unsigned int) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/new_op.cc:54
WARNING Decoded 0x400d7fa5: esphome::esp32_ble_tracker::ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t, esp_ble_gap_cb_param_t*) at /Users/jonatan/Dropbox/Repositories/esphome/.esphome/build/watch/src/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp:241
WARNING Decoded 0x401366d1: btc_gap_ble_cb_to_app at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c:1070
 (inlined by) btc_gap_ble_cb_handler at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c:914
WARNING Decoded 0x401317f2: btc_task at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/bt/common/btc/core/btc_task.c:163
WARNING Decoded 0x40090c72: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c:355 (discriminator 1)
[20:59:13]
[20:59:13]Rebooting...
[20:59:13]ets Jun  8 2016 00:22:57
[20:59:13]
[20:59:13]rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
[20:59:13]configsip: 0, SPIWP:0xee
[20:59:13]clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
[20:59:13]mode:DIO, clock div:2
[20:59:13]load:0x3fff0018,len:4
[20:59:13]load:0x3fff001c,len:1044
[20:59:13]load:0x40078000,len:10124
[20:59:13]load:0x40080400,len:5828
[20:59:13]entry 0x400806a8
[20:59:13][I][logger:214]: Log initialized
[20:59:13][C][ota:458]: There have been 0 suspected unsuccessful boot attempts.
[20:59:13][D][esp32.preferences:114]: Saving preferences to flash...
[20:59:13][I][app:029]: Running through setup()...
[20:59:14][D][esp32_ble_tracker:214]: Starting scan...
[20:59:14][C][wifi:037]: Setting up WiFi...
[20:59:14][I][wifi:245]: WiFi Connecting to 'IoT'...

Configuration

substitutions:
  devicename: watch
  friendly_name: watch
  roomname: Oficina
  yourname: Jonatan
  rssi_present: id(harssi_present).state
  rssi_not_present: id(harssi_not_present).state

esphome:
  name: $devicename
  platform: ESP32
  board: wemos_d1_mini32

wifi:
  networks:
    - ssid: !secret ssid1
      password: !secret ssid1_password
  domain: .local
  use_address: $devicename.local
  fast_connect: True

api:

ota:
    password: !secret ota_password

web_server:

logger:

captive_portal:  

text_sensor:
    - platform: template
      name: $friendly_name Uptime
      id: uptime_human
      icon: mdi:clock-start

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.harssipv  #insert your input.number entity id here
    id: harssi_present
  - platform: homeassistant
    name: HA RSSI Not Present Value
    entity_id: input_number.harssinpv  #insert your input.number entity id here
    id: harssi_not_present

  - platform: uptime
    name: $friendly_name Uptime
    id: uptime_sensor
    update_interval: 5s
    internal: true
    on_raw_value:
      then:
        - text_sensor.template.publish:
            id: uptime_human
            state: !lambda |-
              int seconds = round(id(uptime_sensor).raw_state);
              int days = seconds / (24 * 3600);
              seconds = seconds % (24 * 3600);
              int hours = seconds / 3600;
              seconds = seconds % 3600;
              int minutes = seconds /  60;
              seconds = seconds % 60;
              return (
                (days ? String(days) + "d " : "") +
                (hours ? String(hours) + "h " : "") +
                (minutes ? String(minutes) + "m " : "") +
                (String(seconds) + "s")
              ).c_str();

### Apple Watch PResence
esp32_ble_tracker:
  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 Watch. To also match locked watch use: if (data_flags == 0x98 || data_flags == 0x18) {
              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);
          }

binary_sensor:
  - 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
0nikola1 commented 2 years ago

It depends on ESP version of board which you are using. I had some boards that just aren't for bluetooth as they would crash. I don't have issues with this detection on 1 wifi only board and 3 ethernet boards that I tried so far.

jcastro commented 2 years ago

It depends on ESP version of board which you are using. I had some boards that just aren't for bluetooth as they would crash. I don't have issues with this detection on 1 wifi only board and 3 ethernet boards that I tried so far.

I posted it here as well and it seems I'm not the only one! https://github.com/esphome/issues/issues/3039

dalehumby commented 2 years ago

Hi @jcastro - In the meantime, could you try changing

    window: 500ms

to something lower, like 100ms, or even 50ms. This might reduce the load on the CPU reducing crashes. It does lower the chance of you watch being detected, so might take longer to change from present to not present.