Two lines of yaml should get you a web interface to control your esphome node
web_server:
port: 80
Two lines of yaml should get you a web interface to control your esphome node
web_server:
port: 80
I’m using Tasmota, and have wondered whether I should go with ESPHome (pretty much at a beginner level), But one thing repels me about ESPHome - YAMYL files! I’ve sat for ages looking at a YAML file, wondering why it doesn’t work, only to find that when I’ve re-entered the code exactly as before (yeah - I know about the difference between tabs and spaces) , it finally works! I find YAMYL syntax weird and non-intuitive.
This is my subtitle. Eventually you will grok.
I’ve been exactly where you are… i looked at “weird” yaml and went on. Not for long, though… when i needed my custom function on esp module i went to esphome where i could do it.
Yaml files are not so weird once you learn them. But, isn’t it same for each thing? Like ….autocad or altium designer: it’s super weird if you don’t know how to use it…
Of course, you must be extra carefull regarding spaces, indentation…
‘Grocking’ doesn’t come so easily when you’re 83 years old!
Well, yaml beats Tasmota scripts…
This is what i used for my 2ch dimmer in Tasmota:
;WiFi-2CH-Dimmer v1.3
;QS-WiFi-D02-2C
;MS-105B
>D
sw1=0
sw2=0
x=0
cn1=0
cn2=0
tm1=0
tm2=0
h1=0
h2=0
t1=0
t2=0
sl1=0
sl2=0
di=""
pl=2
pu=10
dd1=0
dd2=0
mp=2.2
sp=2
ll=15
ul=95
dv1=70
dv2=70
p1=0
p2=0
>B
=>Counter1 0
=>Counter2 0
=>Baudrate 9600
=#sd1(dv1)
delay(1000)
=#sd1(0)
=#sd2(0)
>F
cn1=pc[1]
cn2=pc[2]
if chg[cn1]>0
then sw1=1
else sw1=0
endif
if chg[cn2]>0
then sw2=1
else sw2=0
endif
tm1+=1
tm2+=1
if sw1==0
and tm1>pl
and tm1<pu
then
t1^=1
if t1==1
then
=#sd1(dv1)
else
=#sd1(0)
endif
endif
if sw2==0
and tm2>pl
and tm2<pu
then
t2^=1
if t2==1
then
=#sd2(dv2)
else
=#sd2(0)
endif
endif
if sw1>0
then
if h1==0
then
dd1^=1
endif
if tm1>pu
then
h1=1
if t1>0
then
if dd1>0
then
dv1+=sp
if dv1>ul
then
dv1=ul
endif
=#sd1(dv1)
else
dv1-=sp
if dv1<ll
then
dv1=ll
endif
=#sd1(dv1)
endif
endif
endif
else
tm1=0
h1=0
endif
if sw2>0
then
if h2==0
then
dd2^=1
endif
if tm2>pu
then
h2=1
if t2>0
then
if dd2>0
then
dv2+=sp
if dv2>ul
then
dv2=ul
endif
=#sd2(dv2)
else
dv2-=sp
if dv2<ll
then
dv2=ll
endif
=#sd2(dv2)
endif
endif
endif
else
tm2=0
h2=0
endif
>E
sl1=Channel1
if chg[sl1]>0
then
if sl1>0
then
dv1=sl1
=#sd1(dv1)
else
t1=0
=#sd1(0)
endif
endif
sl2=Channel2
if chg[sl2]>0
then
if sl2>0
then
dv2=sl2
=#sd2(dv2)
else
t2=0
=#sd2(0)
endif
endif
p1=pwr[1]
if p1==1
then
t1=1
=#sd1(dv1)
else
t1=0
=#sd1(0)
endif
p2=pwr[2]
if p2==1
then
t2=1
=#sd2(dv2)
else
t2=0
=#sd2(0)
endif
#sd1(x)
di="FF5501"+hn(x*mp)+"0000000A"
=>SerialSend5 %di%
=>Channel1 %x%
#sd2(x)
di="FF550200"+hn(x*mp)+"00000A"
=>SerialSend5 %di%
=>Channel2 %x%
#
As you can see, just jibberish…
And then it doesn’t even work reliable
And this is the same in EspHome:
substitutions:
node_name: qs-wifi-ds02
node_id: IP_62
friendly_node_name: "Dual Channel Dimmer"
esphome:
name: ${node_name}
comment: ${friendly_node_name}
platform: ESP8266
board: esp01_1m
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_iotpw
power_save_mode: none
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: ${node_name} " FB"
password: "fallback"
captive_portal:
# Enable Home Assistant API
api:
encryption:
key: !secret api_encryption
#Enable Over The Air updates
ota:
#Disable logging
logger:
baud_rate: 0
logs:
sensor: ERROR
duty_cycle: ERROR
binary_sensor: ERROR
light: ERROR
# Enable Web server.
web_server:
port: 80
# Sync time with Home Assistant.
time:
- platform: homeassistant
id: homeassistant_time
# Binary Sensors.
binary_sensor:
#Binary sensor (on/off) which reads duty_cyle sensor readings. CH1
- platform: template
id: switch1
internal: true
name: "${node_id} Switch Binary Sensor 1"
# read duty_cycle, convert to on/off
lambda: |-
if (id(sensor_push_switch_1).state < 95.0) {
return true;
} else {
return false;
}
# Short Click - toggle light only
on_click:
max_length: 300ms
then:
light.toggle: light_main_1
# Generic On_Press - log press, toggle DIM Direction and reset press interval counter
on_press:
then:
- logger.log: "Switch 1 Press"
- lambda: |-
if (id(g_direction_1) == 0) {
id(g_direction_1) = 1;
} else {
id(g_direction_1) = 0;
}
id(g_counter_1) = 0;
#Binary sensor (on/off) which reads duty_cyle sensor readings. CH2
- platform: template
id: switch2
internal: true
name: "${node_id} Switch Binary Sensor 2"
# read duty_cycle, convert to on/off
lambda: |-
if (id(sensor_push_switch_2).state < 95.0) {
return true;
} else {
return false;
}
# Short Click - toggle light only
on_click:
max_length: 300ms
then:
light.toggle: light_main_2
# Generic On_Press - log press, toggle DIM Direction and reset press interval counter
on_press:
then:
- logger.log: "Switch 2 Press"
- lambda: |-
if (id(g_direction_2) == 0) {
id(g_direction_2) = 1;
} else {
id(g_direction_2) = 0;
}
id(g_counter_2) = 0;
# Sensors.
sensor:
# Primary template sensor to track Brightness of light object for "on_value" sending to MCU dimmer
# CH1
- platform: template
name: "${node_id} Brightness Sensor CH1"
id: sensor_g_bright_1
internal: true
update_interval: 20ms
# Ensure on_value only triggered when brightness (0-255) changes
filters:
delta: 0.8
# Read brightness (0 - 1) from light , convert to (0-255) for MCU
lambda: |-
if (id(light_main_1).remote_values.is_on()) {
return (int(id(light_main_1).remote_values.get_brightness() * 255));
}
else {
return 0;
}
# On Change send to MCU via UART
on_value:
then:
- uart.write: !lambda |-
return {0xFF, 0x55, 0x01, (char) id(sensor_g_bright_1).state, 0x00, 0x00, 0x00, 0x0A};
- logger.log:
level: INFO
format: "CH1 Sensor Value Change sent to UART %3.1f"
args: ["id(sensor_g_bright_1).state"]
# Sensor to detect button push (via duty_cycle of 50hz mains signal)
- platform: template
name: "${node_id} Brightness Sensor CH2"
id: sensor_g_bright_2
internal: true
update_interval: 20ms
# Ensure on_value only triggered when brightness (0-255) changes
filters:
delta: 0.8
# Read brightness (0 - 1) from light , convert to (0-255) for MCU
lambda: |-
if (id(light_main_2).remote_values.is_on()) {
return (int(id(light_main_2).remote_values.get_brightness() * 255));
}
else {
return 0;
}
# On Change send to MCU via UART
on_value:
then:
- uart.write: !lambda |-
return {0xFF, 0x55, 0x02, 0x00, (char) id(sensor_g_bright_2).state, 0x00, 0x00, 0x0A};
- logger.log:
level: INFO
format: "CH2 Sensor Value Change sent to UART %3.1f"
args: ["id(sensor_g_bright_2).state"]
# Sensor to detect button push (via duty_cycle of 50hz mains signal)
- platform: duty_cycle
pin: GPIO13
internal: true
id: sensor_push_switch_1
name: "${node_id} Sensor Push Switch 1"
update_interval: 20ms
- platform: duty_cycle
pin: GPIO5
internal: true
id: sensor_push_switch_2
name: "${node_id} Sensor Push Switch 2"
update_interval: 20ms
globals:
# Dim direction for Switch 1: 0=Up (brighten) 1=down (dim)
- id: g_direction_1
type: int
restore_value: no
initial_value: "1"
# Counter for time pressed for switch 1
- id: g_counter_1
type: int
restore_value: no
initial_value: "0"
# initial brightness
# Dim direction for Switch 2: 0=Up (brighten) 1=down (dim)
- id: g_direction_2
type: int
restore_value: no
initial_value: "1"
# Counter for time pressed for switch 2
- id: g_counter_2
type: int
restore_value: no
initial_value: "0"
# initial brightness
# Uart definition to talk to MCU dimmer
uart:
tx_pin: GPIO1
rx_pin: GPIO3
stop_bits: 1
baud_rate: 9600
# Dummy light output to allow creation of light object
output:
- platform: esp8266_pwm
pin: GPIO14
frequency: 800 Hz
id: dummy_pwm1
- platform: esp8266_pwm
pin: GPIO16
frequency: 800 Hz
id: dummy_pwm2
# Primary Light object exposed to HA
light:
- platform: monochromatic
default_transition_length: 20ms
restore_mode: RESTORE_DEFAULT_OFF
name: "${node_id} Light 1"
output: dummy_pwm1
id: light_main_1
- platform: monochromatic
default_transition_length: 20ms
restore_mode: RESTORE_DEFAULT_OFF
name: "${node_id} Light 2"
output: dummy_pwm2
id: light_main_2
# Polling object for long press handling of switch for dim/brighten cycle
interval:
- interval: 20ms
then:
- if:
condition:
binary_sensor.is_on: switch1
then:
# Ramp rate for dim is product of interval (20ms) * number of intervals
# Every 20ms Dimmer is increased/decreased by 2/255
# Lower limit = 10%
# Upper limit = 100%
# 100% - 10% = 90% = 230/255. Therefore 230/2 * 20ms = 2.3 seconds for full range
# At full/min brightness - further 16x20ms = 0.32 Seconds "dwell" by resetting counter to 0
# Initial pause for 16x20ms = 0.32s to allow "on_click" to be discounted 1st
# g_direction_1 = 0 (Increasing brightness)
# g_direction_1 = 1 (decreasing brightness)
# g_counter_1 = Interval pulse counter
lambda: |-
float curr_bright = id(light_main_1).remote_values.get_brightness();
id(g_counter_1) += 1;
// If max bright, change direction
if (curr_bright >= 0.999 && id(g_direction_1) == 0) {
id(g_direction_1) = 1;
id(g_counter_1) = 0;
}
// If below min_bright, change direction
if (curr_bright < 0.1 && id(g_direction_1) == 1) {
id(g_direction_1) = 0;
id(g_counter_1) = 0;
}
if (id(g_direction_1) == 0 && id(g_counter_1) > 15) {
// Increase Bright
auto call = id(light_main_1).turn_on();
call.set_brightness(curr_bright + (2.0/255.0));
call.perform();
}
else if(id(g_direction_1) == 1 && id(g_counter_1) > 15) {
// Decrease Bright
auto call = id(light_main_1).turn_on();
call.set_brightness(curr_bright - (2.0/255.0));
call.perform();
}
- if:
condition:
binary_sensor.is_on: switch2
then:
# Ramp rate for dim is product of interval (20ms) * number of intervals
# Every 20ms Dimmer is increased/decreased by 2/255
# Lower limit = 10%
# Upper limit = 100%
# 100% - 10% = 90% = 230/255. Therefore 230/2 * 20ms = 2.3 seconds for full range
# At full/min brightness - further 16x20ms = 0.32 Seconds "dwell" by resetting counter to 0
# Initial pause for 16x20ms = 0.32s to allow "on_click" to be discounted 1st
# g_direction_1 = 0 (Increasing brightness)
# g_direction_1 = 1 (decreasing brightness)
# g_counter_1 = Interval pulse counter
lambda: |-
float curr_bright = id(light_main_2).remote_values.get_brightness();
id(g_counter_2) += 1;
// If max bright, change direction
if (curr_bright >= 0.999 && id(g_direction_2) == 0) {
id(g_direction_2) = 1;
id(g_counter_2) = 0;
}
// If below min_bright, change direction
if (curr_bright < 0.1 && id(g_direction_2) == 1) {
id(g_direction_2) = 0;
id(g_counter_2) = 0;
}
if (id(g_direction_2) == 0 && id(g_counter_2) > 15) {
// Increase Bright
auto call = id(light_main_2).turn_on();
call.set_brightness(curr_bright + (2.0/255.0));
call.perform();
}
else if(id(g_direction_2) == 1 && id(g_counter_2) > 15) {
// Decrease Bright
auto call = id(light_main_2).turn_on();
call.set_brightness(curr_bright - (2.0/255.0));
call.perform();
}
Yes,it is bigger, but way easier to comprehend …and allows me to debug/improve the script (while Tasmota does not)
Well, all i can say is… congratulations! Keep going!
Looks like there is a bit of a push for Matter in Tasmota.
Stupid question but how did you came up with this “script” in the first place?
My Tasmota time is long over (essentially deprecated because of esphome ) but beside the various scattered configurations in the web ui, templates and some (for me) already gibberish commands in the cli I (luckily) never came that “far” to “work” with scripts. Is there some kind of generator for these?
Two lines of code
# Example configuration entry
web_server:
port: 80
I didn’t made it myself…found info from arendst(tasmota); i believe the original author is thxthx0; also blackadder has some info on it.
But my point was, it is impossible to improve this script without being 100% familiar with it.
This whole discussion seriously has internet-warrior vibes too be honest.
I was driven by frustration to replace my Z-Wave plugs with something reliable and easy to manage. In the end my solution with ESPHome plugs were cheaper, easier to manage, and more reliable. Now every smart plug on my network can be controlled reliably. The best part is that they actually work. That is all I ever wanted.
This is simple use what works for you. Both have advantages and disadvantages along with the fact both are evolving.
Esp for streamlined but it fails in the setup area rather badly with the setup since a newcomer is going to lose their mind trying to configure yaml.
Tas one size fits most things isn’t always the way to go.
The great thing is we have options and with the push to improve both things are only going to get better.
Just thinking… perhaps we would come reasonably close to “perfection” if esphome would have similar approach as HA, where you can configure cards via UI (newcomer), but you can also do it (or improve) directly by typing a code (advanced user).
But, as i said: just (crazy) thinking… since massive amount of work would be needed on UI part of ESPHome addon.
Is there a guide anywhere describing how to convert tasmota templates into esphome code?
The guide i found on the esphome website seems to only describe the esphome to tasmota firmware upload process.
To me…tasmota is jibberish…
Pretty sue it is not convertable
Don’t think so. But you find ready made yamls for various devices under this link
All you need from Tasmota are the GPIO used and what they do. Then create a new device in ESPHome.