Setting up hass to send the timer jason to tasmota switch

Hi i am new to Home assitant. I have setup home assistant on my raspberry pi. I am using Sonoff switches for home automation flashed with Tasmota. When i upgraded tasmota to the latest version, it gives an option to set Timer with the cmnd/sonoff/Timer(x) command topic with a valid json. I would like to setup Home assitant to recieve inputs from the user on the name of the sonoff device and the time and send a mqtt command to the tasmota sonoff switch.

the topic to send the command to the mqtt switch would look like
“cmnd/sonoff/Timer1” and the json to be sent as a payload to this topic would look like
{“Arm”: 1, “Time”: “19:23”, “Window”: 0, “Days”: “S------”, “Repeat”: 0, “Output”: 1, “Action”: 2}

please help me with the steps for creating a UI on the Homeassistant screen to recieve inputs on the sonoff device name
time in hh:mm format
action ON/OFF
a button to click for sending this command
then i need help with setting up the automation which gets triggered upon pressing the button. it should take the input values which are entered on the device name, time and action input fields and send a command to the switch1 with the message payload.

Do i need to setup a template for this.?

I’m after the same thing. I want to setup a 4channel relay board with tasmota to run irrigation valves. I have built a UI panel for it and have all the incoming bits of data needed to setup a tasmota timer, but I’m stuck on the automation/template/script to put the data together into a JSON string to put on the MQTT topic.

this is my logic flow:
# when the input_boolean.save_settings is switched on:
# create two MQTT line like this -
# Timer1 {“Arm”:1,“Time”:"<start_time>",“Days”:"<run_days>",“Repeat”:1,“Output”:,“Action”:1}
# Timer1 {“Arm”:1,“Time”:"<end_time>",“Days”:"<run_days>",“Repeat”:1,“Output”:,“Action”:0}
# this then gets sent to the MQTT topic -
# cmnd/sonoff_sprinklers01/
# cmnd/sonoff_sprinklers01/
#
# <run_days> is built from input_boolean.sunday through .saturday. - or 0 is disabled, anything else is enabled.
# <start_time> is built from input_number.start_time_hour and .start_time_minute <00:00> to <23:59>
# <end_time> is built from <start_time> and input_number.run_duration <00:00> to <23:59>
# is from input_select.irrigation_zone [1…4]

You guys should look into how to post to MQTT and how to automation. These are the documentations for automations.

AUTOMATIONS (read them top down):

MQTT is different. You’ll need to figure out how you want to represent the mqtt devices in home assistant. Then can emulate just about any device type: light, sensor, binary sensor, etc. Once you know what you want, look up MQTT in the components library and follow the documentation. Here’s a link to the component library:

I’ve been through all those documents. Trouble is I’m not a programmer. The MQTT is easy, I need to piece together the various parts from the UI to construct the MQTT message. I haven’t seen how to build a simple string that I can pass to an MQTT topic.

the topic is: cmnd/sonoff_sprinklers01/Timer1
the value is variable, but looks similar to this: {“Arm”:1,“Time”:"<end_time>",“Days”:"<run_days>",“Repeat”:1,“Output”:,“Action”:0}

I’m thinking about trying to use Node-Red to do the string construction because I can understand it a little better than HA, but that’s still hard to wrap my head around.

Well it’s really only hard because of the interface that you chose.

You could have used a input_datetime to specify your start time and your duration.

Then piecing together the strings would be easier.

In any case, using an input number, the code would be rather easy. Strings are placed in quotes, and adding them together with a + sign. You have to be wary when using quotes inside strings though, so make sure that you use double quotes to denote the entire string and single quotes inside each piece:

"{'Arm':" + states.input_select.save_settings_to_zone + "'Time':" + etc....

But as I said before, because you are using sliders, this makes it extremely complicated because you need to convert your slider into time. Converting anything into time is a pain in the ass for experienced coders.

You need to know the format that your device accepts, then use strftime() to convert seconds into a time format.

Even if you use input_datetime’s, you’ll need to convert that state into a format that your device uses using strfttime.

As for how to place this into MQTT, you’ll need to use templating. Templating will allow you to piece your strings together as code and then supply it to the MQTT topic.

If you can’t code well, I’d avoid using this all together and try node-red.

Hi i have done a bit of work and figured out how to do the automation. Here is the automation script i have done where i am able to send the timer json to my tasmota loaded sonoff switch from HA. Below is my configuration.yaml file. The initial mqtt section is the definition of the mqtt broker and the parameters. the light and switch section are of platform mqtt.

