Goodbye Tasmota

Thanks, I’ve ordered VL53LOX and will proceed from there…

1 Like

Hello,
this might be a little bit of an old topic, but while googling I came across this one a couple of times and actually want to replay.

Because one of my next projects probably will invalve Bluetooth and ESPHome can be used as a BT proxy, esp home becomes interested for me.

Before today I had 27 tasmota deviced and only 1 esphome. So I decided to start migrating 1 simple device.
I have actually really complex tasmota configurations.
First I had some struggle to get Esphome flashed, but this was because Tasmote wouldn’t install the minimized version.

And I actually think both have strong and weaker points.

  • Tasmota on itself is way easier to configure.
  • EspHome on the other site can be completely managed from HA.
  • but for every config change ESPHome needs to be redeployed where in tasmote you just login and change.
  • For ESPHome I had some struggle with some small blinking led, where is just works out of the box for Tasmota.
  • and, this one is more an issue. If for some reason the update fails, you need to unpower the ESPHome device to get is boot up again. For some devices for me this would mean, flipping the main fuses in the house.
  • And also, sometimes updates fail.

Not sure yet which one I prefer, because I like the centralized configuration, but I’ve already had issues, which I never encountered using Tasmota.

I just want to give you some insight in my first experience, where I say, it isn’t bad, but it could be better.

3 Likes

This is just simple appreciation. Have been using tasmota for WiFi dimmer switches (and other stuff) for a couple years. They worked fine but decided to switch to Esphome after trying it for some other devices, and they appear so much more responsive. I love having a central place to view them. The yaml is so powerful and easier that tasmota and its terminal! I set it up to control hue lights through home assistant but if home assistant is down it will instead directly call the hue bridge!

Very cool stuff so thanks to everyone who contributed to it.

3 Likes

For me there is still some basic things that tasmota has done for ages just better:

  • buttons: in tasmota automatically gets discovered by home assistant as automation triggers, while in esphome this is not possible without using workarounds (it does like Shelly firmware, buttons just work out of the box)
  • covers: tasmota allows granular calibration. In tasmota it is possible to set the halfway level of a cover and it automatically computes a curve (while esphome computes the position only in a linear fashion.

For me if those issues were corrected I would jump to esphome instantly with all esp devices

For me, it was a simple matter of switching from Tasmota to ESPHome, since I only have a few Sonoff Basic R2 devices, and only one of those was running Tasmota. Like others, I like the simplicity of having an easy way to update more than one device, plus the ability to create hardware-specific firmware instead of using a one-size-fits-most approach. I’m going to leave the stock firmware on my Shelly Plus 1 devices, since those work just fine.

2 Likes

you’ve convinced me to stick with Tasmota
Thanks

1 Like

I started with Tasmota for its ease of use, but migrating to Esphome for most of the devices for the following reason - I have several homes tied together with VPN tunnels and I run a main HA instance and a remote instance - now ESPHome let me control via the API from several HA instances in paralel while Tasmota with MQTT is more a point-to-point thing.

I still leave some (critical) devices with Tasmota because of the web interface - as long as I dont understand how to code that with ESPhome.

Tasmota is way easier to understand for beginners I think.

Which smoke detector do you use with ESP Home?

Two lines of yaml should get you a web interface to control your esphome node :point_down:

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.

2 Likes

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…

1 Like

‘Grocking’ doesn’t come so easily when you’re 83 years old! :tired_face:

1 Like

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 :thinking:
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)

1 Like

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? :thinking:

My Tasmota time is long over (essentially deprecated because of esphome :stuck_out_tongue:) 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.

1 Like

This whole discussion seriously has internet-warrior vibes too be honest.

3 Likes