Add easier solution for loops in automations/scripts

I also think that this feature could be a great addition for out of the ordinary uses.

There’s something I’m trying to do that would make use of a loop.

I’m trying to control my A/C temperature with a broadlink RF transmitter.
Basically I have a script that sends a “temperature up” command and another for the “temperature down”.
Since I don’t know the actual setpoint of the A/C, I used an input number that I synchronize witch each up/down calls. Let’s call it the actual A/C value.

I have another input_number that is the desired set point.

I’m trying to find a way to make a script that would loop the up or down scripts until the A/C is at the desired set point.

Using a While(condition) loop for this would work great.
The For loop with a condition would also work, I could just put a large number for the loop counter and add a condition.

I managed to get this working with calling scripts but it’s not very efficient and creates a lots of useless scripts that should be only one really.
Also, using that method, I need to add delay: instructions before calling the other script otherwise it fails saying that the script is already in use…
Those delays makes the temperature changes kinda very slowly. I think all that could be better with the use of loops.

1 Like

You may want to use a simple python_script to perform the looping. A python_script offers you even more flexibility than a regular script.

There’s an example shown here:

The challenge was to send repeated commands (via a Broadlink device) to a fan in order to change its speed. The fan has 8 speed levels and one command is used to step through all the levels. The python_script calculates how many times the command must be sent to change from one speed to another. Then it proceeds to send the command the number of times it had calculated.

In this example, each iteration does two things:

  • Execute the broadlink.send service call (using the contents of the variable service_data).
  • Pause for a half-second.
    for i in range(loop):
      hass.services.call('broadlink', 'send', service_data, False)
      time.sleep(0.5)

It will repeat those two commands the number of times specified by the variable loop.

Calling a python_script (from an automation) is similar to calling a regular script. Here’s an example of calling a python_script and passing it a parameter called fan_speed:

          - service: python_script.fan_speed_control
            data:
              fan_speed: '7'

Nice !

That looks like a very complete solution very similar to what I’m doing.

I don’t know Python much, maybe it’s a good place to start, because I will mostly copy all this…

Where do I find the documentation on how to use Python with HA objects ?

The Developer Docs explain it in detail. However, I caution you that it is written for software developers so it is daunting for non-developers. My suggestion is to ‘learn by example’. Simply search the community forum for ‘python_script’ and read the examples created by other people. Copy and paste and experiment.

Tip:
There’s no need to reload python_scripts like you do with scripts and automations. After you make a change to your python_script file, save it and it will be immediately available to Home Assistant. This makes it easier and faster to experiment and learn from one’s mistakes (and successes).

If you want a sensible use-case: my hearing is not so good. If the fire alarm goes off, I want to ring my doorbells (I have 5 of them distributed through the house, one next to my bed).

If I do

  action:
  - data:
      payload: '14163857'
      topic: home/OpenMQTTGateway/commands/MQTTtoSRFB
    service: mqtt.publish

I just hear a ‘ring…’, no way I’m going to wakeup if there ever is a fire.

So now I have

  - data:
      payload: '14163857'
      topic: home/OpenMQTTGateway/commands/MQTTtoSRFB
    service: mqtt.publish
  - delay: 00:00:01
  - data:
      payload: '14163857'
      topic: home/OpenMQTTGateway/commands/MQTTtoSRFB
    service: mqtt.publish

repeated a 100 times. There must be a better solution for this.

Here’s a python_script that will publish the payload 14163857 to the topic home/OpenMQTTGateway/commands/MQTTtoSRFB, pause for 1 second, then repeat this action for a total of 5 times.

fire_alarm.py

service_data = {'topic':'home/OpenMQTTGateway/commands/MQTTtoSRFB', 'payload':'14163857'}
for i in range(5):
  hass.services.call('mqtt', 'publish', service_data, False)
  time.sleep(1)

Your automation would call it as a service:

  action:
     service: python_script.fire_alarm
2 Likes

Thanks .
.

I need to press volume down on my IR blaster 42 times. I would love this.

42 times?

Yeah, the python_script I posted above can handle that need.

Well… I don’t have three examples, but here’s two (and if python_scripts are the way to go here, happy to pointed in the right direction (again!)).

I want to use a rest_command to POST some data to an external API/URL (solcast.com) every 5 minutes (all day, every day—though from just before sunrise to just after sunset would probably be just as suitable). I can manually trigger it, but I need a lot more data uploaded to calibrate.

I also want to use a rest_command to GET data from solcast.com every 40 minutes (between sunrise and sunset) to conserve my 20 free API calls (:slight_smile: POST API calls don’t count). I’m currently using a RESTful sensor for this, but as that runs all night (as well as during the day) I only get about 10 useful API calls (i.e. daytime ones).

Sounds like what the Time Pattern Trigger was designed to do.

Time Pattern Trigger with a sunrise/sunset condition.

1 Like

Taras, you’re a legend. I’ll give it a try.

Well that seems to be working great for great for my POST of data to solcast.com—thanks very much Taras!

Any suggestions on what/where to read up on using GET in rest_command to set the value of a sensor (so I can control it in the same way as the POST—versus the “always running” RESTful sensor I’m currently using)?

(and apologies to the OP is this is off-topic)

It’s my understanding that GET is the default for rest_command.

Regarding your existing RESTful sensor, the default polling interval (for most platforms that perform polling) is 30 seconds. If that’s too frequent for your sensor’s purpose, you can adjust it using scan_interval. For example, if you want it to poll every 15 minutes, set it to 15 x 60 = 900 seconds.

Yep… GET is default. And I’m aware of the polling interval settings for RESTful sensor (I currently have it set to 4500 seconds).

What I’m hoping to do is either:

  • Some way to stop the RESTful sensor from polling during the night (to conserve my API calls), or

  • Use the rest_command to get the same information at fixed intervals, and only during daytime, (as is now working successfully (thanks!) in POSTing data) and use the data to “set” a sensor (if there is some way to do this)

Hmmm. Here’s an (untested) idea, create an automation that runs periodically, but only during daylight hours, and updates your RESTful sensor via a service call to homeassistant.update_entity.

  • Use your existing RESTful sensor.
  • Set its scan_interval to 86400 seconds so it fires just once a day.
  • Create an automation with a time_pattern trigger (set the interval to whatever you prefer).
  • Set the automation’s condition to run exclusively during daylight hours.
  • Set the automation’s action to run the update_entity service for your RESTful sensor.
1 Like

Initial testing seems to be working—so… awesome! I’m gonna have a play with extreme scan intervals (like… a year (31536000)—apparently others have done this with no issues as yet).

Thanks again!

I don’t like the idea of having to write a Python script to perform a loop in HA. If HA is going to be something for common folks, that will never do.

One other example of a loop that I need right now is following:

  • Burglar Alarm is triggered - > use tts.google_say to repeat message “intruder alert”. Maybe with a delay in between. This should be done until state of alarm is disarmed.

Do you mean that you cannot currently implement it without python_script?

yes, correct!