Import YAML files into repository

This commit is contained in:
2026-01-20 23:08:05 -07:00
parent af94e08fe4
commit 3239e56c8d
31 changed files with 1550 additions and 1 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
# Gitignore settings for ESPHome
# This is an example and may include too much for your use-case.
# You can modify this file to suit your needs.
/.esphome/
/secrets.yaml

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2025 dlitz Copyright (c) 2025-2026 Darsey Litzenberger
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including associated documentation files (the "Software"), to deal in the Software without restriction, including

View File

@@ -0,0 +1,54 @@
esphome:
includes:
- "<lwip/apps/mdns_priv.h>" # for struct mdns_service, struct mdns_txtdata
- "<lwip/init.h>" # for LWIP_VERSION_STRING
bk72xx:
framework:
loglevel: debug
debug:
- mdns
- lwip
sdk_silent: auto
text_sensor:
- platform: libretiny
version:
id: libretiny_version_id
name: LibreTiny Version
- platform: template
name: "LWIP_VERSION_STRING"
entity_category: diagnostic
lambda: |-
static const std::string s = LWIP_VERSION_STRING;
return s;
sensor:
- platform: template
name: "MDNS_TXT_RDATA_SIZE"
accuracy_decimals: 0
entity_category: diagnostic
lambda: |-
#ifdef MDNS_TXT_RDATA_SIZE
return MDNS_TXT_RDATA_SIZE;
#else
return {};
#endif
- platform: template
name: "size of mdns_service.txtdata"
accuracy_decimals: 0
entity_category: diagnostic
lambda: |-
struct mdns_service srv;
return sizeof(srv.txtdata);
- platform: template
name: "size of mdns_txtdata.rdata"
accuracy_decimals: 0
entity_category: diagnostic
lambda: |-
struct mdns_txtdata txt;
return sizeof(txt.rdata);

View File

@@ -0,0 +1,7 @@
packages:
- !include libretiny-mdns-fix.yaml
bk72xx:
framework:
options:
MDNS_TXT_RDATA_SIZE: 384 # https://github.com/esphome/esphome/issues/11281

View File

@@ -0,0 +1,4 @@
sensor:
- platform: internal_temperature
id: cpu_temperature
name: "CPU Temperature"

View File

@@ -0,0 +1,19 @@
# Common options for the ESP-Shelly-C38F SoC
packages:
- !include esp32c3.yaml
esphome:
platformio_options:
board_build.flash_mode: dio
esp32:
variant: esp32c3
# cpu_frequency: 240MHz
flash_size: 8MB
framework:
type: esp-idf
sdkconfig_options:
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: "y" # TLS1.3 support still isn't enabled by default in IDF 5.5.2
# CONFIG_MBEDTLS_DEFAULT_CERTIFICATE_BUNDLE: CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN
# CONFIG_LWIP_NETIF_LOOPBACK: "n" # Apparently there's a bug causing the ICMPv6 Router Solicitation to go out over the loopback interface rather than wifi

25
common/esp32-u4wdh.yaml Normal file
View File

@@ -0,0 +1,25 @@
# Common options for the ESP32-U4WDH SoC
# CPU: ESP32-U4WDH (revision v3.1)
# Features: Wi-Fi, BT, Dual Core + LP Core, 240MHz, Embedded Flash, Vref calibration in eFuse, Coding Scheme None
# Crystal frequency: 40MHz
# Memory: 320KB RAM, 4MB Flash
packages:
- !include esp32.yaml
esphome:
platformio_options:
board_build.flash_mode: dio
esp32:
variant: esp32
# cpu_frequency: 240MHz
flash_size: 4MB
framework:
type: esp-idf
# advanced:
# minimum_chip_revision: "3.1" # Requires ESPHome 2026.1.0 ?
sdkconfig_options:
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: "y" # TLS1.3 support still isn't enabled by default in IDF 5.5.2
CONFIG_MBEDTLS_DEFAULT_CERTIFICATE_BUNDLE: CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN
# CONFIG_LWIP_NETIF_LOOPBACK: "n" # Apparently there's a bug causing the ICMPv6 Router Solicitation to go out over the loopback interface rather than wifi

17
common/esp32.yaml Normal file
View File

@@ -0,0 +1,17 @@
esp32:
variant: esp32
framework:
type: esp-idf
sdkconfig_options:
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: "y" # TLS1.3 support still isn't enabled by default in IDF 5.5.2
# CONFIG_LWIP_NETIF_LOOPBACK: "n" # Apparently there's a bug causing the ICMPv6 Router Solicitation to go out over the loopback interface rather than wifi
# -- begin copied from https://github.com/athom-tech/esp32-configs --
# @grigi found in testing that these options resulted in better responsiveness.
# BLE 4.2 is supported by ALL ESP32 boards that have bluetooth, the original and derivatives.
CONFIG_BT_BLE_42_FEATURES_SUPPORTED: y
# Also enable this on any derivative boards (S2, C3 etc) but not the original ESP32.
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED: y
# Extend the watchdog timeout, so the device reboots if the device appears locked up for over 10 seconds.
CONFIG_ESP_TASK_WDT_TIMEOUT_S: "10"
# -- end copied from https://github.com/athom-tech/esp32-configs --

17
common/esp32c3.yaml Normal file
View File

@@ -0,0 +1,17 @@
esp32:
variant: esp32c3
framework:
type: esp-idf
sdkconfig_options:
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: "y" # TLS1.3 support still isn't enabled by default in IDF 5.5.2
# CONFIG_LWIP_NETIF_LOOPBACK: "n" # Apparently there's a bug causing the ICMPv6 Router Solicitation to go out over the loopback interface rather than wifi
# -- begin copied from https://github.com/athom-tech/esp32-configs --
# @grigi found in testing that these options resulted in better responsiveness.
# BLE 4.2 is supported by ALL ESP32 boards that have bluetooth, the original and derivatives.
# CONFIG_BT_BLE_42_FEATURES_SUPPORTED: y
# Also enable this on any derivative boards (S2, C3 etc) but not the original ESP32.
CONFIG_BT_BLE_50_FEATURES_SUPPORTED: y
# Extend the watchdog timeout, so the device reboots if the device appears locked up for over 10 seconds.
# CONFIG_ESP_TASK_WDT_TIMEOUT_S: "10"
# -- end copied from https://github.com/athom-tech/esp32-configs --

