Closed 3735943886 closed 1 month ago
Because limited resource of ESP I never seen any retry mechanism which talk to Home Assistant or MQTT. Usually BLE devices sends BLE advertisement very frequently so it's not a point to keep old packets. Also if you have several ESPHome BLE gateways located in the same area with high probability than a few of them receives advertisement and forward it to Home Assistant. If you have very important BLE devices and doesn't want to miss any data from them maybe better to parse data on ESP and export it to Home Assistant as a sensors like this.
Sure you can make the queue for packets, store them in ESPHome and send them when Home Assistant become available, below you can see the example. In ESPHome is the no way to understand if event send or not even for build-in service homeassistant.event
. This example uses api_is_connected()
call to check if it's has connection to Home Assistant. You can send saved packets using on_loop
or interval
. max_packet_queue_size
the size of packet queue, you can make it bigger. If queue is full, it's delete older message and add new one.
Hope this example will help you.
ble_gateway:
devices:
- mac_address: 01:23:45:67:89:AB
- mac_address: !secret lywsd03mmc_mac
on_ble_advertise:
then:
script.execute:
id: packet_queue_push
packet: !lambda return packet;
esphome:
on_loop:
then:
- lambda: |-
if (api_is_connected() && !id(packet_queue).empty()) {
auto packet = id(packet_queue).back();
id(packet_queue).pop_back();
ESP_LOGE("packet_queue", "Fire event, packet: %s", packet.c_str());
static auto capi = new esphome::api::CustomAPIDevice();
capi->fire_homeassistant_event("esphome.on_ble_advertise", {{"packet", packet}});
}
#interval:
# - interval: 250ms
# then:
# - lambda: |-
# if (api_is_connected() && !id(packet_queue).empty()) {
# auto packet = id(packet_queue).back();
# id(packet_queue).pop_back();
#
# ESP_LOGE("packet_queue", "Fire event, packet: %s", packet.c_str());
# static auto capi = new esphome::api::CustomAPIDevice();
# capi->fire_homeassistant_event("esphome.on_ble_advertise", {{"packet", packet}});
# }
globals:
- id: packet_queue
type: std::vector<std::string>
restore_value: no
script:
- id: packet_queue_push
mode: queued
parameters:
packet: string
then:
- lambda: |-
static const size_t max_packet_queue_size = 5;
id(packet_queue).insert(id(packet_queue).begin(), packet);
if (id(packet_queue).size() > max_packet_queue_size)
id(packet_queue).pop_back();
ESP_LOGW("packet_queue", "Current queue size: %d", id(packet_queue).size());
for (size_t i = 0; i < id(packet_queue).size(); i++)
ESP_LOGD("packet_queue", "Queue[%d]: %s", i, id(packet_queue)[i].c_str());
Thank you very much. This was exactly what I needed.
In my setup, I use ESPHome to capture BLE advertisements and send them to Home Assistant using the homeassistant.event action. Occasionally, due to network instability or restarting Home Assistant, the event fails to send, leading to data loss. Having a retry mechanism would ensure that events are reliably sent to Home Assistant, improving the overall robustness of the system.
e.g.
Is it possible?