Skip to content

Commit

Permalink
docs(cookbook): Update Holiday Lights example
Browse files Browse the repository at this point in the history
  • Loading branch information
zachowj committed Dec 6, 2021
1 parent c295b08 commit 73b1bf5
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 33 deletions.
50 changes: 17 additions & 33 deletions docs/cookbook/holiday-lights-scheduler-and-demo-mode-for-wled.md
Expand Up @@ -10,14 +10,25 @@ The holiday lights turn on each day at sunset and then off at midnight. It uses

![screenshot of flow](./images/holiday-lights-scheduler-and-demo-mode-for-wled_01.png)

<<< @/examples/cookbook/holiday-lights-scheduler-and-demo-mode-for-wled/holiday-lights-scheduler-and-demo-mode-for-wled.json
### Version 1

## Requirements
<<< @/examples/cookbook/holiday-lights-scheduler-and-demo-mode-for-wled/holiday-lights-scheduler-and-demo-mode-for-wled_v1.json

</code-block>

::: details version 0

- [Home Assistant](https://home-assistant.io) v0.118+
- [WLED](https://github.com/Aircoookie/WLED) v0.11+

[Home Assistant](https://home-assistant.io) v0.118 is required for the WLED preset service. The Home Assistant nodes to control WLED could be replaced with WLED nodes to sidestep these requirements.
<<< @/examples/cookbook/holiday-lights-scheduler-and-demo-mode-for-wled/holiday-lights-scheduler-and-demo-mode-for-wled_v0.json

:::

## Requirements

- [Home Assistant](https://home-assistant.io) v2021.7+
- [WLED](https://github.com/Aircoookie/WLED) v0.11+

### Integrations

Expand All @@ -36,15 +47,15 @@ The two entity nodes will require the Node-RED custom integration but the flow w

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.

1. [Setting up WLED variables](#wled-variable)
1. [Setting up WLED variables](#wled-variables)
1. [Modifing holiday date ranges](#setting-date-ranges-up)
1. [Creating Home Assistant entities](#home-assistant-entities)

### WLED variables

![screenshot of a node that needs to be editted](./images/holiday-lights-scheduler-and-demo-mode-for-wled_03.png)

Edit the inject node, **Setup**, to edit the Home Assistant entity id of the holiday lights and IP address of the WLED controller. The entity of your WLED light needs to be changed in two places.
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

Expand Down Expand Up @@ -153,23 +164,6 @@ input_select:

![screenshot of lovelace ui](./images/holiday-lights-scheduler-and-demo-mode-for-wled_06.png)

#### input_select.holiday_lights_presets

```yaml
input_select:
holiday_lights_presets:
name: Presets
options:
- none
icon: "mdi:animation"
```

::: tip
This one can have any values as the options as they will get overwritten each time the WLED presets are edited in Node-RED.
:::

![screenshot of lovelace ui](./images/holiday-lights-scheduler-and-demo-mode-for-wled_07.png)

## Lovelace UI

![screenshot of lovelace ui](./images/holiday-lights-scheduler-and-demo-mode-for-wled_02.png)
Expand All @@ -178,18 +172,8 @@ This one can have any values as the options as they will get overwritten each ti
title: Holiday Lights
type: entities
entities:
- type: conditional
conditions:
- entity: sensor.holiday_lights_current_preset
state_not: none
- entity: sensor.holiday_lights_current_preset
state_not: "off"
- entity: input_select.holiday_lights_demo_mode
state: "off"
row:
entity: sensor.holiday_lights_current_preset
- entity: light.holiday_lights
- entity: input_select.holiday_lights_presets
- entity: select.holiday_lights_presets
- type: section
label: Demo Mode
- type: conditional
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +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"]]}]

0 comments on commit 73b1bf5

Please sign in to comment.