mirror of
https://github.com/dlitz/esphome-configs-dlitz.git
synced 2026-04-15 22:03:26 -06:00
Add support for Lanbon L9-HF smart switch/ceiling fan speed controller
This commit is contained in:
522
lanbon-l9-hf.yaml
Normal file
522
lanbon-l9-hf.yaml
Normal file
@@ -0,0 +1,522 @@
|
||||
substitutions:
|
||||
calibration_touchscreen_x_min: 0
|
||||
calibration_touchscreen_y_min: 0
|
||||
calibration_touchscreen_x_max: 169
|
||||
calibration_touchscreen_y_max: 319
|
||||
calibration_pulse_power_meter: 0.07874192291723468
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://dlitz/esphome-configs-dlitz/lanbon-l9-hf.yaml@${git_branch}
|
||||
|
||||
packages:
|
||||
- !include common/esp32s3.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
|
||||
|
||||
esp32:
|
||||
cpu_frequency: 240MHz
|
||||
flash_size: 16MB
|
||||
|
||||
esphome:
|
||||
name: lanbon-l9-hf
|
||||
friendly_name: Lanbon L9-HF
|
||||
comment: "Lanbon L9-HF smart switch/ceiling fan speed controller"
|
||||
name_add_mac_suffix: true
|
||||
project:
|
||||
name: "dlitz.lanbon-l9-hf"
|
||||
version: "v0.0.0"
|
||||
|
||||
on_boot:
|
||||
# Fan initialization
|
||||
priority: 800
|
||||
then:
|
||||
- script.execute: fan_uart_init
|
||||
|
||||
psram:
|
||||
speed: 80MHz
|
||||
mode: quad
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
# level: DEBUG
|
||||
# baud_rate: 115200
|
||||
hardware_uart: uart0
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: !secret lanbon-l9-hf-1.hass_api_key
|
||||
|
||||
on_client_connected:
|
||||
- lvgl.label.update:
|
||||
id: label_apistatus
|
||||
text_color: 0x00FF00
|
||||
|
||||
on_client_disconnected:
|
||||
- lvgl.label.update:
|
||||
id: label_apistatus
|
||||
text_color: 0xFF0000
|
||||
|
||||
wifi:
|
||||
# ssid: !secret wifi_ssid
|
||||
# password: !secret wifi_password
|
||||
# fast_connect: true
|
||||
min_auth_mode: WPA2
|
||||
enable_btm: true
|
||||
enable_rrm: true
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
password: !secret default_ap_password
|
||||
|
||||
captive_portal:
|
||||
|
||||
network:
|
||||
enable_ipv6: true
|
||||
# min_ipv6_addr_count: 2
|
||||
|
||||
# TODO: test to make sure bluetooth proxy doesn't cause boot looping!
|
||||
# esp32_ble_tracker:
|
||||
# scan_parameters:
|
||||
# active: false
|
||||
#
|
||||
# bluetooth_proxy:
|
||||
# active: false
|
||||
|
||||
time:
|
||||
- id: !extend ${time_source}
|
||||
on_time:
|
||||
- hours: 23,4
|
||||
minutes: 5
|
||||
seconds: 0
|
||||
then:
|
||||
- switch.turn_on: switch_antiburn
|
||||
- hours: 23,4
|
||||
minutes: 35
|
||||
seconds: 0
|
||||
then:
|
||||
- switch.turn_off: switch_antiburn
|
||||
- seconds: 0
|
||||
minutes: '*'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: label_time
|
||||
text:
|
||||
time_format: "%l:%M %p"
|
||||
time: ${time_source}
|
||||
|
||||
uart:
|
||||
- id: fan_uart
|
||||
tx_pin: GPIO38
|
||||
baud_rate: 115200
|
||||
debug:
|
||||
direction: TX
|
||||
after:
|
||||
bytes: 4
|
||||
|
||||
script:
|
||||
- id: fan_uart_command
|
||||
parameters:
|
||||
cmd: int
|
||||
arg: int
|
||||
then:
|
||||
- lambda: |-
|
||||
uint8_t buf[4] = { 0xef, uint8_t(cmd), uint8_t(arg), 0};
|
||||
buf[3] = buf[0] ^ buf[1] ^ buf[2]; // checksum
|
||||
id(fan_uart).write_array(buf, sizeof(buf));
|
||||
|
||||
- id: fan_uart_init
|
||||
then:
|
||||
- script.execute:
|
||||
id: fan_uart_command
|
||||
cmd: 0x01
|
||||
arg: 0x4e
|
||||
|
||||
- id: fan_uart_set_speed
|
||||
parameters:
|
||||
percent: uint8_t
|
||||
then:
|
||||
- lambda: |-
|
||||
if (percent > 100) {
|
||||
ESP_LOGW("_percent", "called with too-large value %d%%", (int)percent);
|
||||
percent = 100;
|
||||
}
|
||||
id(fan_uart_command)->execute(0x02, percent);
|
||||
|
||||
output:
|
||||
- platform: ledc
|
||||
id: lcd_backlight_output
|
||||
pin:
|
||||
number: GPIO42
|
||||
inverted: false
|
||||
|
||||
- platform: gpio
|
||||
id: relay_output
|
||||
pin:
|
||||
number: GPIO36
|
||||
|
||||
- platform: template
|
||||
id: fan_output
|
||||
type: float
|
||||
write_action:
|
||||
- lambda: |-
|
||||
uint8_t speed = ::round(state);
|
||||
const uint8_t speed_percentages[4] = { 0, 20, 55, 100 };
|
||||
if (speed < 4) {
|
||||
uint8_t percent = speed_percentages[speed];
|
||||
id(fan_uart_set_speed)->execute(percent);
|
||||
}
|
||||
|
||||
fan:
|
||||
- id: fan_id
|
||||
name: Fan
|
||||
platform: speed
|
||||
output: fan_output
|
||||
restore_mode: RESTORE_DEFAULT_OFF
|
||||
speed_count: 3
|
||||
on_state:
|
||||
- lvgl.widget.update:
|
||||
id: fan_speed_0_button
|
||||
state:
|
||||
checked: !lambda 'return !x->state && id(highlight_fan_off_button).state;'
|
||||
- lvgl.widget.update:
|
||||
id: fan_speed_1_button
|
||||
state:
|
||||
checked: !lambda 'return x->state && x->speed == 1;'
|
||||
- lvgl.widget.update:
|
||||
id: fan_speed_2_button
|
||||
state:
|
||||
checked: !lambda 'return x->state && x->speed == 2;'
|
||||
- lvgl.widget.update:
|
||||
id: fan_speed_3_button
|
||||
state:
|
||||
checked: !lambda 'return x->state && x->speed == 3;'
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
name: Proximity Sensor
|
||||
id: proximity_sensor
|
||||
pin: GPIO11
|
||||
on_press:
|
||||
then:
|
||||
- if:
|
||||
condition: lvgl.is_paused
|
||||
then:
|
||||
- logger.log: "LVGL resuming due to proximity sensor."
|
||||
- lvgl.resume:
|
||||
- lvgl.widget.redraw:
|
||||
- light.turn_on: display_backlight
|
||||
|
||||
- platform: template
|
||||
id: lvgl_paused_sensor_id
|
||||
name: LVGL Paused
|
||||
entity_category: diagnostic
|
||||
condition:
|
||||
lvgl.is_paused:
|
||||
|
||||
light:
|
||||
- platform: monochromatic
|
||||
id: display_backlight
|
||||
name: Display Backlight
|
||||
output: lcd_backlight_output
|
||||
restore_mode: ALWAYS_ON
|
||||
entity_category: diagnostic
|
||||
|
||||
spi:
|
||||
type: octal
|
||||
id: display_spi
|
||||
clk_pin: GPIO21
|
||||
data_pins:
|
||||
- GPIO6
|
||||
- GPIO7
|
||||
- GPIO15
|
||||
- GPIO16
|
||||
- GPIO10
|
||||
- GPIO9
|
||||
- ignore_strapping_warning: true
|
||||
number: GPIO46
|
||||
- ignore_strapping_warning: true
|
||||
number: GPIO3
|
||||
|
||||
display:
|
||||
- platform: mipi_spi
|
||||
id: display_id
|
||||
model: st7789v
|
||||
spi_id: display_spi
|
||||
bus_mode: octal
|
||||
dc_pin: GPIO17
|
||||
dimensions:
|
||||
height: 320
|
||||
width: 170
|
||||
offset_height: 0
|
||||
offset_width: 35
|
||||
invert_colors: true
|
||||
show_test_card: false
|
||||
data_rate: 4MHz
|
||||
color_depth: 16BIT
|
||||
color_order: BGR
|
||||
auto_clear_enabled: false
|
||||
update_interval: 250ms
|
||||
|
||||
i2c:
|
||||
- id: touchscreen_i2c
|
||||
sda: GPIO35
|
||||
scl:
|
||||
number: GPIO0
|
||||
ignore_strapping_warning: true
|
||||
scan: true
|
||||
|
||||
touchscreen:
|
||||
- platform: ft63x6
|
||||
id: touchscreen_id
|
||||
display: display_id
|
||||
i2c_id: touchscreen_i2c
|
||||
calibration:
|
||||
x_min: ${calibration_touchscreen_x_min}
|
||||
y_min: ${calibration_touchscreen_y_min}
|
||||
x_max: ${calibration_touchscreen_x_max}
|
||||
y_max: ${calibration_touchscreen_y_max}
|
||||
on_release:
|
||||
- if:
|
||||
condition: lvgl.is_paused
|
||||
then:
|
||||
- logger.log: "LVGL resuming due to screen touch."
|
||||
- lvgl.resume:
|
||||
- lvgl.widget.redraw:
|
||||
- light.turn_on: display_backlight
|
||||
|
||||
sensor:
|
||||
- platform: pulse_meter
|
||||
name: Power
|
||||
id: power_pulse_meter
|
||||
pin: GPIO5
|
||||
unit_of_measurement: 'W'
|
||||
device_class: power
|
||||
state_class: measurement
|
||||
internal_filter_mode: PULSE
|
||||
accuracy_decimals: 1
|
||||
filters:
|
||||
- filter_out: nan
|
||||
- throttle: 15s
|
||||
- multiply: ${calibration_pulse_power_meter}
|
||||
total:
|
||||
name: "Total Pulses" # DEBUG
|
||||
|
||||
- platform: total_daily_energy
|
||||
id: energy
|
||||
name: "Energy"
|
||||
restore: false
|
||||
power_id: power_pulse_meter
|
||||
unit_of_measurement: "kWh"
|
||||
state_class: total_increasing
|
||||
device_class: energy
|
||||
accuracy_decimals: 3
|
||||
filters:
|
||||
# Convert W to kW
|
||||
- multiply: 0.001
|
||||
|
||||
switch:
|
||||
- platform: output
|
||||
name: Relay
|
||||
id: relay
|
||||
output: relay_output
|
||||
restore_mode: RESTORE_DEFAULT_OFF
|
||||
on_turn_on:
|
||||
- lvgl.widget.update:
|
||||
id: light_toggle_button
|
||||
state:
|
||||
checked: true
|
||||
on_turn_off:
|
||||
- lvgl.widget.update:
|
||||
id: light_toggle_button
|
||||
state:
|
||||
checked: false
|
||||
|
||||
- platform: template
|
||||
name: Antiburn
|
||||
id: switch_antiburn
|
||||
icon: mdi:television-shimmer
|
||||
optimistic: true
|
||||
entity_category: diagnostic
|
||||
turn_on_action:
|
||||
- logger.log: "Starting Antiburn"
|
||||
- if:
|
||||
condition: lvgl.is_paused
|
||||
then:
|
||||
- lvgl.resume:
|
||||
- lvgl.widget.redraw:
|
||||
- lvgl.pause:
|
||||
show_snow: true
|
||||
- light.turn_off: display_backlight
|
||||
turn_off_action:
|
||||
- logger.log: "Stopping Antiburn"
|
||||
- if:
|
||||
condition: lvgl.is_paused
|
||||
then:
|
||||
- lvgl.resume:
|
||||
- lvgl.widget.redraw:
|
||||
|
||||
- platform: template
|
||||
id: highlight_fan_off_button
|
||||
name: Highlight Fan-Off Button
|
||||
optimistic: True
|
||||
entity_category: config
|
||||
restore_mode: RESTORE_DEFAULT_ON
|
||||
|
||||
font:
|
||||
- # file: "https://github.com/Pictogrammers/pictogrammers.github.io/raw/refs/heads/main/@mdi/font/7.4.47/fonts/materialdesignicons-webfont.ttf"
|
||||
file: "fonts/pictogrammers/@mdi/font/7.4.47/fonts/materialdesignicons-webfont.ttf"
|
||||
id: mdi_icons
|
||||
bpp: 4
|
||||
size: 52
|
||||
glyphs:
|
||||
- "\U000F0336" # mdi:lightbulb-outline
|
||||
- "\U000F06E9" # mdi:lightbulb-on-outline
|
||||
- "\U000F081D" # mdi:fan-off
|
||||
- "\U000F1472" # mdi:fan-speed-1
|
||||
- "\U000F1473" # mdi:fan-speed-2
|
||||
- "\U000F1474" # mdi:fan-speed-3
|
||||
|
||||
lvgl:
|
||||
id: lvgl_id
|
||||
displays:
|
||||
- display_id
|
||||
touchscreens:
|
||||
- touchscreen_id
|
||||
buffer_size: 25%
|
||||
log_level: WARN
|
||||
on_idle:
|
||||
timeout: 30s
|
||||
then:
|
||||
- logger.log: "LVGL is idle"
|
||||
- light.turn_off: display_backlight
|
||||
- lvgl.pause:
|
||||
style_definitions:
|
||||
- id: header_footer
|
||||
bg_color: 0x2F8CD8
|
||||
bg_grad_color: 0x005782
|
||||
bg_grad_dir: VER
|
||||
bg_opa: COVER
|
||||
border_opa: TRANSP
|
||||
radius: 0
|
||||
pad_all: 0
|
||||
pad_row: 0
|
||||
pad_column: 0
|
||||
border_color: 0x0077b3
|
||||
text_color: 0xFFFFFF
|
||||
width: 100%
|
||||
height: 30
|
||||
top_layer:
|
||||
widgets:
|
||||
- obj:
|
||||
align: TOP_MID
|
||||
styles: header_footer
|
||||
widgets:
|
||||
- label:
|
||||
text:
|
||||
time_format: "%l:%M %p"
|
||||
time: ${time_source}
|
||||
id: label_time
|
||||
align: CENTER
|
||||
text_align: CENTER
|
||||
text_color: 0xFFFFFF
|
||||
- label:
|
||||
text: "\uF1EB"
|
||||
id: label_apistatus
|
||||
align: top_right
|
||||
x: -2
|
||||
y: 7
|
||||
text_align: right
|
||||
text_color: 0xFFFFFF
|
||||
- buttonmatrix:
|
||||
align: bottom_mid
|
||||
styles: header_footer
|
||||
pad_all: 0
|
||||
outline_width: 0
|
||||
id: top_layer
|
||||
items:
|
||||
styles: header_footer
|
||||
rows:
|
||||
- buttons:
|
||||
- id: page_prev
|
||||
text: "\uF053"
|
||||
on_press:
|
||||
then:
|
||||
lvgl.page.previous:
|
||||
- id: page_home
|
||||
text: "\uF015"
|
||||
on_press:
|
||||
then:
|
||||
lvgl.page.show: page_main
|
||||
- id: page_next
|
||||
text: "\uF054"
|
||||
on_press:
|
||||
then:
|
||||
lvgl.page.next:
|
||||
pages:
|
||||
- id: page_main
|
||||
pad_all: 0
|
||||
widgets:
|
||||
- buttonmatrix:
|
||||
id: matrix_id
|
||||
width: 100%
|
||||
height: 260
|
||||
x: 0
|
||||
y: 30
|
||||
pad_top: 2
|
||||
pad_bottom: 0
|
||||
pad_left: 2
|
||||
pad_right: 0
|
||||
pad_row: 3
|
||||
pad_column: 1
|
||||
text_font: mdi_icons
|
||||
rows:
|
||||
- buttons:
|
||||
- id: light_toggle_button
|
||||
text: "\U000F0336" # mdi:lightbulb-outline
|
||||
width: 2
|
||||
control:
|
||||
checkable: true
|
||||
on_click:
|
||||
- switch.toggle: relay
|
||||
- buttons:
|
||||
- id: fan_speed_0_button
|
||||
text: "\U000F081D" # mdi:fan-off
|
||||
control:
|
||||
checkable: true
|
||||
on_click:
|
||||
- fan.turn_off: fan_id
|
||||
- id: fan_speed_1_button
|
||||
text: "\U000F1472" # mdi:fan-speed-1
|
||||
control:
|
||||
checkable: true
|
||||
on_click:
|
||||
- fan.turn_on:
|
||||
id: fan_id
|
||||
speed: 1
|
||||
- buttons:
|
||||
- id: fan_speed_2_button
|
||||
text: "\U000F1473" # mdi:fan-speed-2
|
||||
control:
|
||||
checkable: true
|
||||
on_click:
|
||||
- fan.turn_on:
|
||||
id: fan_id
|
||||
speed: 2
|
||||
- id: fan_speed_3_button
|
||||
text: "\U000F1474" # mdi:fan-speed-3
|
||||
control:
|
||||
checkable: true
|
||||
on_click:
|
||||
- fan.turn_on:
|
||||
id: fan_id
|
||||
speed: 3
|
||||
Reference in New Issue
Block a user