Controlling BLE ceiling light with HA

Trust me when I tell you that the BLE stack in Linux user space SUCKS. You only have the bleek d-bus user space stuff to talk to the BLE kernel module and you don’t really have the ability to control the bt adapter the way that is needed. For example: I was reverse engineering the cync by ge btle stuff and couldn’t reliably get anywhere because of the Linux bt restrictions (like can’t even connect to a device).

If the bleek API thinks it’s getting any btle data that doesn’t conform to standards, it errors out. So any custom Bluetooth stuff is out of the question. It is really quite disappointing.

Tldr; stick with esp32 based btle controller.

Are you completely cutting power to the fan? Just pressing power button on the remote is not enough you need to completely cut power either with your breaker or a relay for it to enter pairing more. My fan’s light also blinks when the pair is successful

I would for the sake of testing put it as close as possible. Use an extension cord if you have to just to rule out the distance being a factor

I have a mini ESP32 C3 board, and I am not able to install to it @NicoIIT

This is my setup:

esphome:
  name: fan

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "CQ9eKokvQxcPtJ2YelCdUoiSbydfR8KpK9ec6Fg2rKc="

ota:
  - platform: esphome
    password: "caf3bb91f14fb099775cb5670ad442ec"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Fan Fallback Hotspot"
    password: "aQOM0grbgQcK"

captive_portal:

external_components:
  source: github://NicoIIT/esphome-components

ble_adv_controller:
  # A controller per device, or per remote in fact as it has the same role
  - id: my_controller
    # encoding: could be any of 'zhijia', 'fanlamp_pro', 'smartlamp_pro' (the 2 last are the same)
    encoding: fanlamp_pro
    # variant: variant of the encoding 
    # For ZhiJia: Can be v0 (MSC16), v1 (MSC26) or v2 (MSC26A), default is v2
    # For Fanlamp: Can be any of 'v1a', 'v1b', 'v2' or 'v3', depending on how old your lamp is... Default is 'v3'
    variant: v3
    # max_duration (default 3000, range 300 -> 10000): the maximum duration in ms during which the command is advertized.
    # if a command is received before the 'max_duration' but after the 'duration', it is processed immediately 
    # Increasing this parameter will have no major consequences, the component will just keep advertize the command
    # Could be interesting at pairing time to have the pairing command advertized for a long time
    max_duration: 3000
    # duration (default 200, range 100 -> 500): the MINIMUM duration in ms during which the command is sent.
    # It corresponds to the maximum time the controlled device is taking to process a command and be ready to receive a new one.
    # if a command is received before the 'duration' it is queued and processed later, 
    # if there is already a similar command pending, in this case the pending command is removed from the queue
    # Increasing this parameter will make the combination of commands slower. See 'Dynamic Configuration'.
    duration: 200
    # reversed: reversing the cold / warm at encoding time, needed for some controllers
    # default to false
    reversed: false
    # forced_id: provide the 4 bytes identifier key extracted from your app phone traffic 
    # to share the same key than the phone
    # example: 0xBFF62757
    # For ZhiJia, default to 0xC630B8 which was the value hard-coded in ble_adv_light component. Max 0xFFFFFF.
    # For FanLamp: default to 0, uses the hash id computed by esphome from the id/name of the controller
    forced_id: 0
    # show_config (default true): shows the dynamic configuration in the device info page in Home Automation
    show_config: true

fan:
  - platform: ble_adv_controller
    ble_adv_controller_id: my_controller
    name: fan
    # speed_count: the number of speed level available on your remote / app. Can be 0 / 3 / 6.
    # if not properly setup the remote and this component does not behave properly together
    # only speed 6 is available for zhijia, and this is the default
    speed_count: 6
    # use_direction: ability to change the fan direction forward / reverse.
    # default to true, not available for zhijia
    use_direction: true
    # use_oscillation: ability to start / stop the fan oscillation.
    # default to false, only available for FanLamp v2 / v3
    use_oscillation: false

button:
  - platform: ble_adv_controller
    ble_adv_controller_id: my_controller
    name: Pair
    # cmd: the action to be executed when the button is pressed
    # any of 'pair', 'unpair', 'custom', 'light_on', ...
    cmd: pair

I get this error:

INFO ESPHome 2024.7.3
INFO Reading configuration /config/fan.yaml...
INFO Generating C++ source...
INFO Compiling app...
Processing fan (board: esp32-c3-devkitm-1; framework: espidf; platform: platformio/[email protected])
--------------------------------------------------------------------------------
HARDWARE: ESP32C3 160MHz, 320KB RAM, 4MB Flash
 - framework-espidf @ 3.40407.240606 (4.4.7) 
 - tool-cmake @ 3.16.4 
 - tool-ninja @ 1.7.1 
 - toolchain-esp32ulp @ 2.35.0-20220830 
 - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5
Reading CMake configuration...
Dependency Graph
|-- noise-c @ 0.1.4
Compiling .pioenvs/fan/src/esphome/components/ble_adv_controller/fanlamp_pro.o
Compiling .pioenvs/fan/src/esphome/components/ble_adv_controller/zhijia.o
Compiling .pioenvs/fan/src/esphome/components/captive_portal/captive_portal.o
Compiling .pioenvs/fan/src/esphome/components/esp32/core.o
Compiling .pioenvs/fan/src/esphome/components/esp32/gpio.o
src/esphome/components/ble_adv_controller/fanlamp_pro.cpp: In function 'uint16_t esphome::bleadvcontroller::sign(uint8_t*, uint8_t, uint16_t)':
src/esphome/components/ble_adv_controller/fanlamp_pro.cpp:78:35: error: 'ESP_AES_ENCRYPT' was not declared in this scope
   mbedtls_aes_crypt_ecb(&aes_ctx, ESP_AES_ENCRYPT, aes_in, aes_out);
                                   ^~~~~~~~~~~~~~~
src/esphome/components/ble_adv_controller/fanlamp_pro.cpp:78:35: note: suggested alternative: 'ESP_BLE_SEC_ENCRYPT'
   mbedtls_aes_crypt_ecb(&aes_ctx, ESP_AES_ENCRYPT, aes_in, aes_out);
                                   ^~~~~~~~~~~~~~~
                                   ESP_BLE_SEC_ENCRYPT
src/esphome/components/ble_adv_controller/fanlamp_pro.cpp: In function 'void esphome::bleadvcontroller::v2_whiten(uint8_t*, uint8_t, uint8_t, uint8_t)':
src/esphome/components/ble_adv_controller/fanlamp_pro.cpp:86:44: error: suggest parentheses around '+' in operand of '&' [-Werror=parentheses]
     buf[i] ^= XBOXES[(seed + i + 9) & 0x1f + (salt & 0x3) * 0x20];
                                       ~~~~~^~~~~~~~~~~~~~~~~~~~~
src/esphome/components/ble_adv_controller/zhijia.cpp: In function 'void esphome::bleadvcontroller::msc16_msc26::aes26Encrypt(uint8_t*, uint8_t*, uint8_t*, uint8_t, uint8_t, uint8_t, uint8_t*, uint8_t*)':
src/esphome/components/ble_adv_controller/zhijia.cpp:240:33: error: suggest parentheses around arithmetic in operand of '^' [-Werror=parentheses]
     txData[8] = (txData[8] & 1) - 1 ^ txData[8];
                 ~~~~~~~~~~~~~~~~^~~
src/esphome/components/ble_adv_controller/zhijia.cpp: In function 'unsigned char* esphome::bleadvcontroller::msc26a::stage2(unsigned char*, unsigned int, unsigned int)':
src/esphome/components/ble_adv_controller/zhijia.cpp:424:32: error: suggest parentheses around arithmetic in operand of '|' [-Werror=parentheses]
                         (uVar4 & 2 | (uVar4 & 1) << 2 | (uVar4 & 0xff) >> 2 & 1)
                          ~~~~~~^~~
src/esphome/components/ble_adv_controller/zhijia.cpp:424:77: error: suggest parentheses around arithmetic in operand of '|' [-Werror=parentheses]
                         (uVar4 & 2 | (uVar4 & 1) << 2 | (uVar4 & 0xff) >> 2 & 1)
                                                         ~~~~~~~~~~~~~~~~~~~~^~~