13
common/factory-reset.yaml Normal file
View File

@@ -0,0 +1,13 @@
factory_reset:
resets_required: 10
max_delay: 10s
on_increment:
- logger.log:
format: "(factory_reset) Fast power cycle count now %u, target %u"
args: [x, target]
button:
- platform: factory_reset
id: button_factory_reset
name: Factory reset
disabled_by_default: true

View File

@@ -0,0 +1,2 @@
preferences:
flash_write_interval: 5min

View File

@@ -0,0 +1,4 @@
esphome:
platformio_options:
platform_packages:
- "library-lwip @ https://github.com/dlitz/lwip.git#mdns-big-txt_bdk"

View File

@@ -0,0 +1,35 @@
substitutions:
ota_password: !secret fallback_ota_password
ota_new_password: ""
ota_update_password: 0
esphome:
on_boot:
- lambda: |-
#define OTA_UPDATE_PASSWORD ${ota_update_password}
#if !(OTA_UPDATE_PASSWORD == 0 || OTA_UPDATE_PASSWORD == 1)
# error ota_update_password must be 0 or 1
#endif
#ifdef USE_OTA_PASSWORD
const bool ota_update_password = bool(OTA_UPDATE_PASSWORD);
const std::string ota_new_password = "${ota_new_password}";
if (ota_update_password) {
if (ota_new_password.empty()) {
ESP_LOGI("ota_update_password", "Setting blank OTA password");
} else {
ESP_LOGI("ota_update_password", "Setting new OTA password");
}
id(ota_id).set_auth_password(ota_new_password);
} else {
ESP_LOGI("ota_update_password", "No new OTA password");
}
#elif OTA_UPDATE_PASSWORD == 1
# error Cannot set new OTA password - not compiled with OTA support (hint: set a dummy ota_password)
#else
# warning No OTA password set.
#endif
ota:
- id: !extend ota_id
platform: esphome
password: "${ota_password or ota_new_password}"

7
common/ota.yaml Normal file
View File

@@ -0,0 +1,7 @@
substitutions:
ota_password: !secret fallback_ota_password
ota:
- platform: esphome
id: ota_id
password: "${ota_password}"

4
common/restart.yaml Normal file
View File

@@ -0,0 +1,4 @@
button:
- platform: restart
id: button_restart
name: Restart

7
common/safe-mode.yaml Normal file
View File

@@ -0,0 +1,7 @@
safe_mode:
reboot_timeout: 10min
button:
- platform: safe_mode
id: button_safe_mode
name: Safe Mode Boot

42
common/shelly-button.yaml Normal file
View File

@@ -0,0 +1,42 @@
substitutions:
# shelly_button_gpio_number: GPIO1
shelly_button_gpio_pin:
number: ${shelly_button_gpio_number}
mode:
input: true
pullup: true
inverted: true
shelly_button_default_action: []
shelly_button_longpress_action: []
# Separate _internal substitutions so that assigning to the above replaces
# (rather than appends to) the default action.
_shelly_button_default_action_internal:
- button.press: button_safe_mode
_shelly_button_longpress_action_internal:
- button.press: button_factory_reset
binary_sensor:
- platform: gpio
id: shelly_button_id
name: "Button"
entity_category: diagnostic
pin: ${shelly_button_gpio_pin}
filters:
- settle: 10ms
on_multi_click:
- timing:
- ON for at least 5s
then:
- logger.log: "Button held for 5s"
- timing:
- ON for at least 10s
then:
- logger.log: "Button held for 10s"
- timing:
- ON for 5s to 10s
- OFF for at least 100ms
then: ${shelly_button_default_action or _shelly_button_default_action_internal}
- timing:
- ON for at least 10s
- OFF for at least 100ms
then: ${shelly_button_longpress_action or _shelly_button_longpress_action_internal}

View File

@@ -0,0 +1,16 @@
substitutions:
# shelly_header_gpio_number: GPIO19
shelly_header_gpio_pin:
number: ${shelly_header_gpio_number}
inverted: true
mode:
input: true
pullup: true
binary_sensor:
- platform: gpio
id: binary_sensor_header_gpio_id
name: "Header GPIO"
entity_category: diagnostic
disabled_by_default: true
pin: ${shelly_header_gpio_pin}

View File

@@ -0,0 +1,26 @@
substitutions:
# shelly_ntc_temperature_pin: GPIO3
sensor:
- platform: ntc
id: ntc_temperature
name: "NTC Temperature"
entity_category: diagnostic
unit_of_measurement: "°C"
accuracy_decimals: 1
icon: "mdi:thermometer"
sensor: temp_resistance_reading
calibration:
b_constant: 3350
reference_resistance: 10kOhm
reference_temperature: 298.15K
- platform: resistance
id: temp_resistance_reading
sensor: temp_analog_reading
configuration: DOWNSTREAM
resistor: 10kOhm
- platform: adc
id: temp_analog_reading
pin: ${shelly_ntc_temperature_pin}
attenuation: 12db

11
common/time.yaml Normal file
View File

@@ -0,0 +1,11 @@
time:
- platform: homeassistant
id: homeassistant_time
# on_time_sync:
# - logger.log: "HA time synchronized!"
- platform: sntp
id: sntp_time
# on_time_sync:
# - logger.log: "SNTP time synchronized!"

16
common/uptime-info.yaml Normal file
View File

@@ -0,0 +1,16 @@
# Requires time.yaml
sensor:
- platform: uptime
id: uptime_seconds
type: seconds
name: Uptime
disabled_by_default: true
- platform: uptime
id: uptime_timestamp
type: timestamp
name: Last Boot
# FIXME: Fix the uptime component so that it can use any configured time
# source, rather than just the first one.
time_id: sntp_time

