Must be a better way of doing this

Probably through AppDaemon but I haven’t learned how to use it yet but until then, is there a better way of doing the following in scripts?

I have a fan that I control through a Tasmota device. It has one push button that goes from High, Medium, Low, Off (in that order) and the Tasmota device toggles de button for 0.5 sec. I defined an input_number variable called ventilateur_salon_speed and 4 scripts. This is the script for Max speed but they are the same, except the number they stop at (0 for Off, 1 for Low, 2 for Medium and 3 for High). The script goes through 3 main actions: Test if already at its required value and if it is, stop the script. If not, turn on the button and decrement the variable. If it reaches 0, start back at 3 then delay so it has time to toggle before continuing. Since it can take 3 iterations (ie, push the button 3 times) to reach the requested speed, it repeat this action 3 times (hence why 3 main actions).

'1586725146435':
  alias: VentilateurSalonSpeedMax
  sequence:
  - condition: template
    value_template: >
      {% if states.input_number.ventilateur_salon_speed.state | float == 3.0 %}false{% else %}true{% endif %}
  - data: {}
    entity_id: switch.ventilateursalonalimentation
    service: switch.turn_on
  - data_template:
      value: '{% if states.input_number.ventilateur_salon_speed.state | float < 1.0 %}3.0{% else
        %}{{ states.input_number.ventilateur_salon_speed.state | float - 1.0 }}{% endif %}'
    entity_id: input_number.ventilateur_salon_speed
    service: input_number.set_value
  - condition: template
    value_template: >
      {% if states.input_number.ventilateur_salon_speed.state | float == 3.0 %}false{% else %}true{% endif %}
  - delay: 00:00:01
  - data: {}
    entity_id: switch.ventilateursalonalimentation
    service: switch.turn_on
  - data_template:
      value: '{% if states.input_number.ventilateur_salon_speed.state | float < 1.0 %}3.0{% else
        %}{{ states.input_number.ventilateur_salon_speed.state | float - 1.0 }}{% endif %}'
    entity_id: input_number.ventilateur_salon_speed
    service: input_number.set_value
  - condition: template
    value_template: >
      {% if states.input_number.ventilateur_salon_speed.state | float == 3.0 %}false{% else %}true{% endif %}
  - delay: 00:00:01
  - data: {}
    entity_id: switch.ventilateursalonalimentation
    service: switch.turn_on
  - data_template:
      value: '{% if states.input_number.ventilateur_salon_speed.state | float < 1.0 %}3.0{% else
        %}{{ states.input_number.ventilateur_salon_speed.state | float - 1.0 }}{% endif %}'
    entity_id: input_number.ventilateur_salon_speed
    service: input_number.set_value

What do you think? Can you improve it? Make it more efficient or fix possible pitfalls?

Edit : forgot to say the scripts are called by Alexa.

Thanks.

So thinking about it while taking my daily walk, I thought that if I added the code that cycle the value in an automation, I could also use Home Assistant to control the fan by simply clicking on its icon in Lovelace. That has simplified the code alot:

Automation:


- id: '1586739684992'
  alias: Salon - Ventilateur
  description: ''
  trigger:
  - entity_id: switch.ventilateursalonalimentation
    platform: state
    to: 'on'
  condition: []
  action:
  - data_template:
      value: '{% if states.input_number.ventilateur_salon_speed.state | float < 1.0
        %}3.0{% else %}{{ states.input_number.ventilateur_salon_speed.state | float
        - 1.0 }}{% endif %}'
    entity_id: input_number.ventilateur_salon_speed
    service: input_number.set_value

Script:

'1586725146435':
  alias: VentilateurSalonSpeedMax
  sequence:
  - condition: template
    value_template: >
      {% if states.input_number.ventilateur_salon_speed.state | float == 3.0 %}false{% else %}true{% endif %}
  - data: {}
    entity_id: switch.ventilateursalonalimentation
    service: switch.turn_on
  - delay: 00:00:01
  - condition: template
    value_template: >
      {% if states.input_number.ventilateur_salon_speed.state | float == 3.0 %}false{% else %}true{% endif %}
  - data: {}
    entity_id: switch.ventilateursalonalimentation
    service: switch.turn_on
  - delay: 00:00:01
  - condition: template
    value_template: >
      {% if states.input_number.ventilateur_salon_speed.state | float == 3.0 %}false{% else %}true{% endif %}
  - data: {}
    entity_id: switch.ventilateursalonalimentation
    service: switch.turn_on

(I moved the delay before the test to make sure the automation had time to run first)

This looks ‘cleaner’.

This could be done with a single script for all speeds. Just pass resulting speed in as an input.

'1586725146435':
  alias: VentilateurSalonSpeed
  sequence:
  - condition: template
    # is_state returns true if the state matches the 2nd parameter. 
    # target_speed is passed in as a string, so no need to convert anything.
    value_template: "{{ is_state('input_number.ventilateur_salon_speed', target_speed) }}"
  - data: {}
    entity_id: switch.ventilateursalonalimentation
    service: switch.turn_on
  - delay: 00:00:01
  - condition: template
    value_template: "{{ is_state('input_number.ventilateur_salon_speed', target_speed) }}"
  - data: {}
    entity_id: switch.ventilateursalonalimentation
    service: switch.turn_on
  - delay: 00:00:01
  - condition: template
    value_template: "{{ is_state('input_number.ventilateur_salon_speed', target_speed) }}"
  - data: {}
    entity_id: switch.ventilateursalonalimentation
    service: switch.turn_on

Now just make sure you pass in the data parameter “target_speed” to this one script.

- service: script.ventilateursalonspeed
  data_template:
    target_speed: "1.0"

I’m not sure what your update scripts do. I mean, I know what the script does, but it’s not changing the input_number. And your automation will only decrement the number when the switch turns on. Maybe the switch turns itself back off?

Thanks. Not sure how I can pass a variable from Alexa to Home Assistant, can it be done?

To answer your question, it’s not changing the input_number but turning on the switch (which Tasmota will turn off by itself 0.5s later to simulate a button press). When that happens, the automation will decrement the input_number (and rollover to 3 when it reaches 0 so it goes 3, 2, 1, 0, 3, etc). The script repeats turning on the switch until (the condition statement) the input_number has reached its target value. So depending what was stored in the input_number when you called a script, to reach the desired speed, the button will be ‘pressed’ once, twice or three times.

I saw loops can be simulated by calling the script on itself. I might try that.

Thanks for the reply.

Yeah, you’re right. Alexa can’t pass variables easily unless you emulate a light and ask it to “turn the fan to 50%”.

Actually, that could work. Create a template light called “fan” and have the brightness control the output. Just round it to the nearest setting.

Or leave 3 scripts…that works just as much :slight_smile:

I actually like the light idea. That way I can say ‘Alexa turn off the living room fan’ instead of ‘Alexa, living room fan to off’ (or, low, medium and max). What variable will be seen on the HA side, brightness?

https://developer.amazon.com/en-US/docs/alexa/device-apis/list-of-interfaces.html

https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-brightnesscontroller.html

Alexa does support a PowerController with is essentially a dimmer switch, but it doesn’t look like Home Assistant can create a template dimmer switch, so you’d be out of luck…or just use the template light.

Brightness will be a value from 0 to 100%. I’m not sure if the alexa skill will auto translate that for you or not, though it’s going to call the light.set_level function…and in the examples on the template light, it looks like a value from 0-255, so I’d assume that.

  - platform: template
    lights:
      fan:
        friendly_name: "Fan Control"
         ...
        set_level:
          service: script.ventilaterusalonspeed
          data_template:
            # Convert to a value of 1, 2, or 3 from the input of 0-255. 
            # 85 is 1/3 of 255. Just round to the closest value. 
            target_speed: "{{ (brightness / 85) | round(0) }}"