myhomeiot / esphome-components

A collection of my ESPHome components
Other
257 stars 25 forks source link

BLE Beacon Devices #4

Closed dmamontov closed 2 years ago

dmamontov commented 2 years ago

I would like to be able to also transmit the packet by UUID beacon and not just by mac address in BLE Gateway. Was there such a plan?

myhomeiot commented 2 years ago

Currently BLE Gateway works only with Passive BLE Monitor, which AFAIK doesn't support device definition by UUID and requires MAC address. What you plan to do in Home Assistant with raw BLE HCI packet received and transferred by BLE Gateway to Home Assistant?

dmamontov commented 2 years ago

Yes, I plan to refine it, I suggest debugging this request as I finalize it. At the moment, I made a PR with the transfer of the gateway id https://github.com/custom-components/ble_monitor/pull/636

Since I started a big project to define rooms in conjunction with your component and Passive BLE Monitor. I will post the first alpha version of the component soon.

Just for the future, I wanted to know if there is such an opportunity in esphome itself.

Thank you. I'll let you know when the mod is ready.

myhomeiot commented 2 years ago

Great! I will test and update readme and examples with gateway_id soon.

Yes, it's possible to add and filter packets by UUID into this component, and it's possible to do it even now, using regular esp32_ble_tracker, on_ble_service_data_advertise, and scan_result_to_hci_packet_hex function from BLE Gateway, but I'm not sure if service_uuid it's a beacon UUID:

esp32_ble_tracker:
  on_ble_service_data_advertise:
    - service_uuid: 181A
      then:
        - homeassistant.event:
            event: esphome.on_ble_advertise
            data:
              packet: !lambda return ble_gateway::BLEGateway::scan_result_to_hci_packet_hex(x.get_scan_result());
        - lambda: |-
            ESP_LOGD("on_ble_service_data_advertise", "[%s] Packet %s", x.address_str().c_str(),
              ble_gateway::BLEGateway::scan_result_to_hci_packet_hex(x.get_scan_result()).c_str());

ble_gateway:

You can also check ESPHome BLE Beacon code maybe it's give you some ideas.

Check, and when your mod will be ready let's me know if you need special UUID filter.

dmamontov commented 2 years ago

As I have promised. Released iBeacon support into beta: https://github.com/custom-components/ble_monitor/releases/tag/7.3.0-beta

myhomeiot commented 2 years ago

As I have promised. Released iBeacon support into beta: https://github.com/custom-components/ble_monitor/releases/tag/7.3.0-beta

Great! Did you manage to filter packets by service UUID or you need dedicated beacon UUID filter?

myhomeiot commented 2 years ago

@dmamontov I don't have Beacon to test but I'm confident that you can use this code in order to filter and send packets only for beacon devices (in this code you can also add check for specific UUID):

esp32_ble_tracker:
  on_ble_advertise:
    then:
      - if:
          condition:
            lambda: return x.get_ibeacon().has_value();
          then:
            - lambda: |-
                if (x.get_ibeacon().has_value()) {
                  auto ibeacon = x.get_ibeacon().value();
                  ESP_LOGD("iBeacon", "iBeacon data:");
                  ESP_LOGD("iBeacon", "  UUID: %s", ibeacon.get_uuid().to_string().c_str());
                  ESP_LOGD("iBeacon", "  Major: %u", ibeacon.get_major());
                  ESP_LOGD("iBeacon", "  Minor: %u", ibeacon.get_minor());
                  ESP_LOGD("iBeacon", "  TXPower: %d", ibeacon.get_signal_power());
                }
            - homeassistant.event:
                event: esphome.on_ble_advertise
                data:
                  packet: !lambda return ble_gateway::BLEGateway::scan_result_to_hci_packet_hex(x.get_scan_result());
dmamontov commented 2 years ago

I'll check today, just today the manufacturer wanted to debug a new one.

dmamontov commented 2 years ago