42
common/wifi-info.yaml Normal file
View File

@@ -0,0 +1,42 @@
sensor:
- platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
- platform: copy # Reports the WiFi signal strength in %
id: wifi_signal_percent
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: diagnostic
device_class: ""
text_sensor:
- platform: wifi_info
ip_address:
name: Device IP Address
address_0:
name: Device IP Address 0
address_1:
name: Device IP Address 1
address_2:
name: Device IP Address 2
# address_3:
# name: Device IP Address 3
# address_4:
# name: Device IP Address 4
ssid:
name: Device Connected SSID
bssid:
name: Device Connected BSSID
mac_address:
name: Device MAC Address
# scan_results:
# name: Device Latest Scan Results
# dns_address:
# name: Device DNS Address
# power_save_mode:
# name: Device Wifi Power Save Mode

0
components/.gitignore vendored Normal file
View File

View File

@@ -0,0 +1,268 @@
substitutions:
# Use BK7231GUIFlashTool to dump tuya_config.json and then paste the result here.
# tuya_config: { ... }
button_default_action: []
_button_default_action_internal:
- button.press: button_toggle_all
# Setting this to true allows LT_AUTO_DOWNLOAD_REBOOT to work, but disables the K3 button.
debug_remove_button_k3: false # set true for LT_AUTO_DOWNLOAD_REBOOT support
packages:
# - !include common/bk72xx-mdns-debug.yaml
- !include common/bk72xx-mdns-fix.yaml
- !include common/cpu-temperature.yaml
- !include common/factory-reset.yaml
- !include common/flash-write-interval.yaml
- !include common/git-branch.yaml
- !include common/ota.yaml
- !include common/ota-update-password.yaml
- !include common/restart.yaml
- !include common/safe-mode.yaml
- !include common/time.yaml
- !include common/uptime-info.yaml
- !include common/wifi-info.yaml
esphome:
name: huacaoe-tywb-4ch-common
friendly_name: "Huacaoe 4-Channel Relay"
comment: "Huacaoe TYWB 4ch-RF 4-channel relay (common template)"
name_add_mac_suffix: true
project:
name: "dlitz.huacaoe-tywb-4ch-common"
version: "v0.0.0"
platformio_options:
upload_speed: 2_000_000
bk72xx:
board: cb3s # Flash size: 2MiB, CPU Frequency: 120MHz
framework: # LibreTiny
options:
# LT_LOG_HEAP: 1
LT_AUTO_DOWNLOAD_REBOOT: 1 # this only works when the RXD1 GPIO is configured as a serial port
# MDNS_TXT_RDATA_SIZE: 384 # https://github.com/esphome/esphome/issues/11281
LWIP_DHCP_DOES_ACD_CHECK: 0 # https://github.com/libretiny-eu/libretiny/issues/316
# version: "1.9.2"
# source: "https://github.com/dlitz/libretiny.git#mdns-big-txt"
external_components:
- source:
type: git
url: https://github.com/dlitz/esphome-configs-dlitz.git
ref: ${git_branch}
refresh: always
# Logs are output on the TXD2 pin (Pin 11 - third from the bottom on the right side)
logger:
level: DEBUG
baud_rate: 115200
debug:
# Enable Home Assistant API with dynamic key
api:
encryption:
wifi:
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
password: !secret fallback_ap_password
captive_portal:
network:
enable_ipv6: true
button:
- platform: template
id: button_toggle_all
name: Toggle All
on_press:
- if:
any:
- switch.is_on: relay_1
- switch.is_on: relay_2
- switch.is_on: relay_3
- switch.is_on: relay_4
then:
- switch.turn_off: relay_1
- switch.turn_off: relay_2
- switch.turn_off: relay_3
- switch.turn_off: relay_4
- logger.log: "Toggle All button pressed: Turned all off"
else:
- switch.turn_on: relay_1
- switch.turn_on: relay_2
- switch.turn_on: relay_3
- switch.turn_on: relay_4
- logger.log: "Toggle All button pressed: Turned all on"
light:
- platform: status_led
name: "Status LED"
id: status_led_id
disabled_by_default: true
entity_category: diagnostic
pin:
number: "${tuya_config.netled1_pin}"
inverted: ${not(tuya_config.netled1_lv | int)}
effects:
- strobe:
name: Blink
colors:
- state: true
duration: 250ms
- state: false
duration: 250ms
- strobe:
name: Fast Blink
colors:
- state: true
duration: 50ms
- state: false
duration: 50ms
binary_sensor:
- platform: status
name: "Status"
id: status_sensor
- platform: gpio
id: toggle_all_button
pin:
number: "${tuya_config.total_bt_pin}"
inverted: ${not(tuya_config.total_bt_lv | int)}
mode:
input: true
pullup: true
filters:
- settle: 10ms
name: "Reset, Toggle All Button"
on_multi_click:
# FIXME: status_led effects get overridden when app is in a warning or error state
- timing:
- ON for at most 1s
- OFF for at least 10ms
then: ${button_default_action or _button_default_action_internal}
- timing:
- ON for at least 2s
then:
- light.turn_on:
id: status_led_id
effect: Blink
- timing:
- ON for 2s to 10s
- OFF for at least 10ms
then:
- logger.log: "Button held for 2-10s: Restart"
- button.press: button_restart
- timing:
- ON for at least 10s
then:
- light.turn_on:
id: status_led_id
effect: Fast Blink
- timing:
- ON for at least 10s
- OFF for at least 10ms
then:
- logger.log: "Button held for over 10s: Factory reset"
- button.press: button_factory_reset
- platform: gpio
name: "Button K1"
id: button_k1
pin:
number: "${tuya_config.bt1_pin}"
inverted: ${not(tuya_config.bt1_lv | int)}
mode:
input: true
pullup: true
filters:
- settle: 10ms
on_click:
then:
- switch.toggle: relay_1
- logger.log: "Button K1 pressed: Toggle Relay 1"
- platform: gpio
name: "Button K2"
id: button_k2
pin:
number: "${tuya_config.bt2_pin}"
inverted: ${not(tuya_config.bt2_lv | int)}
mode:
input: true
pullup: true
filters:
- settle: 10ms
on_click:
then:
- switch.toggle: relay_2
- logger.log: "Button K2 pressed: Toggle Relay 2"
- platform: gpio
name: "Button K3"
id: button_k3
pin:
number: "${tuya_config.bt3_pin}"
inverted: ${not(tuya_config.bt3_lv | int)}
mode:
input: true
pullup: true
filters:
- settle: 10ms
on_click:
then:
- switch.toggle: relay_3
- logger.log: "Button K3 pressed: Toggle Relay 3"
- platform: gpio
name: "Button K4"
id: button_k4
pin:
number: "${tuya_config.bt4_pin}"
inverted: ${not(tuya_config.bt4_lv | int)}
mode:
input: true
pullup: true
filters:
- settle: 10ms
on_click:
then:
- switch.toggle: relay_4
- logger.log: "Button K4 pressed: Toggle Relay 4"
# This allows LT_AUTO_DOWNLOAD_REBOOT to work, but breaks the button.
- id: !remove ${ "button_k3" if debug_remove_button_k3 else ""}
switch:
- platform: gpio
name: "Relay 1"
id: relay_1
pin:
number: "${tuya_config.rl1_pin}"
inverted: ${not(tuya_config.rl1_lv | int)}
- platform: gpio
name: "Relay 2"
id: relay_2
pin:
number: "${tuya_config.rl2_pin}"
inverted: ${not(tuya_config.rl2_lv | int)}
- platform: gpio
id: relay_3
name: "Relay 3"
pin:
number: "${tuya_config.rl3_pin}"
inverted: ${not(tuya_config.rl3_lv | int)}
- platform: gpio
id: relay_4
name: "Relay 4"
pin:
number: "${tuya_config.rl4_pin}"
inverted: ${not(tuya_config.rl4_lv | int)}

