Holiday lights scheduler and demo mode for WLED
Questions and Discussion
Post questions and follow the discussion about this recipe here
Here's a flow to control some outdoor house LEDs hooked up to an ESP8266 running WLED.
The holiday lights turn on each day at sunset and then off at midnight. It uses WLED presets based on the day or season. It has a demo mode that will cycle through all the defined presets or all the included effects.
Version 1
[{"id":"886a465.91a0ab8","type":"switch","z":"894a6b3077af9604","name":"dark?","property":"dark","propertyType":"flow","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":450,"y":240,"wires":[["5e38e1ee8665f5e7"],["90579358.a3dce"]]},{"id":"34cb332b.f8228c","type":"server-state-changed","z":"894a6b3077af9604","name":"Demo Mode","server":"","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_select.holiday_lights_demo_mode","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"off","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"","forType":"num","forUnits":"minutes","ignorePrevStateNull":true,"ignorePrevStateUnknown":true,"ignorePrevStateUnavailable":true,"ignoreCurrentStateUnknown":true,"ignoreCurrentStateUnavailable":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":294,"y":384,"wires":[["df0da821.aa74b8"],["91131276.4f322"]]},{"id":"90579358.a3dce","type":"api-call-service","z":"894a6b3077af9604","name":"turn off holiday lights","server":"","version":3,"debugenabled":false,"service_domain":"light","service":"turn_off","entityId":"{{flow.wledHolidayLightsEntityId}}","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"data"}],"queue":"last","x":692,"y":288,"wires":[[]]},{"id":"dc4b2af1.d366a8","type":"ha-wait-until","z":"894a6b3077af9604","name":"loop","server":"","version":0,"outputs":2,"entityId":"{{flow.wledHolidayLightsEntityId}}","entityIdFilterType":"exact","property":"state","comparator":"is","value":"off","valueType":"str","timeout":"60","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":false,"blockInputOverrides":false,"x":850,"y":240,"wires":[[],["5e38e1ee8665f5e7"]]},{"id":"59e25c2c.a3a514","type":"eztimer","z":"894a6b3077af9604","name":"","debug":false,"autoname":"sunset - 00:00","tag":"test1","suspended":false,"sendEventsOnSuspend":false,"latLongSource":"manual","latLongHaZone":"","lat":"","lon":"","timerType":"1","startupMessage":true,"ontype":"1","ontimesun":"sunset","ontimetod":"17:00","onpropertytype":"flow","onproperty":"dark","onvaluetype":"bool","onvalue":"true","onoffset":"","onrandomoffset":0,"onsuppressrepeats":false,"offtype":"2","offtimesun":"dusk","offtimetod":"00:00","offduration":0,"offpropertytype":"flow","offproperty":"dark","offvaluetype":"bool","offvalue":"false","offoffset":0,"offrandomoffset":0,"offsuppressrepeats":false,"resend":false,"resendInterval":"1m","mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"sat":true,"sun":true,"x":304,"y":240,"wires":[["886a465.91a0ab8"]]},{"id":"f4ab62e2.10029","type":"api-call-service","z":"894a6b3077af9604","name":"turn on holiday lights","server":"","version":3,"debugenabled":false,"service_domain":"select","service":"select_option","entityId":"{{flow.wledHolidayLightsPresetEntityId}}","data":"{\"option\": payload}","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"last","x":900,"y":192,"wires":[[]]},{"id":"98efb1f6.c85b8","type":"ha-wait-until","z":"894a6b3077af9604","name":"loop","server":"","version":0,"outputs":2,"entityId":"{{flow.wledHolidayLightsEntityId}}","entityIdFilterType":"exact","property":"state","comparator":"is","value":"off","valueType":"str","timeout":"$number($entities(\"input_number.holiday_lights_demo_mode_delay\").state)","timeoutType":"jsonata","timeoutUnits":"seconds","entityLocation":"","entityLocationType":"none","checkCurrentState":false,"blockInputOverrides":true,"x":1058,"y":432,"wires":[[],["91131276.4f322"]]},{"id":"91131276.4f322","type":"switch","z":"894a6b3077af9604","name":"which mode?","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"cycle presets","vt":"str"},{"t":"eq","v":"cycle effects","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":470,"y":432,"wires":[["5adba3095728cdab"],["28fd29dc.96d306"]]},{"id":"333ed476.51a77c","type":"api-call-service","z":"894a6b3077af9604","name":"turn on preset","server":"","version":3,"debugenabled":false,"service_domain":"select","service":"select_option","entityId":"{{flow.wledHolidayLightsPresetEntityId}}","data":"{\"option\": name}","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":880,"y":432,"wires":[["98efb1f6.c85b8","d0b9f667.79a8c8"]]},{"id":"fcf7dabd.b7a368","type":"api-call-service","z":"894a6b3077af9604","name":"turn on effect","server":"","version":3,"debugenabled":false,"service_domain":"light","service":"turn_on","entityId":"{{flow.wledHolidayLightsEntityId}}","data":"{\"effect\": name}","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":870,"y":480,"wires":[["98efb1f6.c85b8","d0b9f667.79a8c8"]]},{"id":"df0da821.aa74b8","type":"change","z":"894a6b3077af9604","name":"reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":384,"wires":[["886a465.91a0ab8","98efb1f6.c85b8"]]},{"id":"998c4f75.52cbf","type":"api-call-service","z":"894a6b3077af9604","name":"turn off demo mode","server":"","version":3,"debugenabled":false,"service_domain":"input_select","service":"select_option","entityId":"input_select.holiday_lights_demo_mode","data":"{\"option\": \"off\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":570,"y":528,"wires":[[]]},{"id":"5caeec35.01a114","type":"server-state-changed","z":"894a6b3077af9604","name":"Holiday Lights turned off?","server":"","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"light.wled","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"off","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":false,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":332,"y":528,"wires":[["998c4f75.52cbf"],[]]},{"id":"28fd29dc.96d306","type":"function","z":"894a6b3077af9604","name":"get next effect","func":"const states = global.get(\"homeassistant\").homeAssistant.states;\nconst entityId = flow.get(\"wledHolidayLightsEntityId\");\nconst effects = states[entityId].attributes.effect_list;\nconst activeEffect = states[entityId].attributes.effect;\nlet index = effects.findIndex(ele => ele === activeEffect);\nindex = (index === -1 || index >= effects.length - 1) ? 0 : index + 1;\n\nnode.status({text: effects[index]});\n\nmsg.name = effects[index];\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":672,"y":480,"wires":[["fcf7dabd.b7a368"]]},{"id":"d0b9f667.79a8c8","type":"ha-entity","z":"894a6b3077af9604","name":"current demo","server":"","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Holiday Lights Demo Current"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"name","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":1078,"y":480,"wires":[[]]},{"id":"9168ce00.dc7de","type":"comment","z":"894a6b3077af9604","name":"Scheduler","info":"","x":284,"y":192,"wires":[]},{"id":"241d097a.a3fe76","type":"comment","z":"894a6b3077af9604","name":"Demo Mode","info":"","x":294,"y":336,"wires":[]},{"id":"22f2928a.e2ae9e","type":"inject","z":"894a6b3077af9604","name":"Manual Start","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"dark","v":"true","vt":"bool"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":294,"y":288,"wires":[["5e38e1ee8665f5e7"]]},{"id":"9f8ca90550d41489","type":"inject","z":"894a6b3077af9604","name":"Setup","props":[{"p":"entityId","v":"light.holiday_lights","vt":"str"}],"repeat":"3600","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":284,"y":144,"wires":[["1047f2356f1e5203"]]},{"id":"1047f2356f1e5203","type":"change","z":"894a6b3077af9604","name":"set entity ids here","rules":[{"t":"set","p":"wledHolidayLightsEntityId","pt":"flow","to":"light.wled","tot":"str"},{"t":"set","p":"wledHolidayLightsPresetEntityId","pt":"flow","to":"select.wled_preset","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":144,"wires":[[]]},{"id":"5e38e1ee8665f5e7","type":"function","z":"894a6b3077af9604","name":"date ranges","func":"const now = new Date();\nconst monthDay = getMonthDay(now);\nconst states = global.get(\"homeassistant\").homeAssistant.states;\nconst entityId = flow.get(\"wledHolidayLightsEntityId\");\nconst presetId = flow.get(\"wledHolidayLightsPresetEntityId\");\nconst christmasPresets = [\n \"Christmas\",\n \"Christmas Candy Cane\",\n \"Christmas Classic\",\n \"Christmas Holly Jolly\"\n];\n\nlet updateInterval = 0; // in minutes\nlet preset;\n\nswitch(true) {\n// Winter \n case isToday(214):\n preset = \"Valentine\";\n break;\n// President's Day changes every year, Veteran's Day & Flag Day always the same date\n case isToday(614): // 6/14 Flag Day\n case isToday(1111): // 11/11 Veterans Day\n case isToday(\"President's Day\"):\n case isToday(\"Memorial Day\"):\n preset = \"Red White Blue\";\n break;\n case isToday(317):\n preset = \"St Patty\";\n break;\n case isToday(\"Easter\"):\n preset = \"Easter\";\n break;\n case isToday(\"Ash Wednesday\", \"Easter\"):\n preset = \"Spring\";\n break;\n// Spring\n case isToday(504):\n preset = \"Star Wars\";\n break;\n case isToday(505):\n preset = \"Cinco de Mayo\";\n break;\n// Summer\n case isToday(704):\n preset = \"Fireworks\";\n break;\n// Autumn\n case isToday(1014, 1031):\n preset = \"Halloween\";\n break;\n case isToday(\"Thanksgiving Day\"):\n preset = \"Autumn\";\n break;\n case isToday(1231):\n preset = \"Fireworks White\";\n break;\n case isToday(\"Thanksgiving Day\", 1231):\n case isToday(101, 106):\n preset = getRandomPreset(christmasPresets);\n updateInterval = 60;\n break;\n default:\n const seasons = {\n \"winter\": \"Winter\",\n \"spring\": \"Spring\",\n \"summer\": \"Summer\",\n \"autumn\": \"Autumn\"\n }\n const currentSeason = states[\"sensor.season\"].state;\n preset = seasons[currentSeason];\n break;\n}\n\nnode.status({ text: preset});\nmsg.payload = preset;\nconst secondOutput = updateInterval ? { payload: { timeout: updateInterval } } : { reset: true };\n\nreturn [msg, secondOutput];\n\nfunction isToday(start, end) {\n if (typeof start === \"string\") {\n start = getHolidayDate(now, start)\n }\n if (typeof end === \"string\") {\n end = getHolidayDate(now, end)\n }\n if (end === undefined) return monthDay === start;\n\n return monthDay >= start && monthDay <= end;\n}\n\nfunction getHolidayDate(date, holiday) {\n holiday = holiday.toLowerCase();\n // dates are formatted as month, week, day of the week\n // names should be lowercase\n const holidays = {\n \"martin luther king day\": [0,2,1],\n \"president's day\": [1,2,1],\n \"daylight savings time begins\": [2,1,0],\n \"mother's day\": [4,1,0],\n \"memorial day\": [4,-1,1],\n \"father's day\": [5,2,0],\n \"labor day\": [8,0,1],\n \"columbus day\": [9,1,1],\n \"daylight savings time ends\": [10,0,0],\n \"thanksgiving day\": [10,3,4]\n };\n let holidayDate;\n if(holiday === \"easter\") {\n holidayDate = getEasterDate(date);\n } else if (holiday === \"ash wednesday\") {\n const easter = getEasterDate(date);\n holidayDate = new Date(easter.getFullYear(), easter.getMonth(), (easter.getDate()-46));\n } else {\n const [month, week, day] = holidays[holiday];\n holidayDate = getDate(date.getFullYear(), month, week, day);\n }\n \n const monthDay = getMonthDay(holidayDate);\n \n return monthDay;\n}\n\nfunction getMonthDay(date) {\n const monthString = String(date.getMonth() + 1).padStart(2, \"0\");\n const dayString = String(date.getDate()).padStart(2, \"0\");\n const monthDay = Number(`${monthString}${dayString}`);\n \n return monthDay;\n}\n\nfunction getDate(year, month, week, day) {\n let firstDay = 1;\n if (week < 0) {\n month++;\n firstDay--;\n }\n const date = new Date(year, month, (week * 7) + firstDay);\n if (day < date.getDay()) {\n day += 7;\n }\n date.setDate(date.getDate() - date.getDay() + day);\n return date;\n}\n\n/**\n * Calculates Easter in the Gregorian/Western (Catholic and Protestant) calendar\n * based on the algorithm by Oudin (1940) from http://www.tondering.dk/claus/cal/easter.php\n * @returns {array} [int month, int day]\n */\nfunction getEasterDate(date) {\n const year = date.getFullYear();\n const f = Math.floor,\n // Golden Number - 1\n G = year % 19,\n C = f(year / 100),\n // related to Epact\n H = (C - f(C / 4) - f((8 * C + 13) / 25) + 19 * G + 15) % 30,\n // number of days from 21 March to the Paschal full moon\n I = H - f(H / 28) * (1 - f(29 / (H + 1)) * f((21 - G) / 11)),\n // weekday for the Paschal full moon\n J = (year + f(year / 4) + I + 2 - C + f(C / 4)) % 7,\n // number of days from 21 March to the Sunday on or before the Paschal full moon\n L = I - J,\n month = 3 + f((L + 40) / 44),\n day = L + 28 - 31 * f(month / 4);\n\n return new Date(`${month}/${day}/${year}`);\n}\n\nfunction getRandomPreset(list) {\n const activePreset = states[presetId].state;\n const filteredList = list.filter((e) => e !== activePreset);\n \n return filteredList[Math.floor(Math.random() * filteredList.length)];\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":662,"y":240,"wires":[["f4ab62e2.10029"],["dc4b2af1.d366a8"]]},{"id":"e01d1bd31bd9e634","type":"comment","z":"894a6b3077af9604","name":"Change holiday dates in the \"date ranges\" node","info":"","x":404,"y":96,"wires":[]},{"id":"5adba3095728cdab","type":"function","z":"894a6b3077af9604","name":"get next preset","func":"const states = global.get(\"homeassistant\").homeAssistant.states;\nconst presetId = flow.get(\"wledHolidayLightsPresetEntityId\");\nconst presets = states[presetId].attributes.options;\nconst activePreset = states[presetId].state;\nlet index = presets.findIndex(ele => ele === activePreset);\nindex = index === -1 || index >= presets.length - 1 ? 0 : index +1;\nconst name = presets[index];\n\nnode.status({text: name });\n\nmsg.name = name;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":672,"y":432,"wires":[["333ed476.51a77c"]]}]
version 0
- Home Assistant v0.118+
- WLED v0.11+
[{"id":"eb756b3f.d770f8","type":"subflow","name":"Create HA Helpers","info":"","category":"","in":[{"x":84,"y":96,"wires":[{"id":"7f1493fc.1300fc"}]}],"out":[],"env":[{"name":"serverName","type":"str","value":"Home Assistant","ui":{"label":{"en-US":"HA Server Name"},"type":"input","opts":{"types":["str"]}}},{"name":"helpers","type":"json","value":"[]","ui":{"label":{"en-US":"Helpers"},"type":"input","opts":{"types":["json"]}}}],"color":"#DDAA99","status":{"x":246,"y":48,"wires":[{"id":"a66d5d93.8a5f","port":0}]}},{"id":"7f1493fc.1300fc","type":"function","z":"eb756b3f.d770f8","name":"process helpers","func":"const serverName = toCamelCase(env.get('serverName'));\nconst haServer = global.get(\"homeassistant\")[serverName];\nif(!haServer) {\n node.error(\"Invalid HA server name\");\n return;\n}\nconst states = haServer.states;\nconst helpers = env.get(\"helpers\");\n\nhelpers.forEach(h => {\n const entityId = `${h.type}.${h.id}`;\n if(!states[entityId]) {\n const {id, type, ...data} = h;\n const apiData = {\n entity: h,\n payload: { \n data \n }\n };\n apiData.payload.data.type = `${type}/create`;\n \n node.send(apiData);\n node.status({text: `Creating ${entityId}`});\n }\n});\n\nnode.done();\n\nfunction toCamelCase(str) {\n return str.replace(/(?:^\\w|[A-Z]|\\b\\w|\\s+)/g, (match, index) => {\n if (+match === 0) return '';\n return index === 0 ? match.toLowerCase() : match.toUpperCase();\n });\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","x":224,"y":96,"wires":[["a4a0abd9.7576d8"]]},{"id":"a4a0abd9.7576d8","type":"ha-api","z":"eb756b3f.d770f8","name":"create helper","server":"","debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"","dataType":"json","location":"payload","locationType":"msg","responseType":"json","x":390,"y":96,"wires":[["b76d0c56.d54b9"]]},{"id":"388bb5c7.47346a","type":"ha-api","z":"eb756b3f.d770f8","name":"rename helper entity id","server":"","debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t \"type\":\"config/entity_registry/update\",\t \"entity_id\": entity.type & \".\" & payload.id,\t \"new_entity_id\": entity.type & \".\" & entity.id\t}","dataType":"jsonata","location":"payload","locationType":"msg","responseType":"json","x":788,"y":96,"wires":[[]]},{"id":"b76d0c56.d54b9","type":"switch","z":"eb756b3f.d770f8","name":"need to rename?","property":"payload.id","propertyType":"msg","rules":[{"t":"neq","v":"entity.id","vt":"msg"}],"checkall":"true","repair":false,"outputs":1,"x":570,"y":96,"wires":[["388bb5c7.47346a","3e47440a.eee2cc"]]},{"id":"a66d5d93.8a5f","type":"status","z":"eb756b3f.d770f8","name":"","scope":["7f1493fc.1300fc","858d7015.518f4","3e47440a.eee2cc"],"x":124,"y":48,"wires":[[]]},{"id":"3e47440a.eee2cc","type":"function","z":"eb756b3f.d770f8","name":"rename status","func":"const oldEntityId = `${msg.entity.type}.${msg.payload.id}`;\nconst newEntityId = `${msg.entity.type}.${msg.entity.id}`;\n\nnode.status({text: `Renaming ${oldEntityId} to ${newEntityId}`});","outputs":1,"noerr":0,"initialize":"","finalize":"","x":768,"y":144,"wires":[[]]},{"id":"4762791a.4c5408","type":"function","z":"daf25abf.0203b8","name":"date ranges","func":"const now = new Date();\nconst monthDay = getMonthDay(now);\nconst { idLookup, nameLookup } = flow.get(\"wledHolidayLightsPresets\");\nconst christmasPresets = [\n \"Christmas\",\n \"Christmas Classic\",\n \"Christmas Holly Jolly\",\n \"Christmas Candy Cane\"\n];\nconst states = global.get(\"homeassistant\").homeAssistant.states;\nconst entityId = flow.get(\"wledHolidayLightsEntityId\");\n\nlet updateInterval = 0; // in minutes\nlet preset;\n\nswitch(true) {\n// Winter \n case isToday(214):\n preset = \"Valentine\";\n break;\n// President's Day changes every year, Veteran's Day & Flag Day always the same date\n case isToday(614): // 6/14 Flag Day\n case isToday(1111): // 11/11 Veterans Day\n case isToday(\"President's Day\"):\n case isToday(\"Memorial Day\"):\n preset = \"Red, White, and Blue\";\n break;\n case isToday(317):\n preset = \"St Patty\";\n break;\n case isToday(\"Easter\"):\n preset = \"Easter\";\n break;\n// Spring\n case isToday(504):\n preset = \"Starwars\";\n break;\n case isToday(505):\n preset = \"Cinco de Mayo\";\n break;\n// Summer\n case isToday(704):\n preset = \"Independence Day\";\n break;\n// Autumn\n case isToday(1017, 1031):\n preset = \"Halloween\";\n break;\n case isToday(\"Thanksgiving Day\"):\n preset = \"Autumn\";\n break;\n case isToday(1231):\n preset = \"New Years\";\n break;\n case isToday(\"Thanksgiving Day\", 1231):\n case isToday(101, 106):\n preset = getRandomPreset(christmasPresets);\n updateInterval = 60;\n break;\n default:\n const seasons = {\n \"winter\": \"Winter\",\n \"spring\": \"Spring\",\n \"summer\": \"Summer\",\n \"autumn\": \"Autumn\"\n }\n const currentSeason = states[\"sensor.season\"].state;\n preset = seasons[currentSeason];\n break;\n}\n\nnode.status({ text: preset});\nmsg.payload = nameLookup[preset];\nconst secondOutput = updateInterval ? { payload: { timeout: updateInterval } } : { reset: true };\n\nreturn [msg, secondOutput];\n\nfunction isToday(start, end) {\n if (typeof start === \"string\") {\n start = getHolidayDate(now, start)\n }\n if (typeof end === \"string\") {\n end = getHolidayDate(now, end)\n }\n if (end === undefined) return monthDay === start;\n\n return monthDay >= start && monthDay <= end;\n}\n\nfunction getHolidayDate(date, holiday) {\n holiday = holiday.toLowerCase();\n // dates are formatted as month, week, day of the week\n // names should be lowercase\n const holidays = {\n \"martin luther king day\": [0,2,1],\n \"president's day\": [1,2,1],\n \"daylight savings time begins\": [2,1,0],\n \"mother's day\": [4,1,0],\n \"memorial day\": [4,-1,1],\n \"father's day\": [5,2,0],\n \"labor day\": [8,0,1],\n \"columbus day\": [9,1,1],\n \"daylight savings time ends\": [10,0,0],\n \"thanksgiving day\": [10,3,4]\n };\n let holidayDate;\n if(holiday === \"easter\") {\n holidayDate = getEasterDate(date); \n } else {\n const [month, week, day] = holidays[holiday];\n holidayDate = getDate(date.getFullYear(), month, week, day);\n }\n \n const monthDay = getMonthDay(holidayDate);\n \n return monthDay;\n}\n\nfunction getMonthDay(date) {\n const monthString = String(date.getMonth() + 1).padStart(2, \"0\");\n const dayString = String(date.getDate()).padStart(2, \"0\");\n const monthDay = Number(`${monthString}${dayString}`);\n \n return monthDay;\n}\n\nfunction getDate(year, month, week, day) {\n let firstDay = 1;\n if (week < 0) {\n month++;\n firstDay--;\n }\n const date = new Date(year, month, (week * 7) + firstDay);\n if (day < date.getDay()) {\n day += 7;\n }\n date.setDate(date.getDate() - date.getDay() + day);\n return date;\n}\n\n/**\n * Calculates Easter in the Gregorian/Western (Catholic and Protestant) calendar\n * based on the algorithm by Oudin (1940) from http://www.tondering.dk/claus/cal/easter.php\n * @returns {array} [int month, int day]\n */\nfunction getEasterDate(date) {\n const year = date.getFullYear();\n const f = Math.floor,\n // Golden Number - 1\n G = year % 19,\n C = f(year / 100),\n // related to Epact\n H = (C - f(C / 4) - f((8 * C + 13) / 25) + 19 * G + 15) % 30,\n // number of days from 21 March to the Paschal full moon\n I = H - f(H / 28) * (1 - f(29 / (H + 1)) * f((21 - G) / 11)),\n // weekday for the Paschal full moon\n J = (year + f(year / 4) + I + 2 - C + f(C / 4)) % 7,\n // number of days from 21 March to the Sunday on or before the Paschal full moon\n L = I - J,\n month = 3 + f((L + 40) / 44),\n day = L + 28 - 31 * f(month / 4);\n\n return new Date(`${month}/${day}/${year}`);\n}\n\nfunction getRandomPreset(list) {\n const activePreset = states[entityId].attributes.preset;\n const presetName = idLookup[activePreset];\n const filteredList = list.filter((e) => e !== presetName);\n \n return filteredList[Math.floor(Math.random() * filteredList.length)];\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","x":470,"y":272,"wires":[["91b62e9f.fe736","dece0bc.3c215f8"],["dc570e50.22a3a"]]},{"id":"c46d93f8.1fe18","type":"switch","z":"daf25abf.0203b8","name":"dark?","property":"dark","propertyType":"flow","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":306,"y":272,"wires":[["4762791a.4c5408"],["73710f8.1582bf"]]},{"id":"fe4f63d8.5312c","type":"server-state-changed","z":"daf25abf.0203b8","name":"Demo Mode","server":"","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_select.holiday_lights_demo_mode","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"off","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"","forType":"num","forUnits":"minutes","ignorePrevStateNull":true,"ignorePrevStateUnknown":true,"ignorePrevStateUnavailable":true,"ignoreCurrentStateUnknown":true,"ignoreCurrentStateUnavailable":true,"x":102,"y":464,"wires":[["1a546dd7.2d8ef2"],["92c007de.c4a168"]]},{"id":"73710f8.1582bf","type":"api-call-service","z":"daf25abf.0203b8","name":"turn off holiday lights","server":"","version":1,"debugenabled":false,"service_domain":"light","service":"turn_off","entityId":"{{flow.wledHolidayLightsEntityId}}","data":"","dataType":"json","mergecontext":"","output_location":"payload","output_location_type":"msg","mustacheAltTags":false,"x":500,"y":320,"wires":[[]]},{"id":"dc570e50.22a3a","type":"ha-wait-until","z":"daf25abf.0203b8","name":"loop","server":"","outputs":2,"entityId":"{{flow.wledHolidayLightsEntityId}}","entityIdFilterType":"exact","property":"state","comparator":"is","value":"off","valueType":"str","timeout":"60","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":false,"blockInputOverrides":false,"x":658,"y":272,"wires":[[],["4762791a.4c5408"]]},{"id":"f5422b5c.762798","type":"eztimer","z":"daf25abf.0203b8","name":"","debug":false,"autoname":"sunset - 00:00","tag":"test1","suspended":false,"sendEventsOnSuspend":false,"latLongSource":"manual","latLongHaZone":"zone.home","lat":"","lon":"","timerType":"1","startupMessage":true,"ontype":"1","ontimesun":"sunset","ontimetod":"17:00","onpropertytype":"msg","onproperty":"dark","onvaluetype":"bool","onvalue":"true","onoffset":"","onrandomoffset":0,"onsuppressrepeats":false,"offtype":"2","offtimesun":"dusk","offtimetod":"00:00","offduration":0,"offpropertytype":"msg","offproperty":"dark","offvaluetype":"bool","offvalue":"false","offoffset":0,"offrandomoffset":0,"offsuppressrepeats":false,"resend":false,"resendInterval":"1m","mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"sat":true,"sun":true,"x":112,"y":272,"wires":[["c800976d.89af98"]]},{"id":"91b62e9f.fe736","type":"api-call-service","z":"daf25abf.0203b8","name":"turn on holiday lights","server":"","version":1,"debugenabled":false,"service_domain":"wled","service":"preset","entityId":"{{flow.wledHolidayLightsEntityId}}","data":"{\"preset\": payload}","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":708,"y":224,"wires":[[]]},{"id":"78b7479f.e79dd8","type":"function","z":"daf25abf.0203b8","name":"get preset","func":"// WLED Presets\nconst { nameLookup } = flow.get(\"wledHolidayLightsPresets\");\n\nmsg.payload = nameLookup[msg.payload];\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":668,"y":176,"wires":[["cc0fc459.d7f3a8"]]},{"id":"6a3ef206.84c5fc","type":"api-call-service","z":"daf25abf.0203b8","name":"populate HA dropdown with presets","server":"","version":1,"debugenabled":false,"service_domain":"input_select","service":"set_options","entityId":"input_select.holiday_lights_presets","data":"{\"options\": payload}","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":748,"y":128,"wires":[["d7d3f0e8.9971d"]]},{"id":"a6b79bf.256d268","type":"inject","z":"daf25abf.0203b8","name":"Setup","props":[{"p":"entityId","v":"light.holiday_lights","vt":"str"},{"p":"WLED_IP","v":"","vt":"str"}],"repeat":"3600","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":108,"y":128,"wires":[["4b308915.771578"]]},{"id":"1538c003.e770a","type":"ha-wait-until","z":"daf25abf.0203b8","name":"loop","server":"","outputs":2,"entityId":"{{flow.wledHolidayLightsEntityId}}","entityIdFilterType":"exact","property":"state","comparator":"is","value":"off","valueType":"str","timeout":"$number($entities(\"input_number.holiday_lights_demo_mode_delay\").state)","timeoutType":"jsonata","timeoutUnits":"seconds","entityLocation":"","entityLocationType":"none","checkCurrentState":false,"blockInputOverrides":true,"x":866,"y":512,"wires":[[],["92c007de.c4a168"]]},{"id":"92c007de.c4a168","type":"switch","z":"daf25abf.0203b8","name":"which mode?","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"cycle presets","vt":"str"},{"t":"eq","v":"cycle effects","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":278,"y":512,"wires":[["29bbe4ad.4de71c"],["7f2dc75.a04cf38"]]},{"id":"422a9fe2.d974c","type":"api-call-service","z":"daf25abf.0203b8","name":"turn on preset","server":"","version":1,"debugenabled":false,"service_domain":"wled","service":"preset","entityId":"{{flow.wledHolidayLightsEntityId}}","data":"{\"preset\": preset}","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":688,"y":512,"wires":[["1538c003.e770a","e132c6fa.e3da18"]]},{"id":"9755a99c.54ba18","type":"api-call-service","z":"daf25abf.0203b8","name":"turn on effect","server":"","version":1,"debugenabled":false,"service_domain":"light","service":"turn_on","entityId":"{{flow.wledHolidayLightsEntityId}}","data":"{\"effect\": effect}","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":678,"y":560,"wires":[["1538c003.e770a","e132c6fa.e3da18"]]},{"id":"1a546dd7.2d8ef2","type":"change","z":"daf25abf.0203b8","name":"reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"},{"t":"set","p":"payload","pt":"msg","to":"info","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":258,"y":464,"wires":[["1538c003.e770a","c46d93f8.1fe18"]]},{"id":"71da85fd.de44fc","type":"api-call-service","z":"daf25abf.0203b8","name":"turn off demo mode","server":"","version":1,"debugenabled":false,"service_domain":"input_select","service":"select_option","entityId":"input_select.holiday_lights_demo_mode","data":"{\"option\": \"off\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":378,"y":608,"wires":[[]]},{"id":"320d2444.2aa86c","type":"server-state-changed","z":"daf25abf.0203b8","name":"Holiday Lights turned off?","server":"","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"light.holiday_lights","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"off","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":false,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"x":140,"y":608,"wires":[["71da85fd.de44fc"],[]]},{"id":"7f2dc75.a04cf38","type":"function","z":"daf25abf.0203b8","name":"get next effect","func":"const states = global.get(\"homeassistant\").homeAssistant.states;\nconst entityId = flow.get(\"wledHolidayLightsEntityId\");\nconst effects = states[entityId].attributes.effect_list;\nconst activeEffect = states[entityId].attributes.effect;\nlet index = effects.findIndex(ele => ele === activeEffect);\nindex = (index === -1 || index >= effects.length - 1) ? 0 : index + 1;\n\nnode.status({text: effects[index]});\n\nmsg.effect = msg.name = effects[index];\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":480,"y":560,"wires":[["9755a99c.54ba18"]]},{"id":"29bbe4ad.4de71c","type":"function","z":"daf25abf.0203b8","name":"get next preset","func":"const states = global.get(\"homeassistant\").homeAssistant.states;\nconst entityId = flow.get(\"wledHolidayLightsEntityId\");\nconst { idLookup, nameLookup } = flow.get(\"wledHolidayLightsPresets\");\nconst keys = Object.keys(idLookup);\nconst activePreset = states[entityId].attributes.preset;\nlet index = keys.findIndex(ele => ele == activePreset);\nindex = index === -1 || index >= keys.length - 1 ? 0 : index +1;\nconst name = idLookup[keys[index]];\n\nnode.status({text: name });\n\nmsg.preset = keys[index];\nmsg.name = name;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":480,"y":512,"wires":[["422a9fe2.d974c"]]},{"id":"d89db901.9fd588","type":"function","z":"daf25abf.0203b8","name":"process data","func":"if(msg.statusCode !== 200) {\n node.status({fill: 'red', shape: 'dot', text: `Status Code: ${msg.statusCode}`})\n return;\n}\n\nconst wledPresets = msg.payload;\nconst idLookup = {};\nconst nameLookup = {};\n\nfor(const key in wledPresets) {\n if(Object.keys(wledPresets[key]).length > 0) {\n const name = wledPresets[key].n;\n idLookup[key] = name;\n nameLookup[name] = key;\n }\n}\n\nconst presets = {\n idLookup,\n nameLookup,\n names: Object.values(idLookup).sort()\n};\n\nflow.set(\"wledHolidayLightsPresets\", presets);\nflow.set(\"wledHolidayLightsEntityId\", msg.entityId);\nnode.status({text: `${presets.names.length} Presets Processed`});\n\nmsg.payload = presets.names;\n\nreturn [msg, { payload: \"disable\" }];","outputs":2,"noerr":0,"initialize":"","finalize":"","x":470,"y":128,"wires":[["6a3ef206.84c5fc"],["539eea44.9b6524"]]},{"id":"d7d3f0e8.9971d","type":"change","z":"daf25abf.0203b8","name":"enable","rules":[{"t":"set","p":"payload","pt":"msg","to":"enable","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":962,"y":128,"wires":[["7c6317af.370198"]]},{"id":"539eea44.9b6524","type":"trigger-state","z":"daf25abf.0203b8","name":"Preset Selector","server":"","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"input_select.holiday_lights_presets","entityidfiltertype":"exact","debugenabled":false,"constraints":[{"targetType":"this_entity","targetValue":"","propertyType":"current_state","comparatorType":"is_not","comparatorValueDatatype":"prevEntity","comparatorValue":"state","propertyValue":"new_state.state"}],"outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"str","x":480,"y":176,"wires":[["78b7479f.e79dd8"],[]]},{"id":"e132c6fa.e3da18","type":"ha-entity","z":"daf25abf.0203b8","name":"current demo","server":"","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Holiday Lights Demo Current"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"name","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":886,"y":560,"wires":[[]]},{"id":"a3f0ee9.6fd551","type":"server-events","z":"daf25abf.0203b8","name":"HA Client Events","server":"","event_type":"home_assistant_client","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"waitForRunning":false,"x":112,"y":176,"wires":[["6c13e445.ca929c"]]},{"id":"6c13e445.ca929c","type":"function","z":"daf25abf.0203b8","name":"HA running?","func":"if(msg.payload !== \"running\") return;\n\nconst { names } = flow.get(\"wledHolidayLightsPresets\");\n\nmsg.payload = names;\n\nreturn [msg, { payload: \"disable\" }];","outputs":2,"noerr":0,"initialize":"","finalize":"","x":278,"y":176,"wires":[["6a3ef206.84c5fc"],["539eea44.9b6524"]]},{"id":"afc3f7e9.88ac98","type":"comment","z":"daf25abf.0203b8","name":"Setup","info":"","x":82,"y":32,"wires":[]},{"id":"5b75e78b.d9d608","type":"comment","z":"daf25abf.0203b8","name":"Scheduler","info":"","x":92,"y":224,"wires":[]},{"id":"cc0fc459.d7f3a8","type":"link out","z":"daf25abf.0203b8","name":"turn on holiday lights","links":["d830a00d.1d744"],"x":852,"y":176,"wires":[],"l":true},{"id":"d830a00d.1d744","type":"link in","z":"daf25abf.0203b8","name":"Holiday Lights On","links":["cc0fc459.d7f3a8"],"x":527,"y":224,"wires":[["91b62e9f.fe736"]]},{"id":"215b93f8.a1883c","type":"comment","z":"daf25abf.0203b8","name":"Demo Mode","info":"","x":102,"y":416,"wires":[]},{"id":"4b308915.771578","type":"http request","z":"daf25abf.0203b8","name":"get presets","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://{{WLED_IP}}/presets.json","tls":"","persist":false,"proxy":"","authType":"","x":278,"y":128,"wires":[["d89db901.9fd588"]]},{"id":"7c6317af.370198","type":"delay","z":"daf25abf.0203b8","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1100,"y":128,"wires":[["539eea44.9b6524"]]},{"id":"aea9da7f.af56a8","type":"ha-entity","z":"daf25abf.0203b8","name":"current preset","server":"","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Holiday Lights Current Preset"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":480,"y":368,"wires":[[]]},{"id":"4b02330f.bc08fc","type":"function","z":"daf25abf.0203b8","name":"format","func":"const { idLookup } = flow.get(\"wledHolidayLightsPresets\");\nconst id = msg.data.new_state.attributes.preset || 0;\nconst presetName = idLookup[id] || \"none\";\n\nmsg.payload = msg.payload === \"on\" ? presetName : \"none\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":258,"y":368,"wires":[["aea9da7f.af56a8"]]},{"id":"a3f37acd.911a88","type":"server-state-changed","z":"daf25abf.0203b8","name":"Preset Updated","server":"","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"light.holiday_lights","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":false,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"x":112,"y":368,"wires":[["4b02330f.bc08fc"]]},{"id":"dece0bc.3c215f8","type":"debug","z":"daf25abf.0203b8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":752,"y":336,"wires":[]},{"id":"c800976d.89af98","type":"change","z":"daf25abf.0203b8","name":"","rules":[{"t":"set","p":"dark","pt":"flow","to":"dark","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":223,"y":272,"wires":[["c46d93f8.1fe18"]],"l":false},{"id":"b1ec00ad.8c8f7","type":"subflow:eb756b3f.d770f8","z":"daf25abf.0203b8","name":"","env":[{"name":"helpers","value":"[{\"id\":\"holiday_lights_demo_mode_delay\",\"type\":\"input_number\",\"name\":\"Cycle Delay\",\"initial\":30,\"min\":-5,\"max\":300,\"step\":5,\"icon\":\"mdi:timer-sand\"},{\"id\":\"holiday_lights_demo_mode\",\"type\":\"input_select\",\"name\":\"Mode\",\"options\":[\"off\",\"cycle effects\",\"cycle presets\"],\"initial\":\"off\",\"icon\":\"mdi:animation\"},{\"id\":\"holiday_lights_presets\",\"type\":\"input_select\",\"name\":\"Presets\",\"options\":[\"none\"],\"icon\":\"mdi:animation\"}]","type":"json"}],"x":346,"y":80,"wires":[]},{"id":"297d2a12.388f86","type":"inject","z":"daf25abf.0203b8","name":"Create HA elements","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":138,"y":80,"wires":[["b1ec00ad.8c8f7"]]}]
Requirements
- Home Assistant v2021.7+
- WLED v0.11+
Integrations
The season integration is used to determine the current season and set a WLED preset if no other holiday range is defined.
The two entity nodes will require the Node-RED custom integration but the flow will function fine without it. The UI just won't have the updated current preset and demo effect displayed.
Nodes
Setup
The flow has been modified so that it should run pretty much out of the box after changing the entity id for the light and IP for the WLED controller.
WLED variables
Edit the change node, set entity ids here, to edit the Home Assistant entity id of the holiday lights and the select entity for presets. The entity of your WLED light needs to be changed in two places.
Setting date ranges up
Holidays can be either a single day or a range of dates. If no holiday is defined for the current day it will default to the season preset WINTER
, SPRING
, SUMMER
, and AUTUMN
.
In the date ranges
node, a lot is going on but the main thing is the switch statement that determines which preset to use.
The isToday
function can take two arguments but only the first one is required which is the start date of the holiday. The second argument is the end date of the holiday. Both of the arguments can take a number in the format of MONTHDAY or a holiday name defined in the getHolidayDate
function on line #92.
Lines 16 - 72
switch (true) {
// Winter
case isToday(214):
preset = "Valentine";
break;
// President's Day changes every year, Veteran's Day & Flag Day always the same date
case isToday(614): // 6/14 Flag Day
case isToday(1111): // 11/11 Veterans Day
case isToday("President's Day"):
case isToday("Memorial Day"):
preset = "Red, White, and Blue";
break;
case isToday(317):
preset = "St Patty";
break;
case isToday("Easter"):
preset = "Easter";
break;
// Spring
case isToday(504):
preset = "Starwars";
break;
case isToday(505):
preset = "Cinco de Mayo";
break;
// Summer
case isToday(704):
preset = "Independence Day";
break;
// Autumn
case isToday(1017, 1031):
preset = "Halloween";
break;
case isToday("Thanksgiving Day"):
preset = "Autumn";
break;
case isToday(1231):
preset = "New Years";
break;
case isToday("Thanksgiving Day", 1231):
case isToday(101, 106):
const activePreset = states[entityId].attributes.preset;
const presetName = idLookup[activePreset];
preset = getRandomPreset(christmasPresets.filter((e) => e !== presetName));
updateInterval = 60;
break;
default:
const seasons = {
winter: "Winter",
spring: "Spring",
summer: "Summer",
autumn: "Autumn",
};
const currentSeason = states["sensor.season"].state;
preset = seasons[currentSeason];
break;
}
Home Assistant Entities
Three entities will need to be created in Home Assistant two input_select and an input_number. The helpers configuration, Configuration > Helpers
, can be used or writing them in YAML.
input_number.holiday_lights_demo_mode_delay
input_number:
holiday_lights_demo_mode_delay:
name: Cycle Delay
initial: 30
min: -5
max: 300
step: 5
icon: "mdi:timer-sand"
input_select.holiday_lights_demo_mode
input_select:
holiday_lights_demo_mode:
name: Mode
options:
- off
- cycle effects
- cycle presets
initial: off
icon: "mdi:animation"
Lovelace UI
title: Holiday Lights
type: entities
entities:
- entity: light.holiday_lights
- entity: select.holiday_lights_presets
- type: section
label: Demo Mode
- type: conditional
conditions:
- entity: input_select.holiday_lights_demo_mode
state_not: "off"
row:
entity: sensor.holiday_lights_demo_current
- entity: input_select.holiday_lights_demo_mode
- entity: input_number.holiday_lights_demo_mode_delay
Things that could have been added but never got around to it
- Previous and Next button in the demo UI