The automation section have defined an automation where which is triggered by a state change in the action select component of the input select and the action portion of the automation does an mqtt.publish service with the data in a data template.
The template has two components ie… topic and the payload.
The topic command is constructed for eg… “cmnd/computerroomlight/Timer1”, where computerroomlight and Timer1 are variables taken from the preceding input select sections. The quotes are very important here. Since the whole topic is under double quotes “”, in order to substitue variables i had to use variable names in single quotes for eg.‘input_select.device’ and the rest of the format which is
{{states(‘input_select.device’|string)}}. This is the python format for variable substitution (a little bit confusing but basicaly the curly braces{ indicates start of variable the second curly brace identifies the variable as states (which is a HA defined variable) and with in (), we specify the input select option of whose state we wanted to be substituted in the command. ).

On the payload side it is a little trickier since the payload in my case needs to be json formatted and the json needs “” inside its components. The standard way of doing that in python is to use the escape character . So wherever i have used " , the " gets inserted in the Json that is formed. without the \ character python will see the " as the end of string statement and you will not be able to form the complete json.

so for a json to look like
{“Arm”:1, “Time”:“3:55”,“Window”:0,“Days”:“SMTWTFS”,“Repeat”:0,“Output”:1,“Action”:0}

I had to add the escape character to the template on payload eg
payload = “{“Arm”:1, “Time”:“3:55”,“Window”:0,“Days”:“SMTWTFS”,“Repeat”:0,“Output”:1,“Action”:0}”

I then replaced the fixed timer value of 3:55 and the fixed action of 0 in the above line with variable markings
hence replaced 3.55 with {{states(‘input_datetime.only_time’)|string}}
replace 0 in the last part of the Json under action with {{states(‘input_select.action_select’)|int}}

Below is my configiguration.yaml file section for the above mentioned activity. Hope this helps to clarify as to how to form the Json in the data_template.

mqtt:
broker: 127.0.0.1
port: 1883
client_id: home-assistant-RVR
keepalive: 60
protocol: 3.1
birth_message:
topic: “tele/hass1/LWT”
payload: “Online”
qos: 1
retain: true
will_message:
topic: “tele/hass1/LWT”
payload: “Offline”
qos: 1
retain: false

light :

  • platform: mqtt
    name: “Computer room light”
    state_topic: “stat1/computerroomlight/POWER”
    command_topic: “cmnd/computerroomlight/POWER1”
    availability_topic: “tele/computerroomlight/LWT”
    payload_on: “ON”
    payload_off: “OFF”
    payload_available: “Online”
    payload_not_available: “Offline”
    optimistic: false
    qos: 1
    retain: false

  • platform: mqtt
    name: “Master Bedroom Light”
    state_topic: “stat1/masterbedroomlight/POWER”
    command_topic: “cmnd/masterbedroomlight/POWER1”
    availability_topic: “tele/masterbedroomlight/LWT”
    payload_on: “ON”
    payload_off: “OFF”
    payload_available: “Online”
    payload_not_available: “Offline”
    optimistic: false
    qos: 1
    retain: false

  • platform: mqtt
    name: “Upstairs Hall light”
    state_topic: “stat1/upstairshalllight/POWER”
    command_topic: “cmnd/upstairshalllight/POWER1”
    availability_topic: “tele/upstairshalllight/LWT”
    payload_on: “ON”
    payload_off: “OFF”
    payload_available: “Online”
    payload_not_available: “Offline”
    optimistic: false
    qos: 1
    retain: false

switch :

  • platform: mqtt
    name: “Computer table”
    state_topic: “stat1/computertable/POWER”
    command_topic: “cmnd/computertable/POWER1”
    availability_topic: “tele/computertable/LWT”
    payload_on: “ON”
    payload_off: “OFF”
    payload_available: “Online”
    payload_not_available: “Offline”
    optimistic: false
    qos: 1
    retain: false

  • platform: mqtt
    name: “Computer room fan”
    state_topic: “stat1/computerroomfan/POWER”
    command_topic: “cmnd/computerroomfan/POWER1”
    availability_topic: “tele/computerroomfan/LWT”
    payload_on: “ON”
    payload_off: “OFF”
    payload_available: “Online”
    payload_not_available: “Offline”
    optimistic: false
    qos: 1
    retain: false

  • platform: mqtt
    name: “Master Bedroom fan”
    state_topic: “stat1/masterbedroomfan/POWER”
    command_topic: “cmnd/masterbedroomfan/POWER1”
    availability_topic: “tele/masterbedroomfan/LWT”
    payload_on: “ON”
    payload_off: “OFF”
    payload_available: “Online”
    payload_not_available: “Offline”
    optimistic: false
    qos: 1
    retain: false

  • platform: mqtt
    name: “Upstairs Hall Fan”
    state_topic: “stat1/upstairshallfan/POWER”
    command_topic: “cmnd/upstairshallfan/POWER1”
    availability_topic: “tele/upstairshallfan/LWT”
    payload_on: “ON”
    payload_off: “OFF”
    payload_available: “Online”
    payload_not_available: “Offline”
    optimistic: false
    qos: 1
    retain: false

Text to speech

tts:

  • platform: google

input_select:
device:
name: “enter device id”
options:
- “computerroomfan”
- “computertable”
- “masterbedroomfan”
- “masterbedroomlight”
- “computerroomlight”
- “upstairshallfan”
- “upstairshalllight”

 action_select:
    name: "select action"
    options:
        - "0"
        - "1"
        - "2"
    initial: "2"
 timer_select:
    name: "select Timer"
    options:
        - "Timer1"
        - "Timer2"
        - "Timer3"
        - "Timer4"
    initial: "Timer1"   

input_datetime:
only_time:
name : “set time for timer”
has_date: false
has_time: true
initial: now()

automation:

  • alias: Automation2
    action:
    • data_template:
      topic: “cmnd/{{states(‘input_select.device’|string)}}/{{states(‘input_select.timer_select’)|string}}”
      payload: “{“Arm”: 1,“Time”: “{{states(‘input_datetime.only_time’)|string}}”, “Window”: 0, “Days”: “SMTWTFS”, “Repeat”: 0, “Output”: 1, “Action”:{{states(‘input_select.action_select’)|int}}}”
      service: mqtt.publish
      trigger:
    • platform: state
      entity_id: input

After posting this i noticed that the Html editor used for posting is removing the escape character \ from the text, hence the actual json template is not showing correctly. I have attached a pic version of my configuration.yaml for better understanding.

Thank you, I appreciate the help here! I’m not stuck to the sliders, I was trying to find examples and all I found was the slider input so I started with that. After the comments from Ramanan I think I have a HA automation that is getting closer.

- alias: setup_timers
  trigger:
    platform: state
	entity_id: input_boolean.save_settings
	to: 'on'
  action:
	- data_template:
      topic: cmnd/sonoff_sprinklers01/Timer{{states('input_select.zone')|string}}"
	  payload: "{\"Arm\": 1, \"Time\":"{{states('input_datetime.start_time')|string}}",\"Window\":0,\"Days\":"input_text.days",\"Repeat\":1,\"Output\":"input_select.zone|int",\"Action\":1}"
	  service: mqtt.publish
	- data_template:
      topic: cmnd/sonoff_sprinklers01/Timer{{states('input_select.zone')|string}}"
	  payload: "{\"Arm\": 1, \"Time\":"{{states('input_datetime.start_time')+states('input_datetime.duration_time')|string}}",\"Window\":0,\"Days\":"input_text.days",\"Repeat\":1,\"Output\":"input_select.zone|int",\"Action\":0}"
	  service: mqtt.publish
    - service: input_boolean.turn_off
	  data:
	    entity_id: input_boolean.save_timer

I think I have something, but this code gives me errors and I’m lost. If it’s this easy in HA I’ll do it there. Otherwise I did complete a Node-Red flow that publishes the correct MQTT.

change the line
topic: cmnd/sonoff_sprinklers01/Timer{{states(‘input_select.zone’)|string}}"

to
topic: “cmnd/sonoff_sprinklers01/Timer{{states(‘input_select.zone’)|string}}”

you seem to have " missing in the begining before the cmnd in each of the topics.

This keeps throwing errors and I can’t figure out why

- alias: setup_timers
  trigger:
    platform: state
    entity_id: input_boolean.save_settings
    to: 'on'
  action:
    - service: mqtt.publish
      data_template:
        topic: "cmnd/sonoff_sprinklers01/Timer1"
        payload_template: "{\"Arm\": 1, \"Time\":\"" + {{states('input_datetime.start_time')|string}} + "\",\"Window\":0,\"Days\":\"" + {{states('input_text.days')|string}} + "\",\"Repeat\":1,\"Output\":1,\"Action\":1}"
        #payload_template: "{\"Arm\":1,\"Time\":\"12:34\",\"Window\":0,\"Days\":\"SMTWTFS\",\"Repeat\":1,\"Output\":1,\"Action\":1}"
    - service: input_boolean.turn_off
      data:
        entity_id: input_boolean.save_timer

specifically on the payload_template line.

templates need to be a string, you are trying to do addition inside the template without following templating rules. You also are trying to do alot in 1 line, and it will get confusing especially seeing as you are attempting to use quotes within quotes. I suggest you read up on jinja. All templating is jinja code and follows strict guildelines. The thing you are missing is the fact that the payload template needs to be encapsulated in “{{ }}” when it is one line. Here are examples of single line and multi line:

single-line example:

payload_template: '{{ "{\"Arm\": 1, \"Time\":\"" + states(\"input_datetime.start_time\") + "\",\"Window\":0,\"Days\":\"" + states(\"input_text.days\") + "\",\"Repeat\":1,\"Output\":1,\"Action\":1}" }}'

To be honest, I’m not sure if the single line will work because you have 3 levels of quotes within quotes. It’s messy and extremely hard to read. I would go with the multi line example.

Multi-line example:

payload_template: >
  {% set section1 = "{'Arm': 1, 'Time': '" %}
  {% set section2 = "','Window':0,'Days': '" %}
  {% set section3 = "', 'Repeat':1, 'Output':1,'Action':1}" %}
  {{ section1 + states('input_datetime.start_time') + section2 + states('input_text.days') + section3 }}

Thank you for the direction petro. I tried and tried to get my template to work but I gave up after getting error messages I couldn’t figure out. It was going too slowly for me and I ended up building a Node-RED flow to read the data out of Home Assistant and build the MQTT message.

Not only does it program the sonoff with the timer to turn on and off, it reads the timer back out of the sonoff when each program is selected from the input_select.

1 Like

Edited to update the flow. It’s simpler and debugged. Still only supports one 4ch.

In case anyone gets here, I’ll add my solution. It’s a HA front-end with Node-RED doing the work. When a zone is selected from the drop down it queries the sonoff for its stored settings and updates the HA UI. As settings are changed their states are tracked and when the save toggle is clicked it gathers them all together and sends the MQTT commands to the sonoff.

HA user interface:

Node-RED flow:

There’s a lot going on. HA has to have all the inputs setup, but Node-RED does the actual talking to the sonoff. There is a noticeable delay when reading the settings out of the sonoff, but I’ll live with it.

[{“id”:“72f1bcae.a467f4”,“type”:“tab”,“label”:“Irrigation”,“disabled”:false,“info”:“”},{“id”:“776aecc8.bb5974”,“type”:“function”,“z”:“72f1bcae.a467f4”,“name”:“Build Strings”,“func”:“// build the MQTT string to send to the Tasmota device\n// there should always be on on and off timer\n//\n// set your MQTT path!\n//\n// example to turn on timer1 at 2:23 on Tues, Wed, Sat\n// Timer1 {"Arm":1,"Time":"02:23",Days":"–TW–S","Repeat":1,"Output":1,"Action":1}\n\n// build the payload with flow variables\nvar msg1 = { payload: "{\"Arm\":\"" + flow.get(‘armed’) + "\",\"Time\":\"" + flow.get(‘start’) + "\",\"Days\":\"" + flow.get(‘days’) +"\", \"Repeat\":\"1\",\"Output\":" + flow.get(‘zone’) +",\"Action\":\"1\"}" };\nvar msg2 = { payload: "{\"Arm\":\"" + flow.get(‘armed’) + "\",\"Time\":\"" + flow.get(‘end’) + "\",\"Days\":\"" + flow.get(‘days’) +"\", \"Repeat\":\"1\",\"Output\":" + flow.get(‘zone’) +",\"Action\":\"0\"}" };\nvar zone = flow.get(‘zone’);\n// build the topic (MQTT topic too) based on selected zone\nswitch (zone){\ncase 0:\n msg1.topic = ‘’;\n msg2.topic = ‘’;\n break;\ncase 1:\n msg1.topic = ‘cmnd/sonoff_garden_1/Timer1’;\n msg2.topic = ‘cmnd/sonoff_garden_1/Timer2’;\n break;\ncase 2:\n msg1.topic = ‘cmnd/sonoff_garden_1/Timer3’;\n msg2.topic = ‘cmnd/sonoff_garden_1/Timer4’;\n break;\ncase 3:\n msg1.topic = ‘cmnd/sonoff_garden_1/Timer5’;\n msg2.topic = ‘cmnd/sonoff_garden_1/Timer6’;\n break;\ncase 4:\n msg1.topic = ‘cmnd/sonoff_garden_1/Timer7’;\n msg2.topic = ‘cmnd/sonoff_garden_1/Timer8’;\n break;\n}\n\n// the third output is to trigger resetting the \n// zone selection, which will trigger reading \n// back from the Tasmota the settings\nmsg.payload = ‘on’;\nnode.status({text:‘zone:’+flow.get(‘zone’)});\nif (zone !== 0) return [msg1,msg2, msg];”,“outputs”:3,“noerr”:0,“x”:430,“y”:390,“wires”:[[“3e30b4aa.8c73ec”],[“3e30b4aa.8c73ec”],[“ce931c43.4359a”]]},{“id”:“15fa380f.215fc8”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Save Button”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_boolean.save_timer”,“entityidfiltertype”:“substring”,“haltifstate”:“off”,“x”:100,“y”:390,“wires”:[[“ab8fdfb.88d9c2”]]},{“id”:“5968c4f7.fa495c”,“type”:“function”,“z”:“72f1bcae.a467f4”,“name”:“days encoder”,“func”:“// encode seperate booleans into a string for \n// days to activate\n\n// get the flow variable and split it out\nvar week = flow.get(‘days’);\nvar sun=week.substr(0,1);\nvar mon=week.substr(1,1);\nvar tue=week.substr(2,1);\nvar wed=week.substr(3,1);\nvar thu=week.substr(4,1);\nvar fri=week.substr(5,1);\nvar sat=week.substr(6,1);\n\n// make updates based on user input\nif (msg.topic == ‘input_boolean.sunday’) {\n //sunday\n if (msg.payload == ‘on’) {sun=‘1’} else {sun=‘0’}\n} else if (msg.topic == ‘input_boolean.monday’) {\n //monday\n if (msg.payload == ‘on’) {mon=‘1’} else {mon=‘0’}\n} else if (msg.topic == ‘input_boolean.tuesday’) {\n //tuesday\n if (msg.payload == ‘on’) {tue=‘1’} else {tue=‘0’}\n} else if (msg.topic == ‘input_boolean.wednesday’) {\n //wednesday\n if (msg.payload == ‘on’) {wed=‘1’} else {wed=‘0’}\n} else if (msg.topic == ‘input_boolean.thursday’) {\n //thursday\n if (msg.payload == ‘on’) {thu=‘1’} else {thu=‘0’}\n} else if (msg.topic == ‘input_boolean.friday’) {\n //friday\n if (msg.payload == ‘on’) {fri=‘1’} else {fri=‘0’}\n} else if (msg.topic == ‘input_boolean.saturday’) {\n //saturday\n if (msg.payload == ‘on’) {sat=‘1’} else {sat=‘0’}\n}\n\n// recombine the string\nweek = sun+mon+tue+wed+thu+fri+sat;\nflow.set(‘days’,week);\n\nnode.status({text:flow.get(‘days’)});\nreturn msg;”,“outputs”:1,“noerr”:0,“x”:710,“y”:165,“wires”:[]},{“id”:“ab8fdfb.88d9c2”,“type”:“api-call-service”,“z”:“72f1bcae.a467f4”,“name”:“Clear Button”,“server”:“157fbb29.ba9835”,“service_domain”:“input_boolean”,“service”:“turn_off”,“data”:“{ "entity_id": "input_boolean.save_timer" }”,“mergecontext”:“”,“x”:265,“y”:390,“wires”:[[“776aecc8.bb5974”]]},{“id”:“3e30b4aa.8c73ec”,“type”:“mqtt out”,“z”:“72f1bcae.a467f4”,“name”:“Publish to MQTT”,“topic”:“”,“qos”:“2”,“retain”:“false”,“broker”:“940130c6.3f4e2”,“x”:735,“y”:435,“wires”:},{“id”:“f4614267.37f68”,“type”:“function”,“z”:“72f1bcae.a467f4”,“name”:“Select Timers”,“func”:“// send the MQTT command to read timer settings\n// from the Tasmota device\n//\n// set your MQTT path!\n//\nif (msg.payload == "Select") {\n flow.set(‘zone’, 0);\n} else {\n var msg1 = { payload: null };\n var msg2 = { payload: null};\n var zone = parseInt(msg.payload);\n\n flow.set(‘zone’, zone);\n\n switch (zone){\n case 1:\n msg1.topic = ‘cmnd/sonoff_garden_1/Timer1’;\n msg2.topic = ‘cmnd/sonoff_garden_1/Timer2’;\n break;\n case 2:\n msg1.topic = ‘cmnd/sonoff_garden_1/Timer3’;\n msg2.topic = ‘cmnd/sonoff_garden_1/Timer4’;\n break;\n case 3:\n msg1.topic = ‘cmnd/sonoff_garden_1/Timer5’;\n msg2.topic = ‘cmnd/sonoff_garden_1/Timer6’;\n break;\n case 4:\n msg1.topic = ‘cmnd/sonoff_garden_1/Timer7’;\n msg2.topic = ‘cmnd/sonoff_garden_1/Timer8’;\n break;\n }\n return [msg1, msg2];\n}\nnode.status({text:‘zone:’+msg.payload});\n”,“outputs”:2,“noerr”:0,“x”:485,“y”:465,“wires”:[[“3e30b4aa.8c73ec”],[“3e30b4aa.8c73ec”]]},{“id”:“d338acd7.85452”,“type”:“mqtt in”,“z”:“72f1bcae.a467f4”,“name”:“”,“topic”:“stat/sonoff_garden_1/+”,“qos”:“0”,“broker”:“940130c6.3f4e2”,“x”:130,“y”:45,“wires”:[[“3e1013a0.2fdedc”]]},{“id”:“82735e74.6983”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Zone”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_select.irrigation_zone”,“entityidfiltertype”:“substring”,“haltifstate”:“”,“x”:80,“y”:450,“wires”:[[“b0db5a30.2e9a88”]],“outputLabels”:[“?”]},{“id”:“aa69a80d.ffacd8”,“type”:“function”,“z”:“72f1bcae.a467f4”,“name”:“decoder”,“func”:“// extract the timer data and rebuild the UI\nvar timer1 = Object.values(msg.payload)[0];\nvar timer2 = Object.values(msg.payload)[1];\n\n// no zone selected\nif (flow.get(‘zone’) == ‘0’) {\n //set all msgs to off/0 and exit\n\t// clear all the boolean switches\n\tnode.send({payload: {data:{entity_id:"input_boolean.armed"},"domain":"input_boolean", service: "turn_off"}});\n\tnode.send({payload: {data:{entity_id:"input_boolean.sunday"},"domain":"input_boolean", service: "turn_off"}});\n\tnode.send({payload: {data:{entity_id:"input_boolean.monday"},"domain":"input_boolean", service: "turn_off"}});\n\tnode.send({payload: {data:{entity_id:"input_boolean.tuesday"},"domain":"input_boolean", service: "turn_off"}});\n\tnode.send({payload: {data:{entity_id:"input_boolean.wednesday"},"domain":"input_boolean", service: "turn_off"}});\n\tnode.send({payload: {data:{entity_id:"input_boolean.thursday"},"domain":"input_boolean", service: "turn_off"}});\n\tnode.send({payload: {data:{entity_id:"input_boolean.friday"},"domain":"input_boolean", service: "turn_off"}});\n\tnode.send({payload: {data:{entity_id:"input_boolean.saturday"},"domain":"input_boolean", service: "turn_off"}});\n\tnode.send({payload: {data:{entity_id:"input_boolean.saturday"},"domain":"input_boolean", service: "turn_off"}});\n\n\t// clear the sliders\n\tnode.send({payload: {data:{ "entity_id": "input_number.start_time_hour", "value":0 },domain:"input_number", service: "set_value"}});\n\tnode.send({payload: {data:{ "entity_id": "input_number.start_time_minute", "value":0 },domain:"input_number", service: "set_value"}});\n\tnode.send({payload: {data:{ "entity_id": "input_number.run_duration", "value":0 },domain:"input_number", service: "set_value"}});\n} else {\n// zones 1-4 selected\n // armed\n if (timer1.Arm == "1") {\n node.send({payload: {data:{entity_id:"input_boolean.armed"},"domain":"input_boolean", service: "turn_on"}});\n flow.set(‘armed’,1);\n } else {\n node.send({payload: {data:{entity_id:"input_boolean.armed"},"domain":"input_boolean", service: "turn_off"}});\n flow.set(‘armed’,0);\n }\n \n // set the flow variable for days to run\n flow.set(‘days’,timer1.Days); // store the entire week\n // Sunday\n if (timer1.Days.substr(0,1) != "0") {\n node.send({payload: {data:{entity_id:"input_boolean.sunday"},"domain":"input_boolean", service: "turn_on"}});\n } else {\n node.send({payload: {data:{entity_id:"input_boolean.sunday"},"domain":"input_boolean", service: "turn_off"}});\n }\n\n // Monday\n if (timer1.Days.substr(1,1) != "0") {\n node.send({payload: {data:{entity_id:"input_boolean.monday"},"domain":"input_boolean", service: "turn_on"}});\n } else {\n node.send({payload: {data:{entity_id:"input_boolean.monday"},"domain":"input_boolean", service: "turn_off"}});\n }\n\n // Tuesday\n if (timer1.Days.substr(2,1) != "0") {\n node.send({payload: {data:{entity_id:"input_boolean.tuesday"},"domain":"input_boolean", service: "turn_on"}});\n } else {\n node.send({payload: {data:{entity_id:"input_boolean.tuesday"},"domain":"input_boolean", service: "turn_off"}});\n }\n\n // Wednesday\n if (timer1.Days.substr(3,1) != "0") {\n node.send({payload: {data:{entity_id:"input_boolean.wednesday"},"domain":"input_boolean", service: "turn_on"}});\n } else {\n node.send({payload: {data:{entity_id:"input_boolean.wednesday"},"domain":"input_boolean", service: "turn_off"}});\n }\n\n // Thrusday\n if (timer1.Days.substr(4,1) != "0") {\n node.send({payload: {data:{entity_id:"input_boolean.thursday"},"domain":"input_boolean", service: "turn_on"}});\n } else {\n node.send({payload: {data:{entity_id:"input_boolean.thursday"},"domain":"input_boolean", service: "turn_off"}});\n }\n\n // Friday\n if (timer1.Days.substr(5,1) != "0") {\n node.send({payload: {data:{entity_id:"input_boolean.friday"},"domain":"input_boolean", service: "turn_on"}});\n } else {\n node.send({payload: {data:{entity_id:"input_boolean.friday"},"domain":"input_boolean", service: "turn_off"}});\n }\n\n // Saturday\n if (timer1.Days.substr(6,1) != "0") {\n node.send({payload: {data:{entity_id:"input_boolean.saturday"},"domain":"input_boolean", service: "turn_on"}});\n } else {\n node.send({payload: {data:{entity_id:"input_boolean.saturday"},"domain":"input_boolean", service: "turn_off"}});\n }\n\n // get the start time\n var start_hour = parseInt(timer1.Time.substr(0,2));\n var start_min = parseInt(timer1.Time.substr(3,2));\n //node.warn(‘start1=’+start_hour+‘:’+start_min); \n \n // format payload for start hour and minute\n node.send({payload: {data:{"entity_id":"input_number.start_time_hour", "value": start_hour},"domain":"input_number", service: "set_value"}});\n node.send({payload: {data:{"entity_id":"input_number.start_time_minute", "value": start_min},"domain":"input_number", service: "set_value"}});\n \n // set the flow variables, add leading 0 padding \n if (start_hour < 10) { start_hour=‘0’+start_hour; }\n if (start_min < 10) { start_min=‘0’+start_min; }\n flow.set(‘hour’,start_hour); // store the hour\n flow.set(‘minute’,start_min); // store the minute\n flow.set(‘start’, start_hour+‘:’+start_min);\n\n // get the end time\n var end_hour = timer2.Time.substr(0,2);\n var end_min = timer2.Time.substr(3,2);\n flow.set(‘end’,end_hour+‘:’+end_min);\n //node.warn(‘end=’+end_hour+‘:’+end_min); \n \n // calculate the duration. Works for any number of minutes, doesn’t work across days\n var dur_hour = parseInt(end_hour) - parseInt(start_hour);\n var dur_min = parseInt(end_min) - parseInt(start_min) + (60 * dur_hour);\n flow.set(‘duration’,dur_min);\n \n node.send({payload: {data:{"entity_id":"input_number.run_duration", "value": dur_min},"domain":"input_number", service: "set_value"}});\n}\n\nnode.status({text:‘zone:’+flow.get(‘zone’)+’ armed:‘+flow.get(‘armed’)+’ days:‘+flow.get(‘days’)+ ’ start:’+flow.get(‘start’)+’ end:'+flow.get(‘end’)});\n//return [msg0,msg1,msg2,msg3,msg4,msg5,msg6,msg7,msg8,msg9,msg10];”,“outputs”:1,“noerr”:0,“x”:120,“y”:225,“wires”:[[“3bab667f.cc680a”]]},{“id”:“4fb87809.bbb2d8”,“type”:“json”,“z”:“72f1bcae.a467f4”,“name”:“Make Obj”,“property”:“payload”,“action”:“obj”,“pretty”:false,“x”:120,“y”:135,“wires”:[[“e1b2979d.1a2688”]]},{“id”:“e1b2979d.1a2688”,“type”:“join”,“z”:“72f1bcae.a467f4”,“name”:“combine”,“mode”:“custom”,“build”:“merged”,“property”:“payload”,“propertyType”:“msg”,“key”:“topic”,“joiner”:“\n”,“joinerType”:“str”,“accumulate”:false,“timeout”:“”,“count”:“2”,“reduceRight”:false,“reduceExp”:“”,“reduceInit”:“”,“reduceInitType”:“”,“reduceFixup”:“”,“x”:120,“y”:180,“wires”:[[“aa69a80d.ffacd8”]]},{“id”:“3e1013a0.2fdedc”,“type”:“function”,“z”:“72f1bcae.a467f4”,“name”:“Filter”,“func”:“// only pass along messages that have ‘Timer’ in the\n// payload. This is to filter only the relevant \n// timer data\nif (msg.payload.search(‘Timer’) != -1) {return msg}\nelse {return null}\n”,“outputs”:1,“noerr”:0,“x”:125,“y”:90,“wires”:[[“4fb87809.bbb2d8”]]},{“id”:“207b42d7.1a9b3e”,“type”:“api-call-service”,“z”:“72f1bcae.a467f4”,“name”:“Clear Inputs”,“server”:“157fbb29.ba9835”,“service_domain”:“”,“service”:“”,“data”:“”,“mergecontext”:“”,“x”:835,“y”:390,“wires”:[]},{“id”:“3bab667f.cc680a”,“type”:“api-call-service”,“z”:“72f1bcae.a467f4”,“name”:“Set values”,“server”:“157fbb29.ba9835”,“service_domain”:“”,“service”:“”,“data”:“”,“mergecontext”:“”,“x”:130,“y”:285,“wires”:[]},{“id”:“b69e90c6.22d75”,“type”:“function”,“z”:“72f1bcae.a467f4”,“name”:“Store ‘arm’”,“func”:“// setup the ‘armed’ boolean\nif (msg.payload == ‘on’) {\n flow.set(‘armed’,1);\n} else {\n flow.set(‘armed’,0);\n}\nnode.status({text:flow.get(‘armed’)});\nreturn msg;”,“outputs”:1,“noerr”:0,“x”:865,“y”:75,“wires”:[]},{“id”:“63e8e488.23aa2c”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Armed”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_boolean.armed”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:680,“y”:75,“wires”:[[“b69e90c6.22d75”]],“outputLabels”:[“?”]},{“id”:“70386c41.b85394”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Sun”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_boolean.sunday”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:500,“y”:45,“wires”:[[“5968c4f7.fa495c”]],“outputLabels”:[“?”]},{“id”:“b8a9cf1e.f3b6f”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Tues”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_boolean.tuesday”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:500,“y”:135,“wires”:[[“5968c4f7.fa495c”]],“outputLabels”:[“?”]},{“id”:“fb6477b4.0fdbf8”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Wed”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_boolean.wednesday”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:500,“y”:180,“wires”:[[“5968c4f7.fa495c”]],“outputLabels”:[“?”]},{“id”:“e7ff1abf.727948”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Thu”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_boolean.thursday”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:500,“y”:225,“wires”:[[“5968c4f7.fa495c”]],“outputLabels”:[“?”]},{“id”:“2eb1d94d.ede0f6”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Fri”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_boolean.friday”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:500,“y”:270,“wires”:[[“5968c4f7.fa495c”]],“outputLabels”:[“?”]},{“id”:“a478a6bc.d2bfe8”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Sat”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_boolean.saturday”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:500,“y”:315,“wires”:[[“5968c4f7.fa495c”]],“outputLabels”:[“?”]},{“id”:“c5a7417d.1a0be”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Mon”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_boolean.monday”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:500,“y”:90,“wires”:[[“5968c4f7.fa495c”]],“outputLabels”:[“?”]},{“id”:“f168803d.26072”,“type”:“function”,“z”:“72f1bcae.a467f4”,“name”:“time encoder”,“func”:“// read in the flow variables\nvar start = flow.get(‘start’);\nvar hour = flow.get(‘hour’);\nvar minute = flow.get(‘minute’);\nvar end = flow.get(‘end’);\nvar duration = flow.get(‘duration’);\n\n// extract the value to be updated\nif (msg.topic == ‘input_number.start_time_hour’) {\n hour = parseInt(msg.payload);\n if (hour < 10) {hour = ‘0’+hour}\n} \nif (msg.topic == ‘input_number.start_time_minute’) {\n minute = parseInt(msg.payload);\n if (minute < 10){minute = ‘0’+minute}\n}\nif (msg.topic == ‘input_number.run_duration’) {\n duration = parseInt(msg.payload);\n}\n\n// setup the new flow variables\nflow.set(‘hour’, hour);\nflow.set(‘minute’, minute);\nflow.set(‘start’,hour+‘:’+minute);\nflow.set(‘duration’,duration);\n\n// calculate the end time based on the duration\nvar endMin = parseInt(flow.get(‘minute’)) + parseInt(duration);\nvar endHr = parseInt(flow.get(‘hour’));\nendHr = parseInt(endHr + parseInt(endMin/60));\nendMin = parseInt(endMin - 60parseInt(endMin/60));\n//node.warn(‘endMin=’+endMin);\n//node.warn(‘endHr=’+endHr);\n\n// add padding\nif (endMin < 10){ endMin = "0" + endMin}\nif (endHr < 10){ endHr = "0" + endHr}\nflow.set(‘end’,endHr + ":" + endMin);\n\nnode.status({text:‘{start:’+flow.get(‘start’)+‘} {end:’+flow.get(‘end’)+‘}’});\nreturn msg;“,“outputs”:1,“noerr”:0,“x”:895,“y”:285,“wires”:[[]]},{“id”:“37ef85fa.984f4a”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Duration”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_number.run_duration”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:690,“y”:330,“wires”:[[“f168803d.26072”]],“outputLabels”:[”?“]},{“id”:“9197e9b.4390218”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Start Minute”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_number.start_time_minute”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:700,“y”:285,“wires”:[[“f168803d.26072”]],“outputLabels”:[”?“]},{“id”:“494ab671.5611c8”,“type”:“server-state-changed”,“z”:“72f1bcae.a467f4”,“name”:“Start Hour”,“server”:“157fbb29.ba9835”,“entityidfilter”:“input_number.start_time_hour”,“entityidfiltertype”:“substring”,“haltifstate”:“null”,“x”:690,“y”:240,“wires”:[[“f168803d.26072”]],“outputLabels”:[”?“]},{“id”:“ce931c43.4359a”,“type”:“function”,“z”:“72f1bcae.a467f4”,“name”:“clear”,“func”:”// clear all the boolean switches\nnode.send({payload: {data:{entity_id:"input_boolean.armed"},"domain":"input_boolean", service: "turn_off"}});\nnode.send({payload: {data:{entity_id:"input_boolean.sunday"},"domain":"input_boolean", service: "turn_off"}});\nnode.send({payload: {data:{entity_id:"input_boolean.monday"},"domain":"input_boolean", service: "turn_off"}});\nnode.send({payload: {data:{entity_id:"input_boolean.tuesday"},"domain":"input_boolean", service: "turn_off"}});\nnode.send({payload: {data:{entity_id:"input_boolean.wednesday"},"domain":"input_boolean", service: "turn_off"}});\nnode.send({payload: {data:{entity_id:"input_boolean.thursday"},"domain":"input_boolean", service: "turn_off"}});\nnode.send({payload: {data:{entity_id:"input_boolean.friday"},"domain":"input_boolean", service: "turn_off"}});\nnode.send({payload: {data:{entity_id:"input_boolean.saturday"},"domain":"input_boolean", service: "turn_off"}});\nnode.send({payload: {data:{entity_id:"input_boolean.saturday"},"domain":"input_boolean", service: "turn_off"}});\n\n// clear the input selection\nnode.send({payload: {data:{ "entity_id": "input_select.irrigation_zone", "option":"Select" },domain:"input_select", service: "select_option"}});\n\n// clear the sliders\nnode.send({payload: {data:{ "entity_id": "input_number.start_time_hour", "value":0 },domain:"input_number", service: "set_value"}});\nnode.send({payload: {data:{ "entity_id": "input_number.start_time_minute", "value":0 },domain:"input_number", service: "set_value"}});\nnode.send({payload: {data:{ "entity_id": "input_number.run_duration", "value":0 },domain:"input_number", service: "set_value"}});\n\n",“outputs”:1,“noerr”:0,“x”:695,“y”:390,“wires”:[[“207b42d7.1a9b3e”]]},{“id”:“80b83e2.5b612c”,“type”:“comment”,“z”:“72f1bcae.a467f4”,“name”:“Setup instructions”,“info”:"Setup your HA I/O in:\n the HA input nodes\n* the HA output nodes\n\nSetup your MQTT server in:\n* the MQTT input node\n* the Publish to MQTT output node\n\nSet your MQTT path in :\n* the MQTT input node\n* the Build Strings function node\n* the Select Timers function node\n”,“x”:345,“y”:90,“wires”:},{“id”:“63b8f367.34910c”,“type”:“comment”,“z”:“72f1bcae.a467f4”,“name”:“HA groups config”,“info”:“garden:\n view: no\n control: hidden\n name: "Garden Irrigation"\n icon: ‘mdi:flower’\n entities:\n - switch.garden1_zone_1\n - switch.garden1_zone_2\n - switch.garden1_zone_3\n - switch.garden1_zone_4\n - group.timer_settings\n\n\ntimer_settings:\n view: no\n control: hidden\n name: "Zone Settings"\n icon: mdi:settings\n entities:\n - input_select.irrigation_zone\n - input_boolean.armed\n - input_boolean.sunday\n - input_boolean.monday\n - input_boolean.tuesday\n - input_boolean.wednesday\n - input_boolean.thursday\n - input_boolean.friday\n - input_boolean.saturday\n - input_number.start_time_hour\n - input_number.start_time_minute\n - input_number.run_duration\n - input_boolean.save_timer”,“x”:335,“y”:135,“wires”:},{“id”:“2e7e3696.fdc50a”,“type”:“comment”,“z”:“72f1bcae.a467f4”,“name”:“HA inputs”,“info”:“# input_select.yaml\nirrigation_zone:\n name: "Select Zone:"\n icon: mdi:arrange-bring-to-front\n options:\n - Select\n - 1\n - 2\n - 3\n - 4\n initial: Select\n\n#input_boolean.yaml \n armed:\n name: Armed\n icon: mdi:alarm-light\n initial: off\n sunday:\n name: Sunday\n icon: mdi:calendar\n initial: off\n monday:\n name: Monday\n icon: mdi:calendar\n initial: off\n tuesday:\n name: Tuesday\n icon: mdi:calendar\n initial: off\n wednesday:\n name: Wednesday\n icon: mdi:calendar\n initial: off\n thursday:\n name: Thursday\n icon: mdi:calendar\n initial: off\n friday:\n name: Friday\n icon: mdi:calendar\n initial: off\n saturday:\n name: Saturday\n icon: mdi:calendar\n initial: off\n save_timer:\n name: Save Settings\n initial: off\n icon: mdi:lock-reset\n\n\n\n#input_number.yaml \nstart_time_hour:\n name: "Hour"\n initial: 0\n min: 0\n max: 23\n step: 1\n icon: mdi:timer\nstart_time_minute:\n name: "Minute"\n initial: 0\n min: 0\n max: 55\n step: 5\n icon: mdi:timer\nrun_duration:\n name: "Duration"\n initial: 30\n min: 0\n max: 120\n step: 2\n icon: mdi:timer”,“x”:315,“y”:180,“wires”:},{“id”:“b0db5a30.2e9a88”,“type”:“switch”,“z”:“72f1bcae.a467f4”,“name”:“Select”,“property”:“payload”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“Select”,“vt”:“str”},{“t”:“else”}],“checkall”:“true”,“repair”:false,“outputs”:2,“x”:290,“y”:450,“wires”:[[“ce931c43.4359a”],[“f4614267.37f68”]]},{“id”:“157fbb29.ba9835”,“type”:“server”,“z”:“”,“name”:“Home Assistant”,“url”:“http://hassio/homeassistant",“pass”:“”},{“id”:“940130c6.3f4e2”,“type”:“mqtt-broker”,“z”:“”,“name”:“Mesquito”,“broker”:“localhost”,“port”:“1883”,“clientid”:“”,“usetls”:false,“compatmode”:true,“keepalive”:“60”,“cleansession”:true,“birthTopic”:“”,“birthQos”:“0”,“birthPayload”:“”,“closeTopic”:“”,“closeQos”:“0”,“closePayload”:“”,“willTopic”:“”,“willQos”:“0”,“willPayload”:"”}]

1 Like

Hi,

here is what I did to make it work only with hassio (without node-red). The thing is to pay attention to the topic path. Depending on your device configuration, cmnd must be used before or after the topic name:

data:
  payload_template: >-
    {"Arm":1,"Time":"{{ (now().strftime("%s") | int + (1*60)) |
    timestamp_custom("%H:%M",false)
    }}","Window":0,"Days":"SMTWTFS","Repeat":1,"Output":"0","Action":0}
  topic: sprinkler_02/cmnd/Timer1
service: mqtt.publish

I have put this in a script and it works well.

Hello Jon,
I have recently seen your Node Red flow for the garden irrigation system. The code you kindly set out here will not import into Node Red due to syntax errors. I wondered whether you could post again please, I am interested to experiment with it and custom to a home heating system using the Sonoff 4ch switch with tasmota.
Many thanks, regards, Jim

Hi, spent a few hours trying to understand how to do this.

I generally try to ensure I can do things manually before I get them working in HA.

Great guide on how to do this here --> http://40mph.serveblog.net/doku.php?id=blog:sonoff-tasmota_use_timers_via_mqtt

Noticed that “Arm” is now “Enable” in latest Tasmota firmware (I have 9.2.0.2).

I was able to achieve my goal of having the ability to our turn ceiling fans off after an hour. Modified the code above as working for me:

  payload_template: >-
    {"Enable":1,"Time":"{{ (now().strftime("%s") | int + (60*60)) |
    timestamp_custom("%H:%M",false)
    }}","Window":0,"Days":"SMTWTFS","Repeat":0,"Output":"1","Action":0}

View of it in the script creation GUI in HA.

image