View File

@@ -0,0 +1,21 @@
# https://www.amazon.ca/dp/B0DF7LPGRK
substitutions:
# tuya_config.json generated by BK7231GUIFlashTool
tuya_config: {"rl1_lv":"1","bt1_pin":"10","net_trig":"4","netled1_lv":"0","onoff_rst_type":"0","total_bt_pin":"9","nety_led":"1","total_stat":"0","bt1_lv":"0","remote_add_dp":"49","remote_list_dp":"50","rf_width":"345","module":"CB3S","rl2_pin":"6","series_ctrl":"0","cyc_dpid":"43","bt2_lv":"0","rl1_pin":"24","rl4_lv":"1","onoff_rst_m":"0","rl3_pin":"26","rl3_lv":"1","rand_dpid":"42","rl4_pin":"14","jv":"100","bt3_lv":"0","reset_t":"5","netled1_pin":"20","rl2_lv":"1","net_type":"0","bt4_pin":"7","inch_dp":"44","bt3_pin":"8","ch_cddpid1":"9","remote_io":"22","init_conf":"38","bt4_lv":"0","zero_select":"0","onoff_type":"2","bt2_pin":"11","ch_cddpid4":"12","ch_cddpid2":"10","ch_cddpid3":"11","total_bt_lv":"0","remote_select":"1","ch_num":"4","ch_dpid3":"3","ch_dpid4":"4","netn_led":"0","ch_dpid1":"1","ch_dpid2":"2","crc":"79"}
dashboard_import:
package_import_url: github://dlitz/esphome-configs-dlitz/huacaoe-tywb-4ch-grey.yaml@${git_branch}
# import_full_config: true
packages:
- !include huacaoe-tywb-4ch-common.yaml
esphome:
name: huacaoe-tywb-4ch-grey
friendly_name: "Huacaoe 4-Channel Relay"
comment: "Huacaoe TYWB 4ch-RF 4-channel relay (grey, 7-32V power, 5-pin external switch port, ASIN:B0DSM7PLDT)"
name_add_mac_suffix: true
project:
name: "dlitz.huacaoe-tywb-4ch-grey"
version: "v0.0.0"

View File

@@ -0,0 +1,20 @@
# https://www.amazon/ca/dp/B0DF7LPGRK
substitutions:
# tuya_config.json generated by BK7231GUIFlashTool
tuya_config: {"rl1_lv":"1","bt1_pin":"8","net_trig":"4","netled1_lv":"0","onoff_rst_type":"0","total_bt_pin":"7","nety_led":"0","total_stat":"0","bt1_lv":"0","remote_add_dp":"49","remote_list_dp":"50","module":"CB3S","rl2_pin":"6","series_ctrl":"0","cyc_dpid":"43","bt2_lv":"0","rl1_pin":"24","rl4_lv":"1","onoff_rst_m":"0","rl3_pin":"26","rl3_lv":"1","rand_dpid":"42","rl4_pin":"14","jv":"100","bt3_lv":"0","reset_t":"7","netled1_pin":"22","rl2_lv":"1","net_type":"0","bt4_pin":"11","inch_dp":"44","bt3_pin":"10","ch_cddpid1":"9","init_conf":"38","bt4_lv":"0","zero_select":"0","onoff_type":"2","bt2_pin":"9","ch_cddpid4":"12","ch_cddpid2":"10","ch_cddpid3":"11","total_bt_lv":"0","remote_select":"0","ch_num":"4","ch_dpid3":"3","ch_dpid4":"4","netn_led":"0","ch_dpid1":"1","ch_dpid2":"2","crc":"73"}
dashboard_import:
package_import_url: github://dlitz/esphome-configs-dlitz/huacaoe-tywb-4ch-white.yaml@${git_branch}
# import_full_config: true
packages:
- !include huacaoe-tywb-4ch-common.yaml
esphome:
name: "huacaoe-tywb-4ch-white"
friendly_name: "Huacaoe 4-Channel Relay"
comment: "Huacaoe TYWB 4ch-RF 4-channel relay (white, 7-32V power, no external switch port, ASIN:B0DF7LPGRK)"
project:
name: "dlitz.huacaoe-tywb-4ch-white"
version: "v0.0.0"

