#:########################################################################################:# # TITLE: STAIR OCCUPANCY AND UNDERHOUSE ENVIRONMENT # zorruno.com layout v1.1 2026 #:########################################################################################:# # REPO: # https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-occupancystair.yaml #:########################################################################################:# # VERSIONS: # V2.2 2026-02-25 Updated yaml to zorruno layout V1.1 # V2.1 2025-08-25 Added some MQTT to send commands to turn on remote lights # V2.0 2025-06-05 YAML Tidyups #:########################################################################################:# # HARDWARE: # D1 Mini ESP32 with: # - HiLink LD2410 mmWave presence sensor (UART) # - BME280 Temp/Humidity/Pressure sensor (I2C) # - Generic PIR sensor (GPIO) # # References: # - https://esphome.io/components/sensor/ld2410.html # - https://www.simplysmart.house/blog/presence-detection-ld2410-home-assistant # - https://github.com/patrick3399/Hi-Link_mmWave_Radar_ESPHome/tree/main #:########################################################################################:# # OPERATION NOTES: # - Provides mmWave presence (moving/still) plus PIR motion. # - Provides environment sensors (BME280). # - When mmWave presence/moving target or PIR triggers, a script publishes MQTT commands to a remote # light controller (e.g. stair footer lights) for a configurable auto-on duration. # - Auto control can be enabled/disabled with "Stair Footer Lights Auto". # - Auto duration is controlled by "Stair Footer Lights Auto Time" (seconds). # - LD2410 exposes configuration entities (numbers/selects/switches/buttons/text sensors). #:########################################################################################:# # MQTT COMMANDS: # This device publishes MQTT commands to a remote device: # - Topic: ${mqtt_remote_device1_command_topic} # - Payloads: ${mqtt_remote_device_command_ON}, ${mqtt_remote_device_command_OFF} # # Example (as configured by substitutions): # - ${mqtt_command_main_topic}/stair-footerlights -> ON, OFF #:########################################################################################:# # OFFLINE NOTES: # a) Home Assistant OFFLINE, but Network and MQTT ONLINE # - mmWave/PIR and BME280 sensing continues locally. # - Remote light control via MQTT publish continues (auto script still publishes). # - HA entities are unavailable until HA returns. # b) MQTT OFFLINE (but WiFi/Network and HA API ONLINE) # - Sensing continues and HA API entities remain available. # - Remote light control will NOT work (MQTT publishes fail while MQTT is down). # c) Entire WiFi/Network OFFLINE # - Sensing continues locally, but no HA API and no MQTT remote control. # - SNTP is not needed (no timeclocks used). #:########################################################################################:# #:########################################################################################:# # SUBSTITUTIONS: Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) #:########################################################################################:# substitutions: # Device Naming device_name: "esp-occupancystair" friendly_name: "Stair Occupancy and Underhouse Environment" description_comment: "D1 Mini ESP32 with LD2410 mmWave for internal stairwell and environment sensors for under house (Layout V1.1)" device_area: "Underhouse" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming project_name: "Generic.ESP32" project_version: "v2.2" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords & Secrets (unfortunately you can't use substitutions inside secrets names) api_key: !secret esp-api_key ota_pass: !secret esp-ota_pass static_ip_address: !secret esp-occupancystair_ip mqtt_command_main_topic: !secret mqtt_command_main_topic mqtt_status_main_topic: !secret mqtt_status_main_topic # If we are changing IP addresses, you must update the current IP address here, otherwise it remains # Don't forget to switch it back when changed. current_ip_address: ${static_ip_address} # Device Settings log_level: "INFO" # NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE update_interval: "60s" # update time for general sensors etc # MQTT REMOTE Controls mqtt_remote_device1_name: "stair-footerlights" mqtt_remote_device1_command_topic: "${mqtt_command_main_topic}/${mqtt_remote_device1_name}" mqtt_remote_device_command_ON: "ON" mqtt_remote_device_command_OFF: "OFF" #:########################################################################################:# # PACKAGES: Included Common Packages # https://esphome.io/components/packages.html #:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include file: common/network_common.yaml vars: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" local_current_ip_address: "${current_ip_address}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include file: common/api_common.yaml #file: common/api_common_noencryption.yaml vars: local_api_key: "${api_key}" #### MQTT #### common_mqtt: !include file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml #### SNTP (Only use if you want/need accurate timeclocks) #### #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### diag_basic: !include common/include_basic_diag_sensors.yaml diag_more: !include common/include_more_diag_sensors.yaml #diag_debug: !include common/include_debug_diag_sensors.yaml #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml #:########################################################################################:# # ESPHOME: # https://esphome.io/components/esphome.html #:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" comment: "${description_comment}" # appears on the esphome page in HA area: "${device_area}" min_version: 2024.6.0 #:########################################################################################:# # ESP PLATFORM AND FRAMEWORK: # https://esphome.io/components/esp32.html #:########################################################################################:# esp32: board: esp32dev framework: type: esp-idf # "esp-idf" OR "arduino" version: recommended #:########################################################################################:# # GLOBAL VARIABLES: # https://esphome.io/components/globals.html #:########################################################################################:# globals: - id: stair_footer_auto_default_s type: int restore_value: true initial_value: "20" #:########################################################################################:# # I2C BUS: # https://esphome.io/components/i2c.html #:########################################################################################:# i2c: sda: GPIO19 scl: GPIO21 scan: true frequency: 100kHz #:########################################################################################:# # LOGGING: # https://esphome.io/components/logger.html #:########################################################################################:# logger: level: "${log_level}" baud_rate: 0 #:########################################################################################:# # UART: # https://esphome.io/components/uart.html #:########################################################################################:# uart: id: ld2410_uart rx_pin: GPIO16 tx_pin: GPIO17 baud_rate: 256000 data_bits: 8 stop_bits: 1 parity: NONE #:########################################################################################:# # STATUS LED: # https://esphome.io/components/status_led.html #:########################################################################################:# status_led: pin: number: GPIO2 ignore_strapping_warning: true inverted: false #:########################################################################################:# # LD2410: # https://esphome.io/components/sensor/ld2410.html #:########################################################################################:# ld2410: uart_id: ld2410_uart #:########################################################################################:# # NUMBER COMPONENT: # https://esphome.io/components/number/ #:########################################################################################:# number: - platform: ld2410 timeout: name: "Timeout" light_threshold: name: "Light Threshold" max_move_distance_gate: name: "Max Move Distance Gate" max_still_distance_gate: name: "Max Still Distance Gate" g0: move_threshold: name: "g0 move threshold" still_threshold: name: "g0 still threshold" g1: move_threshold: name: "g1 move threshold" still_threshold: name: "g1 still threshold" g2: move_threshold: name: "g2 move threshold" still_threshold: name: "g2 still threshold" g3: move_threshold: name: "g3 move threshold" still_threshold: name: "g3 still threshold" g4: move_threshold: name: "g4 move threshold" still_threshold: name: "g4 still threshold" g5: move_threshold: name: "g5 move threshold" still_threshold: name: "g5 still threshold" g6: move_threshold: name: "g6 move threshold" still_threshold: name: "g6 still threshold" g7: move_threshold: name: "g7 move threshold" still_threshold: name: "g7 still threshold" g8: move_threshold: name: "g8 move threshold" still_threshold: name: "g8 still threshold" - platform: template id: stair_footer_auto_time_s name: "Stair Footer Lights Auto Time" unit_of_measurement: "s" min_value: 10 max_value: 300 step: 1 optimistic: true restore_value: true initial_value: 20 #:########################################################################################:# # SELECT COMPONENT: # https://esphome.io/components/select/index.html #:########################################################################################:# select: - platform: ld2410 distance_resolution: name: "${friendly_name} LD2140 Distance Resolution" baud_rate: name: "${friendly_name} LD2140 Baud Rate" light_function: name: "${friendly_name} LD2140 Light Function" out_pin_level: name: "${friendly_name} LD2140 Out Pin Level" #:########################################################################################:# # SENSOR COMPONENT: # https://esphome.io/components/sensor/ #:########################################################################################:# sensor: - platform: bme280_i2c temperature: name: "Temperature" accuracy_decimals: 1 oversampling: 2x pressure: name: "Pressure" oversampling: 2x humidity: name: "Humidity" accuracy_decimals: 1 oversampling: 2x address: 0x76 update_interval: "${update_interval}" - platform: ld2410 light: name: "Light" moving_distance: name: "Moving Distance" still_distance: name: "Still Distance" moving_energy: name: "Move Energy" still_energy: name: "Still Energy" detection_distance: name: "Detection Distance" g0: move_energy: name: "g0 move energy" still_energy: name: "g0 still energy" g1: move_energy: name: "g1 move energy" still_energy: name: "g1 still energy" g2: move_energy: name: "g2 move energy" still_energy: name: "g2 still energy" g3: move_energy: name: "g3 move energy" still_energy: name: "g3 still energy" g4: move_energy: name: "g4 move energy" still_energy: name: "g4 still energy" g5: move_energy: name: "g5 move energy" still_energy: name: "g5 still energy" g6: move_energy: name: "g6 move energy" still_energy: name: "g6 still energy" g7: move_energy: name: "g7 move energy" still_energy: name: "g7 still energy" g8: move_energy: name: "g8 move energy" still_energy: name: "g8 still energy" #:########################################################################################:# # SWITCH COMPONENT: # https://esphome.io/components/switch/ #:########################################################################################:# switch: - platform: ld2410 engineering_mode: name: "${friendly_name} LD2140 Engineering Mode" #bluetooth: # name: "${friendly_name} LD2140 Control Bluetooth" - platform: template id: stair_footer_auto_enabled name: "Stair Footer Lights Auto" optimistic: true restore_mode: RESTORE_DEFAULT_ON #:########################################################################################:# # BINARY SENSORS: # https://esphome.io/components/binary_sensor/ #:########################################################################################:# binary_sensor: - platform: ld2410 has_target: name: "mmWave Presence" on_press: - if: condition: switch.is_on: stair_footer_auto_enabled then: - script.execute: stair_footer_auto_script has_moving_target: name: "mmWave Moving Target" on_press: - if: condition: switch.is_on: stair_footer_auto_enabled then: - script.execute: stair_footer_auto_script has_still_target: name: "mmWave Still Target" out_pin_presence_status: name: "LD2140 Out Pin Presence Status" entity_category: diagnostic # Generic PIR Sensor (GPIO13) - platform: gpio pin: number: GPIO13 mode: input: true pullup: true inverted: true name: "PIR Sensor" device_class: motion filters: - delayed_on: 50ms on_press: - if: condition: switch.is_on: stair_footer_auto_enabled then: - script.execute: stair_footer_auto_script #:########################################################################################:# # BUTTON COMPONENT: # https://esphome.io/components/button/index.html #:########################################################################################:# button: - platform: ld2410 factory_reset: name: "${friendly_name} LD2140 Factory reset" restart: name: "${friendly_name} LD2140 Restart" query_params: name: "Query Parameters" #:########################################################################################:# # TEXT SENSOR COMPONENT: # https://esphome.io/components/text_sensor/ #:########################################################################################:# text_sensor: - platform: ld2410 version: name: "${friendly_name} LD2140 Firmware Version" #mac_address: # name: "${friendly_name} LD2140 BT MAC Address" #:########################################################################################:# # SCRIPT COMPONENT: # https://esphome.io/components/script.html #:########################################################################################:# script: - id: stair_footer_auto_script mode: restart then: # Turn lights on (command the Top switch's footer relay) - mqtt.publish: topic: "${mqtt_remote_device1_command_topic}" payload: "${mqtt_remote_device_command_ON}" retain: false # Wait for the HA-adjustable timeout - delay: !lambda "return (uint32_t)(id(stair_footer_auto_time_s).state) * 1000;" # Turn lights back off - mqtt.publish: topic: "${mqtt_remote_device1_command_topic}" payload: "${mqtt_remote_device_command_OFF}" retain: false