mirror of
https://github.com/dlitz/esphome-configs-dlitz.git
synced 2026-04-15 22:03:26 -06:00
512 lines
15 KiB
YAML
512 lines
15 KiB
YAML
# shelly plug us gen4
|
|
# PCB markings: "US_plug_Gen4_V0.0.3"
|
|
# Model: S4PL-00116US
|
|
# Case markings: B2508
|
|
# SoC: ESP-Shelly-C68F
|
|
# CPU: ESP32-C6 variant
|
|
# Power sensor: BL0942
|
|
|
|
# References:
|
|
# - https://documentation.espressif.com/esp32-c6_datasheet_en.pdf
|
|
# - https://documentation.espressif.com/esp32-c6_technical_reference_manual_en.pdf
|
|
# - https://optoelectronics.liteon.com/upload/download/DS86-2013-0004/LTR-303ALS-01_DS_V1.1.PDF
|
|
# - https://www.belling.com.cn/media/file_object/bel_product/BL0942/datasheet/BL0942_V1.06_en.pdf
|
|
|
|
# GPIOs:
|
|
# GPIO3 - NTC? Maybe? Maybe not?
|
|
# GPIO4 - Relay
|
|
# GPIO5? - seems to have some other device transmitting on it (maybe the Zigbee interface? maybe just a floating pin? ADC?)
|
|
# GPIO6 - WS2812-compatible LED strip (12 LEDs)
|
|
# GPIO7 - Button (active low)
|
|
# GPIO9 - boot strapping pin (-> DTR)
|
|
# GPIO10 - I2C SDA
|
|
# GPIO11 - I2C SCL
|
|
# GPIO16 - U0TXD
|
|
# GPIO17 - U0RXD
|
|
# GPIO18 - BL0942 RX
|
|
# GPIO19 - BL0942 TX
|
|
|
|
# Test points:
|
|
# TP1: +3.3V
|
|
# TP2: GPIO9
|
|
# TP3: EN
|
|
# TP4: GND
|
|
# TP5: RxD
|
|
# TP6: TxD
|
|
|
|
# Floating GPIO values: Pulled-down GPIO values: Pulled-up GPIO values:
|
|
# - 'GPIO0': LOW - 'GPIO0': LOW - 'GPIO0': HIGH
|
|
# - 'GPIO1': LOW - 'GPIO1': LOW - 'GPIO1': HIGH
|
|
# - 'GPIO2': HIGH - 'GPIO2': HIGH ! 'GPIO2': HIGH
|
|
# - 'GPIO3': HIGH * 'GPIO3': LOW - 'GPIO3': HIGH
|
|
# - 'GPIO4': LOW - 'GPIO4': LOW ! 'GPIO4': LOW - Relay
|
|
# - 'GPIO5': LOW - 'GPIO5': LOW - 'GPIO5': HIGH
|
|
# - 'GPIO6': LOW - 'GPIO6': LOW ! 'GPIO6': LOW
|
|
# - 'GPIO7': HIGH - 'GPIO7': HIGH ! 'GPIO7': HIGH - Button
|
|
# - 'GPIO8': HIGH - 'GPIO8': HIGH ! 'GPIO8': HIGH
|
|
# - 'GPIO9': HIGH - 'GPIO9': HIGH ! 'GPIO9': HIGH - Boot select pin
|
|
# - 'GPIO10': HIGH - 'GPIO10': HIGH ! 'GPIO10': HIGH - I2C SDA
|
|
# - 'GPIO11': HIGH - 'GPIO11': HIGH ! 'GPIO11': HIGH - I2C SCL
|
|
# - 'GPIO12': LOW - 'GPIO12': LOW - 'GPIO12': HIGH
|
|
# - 'GPIO13': HIGH * 'GPIO13': LOW - 'GPIO13': HIGH
|
|
# - 'GPIO14': LOW - 'GPIO14': LOW - 'GPIO14': HIGH
|
|
# - 'GPIO15': LOW - 'GPIO15': LOW - 'GPIO15': HIGH
|
|
# - 'GPIO17': HIGH - 'GPIO17': HIGH ! 'GPIO17': HIGH - U0RXD
|
|
# - 'GPIO18': HIGH * 'GPIO18': LOW - 'GPIO18': HIGH
|
|
# - 'GPIO19': HIGH # flickers on and off * 'GPIO19': LOW - 'GPIO19': HIGH
|
|
# - 'GPIO20': LOW - 'GPIO20': LOW ! 'GPIO20': LOW
|
|
# - 'GPIO21': LOW - 'GPIO21': LOW - 'GPIO21': HIGH
|
|
# - 'GPIO22': LOW - 'GPIO22': LOW - 'GPIO22': HIGH
|
|
# - 'GPIO23': LOW - 'GPIO23': LOW - 'GPIO23': HIGH
|
|
|
|
# I2C devices:
|
|
# 0x29 - Liteon LTR-303ALS illuminance sensor (or compatible)
|
|
|
|
|
|
# There's an illuminance sensor
|
|
|
|
# "shelly_pm_bl0942.cp:102 BL0942 Voltage coeff 4012891.1, Current coeff 399000.0, Power coeff 102974600.0, Energy coeff 11909381970.3"
|
|
# "shelly_ltr303_sensor.cpp"
|
|
|
|
# TODO:
|
|
# - Overheating protection
|
|
# - Overvoltage protection
|
|
# - Overcurrent protection
|
|
# - Overpower protection
|
|
|
|
substitutions:
|
|
#calibration_voltage_reference: 15873.35944299 # esphome default
|
|
#calibration_voltage_reference: 14393.902006359718 # calibrated on device ec:da:3b:c4:9f:7c
|
|
calibration_voltage_reference: 4012891.1 # from Shelly firmware log
|
|
#calibration_current_reference: 251213.46469622 # esphome default
|
|
#calibration_current_reference: 245340.94214487978 # calibrated on device ec:da:3b:c4:9f:7c
|
|
calibration_current_reference: 399000.0 # from Shelly firmware log
|
|
calibration_power_reference: 102974600.0 # from Shelly firmware log
|
|
calibration_energy_reference: 11909381970.3 # from Shelly firmware log
|
|
line_frequency: 60Hz
|
|
update_interval: 5s
|
|
|
|
shelly_ntc_temperature_pin: GPIO5 # (?)
|
|
|
|
dashboard_import:
|
|
package_import_url: github://dlitz/esphome-configs-dlitz/shelly-plug-us-gen4.yaml@${git_branch}
|
|
|
|
packages:
|
|
- !include common/esp-shelly-c68f.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-ntc-temperature.yaml
|
|
- !include common/time.yaml
|
|
- !include common/uptime-info.yaml
|
|
- !include common/wifi-info.yaml
|
|
|
|
esphome:
|
|
name: shelly-plug-us-gen4
|
|
friendly_name: "Shelly Plug US Gen4"
|
|
comment: "Shelly Plus US Gen4 - Smart plug with multi-protocol connectivity, power metering and LED indication"
|
|
name_add_mac_suffix: true
|
|
project:
|
|
name: "dlitz.shelly-plug-us-gen4"
|
|
version: "v0.0.0"
|
|
|
|
# Enable logging
|
|
logger:
|
|
level: DEBUG
|
|
baud_rate: 115200
|
|
hardware_uart: uart0
|
|
logs:
|
|
ltr_als_ps: INFO
|
|
|
|
# debug:
|
|
|
|
# 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 default_ap_password
|
|
|
|
captive_portal:
|
|
|
|
network:
|
|
enable_ipv6: true
|
|
|
|
i2c:
|
|
sda: GPIO10
|
|
scl: GPIO11
|
|
frequency: 100kHz
|
|
scan: true
|
|
|
|
# esp32_ble_tracker:
|
|
# scan_parameters:
|
|
# active: false
|
|
#
|
|
# bluetooth_proxy:
|
|
# active: false
|
|
|
|
sensor:
|
|
- id: !extend ntc_temp_analog_reading
|
|
update_interval: 5s
|
|
- id: !extend cpu_temperature
|
|
update_interval: 5s
|
|
- platform: ltr_als_ps
|
|
address: 0x29
|
|
update_interval: 30s
|
|
type: ALS
|
|
ambient_light:
|
|
name: "LTR303 Ambient light"
|
|
infrared_counts:
|
|
name: "LTR303 Infrared counts"
|
|
full_spectrum_counts:
|
|
name: "LTR303 Full spectrum counts"
|
|
actual_gain:
|
|
name: "LTR303 Actual gain"
|
|
actual_integration_time:
|
|
name: "LTR303 Actual integration time"
|
|
|
|
- platform: bl0942
|
|
id: bl0942_id
|
|
uart_id: bl0942_uart_id
|
|
update_interval: ${update_interval}
|
|
voltage_reference: ${calibration_voltage_reference}
|
|
current_reference: ${calibration_current_reference}
|
|
power_reference: ${calibration_power_reference}
|
|
energy_reference: ${calibration_energy_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
|
|
|
|
- { platform: adc, name: ADC_GPIO0, pin: GPIO0, update_interval: 5s }
|
|
- { platform: adc, name: ADC_GPIO1, pin: GPIO1, update_interval: 5s }
|
|
- { platform: adc, name: ADC_GPIO2, pin: GPIO2, update_interval: 5s }
|
|
- { platform: adc, name: ADC_GPIO3, pin: GPIO3, update_interval: 5s }
|
|
#- { platform: adc, name: ADC_GPIO4, pin: GPIO4, update_interval: 5s }
|
|
#- { platform: adc, name: ADC_GPIO5, pin: GPIO5, update_interval: 5s }
|
|
#- { platform: adc, name: ADC_GPIO6, pin: GPIO6, update_interval: 5s }
|
|
|
|
- platform: template
|
|
name: App state (uint8)
|
|
lambda: |-
|
|
return App.get_app_state();
|
|
update_interval: 1s
|
|
|
|
uart:
|
|
- id: bl0942_uart_id
|
|
tx_pin: GPIO18
|
|
rx_pin:
|
|
number: GPIO19
|
|
mode:
|
|
input: true
|
|
pullup: true
|
|
baud_rate: 9600
|
|
debug:
|
|
direction: BOTH
|
|
after:
|
|
delimiter: "\n"
|
|
sequence:
|
|
- lambda: UARTDebug::log_hex(direction, bytes, 32);
|
|
|
|
output:
|
|
- platform: gpio
|
|
id: "relay_output"
|
|
pin: GPIO4
|
|
|
|
- platform: template
|
|
id: status_led_output
|
|
type: binary
|
|
write_action:
|
|
- lambda: |-
|
|
static int prev_state = -1;
|
|
//ESP_LOGD("my_status", "prev_state: %d, state: %d, state size: %d", prev_state, (int)state, sizeof(state));
|
|
if (prev_state <= 0 && state > 0) {
|
|
prev_state = state;
|
|
auto call = id(rgb_led).turn_on();
|
|
call.set_brightness(0.30);
|
|
call.set_rgb(1.0, 0.5, 0.0); // amber
|
|
call.set_transition_length(0);
|
|
call.set_publish(false); // Don't spam the logs
|
|
call.perform();
|
|
} else if (prev_state > 0 && state == 0) {
|
|
prev_state = state;
|
|
auto call = id(rgb_led).make_call();
|
|
call.from_light_color_values(id(rgb_led).remote_values);
|
|
call.set_transition_length(0);
|
|
call.set_publish(false); // Don't spam the logs
|
|
call.perform();
|
|
}
|
|
|
|
light:
|
|
- platform: esp32_rmt_led_strip
|
|
id: rgb_led
|
|
name: RGB LED
|
|
#entity_category: config
|
|
pin: GPIO6
|
|
rgb_order: GRB
|
|
chipset: WS2812
|
|
rmt_symbols: 48
|
|
num_leds: 12
|
|
restore_mode: ALWAYS_ON
|
|
initial_state: # XXX This doesn't seem to work for some rason
|
|
state: true
|
|
red: 0%
|
|
green: 100%
|
|
blue: 0%
|
|
brightness: 30%
|
|
effects:
|
|
- strobe:
|
|
- addressable_color_wipe:
|
|
name: Identify
|
|
add_led_interval: 100ms
|
|
colors:
|
|
- red: 0%
|
|
green: 0%
|
|
blue: 100%
|
|
num_leds: 3
|
|
- red: 0%
|
|
green: 0%
|
|
blue: 100%
|
|
num_leds: 3
|
|
- red: 0%
|
|
green: 50%
|
|
blue: 50%
|
|
num_leds: 3
|
|
- red: 0%
|
|
green: 50%
|
|
blue: 50%
|
|
num_leds: 3
|
|
- strobe:
|
|
name: Blink Green
|
|
colors:
|
|
- state: true
|
|
brightness: 100%
|
|
red: 0%
|
|
green: 100%
|
|
blue: 0%
|
|
duration: 250ms
|
|
- state: false
|
|
brightness: 0%
|
|
duration: 250ms
|
|
- strobe:
|
|
name: Fast Blink Red Blue
|
|
colors:
|
|
- state: true
|
|
brightness: 100%
|
|
red: 100%
|
|
green: 0%
|
|
blue: 0%
|
|
duration: 50ms
|
|
- state: true
|
|
brightness: 100%
|
|
red: 0%
|
|
green: 0%
|
|
blue: 100%
|
|
duration: 50ms
|
|
|
|
- platform: status_led
|
|
internal: true
|
|
id: status_led_id
|
|
output: status_led_output
|
|
|
|
switch:
|
|
- platform: output
|
|
id: "relay"
|
|
name: "Relay"
|
|
output: "relay_output"
|
|
restore_mode: RESTORE_DEFAULT_OFF
|
|
on_turn_on:
|
|
- logger.log: "Relay turned on"
|
|
on_turn_off:
|
|
- logger.log: "Relay turned off"
|
|
|
|
- platform: template
|
|
name: Identify
|
|
entity_category: config
|
|
optimistic: true
|
|
turn_on_action:
|
|
- light.turn_on:
|
|
id: rgb_led
|
|
effect: Identify
|
|
- logger.log:
|
|
format: "identify ON"
|
|
level: INFO
|
|
turn_off_action:
|
|
- light.turn_off:
|
|
id: rgb_led
|
|
- logger.log:
|
|
format: "identify OFF"
|
|
level: INFO
|
|
|
|
- platform: template
|
|
id: trig_warning
|
|
name: Trigger warning
|
|
entity_category: diagnostic
|
|
disabled_by_default: true
|
|
optimistic: true
|
|
turn_on_action:
|
|
- lambda: |-
|
|
id(trig_warning).status_set_warning(LOG_STR("foo"));
|
|
turn_off_action:
|
|
- lambda: |-
|
|
id(trig_warning).status_clear_warning();
|
|
|
|
- platform: template
|
|
id: trig_error
|
|
name: Trigger error
|
|
entity_category: diagnostic
|
|
disabled_by_default: true
|
|
optimistic: true
|
|
turn_on_action:
|
|
- lambda: |-
|
|
id(trig_error).status_set_error(LOG_STR("foo"));
|
|
turn_off_action:
|
|
- lambda: |-
|
|
id(trig_error).status_clear_error();
|
|
|
|
binary_sensor:
|
|
- platform: gpio
|
|
id: button_id
|
|
name: "Button"
|
|
pin:
|
|
number: GPIO7
|
|
inverted: true
|
|
mode:
|
|
input: true
|
|
pullup: true
|
|
filters:
|
|
- settle: 10ms
|
|
on_multi_click:
|
|
- timing:
|
|
- ON for at most 1s
|
|
- OFF for at least 10ms
|
|
then:
|
|
- switch.toggle: relay
|
|
- logger.log: "Button pressed. Toggled relay."
|
|
- timing:
|
|
- ON for at least 5s
|
|
then:
|
|
- light.turn_on:
|
|
id: status_led_id
|
|
effect: Blink Greem
|
|
- timing:
|
|
- ON for 5s to 10s
|
|
- OFF for at least 10ms
|
|
then:
|
|
- logger.log: "Button held for 5-10s: Restart"
|
|
- button.press: button_restart
|
|
- timing:
|
|
- ON for at least 10s
|
|
then:
|
|
- light.turn_on:
|
|
id: status_led_id
|
|
effect: Fast Blink Red Blue
|
|
- 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
|