2
secrets.example.yaml Normal file
View File

@@ -0,0 +1,2 @@
fallback_ap_password: ""
fallback_ota_password: ""

281
shelly-em-gen3.yaml Normal file
View File

@@ -0,0 +1,281 @@
# Shelly EM Gen3
# PCB markings: "EM Gen3_v0.1.3", "B2519"
# SoC: ESP-Shelly-C38F (similar to ESP32-C3)
# CPU: ESP32-C3 (QFN32) (revision v0.4)
# Features: Wi-Fi, BT 5 (LE), Single Core, 160MHz, Embedded Flash 8MB (GD)
# Crystal frequency: 40MHz
# References:
# - https://devices.esphome.io/devices/shelly-em-gen3/
# - https://community.home-assistant.io/t/shelly-em-gen3-solved/944171
# - https://kb.shelly.cloud/knowledge-base/shelly-em-gen3
#
# GPIOs:
# GPIO0 - Dry-contact relay (normally open)
# GPIO1 - Pushbutton
# GPIO3 - ADC for NTC temperature probe
# GPIO6 - I2C SCL
# GPIO7 - I2C SDA
# GPIO9 - Status LED (active low)
# GPIO18 - Pin 1 of 7-pin header
#
# I2C devices:
# 0x38 - ADE7953 Power Sensor
# 0x51 - AiP8563 Battery-backed real-time clock (not configured here)
# Outputting LOW on GPIO5 seems to produce HIGH on GPIO4, and vice versa
substitutions:
# Set dual_sensors to false to remove the "B" and "Total" sensors
dual_sensors: true
# How often to update the power meter.
update_interval: 20s
# Calibrated on US-style 120V power with 50A current transformers.
# You may need to calibrate this yourself if the numbers are inaccurate.
calibration_voltage_gain: 0x32c78f # Calibrated on device E4:B0:63:D4:3E:00
calibration_current_gain_a: 0x490bb5 # Calibrated on device E4:B0:63:D4:3E:00
calibration_current_gain_b: 0x498c15 # Calibrated on device E4:B0:63:D4:3E:00
# GPIOs for this type of device
shelly_button_gpio_number: GPIO1
shelly_header_gpio_number: GPIO18
shelly_ntc_temperature_pin: GPIO3
dashboard_import:
package_import_url: github://dlitz/esphome-configs-dlitz/shelly-em-gen3.yaml@${git_branch}
packages:
- !include common/esp-shelly-c38f.yaml
- !include common/cpu-temperature.yaml
- !include common/factory-reset.yaml
- !include common/flash-write-interval.yaml
- !include common/git-branch.yaml
- !include common/ota.yaml
- !include common/ota-update-password.yaml
- !include common/restart.yaml
- !include common/safe-mode.yaml
- !include common/shelly-button.yaml
- !include common/shelly-header-gpio.yaml
- !include common/shelly-ntc-temperature.yaml
- !include common/time.yaml
- !include common/uptime-info.yaml
- !include common/wifi-info.yaml
esphome:
name: "shelly-em-gen3"
friendly_name: "Shelly EM Gen3"
comment: "Shelly EM Gen3 - Smart wifi and bluetooth energy meter with dual current transformers"
name_add_mac_suffix: true
project:
name: "dlitz.shelly-em-gen3"
version: "v0.0.0"
min_version: 2025.11.3 # for ade7953 bugfix #12180
# Enable logging
logger:
level: DEBUG
hardware_uart: uart0
# Enable Home Assistant API with dynamic key
api:
encryption:
wifi:
# ssid: !secret wifi_ssid
# password: !secret wifi_password
# fast_connect: true
enable_btm: true
enable_rrm: true
min_auth_mode: WPA2
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
password: !secret fallback_ap_password
captive_portal:
network:
enable_ipv6: true
i2c:
scl: GPIO6
sda: GPIO7
scan: true
# esp32_ble_tracker:
# scan_parameters:
# active: false
#
# bluetooth_proxy:
# active: false
light:
- platform: status_led
name: "Status LED"
id: status_led_id
disabled_by_default: true
entity_category: diagnostic
pin:
number: GPIO9
inverted: true
ignore_strapping_warning: true
switch:
# Dry-contact relay - normally open
- platform: gpio
name: Relay
id: relay_id
pin: GPIO0
sensor:
# Note that on the Shelly EM Gen3, channels "A" and "B" are swapped between the chipset and the labels on the device.
# This device also apparently does not need/have an irq_pin.
- platform: ade7953_i2c
id: ade7953_id
update_interval: ${update_interval}
use_accumulated_energy_registers: true
voltage_gain: ${calibration_voltage_gain}
current_gain_a: ${calibration_current_gain_a}
current_gain_b: ${calibration_current_gain_b}
voltage:
id: line_voltage
name: Voltage
frequency:
id: line_frequency
name: Frequency
current_b:
id: current_a
name: ${ "Current A" if dual_sensors else "Current" }
accuracy_decimals: 3
current_a:
id: current_b
name: Current B
accuracy_decimals: 3
power_factor_b:
id: power_factor_a
name: ${ "Power Factor A" if dual_sensors else "Power Factor" }
filters:
- multiply: -1
power_factor_a:
id: power_factor_b
name: "Power Factor B"
filters:
- multiply: -1
apparent_power_b:
id: apparent_power_a
name: ${ "Apparent Power A" if dual_sensors else "Apparent Power" }
apparent_power_a:
id: apparent_power_b
name: "Apparent Power B"
active_power_b:
id: active_power_a
name: ${ "Power A" if dual_sensors else "Power" }
active_power_a:
id: active_power_b
name: "Power B"
reactive_power_b:
id: reactive_power_a
name: ${ "Reactive Power A" if dual_sensors else "Reactive Power" }
filters:
- multiply: -1
reactive_power_a:
id: reactive_power_b
name: "Reactive Power B"
filters:
- multiply: -1
- platform: integration
id: energy_a
name: ${ "Energy A" if dual_sensors else "Energy" }
sensor: active_power_a
restore: false
time_unit: h
icon: mdi:meter-electric
unit_of_measurement: "kWh"
state_class: total_increasing
device_class: energy
accuracy_decimals: 3
filters:
- multiply: 0.001
- platform: integration
id: energy_b
name: 'Energy B'
sensor: active_power_b
restore: false
time_unit: h
icon: mdi:meter-electric
unit_of_measurement: "kWh"
state_class: total_increasing
device_class: energy
accuracy_decimals: 3
filters:
- multiply: 0.001
- platform: total_daily_energy
id: daily_energy_consumed_a
name: ${ "Daily Energy Consumed A" if dual_sensors else "Daily Energy Consumed" }
power_id: active_power_a
icon: "mdi:hours-24"
unit_of_measurement: "kWh"
state_class: total_increasing
device_class: energy
accuracy_decimals: 3
filters:
- multiply: 0.001
- platform: total_daily_energy
id: daily_energy_consumed_b
name: "Daily Energy Consumed B"
power_id: active_power_b
icon: "mdi:hours-24"
unit_of_measurement: "kWh"
state_class: total_increasing
device_class: energy
accuracy_decimals: 3
filters:
- multiply: 0.001
- platform: combination
id: power_ab
type: sum
name: "Power Total"
sources:
- source: active_power_a
- source: active_power_b
device_class: power
state_class: measurement
- platform: combination
id: energy_ab
type: sum
name: "Energy Total"
sources:
- source: energy_a
- source: energy_b
state_class: total_increasing
accuracy_decimals: 3
- platform: combination
id: daily_energy_consumed_ab
type: sum
name: "Daily Energy Consumed Total"
sources:
- source: daily_energy_consumed_a
- source: daily_energy_consumed_b
state_class: total_increasing
accuracy_decimals: 3
- id: !remove ${ "active_power_b" if not dual_sensors else "" }
- id: !remove ${ "apparent_power_b" if not dual_sensors else "" }
- id: !remove ${ "current_b" if not dual_sensors else "" }
- id: !remove ${ "daily_energy_consumed_b" if not dual_sensors else "" }
- id: !remove ${ "daily_energy_consumed_ab" if not dual_sensors else "" }
- id: !remove ${ "energy_ab" if not dual_sensors else "" }
- id: !remove ${ "energy_b" if not dual_sensors else "" }
- id: !remove ${ "power_ab" if not dual_sensors else "" }
- id: !remove ${ "power_factor_b" if not dual_sensors else "" }
- id: !remove ${ "reactive_power_b" if not dual_sensors else "" }

