There’s a long thread on the forums for how to control this garage door. I was feeling a little lazy so I’ve not done that yet, but the Bluetooth app that Hörmann provide was too tempting, so I have an ESPhome snippet to do decode the BLE adverts.
Now I can have my HA automation tell me I’ve left the garage door open, which is the critical part for me.
This is fantastic. I tried several times to get https://community.home-assistant.io/t/hormann-garage-door-opener-receive-only/871821 working, but after my wife couldn’t open the gate for the third time because something went wrong again, I gave up on this approach. What I mainly wanted to know was whether my gates were open or closed. For that, this solution is ideal and very simple. I further adapted the script using ChatGPT so that I can use my two gates and also get the statuses open, opening, closing, and closed.
substitutions:
garage_right_mac: "XX:XX:XX:XX:XX:XX"
garage_left_mac: "XX:XX:XX:XX:XX:XX"
esphome:
name: garage_doors
friendly_name: Garage Doors
logger:
esp32:
board: esp32dev
framework:
type: esp-idf
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "BLE-Proxy-Garage"
password: "password"
captive_portal:
improv_serial:
api:
reboot_timeout: 1h
# ==================================================
# Globals (store previous position)
# ==================================================
globals:
- id: right_last_percent
type: int
restore_value: no
initial_value: '0'
- id: left_last_percent
type: int
restore_value: no
initial_value: '0'
# ==================================================
# Sensors
# ==================================================
sensor:
# Wi-Fi RSSI
- platform: wifi_signal
name: "Garage Doors WiFi RSSI"
id: wifi_rssi
unit_of_measurement: "dBm"
update_interval: 60s
# Right door position
- platform: template
name: "Garage Door Right Position"
id: door_right_percent
unit_of_measurement: "%"
accuracy_decimals: 0
filters:
- or:
- throttle: 60s
- delta: 1.0
# Left door position
- platform: template
name: "Garage Door Left Position"
id: door_left_percent
unit_of_measurement: "%"
accuracy_decimals: 0
filters:
- or:
- throttle: 60s
- delta: 1.0
# BLE RSSI right
- platform: template
name: "Garage Door Right BLE RSSI"
id: door_right_rssi
unit_of_measurement: "dBm"
accuracy_decimals: 0
filters:
- throttle: 60s
- median:
window_size: 3
# BLE RSSI left
- platform: template
name: "Garage Door Left BLE RSSI"
id: door_left_rssi
unit_of_measurement: "dBm"
accuracy_decimals: 0
filters:
- throttle: 60s
- median:
window_size: 3
# ==================================================
# Text sensors (door status)
# ==================================================
text_sensor:
- platform: template
name: "Garage Door Right Status"
id: door_right_status
- platform: template
name: "Garage Door Left Status"
id: door_left_status
# ==================================================
# BLE tracker (read-only)
# ==================================================
esp32_ble_tracker:
on_ble_advertise:
# ===== Garage Door Right =====
- mac_address: ${garage_right_mac}
then:
- lambda: |-
auto mfrs = x.get_manufacturer_datas();
if (mfrs.size() != 2) return;
int percent = mfrs[1].data[1] / 2;
int rssi = x.get_rssi();
if (percent < 0) percent = 0;
if (percent > 100) percent = 100;
id(door_right_percent).publish_state(percent);
id(door_right_rssi).publish_state(rssi);
int last = id(right_last_percent);
std::string new_status;
if (percent == 0) {
new_status = "Closed";
} else if (percent == 100) {
new_status = "Open";
} else if (percent > last) {
new_status = "Opening";
} else if (percent < last) {
new_status = "Closing";
}
if (!new_status.empty() && id(door_right_status).state != new_status) {
id(door_right_status).publish_state(new_status);
}
id(right_last_percent) = percent;
# ===== Garage Door Left =====
- mac_address: ${garage_left_mac}
then:
- lambda: |-
auto mfrs = x.get_manufacturer_datas();
if (mfrs.size() != 2) return;
int percent = mfrs[1].data[1] / 2;
int rssi = x.get_rssi();
if (percent < 0) percent = 0;
if (percent > 100) percent = 100;
id(door_left_percent).publish_state(percent);
id(door_left_rssi).publish_state(rssi);
int last = id(left_last_percent);
std::string new_status;
if (percent == 0) {
new_status = "Closed";
} else if (percent == 100) {
new_status = "Open";
} else if (percent > last) {
new_status = "Opening";
} else if (percent < last) {
new_status = "Closing";
}
if (!new_status.empty() && id(door_left_status).state != new_status) {
id(door_left_status).publish_state(new_status);
}
id(left_last_percent) = percent;