Howdy,
I have the following scenario, i have a regular light switch connected to a shelly, so i get a on and a off state. To make sure i dont trigger from anything an undefined state i switch only on the state change from on to off and from off to on.
On a trigger i want to:
On first press,:
- if any light is on, turn them om.
- if no lights are on, turn them on 100%
subsequent presses should:
- if you turned the light to 100%, now go 50%
- if you set the light to 50% now go off
- if you set the light off, now go 100%
Before i used this this nifty peace of code in node red, which is very easy to expand with more conditions.
export
[{"id":"3d958283059b7308","type":"api-call-service","z":"9d267bfa767e8a46","name":"Turn on with given parameters","server":"90c6e8da.709198","version":5,"debugenabled":false,"domain":"light","service":"turn_on","areaId":[],"deviceId":[],"entityId":["light.0_woonkamer_bank_lamp_leeshoek","light.0_woonkamer_bank_spot_links","light.0_woonkamer_bank_spot_rechts"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":830,"y":240,"wires":[[]]},{"id":"a9bd982346aba1d9","type":"api-call-service","z":"9d267bfa767e8a46","name":"Turnoff","server":"90c6e8da.709198","version":5,"debugenabled":false,"domain":"light","service":"turn_off","areaId":[],"deviceId":[],"entityId":["light.0_woonkamer_bank_lamp_leeshoek","light.0_woonkamer_bank_spot_links","light.0_woonkamer_bank_spot_rechts"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":880,"y":140,"wires":[[]]},{"id":"60b7c4dfa092fa24","type":"api-current-state","z":"9d267bfa767e8a46","name":"Bank=On","server":"90c6e8da.709198","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"light.0_woonkamer_bank_spot_links","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":0,"forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":520,"y":60,"wires":[["13db3a385d4109ea"],["c60a3e73392efc58"]]},{"id":"3929e74b611f7362","type":"api-current-state","z":"9d267bfa767e8a46","name":"BankLL=On","server":"90c6e8da.709198","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"light.0_woonkamer_bank_lamp_leeshoek","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":0,"forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":530,"y":140,"wires":[["13db3a385d4109ea"],["ac8a21acb67e1b01"]]},{"id":"ac8a21acb67e1b01","type":"function","z":"9d267bfa767e8a46","name":"Scene switcher","func":"//var count = context.get(\"counter\");\n\n// initialise the counter to 0 if it doesn't exist already\nvar counter = context.get('counter');\n\nvar NOC = node.outputCount\n//msg.noc = NOC;\n\nif (msg.payload == \"Reset\")\n{\n context.set('counter',0);\n return\n}\nelse\n{\n counter += 1;\n if (counter == node.outputCount)\n {context.set('counter',0); msg.payload = \"reset counter\";}\n else\n {context.set('counter',counter); msg.rep = 1; msg.payload = \"increase counter\"}\n}\n\nmsg.count = counter;\nif (counter == 1)\n{\n return [msg];\n} \nif (counter == 2)\n{\n return [null,msg];\n}\nif (counter == 3)\n{\n return [null,null,msg];\n}\nif (counter == 4)\n{\n return [null,null,null,msg];\n}","outputs":3,"timeout":"","noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nif (context.get(\"counter\") === undefined) {\n context.set(\"counter\", 0)\n}\n","finalize":"","libs":[],"x":260,"y":200,"wires":[["5c72f13b07c638fe","60b7c4dfa092fa24"],["5c72f13b07c638fe","e8fb5f7642525899"],["cc1e4c3f2aea8683"]]},{"id":"5c72f13b07c638fe","type":"trigger","z":"9d267bfa767e8a46","name":"","op1":"","op2":"Reset","op1type":"nul","op2type":"str","duration":"3","extend":true,"overrideDelay":false,"units":"s","reset":"on","bytopic":"all","topic":"topic","outputs":1,"x":260,"y":140,"wires":[["ac8a21acb67e1b01"]]},{"id":"e8fb5f7642525899","type":"function","z":"9d267bfa767e8a46","name":"100%","func":"msg.payload = \n{\n\"data\": {\n \"transition\":\"1\",\n \"brightness\":\"255\"\n }\n};\nreturn [msg];","outputs":1,"timeout":"","noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nif (context.get(\"counter\") === undefined) {\n context.set(\"counter\", 0)\n}\n","finalize":"","libs":[],"x":490,"y":220,"wires":[["6425268fb368e5d1"]]},{"id":"cc1e4c3f2aea8683","type":"function","z":"9d267bfa767e8a46","name":"50%","func":"msg.payload = \n{\n\"data\": {\n \"transition\":\"1\",\n \"brightness\":\"125\"\n }\n};\nreturn [msg];","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nif (context.get(\"counter\") === undefined) {\n context.set(\"counter\", 0)\n}\n","finalize":"","libs":[],"x":490,"y":260,"wires":[["6425268fb368e5d1"]]},{"id":"32697471a0b2d10d","type":"link in","z":"9d267bfa767e8a46","name":"In_S_T_Shelly_Bank_Input","links":["ee464e442f6f8044"],"x":115,"y":200,"wires":[["ac8a21acb67e1b01"]]},{"id":"c60a3e73392efc58","type":"api-current-state","z":"9d267bfa767e8a46","name":"Bank=On","server":"90c6e8da.709198","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"light.0_woonkamer_bank_spot_rechts","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":0,"forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":520,"y":100,"wires":[["13db3a385d4109ea"],["3929e74b611f7362"]]},{"id":"13db3a385d4109ea","type":"junction","z":"9d267bfa767e8a46","x":680,"y":100,"wires":[["a9bd982346aba1d9"]]},{"id":"6425268fb368e5d1","type":"junction","z":"9d267bfa767e8a46","x":640,"y":240,"wires":[["3d958283059b7308"]]},{"id":"90c6e8da.709198","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]But since i’m migrating to home asistant automations i had to think of something else:
This brainstorming and trying to explain it to strangers helped me so i though why not share, and maby even get some feedback to improve:
so here is what i build in home assistant:
alias: LightSwitchingBetweenScenes
description: "First test of automation to switch between scene's"
trigger:
- platform: state
entity_id:
- binary_sensor.0_wnk_btn_naastdeur_tafel
from: "on"
to: "off"
alias: Button pressed up
- platform: state
entity_id:
- binary_sensor.0_wnk_btn_naastdeur_tafel
from: "off"
to: "on"
alias: Button pressed down
condition: null
action:
- if:
- condition: template
value_template: "{{ LastRunWasXSecondsAgo > 5 }}"
alias: If last run was longer then 5 seconds ago
then:
- alias: Execute first press procedure, turn on or off based on state
if:
- condition: state
entity_id: light.0_wer_lmp_group
state: "on"
then:
- service: scene.turn_on
metadata: {}
target:
entity_id: scene.0_wer_lmp_group_0_all_off
else:
- service: scene.turn_on
metadata: {}
target:
entity_id: scene.0_wer_lmp_group_1_all_on
else:
- choose:
- conditions:
- alias: if you turned the light to 100%, now go 50%
condition: and
conditions:
- alias: All on before All Off
condition: template
value_template: >-
{{ as_timestamp(states('scene.0_wer_lmp_group_1_all_on'))
> as_timestamp(states('scene.0_wer_lmp_group_0_all_Off'))
}}
- alias: All on before All 50
condition: template
value_template: >-
{{ as_timestamp(states('scene.0_wer_lmp_group_1_all_on'))
> as_timestamp(states('scene.0_wer_lmp_group_2_all_50'))
}}
sequence:
- service: scene.turn_on
metadata: {}
target:
entity_id: scene.0_wer_lmp_group_2_all_50
- conditions:
- alias: if you set the light to 50% now go off
condition: and
conditions:
- alias: All 50 before All Off
condition: template
value_template: >-
{{ as_timestamp(states('scene.0_wer_lmp_group_2_all_50'))
> as_timestamp(states('scene.0_wer_lmp_group_0_all_Off'))
}}
- alias: All 50 before All on
condition: template
value_template: >-
{{ as_timestamp(states('scene.0_wer_lmp_group_2_all_50'))
> as_timestamp(states('scene.0_wer_lmp_group_1_all_On'))
}}
sequence:
- service: scene.turn_on
metadata: {}
target:
entity_id: scene.0_wer_lmp_group_0_all_off
- conditions:
- alias: if you set the light off, now go 100%
condition: and
conditions:
- alias: All off before all on
condition: template
value_template: >-
{{ as_timestamp(states('scene.0_wer_lmp_group_0_all_off'))
> as_timestamp(states('scene.0_wer_lmp_group_1_all_On'))
}}
- alias: All off before All 50
condition: template
value_template: >-
{{ as_timestamp(states('scene.0_wer_lmp_group_0_all_off'))
> as_timestamp(states('scene.0_wer_lmp_group_2_all_50'))
}}
sequence:
- service: scene.turn_on
metadata: {}
target:
entity_id: scene.0_wer_lmp_group_1_all_on
variables:
alias: Last Run Was X Seconds Ago
LastRunWasXSecondsAgo: >
{{ as_timestamp(now()) -
as_timestamp(state_attr(this.entity_id,'last_triggered')) }}
mode: queued
I’m noticing the yaml code doesnt copy and past nice into the < details > hidy hole i used for the node red code, if there is a better way to paste and show it please let me know, looking forward to sharing more code here ![]()
I will try to make this into a script which will take in the scenes as a variable, but thats for later expansion. Also expanding for more then 3 scenes would give code bloat, so any tips to make it more compact are always welcome.
Also i am considering different behavior at night and during the day, but i guess once i make a script, i can just change up the order and call the correct script for the current TOD/brightness outside.
one thing that took me some time, I had to use the LastRunWasXSecondsAgo variable, because as_timestamp(state_attr(this.entity_id,'last_triggered')) would already be updated to the current time in the action. and funny enough you don’t see the
variables:
alias: Last Run Was X Seconds Ago
LastRunWasXSecondsAgo: >
{{ as_timestamp(now()) -
as_timestamp(state_attr(this.entity_id,'last_triggered')) }}
part in the visual editor