249
shelly-plus-1pm-ul.yaml Normal file
View File

@@ -0,0 +1,249 @@
# Shelly Plus 1PM UL
# PCB markings: "Shelly 1PM+_v0.2.2", "B2519"
# CPU: ESP32-U4WDH (revision v3.1)
# Features: Wi-Fi, BT, Dual Core + LP Core, 240MHz, Embedded Flash, Vref calibration in eFuse, Coding Scheme None
# Crystal frequency: 40MHz
# References:
# - https://devices.esphome.io/devices/shelly-plus-1pm/
# - https://kb.shelly.cloud/knowledge-base/shelly-plus-1pm-ul
#
# GPIOs:
# GPIO0 - Status LED and programming strapping pin
# GPIO5 - BL0937 CF pin
# GPIO18 - BL0937 CF1 pin
# GPIO19 - Pin 1 of 7-pin header
# GPIO23 - BL0937 SEL pin
# GPIO25 - Pushbutton
# GPIO26 - Dry-contact relay (normally open)
# GPIO32 - ADC for NTC temperature probe
substitutions:
device_name: "Shelly Plus 1PM UL"
# Higher value gives lower watt readout
current_res: "0.001"
# Lower value gives lower voltage readout
voltage_div: "1925"
shelly_button_gpio_number: GPIO25
shelly_header_gpio_number: GPIO19
shelly_ntc_temperature_pin: GPIO32
calibration_relay_adc_multiplier: 0.96184045 # Calibrated on device 88:13:bf:a1:be:b4
name: shelly-plus-1pm-ul
friendly_name: "${device_name}"
room: ""
device_description: "Shelly Plus 1PM UL - UL-certified small form factor smart switch with power measurement"
dashboard_import:
package_import_url: github://dlitz/esphome-configs-dlitz/shelly-plus-1pm-ul.yaml@${git_branch}
packages:
- !include common/esp32-u4wdh.yaml
- !include common/cpu-temperature.yaml
- !include common/factory-reset.yaml
- !include common/flash-write-interval.yaml
- !include common/git-branch.yaml
- !include common/ota.yaml
- !include common/ota-update-password.yaml
- !include common/restart.yaml
- !include common/safe-mode.yaml
- !include common/shelly-button.yaml
- !include common/shelly-header-gpio.yaml
- !include common/shelly-ntc-temperature.yaml
- !include common/time.yaml
- !include common/uptime-info.yaml
- !include common/wifi-info.yaml
external_components:
- source:
type: git
url: https://github.com/dlitz/esphome-configs-dlitz.git
ref: ${git_branch}
refresh: always
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
area: "${room}"
comment: "${device_description}"
name_add_mac_suffix: true
project:
name: "dlitz.shelly-plus-1pm-ul"
version: "v0.0.0"
logger:
level: DEBUG
hardware_uart: uart0
debug:
api:
encryption:
wifi:
# ssid: !secret wifi_ssid
# password: !secret wifi_password
# fast_connect: true
enable_btm: true
enable_rrm: true
min_auth_mode: WPA2
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
password: !secret fallback_ap_password
# web_server:
captive_portal:
output:
- platform: gpio
id: "relay_output"
pin: GPIO26
switch:
- platform: output
id: "relay"
name: "Relay"
output: "relay_output"
binary_sensor:
- platform: gpio
name: "Switch"
pin: GPIO4
on_press:
then:
- switch.turn_on: "relay"
on_release:
then:
- switch.turn_off: "relay"
filters:
- delayed_on_off: 50ms
sensor:
- id: !extend temp_analog_reading
update_interval: 5s
- id: !extend ntc_temperature
on_value_range:
- above: "80.0"
then:
- switch.turn_off: "relay"
- platform: adc
name: "Relay Supply Voltage"
pin: GPIO33
attenuation: 12db
filters:
- multiply: ${ 8 * calibration_relay_adc_multiplier }
- platform: hlw8012
model: BL0937
id: bl0937_id
sel_pin:
number: GPIO23
inverted: true
cf_pin:
number: GPIO5
ignore_strapping_warning: true
cf1_pin: GPIO18
current_resistor: ${current_res}
voltage_divider: ${voltage_div}
current:
name: "Current"
id: current
unit_of_measurement: A
accuracy_decimals: 3
icon: mdi:flash-outline
on_value:
then:
- component.update: apparent_power
# on_value_range:
# - above: "16"
# then:
# - switch.turn_off: "relay"
# - logger.log: "Over-current protection triggered!"
voltage:
name: "Voltage"
id: voltage
unit_of_measurement: V
accuracy_decimals: 1
icon: mdi:flash-outline
on_value:
then:
- component.update: apparent_power
# on_value_range:
# - above: "250"
# then:
# - switch.turn_off: "relay"
# - logger.log: "Over-voltage protection triggered!"
power:
name: "Power"
unit_of_measurement: W
id: power
icon: mdi:flash-outline
on_value_range:
- above: "3600"
then:
- switch.turn_off: "relay"
- logger.log: "Over-power protection triggered!"
change_mode_every: 2
update_interval: 10s
- platform: total_daily_energy
id: daily_energy_consumed
name: "Daily Energy Consumed"
power_id: power
filters:
- multiply: 0.001
unit_of_measurement: kWh
icon: mdi:clock-alert
- platform: template
id: apparent_power
name: "Apparent Power"
state_class: measurement
device_class: apparent_power
unit_of_measurement: "VA"
update_interval: never
lambda: |-
return id(voltage).state * id(current).state;
on_value:
then:
- component.update: power_factor
- component.update: reactive_power
- platform: template
id: reactive_power
name: "Reactive Power"
state_class: measurement
device_class: reactive_power
unit_of_measurement: "var"
update_interval: never
lambda: |-
return id(apparent_power).state * (1 - id(power_factor).state);
- platform: template
id: power_factor
name: "Power Factor"
state_class: measurement
device_class: power_factor
update_interval: never
lambda: |-
float r = id(power).state;
float a = id(apparent_power).state;
if (r == 0.0 && a == 0.0) {
return 1.0;
}
return r / a;
on_value:
then:
- component.update: reactive_power
light:
- platform: status_led
name: "Status LED"
id: status_led_id
disabled_by_default: true
entity_category: diagnostic
pin:
number: GPIO0
inverted: true
ignore_strapping_warning: true