@myhomeiot This is how it works, but the uuid returned is not correct in the log. BBFB5D85-5E46-5D89-DF49-C18E887662F1 instead of F1627688-8EC1-49DF-895D-465E855DFBBB apparently the order is reversed.

But the package is correct.

It still lacks a full filter. Otherwise, I have a lot of beacons in my house in other apartments, and it catches everything).

esp32_ble_tracker:
  on_ble_advertise:
    then:
      - if:
          condition:
            lambda: return x.get_ibeacon().has_value();
          then:
            - lambda: |-
                if (x.get_ibeacon().has_value()) {
                  auto ibeacon = x.get_ibeacon().value();
                  ESP_LOGD("iBeacon", "iBeacon data:");
                  ESP_LOGD("iBeacon", "  UUID: %s", ibeacon.get_uuid().to_string().c_str());
                  ESP_LOGD("iBeacon", "  Major: %u", ibeacon.get_major());
                  ESP_LOGD("iBeacon", "  Minor: %u", ibeacon.get_minor());
                  ESP_LOGD("iBeacon", "  TXPower: %d", ibeacon.get_signal_power());
                  ESP_LOGD("iBeacon", "  Packet: %s", ble_gateway::BLEGateway::scan_result_to_hci_packet_hex(x.get_scan_result()).c_str());
                }
            - homeassistant.event:
                event: esphome.on_ble_advertise
                data:
                  packet: !lambda return ble_gateway::BLEGateway::scan_result_to_hci_packet_hex(x.get_scan_result());

There is software for ibeacon emulation on phones: Android: Beacon Simulator, Home Assistant Companion iOS: Locate Beacon

myhomeiot commented 2 years ago

@dmamontov In ESPHome they reverse the UUID back and forth from version to version, for now you can use this code to filter beacons by UUID:

esp32_ble_tracker:
  on_ble_advertise:
    then:
      - if:
          condition:
            lambda: |-
              static const std::vector<esp32_ble_tracker::ESPBTUUID> uuids = {
                esp32_ble_tracker::ESPBTUUID::from_raw("00000000-0000-0000-0000-000000000000"),
                esp32_ble_tracker::ESPBTUUID::from_raw("00112233-4455-6677-8899-AABBCCDDEEFF"),
                esp32_ble_tracker::ESPBTUUID::from_raw("74278BDA-B644-4520-8F0C-720EAF059935")
              };

              if (!x.get_ibeacon().has_value())
                return false;
              auto ibeacon = x.get_ibeacon().value();
              auto bt_uuid = ibeacon.get_uuid().as_128bit().get_uuid();
              std::reverse(bt_uuid.uuid.uuid128, bt_uuid.uuid.uuid128 + bt_uuid.len);
              auto uuid = esp32_ble_tracker::ESPBTUUID::from_uuid (bt_uuid);
              bool result = std::find(uuids.begin(), uuids.end(), uuid) != uuids.end();
              if (result)
                ESP_LOGW("iBeacon", "UUID: %s, major/minor: %u/%u, TX power: %d",
                  uuid.to_string().c_str(), ibeacon.get_major(), ibeacon.get_minor(), ibeacon.get_signal_power());
              else
                ESP_LOGD("iBeacon", "UUID: %s", uuid.to_string().c_str());
              return result;
          then:
            - homeassistant.event:
                event: esphome.on_ble_advertise
                data:
                  packet: !lambda return ble_gateway::BLEGateway::scan_result_to_hci_packet_hex(x.get_scan_result());
dmamontov commented 2 years ago

Fine. I will update the firmware in all gateways, test and write to you.

dmamontov commented 2 years ago

Everything works great. I will add another sending interval, otherwise the beacons advertise too much (the ones that I have). Thank you.

myhomeiot commented 2 years ago

Excellent! I think for now it's will be as solution for iBeacon. If I will see how it's can be integrated inside the ble_gateway component I will do it, but for now this solution using lambda looks for me better and more flexible.

I added this as example here.