src/esphome/components/ble_adv_controller/zhijia.cpp:423:36: error: suggest parentheses around arithmetic in operand of '|' [-Werror=parentheses]
                        (uVar4 >> 3 & 1 |
                         ~~~~~~~~~~~^~~
src/esphome/components/ble_adv_controller/zhijia.cpp:422:44: error: suggest parentheses around arithmetic in operand of '|' [-Werror=parentheses]
                       ((uVar4 & 0xff) >> 4 & 1 |
                        ~~~~~~~~~~~~~~~~~~~~^~~
src/esphome/components/ble_adv_controller/zhijia.cpp:421:34: error: suggest parentheses around arithmetic in operand of '|' [-Werror=parentheses]
                      (uVar4 >> 5 & 1 |
                       ~~~~~~~~~~~^~~
src/esphome/components/ble_adv_controller/zhijia.cpp:420:33: error: suggest parentheses around arithmetic in operand of '|' [-Werror=parentheses]
           (uint8_t)((uVar4 >> 6 & 1 |
                      ~~~~~~~~~~~^~~
src/esphome/components/ble_adv_controller/zhijia.cpp:419:33: error: suggest parentheses around arithmetic in operand of '|' [-Werror=parentheses]
           (uint8_t)(uVar4 >> 7) & 1 |
           ~~~~~~~~~~~~~~~~~~~~~~^~~
src/esphome/components/ble_adv_controller/zhijia.cpp: In function 'void esphome::bleadvcontroller::msc26a::whitening_encode(unsigned char*, int, unsigned int*)':
src/esphome/components/ble_adv_controller/zhijia.cpp:500:49: error: suggest parentheses around arithmetic in operand of '^' [-Werror=parentheses]
       iVar4 += (uVar2 ^ bVar1 >> (uVar3 & 0xff) & 1) << (uVar3 & 0xff);
                         ~~~~~~~~~~~~~~~~~~~~~~~~^~~
cc1plus: some warnings being treated as errors
*** [.pioenvs/fan/src/esphome/components/ble_adv_controller/fanlamp_pro.o] Error 1
cc1plus: some warnings being treated as errors
*** [.pioenvs/fan/src/esphome/components/ble_adv_controller/zhijia.o] Error 1
========================= [FAILED] Took 23.37 seconds =========================

And if I remove the framework type I get this error:

INFO ESPHome 2024.7.3
INFO Reading configuration /config/fan.yaml...
INFO Generating C++ source...
INFO Compiling app...
Processing fan (board: esp32-c3-devkitm-1; framework: arduino; platform: platformio/[email protected])
--------------------------------------------------------------------------------
Removing unused dependencies...
Library Manager: Installing esphome/AsyncTCP-esphome @ 2.1.3
INFO Installing esphome/AsyncTCP-esphome @ 2.1.3
Unpacking  [####################################]  100%
Library Manager: [email protected] has been installed!
INFO [email protected] has been installed!
Library Manager: Installing esphome/ESPAsyncWebServer-esphome @ 3.2.2
INFO Installing esphome/ESPAsyncWebServer-esphome @ 3.2.2
Unpacking  [####################################]  100%
Library Manager: [email protected] has been installed!
INFO [email protected] has been installed!
Library Manager: Resolving dependencies...
INFO Resolving dependencies...
HARDWARE: ESP32C3 160MHz, 320KB RAM, 4MB Flash
 - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5
Dependency Graph
|-- AsyncTCP-esphome @ 2.1.3
|-- WiFi @ 2.0.0
|-- FS @ 2.0.0
|-- Update @ 2.0.0
|-- ESPAsyncWebServer-esphome @ 3.2.2
|-- DNSServer @ 2.0.0
|-- ESPmDNS @ 2.0.0
|-- noise-c @ 0.1.4
Compiling .pioenvs/fan/src/esphome/components/api/api_connection.cpp.o
Compiling .pioenvs/fan/src/esphome/components/api/api_frame_helper.cpp.o
Compiling .pioenvs/fan/src/esphome/components/api/api_pb2.cpp.o
Compiling .pioenvs/fan/src/esphome/components/api/api_pb2_service.cpp.o
Compiling .pioenvs/fan/src/esphome/components/api/api_server.cpp.o
Compiling .pioenvs/fan/src/esphome/components/api/list_entities.cpp.o
Compiling .pioenvs/fan/src/esphome/components/api/proto.cpp.o
Compiling .pioenvs/fan/src/esphome/components/api/subscribe_state.cpp.o
Compiling .pioenvs/fan/src/esphome/components/api/user_services.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ble_adv_controller/ble_adv_controller.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ble_adv_controller/ble_adv_handler.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ble_adv_controller/button/ble_adv_button.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ble_adv_controller/fan/ble_adv_fan.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ble_adv_controller/fanlamp_pro.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ble_adv_controller/zhijia.cpp.o
Compiling .pioenvs/fan/src/esphome/components/button/button.cpp.o
Compiling .pioenvs/fan/src/esphome/components/captive_portal/captive_portal.cpp.o
Compiling .pioenvs/fan/src/esphome/components/esp32/core.cpp.o
Compiling .pioenvs/fan/src/esphome/components/esp32/gpio.cpp.o
Compiling .pioenvs/fan/src/esphome/components/esp32/preferences.cpp.o
Compiling .pioenvs/fan/src/esphome/components/esp32_ble/ble.cpp.o
Compiling .pioenvs/fan/src/esphome/components/esp32_ble/ble_advertising.cpp.o
Compiling .pioenvs/fan/src/esphome/components/esp32_ble/ble_uuid.cpp.o
Compiling .pioenvs/fan/src/esphome/components/esphome/ota/ota_esphome.cpp.o
Compiling .pioenvs/fan/src/esphome/components/fan/fan.cpp.o
Compiling .pioenvs/fan/src/esphome/components/fan/fan_state.cpp.o
Compiling .pioenvs/fan/src/esphome/components/logger/logger.cpp.o
Compiling .pioenvs/fan/src/esphome/components/logger/logger_esp32.cpp.o
Compiling .pioenvs/fan/src/esphome/components/logger/logger_esp8266.cpp.o
Compiling .pioenvs/fan/src/esphome/components/logger/logger_host.cpp.o
Compiling .pioenvs/fan/src/esphome/components/logger/logger_libretiny.cpp.o
Compiling .pioenvs/fan/src/esphome/components/logger/logger_rp2040.cpp.o
Compiling .pioenvs/fan/src/esphome/components/md5/md5.cpp.o
Compiling .pioenvs/fan/src/esphome/components/mdns/mdns_component.cpp.o
Compiling .pioenvs/fan/src/esphome/components/mdns/mdns_esp32.cpp.o
Compiling .pioenvs/fan/src/esphome/components/mdns/mdns_esp8266.cpp.o
Compiling .pioenvs/fan/src/esphome/components/mdns/mdns_host.cpp.o
Compiling .pioenvs/fan/src/esphome/components/mdns/mdns_libretiny.cpp.o
Compiling .pioenvs/fan/src/esphome/components/mdns/mdns_rp2040.cpp.o
Compiling .pioenvs/fan/src/esphome/components/network/util.cpp.o
Compiling .pioenvs/fan/src/esphome/components/number/automation.cpp.o
Compiling .pioenvs/fan/src/esphome/components/number/number.cpp.o
Compiling .pioenvs/fan/src/esphome/components/number/number_call.cpp.o
Compiling .pioenvs/fan/src/esphome/components/number/number_traits.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ota/ota_backend.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ota/ota_backend_arduino_esp32.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ota/ota_backend_arduino_esp8266.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ota/ota_backend_arduino_libretiny.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ota/ota_backend_arduino_rp2040.cpp.o
Compiling .pioenvs/fan/src/esphome/components/ota/ota_backend_esp_idf.cpp.o
Compiling .pioenvs/fan/src/esphome/components/safe_mode/safe_mode.cpp.o
Compiling .pioenvs/fan/src/esphome/components/select/select.cpp.o
Compiling .pioenvs/fan/src/esphome/components/select/select_call.cpp.o
Compiling .pioenvs/fan/src/esphome/components/select/select_traits.cpp.o
Compiling .pioenvs/fan/src/esphome/components/socket/bsd_sockets_impl.cpp.o
Compiling .pioenvs/fan/src/esphome/components/socket/lwip_raw_tcp_impl.cpp.o
Compiling .pioenvs/fan/src/esphome/components/socket/lwip_sockets_impl.cpp.o
Compiling .pioenvs/fan/src/esphome/components/socket/socket.cpp.o
Compiling .pioenvs/fan/src/esphome/components/web_server_base/web_server_base.cpp.o
Compiling .pioenvs/fan/src/esphome/components/wifi/wifi_component.cpp.o
Compiling .pioenvs/fan/src/esphome/components/wifi/wifi_component_esp32_arduino.cpp.o
Compiling .pioenvs/fan/src/esphome/components/wifi/wifi_component_esp8266.cpp.o
Compiling .pioenvs/fan/src/esphome/components/wifi/wifi_component_esp_idf.cpp.o
Compiling .pioenvs/fan/src/esphome/components/wifi/wifi_component_libretiny.cpp.o
Compiling .pioenvs/fan/src/esphome/components/wifi/wifi_component_pico_w.cpp.o
Compiling .pioenvs/fan/src/esphome/core/application.cpp.o
Compiling .pioenvs/fan/src/esphome/core/color.cpp.o
Compiling .pioenvs/fan/src/esphome/core/component.cpp.o
Compiling .pioenvs/fan/src/esphome/core/component_iterator.cpp.o
Compiling .pioenvs/fan/src/esphome/core/controller.cpp.o
Compiling .pioenvs/fan/src/esphome/core/entity_base.cpp.o
Compiling .pioenvs/fan/src/esphome/core/helpers.cpp.o
Compiling .pioenvs/fan/src/esphome/core/log.cpp.o
Compiling .pioenvs/fan/src/esphome/core/ring_buffer.cpp.o
Compiling .pioenvs/fan/src/esphome/core/scheduler.cpp.o
Compiling .pioenvs/fan/src/esphome/core/string_ref.cpp.o
Compiling .pioenvs/fan/src/esphome/core/time.cpp.o
Compiling .pioenvs/fan/src/esphome/core/util.cpp.o
Compiling .pioenvs/fan/src/main.cpp.o
Building .pioenvs/fan/bootloader.bin
Creating esp32c3 image...
Successfully created esp32c3 image.
Generating partitions .pioenvs/fan/partitions.bin
Compiling .pioenvs/fan/libe11/AsyncTCP-esphome/AsyncTCP.cpp.o
Compiling .pioenvs/fan/lib13d/WiFi/WiFi.cpp.o
Compiling .pioenvs/fan/lib13d/WiFi/WiFiAP.cpp.o
Compiling .pioenvs/fan/lib13d/WiFi/WiFiClient.cpp.o
Archiving .pioenvs/fan/libe11/libAsyncTCP-esphome.a
Compiling .pioenvs/fan/lib13d/WiFi/WiFiGeneric.cpp.o
Compiling .pioenvs/fan/lib13d/WiFi/WiFiMulti.cpp.o
Compiling .pioenvs/fan/lib13d/WiFi/WiFiSTA.cpp.o
Compiling .pioenvs/fan/lib13d/WiFi/WiFiScan.cpp.o
Compiling .pioenvs/fan/lib13d/WiFi/WiFiServer.cpp.o
Compiling .pioenvs/fan/lib13d/WiFi/WiFiUdp.cpp.o
Compiling .pioenvs/fan/liba49/FS/FS.cpp.o
Compiling .pioenvs/fan/liba49/FS/vfs_api.cpp.o
Compiling .pioenvs/fan/lib8c7/Update/HttpsOTAUpdate.cpp.o
Archiving .pioenvs/fan/lib13d/libWiFi.a
Compiling .pioenvs/fan/lib8c7/Update/Updater.cpp.o
Compiling .pioenvs/fan/lib325/ESPAsyncWebServer-esphome/AsyncEventSource.cpp.o
Compiling .pioenvs/fan/lib325/ESPAsyncWebServer-esphome/AsyncWebSocket.cpp.o
Archiving .pioenvs/fan/liba49/libFS.a
Compiling .pioenvs/fan/lib325/ESPAsyncWebServer-esphome/WebAuthentication.cpp.o
Archiving .pioenvs/fan/lib8c7/libUpdate.a
Compiling .pioenvs/fan/lib325/ESPAsyncWebServer-esphome/WebHandlers.cpp.o
Compiling .pioenvs/fan/lib325/ESPAsyncWebServer-esphome/WebRequest.cpp.o
Compiling .pioenvs/fan/lib325/ESPAsyncWebServer-esphome/WebResponses.cpp.o
Compiling .pioenvs/fan/lib325/ESPAsyncWebServer-esphome/WebServer.cpp.o
Compiling .pioenvs/fan/lib946/DNSServer/DNSServer.cpp.o
Archiving .pioenvs/fan/lib946/libDNSServer.a
Compiling .pioenvs/fan/libf06/ESPmDNS/ESPmDNS.cpp.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c.o
Archiving .pioenvs/fan/lib325/libESPAsyncWebServer-esphome.a
Compiling .pioenvs/fan/libccb/libsodium/crypto_core/ed25519/core_ed25519.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_core/ed25519/core_ristretto255.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_core/ed25519/ref10/ed25519_ref10.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_hash/crypto_hash.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_hash/sha256/cp/hash_sha256_cp.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_hash/sha256/hash_sha256.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_onetimeauth/crypto_onetimeauth.c.o
Archiving .pioenvs/fan/libf06/libESPmDNS.a
Compiling .pioenvs/fan/libccb/libsodium/crypto_onetimeauth/poly1305/donna/poly1305_donna.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_scalarmult/crypto_scalarmult.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_scalarmult/curve25519/scalarmult_curve25519.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_stream/chacha20/ref/chacha20_ref.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_stream/chacha20/stream_chacha20.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_stream/crypto_stream.c.o
Compiling .pioenvs/fan/libccb/libsodium/crypto_verify/sodium/verify.c.o
Compiling .pioenvs/fan/libccb/libsodium/sodium/codecs.c.o
Compiling .pioenvs/fan/libccb/libsodium/sodium/core.c.o
Compiling .pioenvs/fan/libccb/libsodium/sodium/runtime.c.o
Compiling .pioenvs/fan/libccb/libsodium/sodium/utils.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/openssl/cipher-aesgcm.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/ref/cipher-aesgcm.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/ref/cipher-chachapoly.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/ref/dh-curve25519.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/ref/hash-blake2b.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/ref/hash-blake2s.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/ref/hash-sha256.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/sodium/cipher-aesgcm.c.o
Archiving .pioenvs/fan/libccb/libsodium.a
Compiling .pioenvs/fan/libe6a/noise-c/backend/sodium/cipher-chachapoly.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/sodium/dh-curve25519.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/sodium/hash-blake2b.c.o
Compiling .pioenvs/fan/libe6a/noise-c/backend/sodium/hash-sha256.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/aes/rijndael-alg-fst.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/blake2/blake2b.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/blake2/blake2s.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/chacha/chacha.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/donna/curve25519-donna-c64.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/donna/curve25519-donna.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/donna/poly1305-donna.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/sha2/sha256.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/sha2/sha512.c.o
Compiling .pioenvs/fan/libe6a/noise-c/crypto/x25519/x25519.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/cipherstate.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/dhstate.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/errors.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/handshakestate.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/hashstate.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/internal.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/names.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/patterns.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/rand_os.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/rand_sodium.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/randstate.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/signstate.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/symmetricstate.c.o
Compiling .pioenvs/fan/libe6a/noise-c/protocol/util.c.o
Compiling .pioenvs/fan/FrameworkArduino/Esp.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/FirmwareMSC.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/FunctionalInterrupt.cpp.o
Archiving .pioenvs/fan/libe6a/libnoise-c.a
Compiling .pioenvs/fan/FrameworkArduino/HWCDC.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/HardwareSerial.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/IPAddress.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/IPv6Address.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/MD5Builder.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/Print.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/Stream.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/StreamString.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/Tone.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/USB.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/USBCDC.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/USBMSC.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/WMath.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/WString.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/base64.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/cbuf.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-adc.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-bt.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-cpu.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-dac.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-gpio.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-i2c-slave.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-i2c.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-ledc.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-matrix.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-misc.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-psram.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-rgb-led.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-rmt.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-sigmadelta.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-spi.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-time.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-timer.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-tinyusb.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-touch.c.o
Compiling .pioenvs/fan/FrameworkArduino/esp32-hal-uart.c.o
Compiling .pioenvs/fan/FrameworkArduino/firmware_msc_fat.c.o
Compiling .pioenvs/fan/FrameworkArduino/libb64/cdecode.c.o
Compiling .pioenvs/fan/FrameworkArduino/libb64/cencode.c.o
Compiling .pioenvs/fan/FrameworkArduino/main.cpp.o
Compiling .pioenvs/fan/FrameworkArduino/stdlib_noniso.c.o
Compiling .pioenvs/fan/FrameworkArduino/wiring_pulse.c.o
Compiling .pioenvs/fan/FrameworkArduino/wiring_shift.c.o
Archiving .pioenvs/fan/libFrameworkArduino.a
Linking .pioenvs/fan/firmware.elf
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: .pioenvs/fan/src/esphome/components/ble_adv_controller/ble_adv_controller.cpp.o: in function `void esphome::api::UserServiceBase<int, int, int, int, int>::execute_<0, 1, 2, 3, 4>(std::vector<esphome::api::ExecuteServiceArgument, std::allocator<esphome::api::ExecuteServiceArgument> >, esphome::seq<0, 1, 2, 3, 4>)':
/data/build/fan/src/esphome/components/api/user_services.h:57: undefined reference to `int esphome::api::get_execute_arg_value<int>(esphome::api::ExecuteServiceArgument const&)'
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/build/fan/src/esphome/components/api/user_services.h:57: undefined reference to `int esphome::api::get_execute_arg_value<int>(esphome::api::ExecuteServiceArgument const&)'
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/build/fan/src/esphome/components/api/user_services.h:57: undefined reference to `int esphome::api::get_execute_arg_value<int>(esphome::api::ExecuteServiceArgument const&)'
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/build/fan/src/esphome/components/api/user_services.h:57: undefined reference to `int esphome::api::get_execute_arg_value<int>(esphome::api::ExecuteServiceArgument const&)'
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/build/fan/src/esphome/components/api/user_services.h:57: undefined reference to `int esphome::api::get_execute_arg_value<int>(esphome::api::ExecuteServiceArgument const&)'
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: .pioenvs/fan/src/esphome/components/ble_adv_controller/ble_adv_controller.cpp.o: in function `esphome::api::UserServiceBase<int, int, int, int, int>::encode_list_service_response()':
/data/build/fan/src/esphome/components/api/user_services.h:35: undefined reference to `esphome::api::enums::ServiceArgType esphome::api::to_service_arg_type<int>()'
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/build/fan/src/esphome/components/api/user_services.h:35: undefined reference to `esphome::api::enums::ServiceArgType esphome::api::to_service_arg_type<int>()'
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/build/fan/src/esphome/components/api/user_services.h:35: undefined reference to `esphome::api::enums::ServiceArgType esphome::api::to_service_arg_type<int>()'
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/build/fan/src/esphome/components/api/user_services.h:35: undefined reference to `esphome::api::enums::ServiceArgType esphome::api::to_service_arg_type<int>()'
/cache/platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/build/fan/src/esphome/components/api/user_services.h:35: undefined reference to `esphome::api::enums::ServiceArgType esphome::api::to_service_arg_type<int>()'
collect2: error: ld returned 1 exit status
*** [.pioenvs/fan/firmware.elf] Error 1
========================= [FAILED] Took 196.30 seconds =========================

Maybe this is a better fit?

However it is not clear if this is has BLE?

Same here. Won’t link objects for ESP32 C3.
Successfully built using this patch api services remote_transmitter compile error esp32c3 #2 · Issue #3564 · esphome/issues · GitHub

Hello @joq3, I just corrected the compilation issues you had with your board:

  • I never tested the esp-idf framework before, and it has a compiler that is not able to properly apply the c++ operator precedence it seems. I updated the code to have it work with its limited knowledge.
  • For the linkage issue, as highlighted by @gyp5y there is a known issue on the ESP32-C3 board for this using “int” for api parameters. I replaced them by “float” which is completely acceptable for the purpose of this api and all is working OK.

Just be sure to refresh to latest version (refresh: 0s in external_components) and you should be ok!

Thank you! Actually ended up buying a WROOM which worked instantly.

However I have a small issue. If I cut power to the ESP32 and power it up again, it will always start the fan at 100% even if I use Home Assistant to set_percentage (which also starts the fan). After turning off the fan in Home Assistant it will work as expected and remember the last setting.
Is it possible to set a default speed for the fan to always start at?

I just implemented the ESPHome standard restore_mode for Fan as it was not using the parent one, it is now available for both Fan and Light! See updated doc.

EDIT: should you not want to save the last state and restore it at reboot, you can still benefit from ESPHome Fan automation and perform action on boot such as this one:

esphome:
  on_boot:
    priority: -100
    then:
      fan.turn_on:
        id: my_fan
        speed: 3
        direction: forward
        oscillating: false

EDIT: One more thing, i see you added duration as a slider in HA. Can I get the same for min_brightness? Thanks a bunch!

@Maxcodesthings , you have it now !

Amazing, installing it now with refresh: 0s and hoping it will work.
Thank you for your great work!

Is it technically impossible for ESPHome and Home Assistant to detect the state of the fan/light when it is turned on or changed from the included remote?
Or will this be something that might work in the future?

Thanks!

As detailed in the doc, the communication between the remote (or phone app / esp32 board) and the controlled device is unidirectional: the device do never share its effective state so there is no way to update HA from the device.

Still it is not completely impossible, we would need:

  1. to listen to the messages sent by the remote
  2. to decode them
  3. to align the state of the entity accordingly

The part (3) is feasible as we are already doing it the reverse way, still it requires some work.

The part (2) might be partially feasible, at least we know how to do it for some of the encoding / variant but not for all of them. Decoding all the encoding / variants would be the part that would require the more work.

The part (1) may in fact be the more challenging: despite we know how to listen to SOME of the BLE ADV messages using esp_ble32_tracker ESPHome component, we may not capture all of them, and it may be technically difficult to run at the same time and on the same ESP32 board the listening and advertising part as they are using the same technical stack and may conflict sharing it.

Moreover it would also require that all the messages received by the device are also received by the ESP32 board, which may not be the case if there is an obstacle in between the remote and the ESP32 board, but no obstacle in between the remote and the device (or the reverse).

A way to make it more reliable would be to unpair the remote (and/or the phone app) from the device and have the board be the only one paired to the device. The board would listen to the remote, decode the requested state and issue the command to the device. This way of proceeding would be the way to go (we can even imagine re using the remotes for other purposes!)

To conclude: yes it would be feasible but it would require a lot of work to implement this feature, and it might not be highly reliable. If time permit / people want to work on it, maybe one day…

Makes total sense! Is there any available remote which is good for this application. The easiest way would be to find a zigbee remote which communicates with Home Assistant?

If you would find a bluetooth remote there’s a lot of work to be able to pair it with the ESP device I imagine?

Can I pair 2 devices (fan/lamp) with one ESP32 device? I have 1 lamp working fine, ESP32 is placed in range of 2 lamps.

Yes you can!
Just define another controller with another id, and its associated light / fan / pair button:

ble_adv_controller:
  - id: my_controller_1
    encoding: zhijia
  - id: my_controller_2
    encoding: zhijia

light:
  - platform: ble_adv_controller
    ble_adv_controller_id: my_controller_1
    name: My Light 1
  - platform: ble_adv_controller
    ble_adv_controller_id: my_controller_2
    name: My Light 2

fan:
  - platform: ble_adv_controller
    ble_adv_controller_id: my_controller_1
    name: My Fan 1
  - platform: ble_adv_controller
    ble_adv_controller_id: my_controller_2
    name: My Fan 2

button:
  - platform: ble_adv_controller
    ble_adv_controller_id: my_controller_1
    name: Pair 1
    cmd: pair
  - platform: ble_adv_controller
    ble_adv_controller_id: my_controller_2
    name: Pair 2
    cmd: pair

thanks, is there any limit of devices to control?

Yes, but It is difficult to give a number. I defined 10+ for test purposes with no issue but they did not control real devices… If you do not want to control them at the same time there will be no issue, but latency issue will probably come while performing simultaneous commands to several devices at the same time as they need to share the same technical BLE ADV stack: the more devices, the more latency on simultaneous commands… With the default setup each command is holding the stack for 100ms, so if you send a command to 10 devices simultaneously it will take minimum 1s to have them applied to all devices, and up to 2s or 3s if retries are needed.

Hello !
I’m trying to update ESPhome and I get this error

INFO ESPHome 2024.8.0
INFO Reading configuration /config/esphome/flower.yaml...
Failed config

ble_adv_controller: [source /config/esphome/flower.yaml:45]
  
  Invalid 'forced_id' for zhijia - v0: 0xC630B8. Maximum: 0xFFFF.
  - id: my_controller
    encoding: zhijia
    duration: 360
    seq_duration: 120
    variant: v0

@sasha8761 , I just pushed a new (big) update that should include the fix for this issue, let me now if OK.