131
shelly-plus-i4.yaml Normal file
View File

@@ -0,0 +1,131 @@
# Shelly Plus i4
# PCB markings: "Shelly i4_v0.1.1", "B2724"
# CPU: ESP32-U4WDH (revision v3.1)
# Features: Wi-Fi, BT, Dual Core + LP Core, 240MHz, Embedded Flash, Vref calibration in eFuse, Coding Scheme None
# Crystal frequency: 40MHz
# References:
# - https://devices.esphome.io/devices/shelly-plus-i4/
# - https://kb.shelly.cloud/knowledge-base/shelly-plus-i4
#
# GPIOs:
# GPIO0 - Status LED and programming strapping pin
# GPIO12 - Switch 1
# GPIO14 - Switch 2
# GPIO19 - Pin 1 of 7-pin header
# GPIO25 - Pushbutton
# GPIO26 - Switch 4
# GPIO27 - Switch 3
# GPIO32 - ADC for NTC temperature probe
substitutions:
device_name: "Shelly Plus i4"
shelly_button_gpio_number: GPIO25
shelly_header_gpio_number: GPIO19
shelly_ntc_temperature_pin: GPIO32
name: shelly-plus-i4
friendly_name: "${device_name}"
room: ""
device_description: "Shelly Plus i4 - 4x smart Wi-Fi switch inputs"
dashboard_import:
package_import_url: github://dlitz/esphome-configs-dlitz/shelly-plus-i4.yaml@${git_branch}
packages:
- !include common/esp32-u4wdh.yaml
- !include common/cpu-temperature.yaml
- !include common/factory-reset.yaml
- !include common/flash-write-interval.yaml
- !include common/git-branch.yaml
- !include common/ota.yaml
- !include common/ota-update-password.yaml
- !include common/restart.yaml
- !include common/safe-mode.yaml
- !include common/shelly-button.yaml
- !include common/shelly-header-gpio.yaml
- !include common/shelly-ntc-temperature.yaml
- !include common/time.yaml
- !include common/uptime-info.yaml
- !include common/wifi-info.yaml
external_components:
- source:
type: git
url: https://github.com/dlitz/esphome-configs-dlitz.git
ref: ${git_branch}
refresh: always
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
area: "${room}"
comment: "${device_description}"
name_add_mac_suffix: true
project:
name: "dlitz.shelly-plus-i4"
version: "v0.0.0"
logger:
level: DEBUG
debug:
api:
encryption:
wifi:
# ssid: !secret wifi_ssid
# password: !secret wifi_password
# fast_connect: true
enable_btm: true
enable_rrm: true
min_auth_mode: WPA2
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
password: !secret fallback_ap_password
# web_server:
captive_portal:
binary_sensor:
- platform: gpio
id: sw1
name: "Switch 1"
pin:
number: GPIO12
ignore_strapping_warning: true
filters:
- settle: 50ms
- platform: gpio
id: sw2
name: "Switch 2"
pin: GPIO14
filters:
- settle: 50ms
- platform: gpio
id: sw3
name: "Switch 3"
pin: GPIO27
filters:
- settle: 50ms
- platform: gpio
id: sw4
name: "Switch 4"
pin: GPIO26
filters:
- settle: 50ms
light:
- platform: status_led
name: "Status LED"
id: status_led_id
disabled_by_default: true
entity_category: diagnostic
pin:
number: GPIO0
inverted: true
ignore_strapping_warning: true

204
shelly-pm-mini-gen3.yaml Normal file
View File

@@ -0,0 +1,204 @@
# MAC address: ec:da:3b:c4:9f:7c
# Device: Shelly PM Mini Gen3
# References:
# - https://devices.esphome.io/devices/shelly-pm-mini-gen3/
# - https://kb.shelly.cloud/knowledge-base/shelly-pm-mini-gen3
substitutions:
# calibration_voltage_reference: 15873.35944299 # esphome default
calibration_voltage_reference: 14393.902006359718 # calibrated on device ec:da:3b:c4:9f:7c
# calibration_current_reference: 251213.46469622 # esphome default
calibration_current_reference: 245340.94214487978 # calibrated on device ec:da:3b:c4:9f:7c
device_name: "Shelly PM Mini Gen3"
line_frequency: 60Hz
shelly_button_gpio_number: GPIO1
shelly_ntc_temperature_pin: GPIO3
update_interval: 5s
dashboard_import:
package_import_url: github://dlitz/esphome-configs-dlitz/shelly-pm-mini-gen3.yaml@${git_branch}
packages:
- !include common/esp-shelly-c38f.yaml # TODO: Does this device have this SoC
- !include common/cpu-temperature.yaml
- !include common/factory-reset.yaml
- !include common/flash-write-interval.yaml
- !include common/git-branch.yaml
- !include common/ota.yaml
- !include common/ota-update-password.yaml
- !include common/restart.yaml
- !include common/safe-mode.yaml
- !include common/shelly-button.yaml
- !include common/shelly-ntc-temperature.yaml
- !include common/time.yaml
- !include common/uptime-info.yaml
- !include common/wifi-info.yaml
esphome:
name: "shelly-pm-mini-gen3"
friendly_name: "shelly-pm-mini-gen3"
comment: "Shelly PM Mini Gen3 - Smart wifi energy meter"
name_add_mac_suffix: true
project:
name: "dlitz.shelly-pm-mini-gen3"
version: "v0.0.0"
min_version: 2025.11.3 # for ade7953 bugfix #12180
# Enable logging
logger:
hardware_uart: uart0
# Enable Home Assistant API
api:
encryption:
wifi:
# ssid: !secret wifi_ssid
# password: !secret wifi_password
# fast_connect: true
enable_btm: true
enable_rrm: true
min_auth_mode: WPA2
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
password: !secret fallback_ap_password
captive_portal:
network:
enable_ipv6: true
# min_ipv6_addr_count: 2
# esp32_ble_tracker:
# scan_parameters:
# active: false
# bluetooth_proxy:
# active: false
light:
- platform: status_led
name: "Status LED"
id: status_led_id
disabled_by_default: true
entity_category: diagnostic
pin:
number: GPIO0
inverted: true
sensor:
- platform: bl0942
id: bl0942_id
uart_id: uart_0
update_interval: ${update_interval}
voltage_reference: ${calibration_voltage_reference}
current_reference: ${calibration_current_reference}
line_frequency: ${line_frequency}
voltage:
name: "Voltage"
id: voltage
icon: mdi:alpha-v-circle-outline
device_class: voltage
on_value:
then:
- component.update: apparent_power
current:
name: "Current"
id: current
icon: mdi:alpha-a-circle-outline
device_class: current
on_value:
then:
- component.update: apparent_power
power:
name: "Power"
id: power
icon: mdi:transmission-tower
device_class: power
state_class: measurement
on_value:
then:
- component.update: power_factor
energy:
name: "Energy"
id: energy
icon: mdi:meter-electric
device_class: energy
frequency:
name: "Frequency"
id: line_frequency
accuracy_decimals: 2
icon: mdi:cosine-wave
device_class: frequency
state_class: measurement
- platform: total_daily_energy
id: daily_energy_consumed_id
name: "Daily Energy Consumed"
power_id: power
icon: mdi:hours-24
unit_of_measurement: "kWh"
state_class: total_increasing
device_class: energy
accuracy_decimals: 3
filters:
- multiply: 0.001
- platform: template
id: apparent_power
name: "Apparent Power"
state_class: measurement
device_class: apparent_power
unit_of_measurement: "VA"
update_interval: never
lambda: |-
return id(voltage).state * id(current).state;
on_value:
then:
- component.update: power_factor
- component.update: reactive_power
- platform: template
id: reactive_power
name: "Reactive Power"
state_class: measurement
device_class: reactive_power
unit_of_measurement: "var"
update_interval: never
lambda: |-
return id(apparent_power).state * (1 - id(power_factor).state);
- platform: template
id: power_factor
name: "Power Factor"
state_class: measurement
device_class: power_factor
update_interval: never
lambda: |-
float r = id(power).state;
float a = id(apparent_power).state;
if (r == 0.0 && a == 0.0) {
return 1.0;
}
return r / a;
on_value:
then:
- component.update: reactive_power
uart:
- id: uart_0
tx_pin: GPIO6
rx_pin:
number: GPIO7
mode:
pullup: true
input: true
baud_rate: 9600
debug:
direction: BOTH
after:
delimiter: "\n"
sequence:
- lambda: UARTDebug::log_hex(direction, bytes, 32);