24 Hour Freeze Warning
This checks openweathermap.org for the low temperatures for the next 24 hours and provides an alert to Home Assistant if outside temperature is or will go below freezing. Imperial (Farenheit) temperature is used and US Zip code is used, but the flow can easily be edited to long/latitude. See Forecast Api documentation for options. Make sure you update the "Get 5 Day Forecast" node to edit the url to put in your zip and token "http://api.openweathermap.org/data/2.5/forecast?zip=zip=[REPLACE_WITH_YOUR_ZIP_AND_COUNTRY_ID]&appid=[REPLACE_WITH_YOUR_API_KEY]&units=imperial" (api token you can get free at Openweathermap.org). The message states the first time the temperature dips below freezing and also states the lowest temperature in next 24 hours.
Example screenshot of Windows Desktop notification using Homeassistant Taskbar Menu:
[{"id":"50f4811c.4a351","type":"http request","z":"9f91b407.d238f8","name":"Get 5 Day Forecast","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://api.openweathermap.org/data/2.5/forecast?zip=[REPLACE_WITH_YOUR_ZIP_AND_COUNTRY_ID]&appid=[REPLACE_WITH_YOUR_API_KEY]&units=imperial","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":220,"y":1260,"wires":[["e77fb078dcb945ae"]]},{"id":"51c0dd1a.9c7f74","type":"inject","z":"9f91b407.d238f8","name":"Check for Freezing Temps 2x a Day","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"43200","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":210,"y":1100,"wires":[["50f4811c.4a351","c4304fc697f1d0bc"]]},{"id":"c4304fc697f1d0bc","type":"http request","z":"9f91b407.d238f8","name":"Get Current Weather","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://api.openweathermap.org/data/2.5/weather?zip=[REPLACE_WITH_YOUR_ZIP_AND_COUNTRY_ID]&appid=[REPLACE_WITH_YOUR_API_KEY]&units=imperial","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":220,"y":1180,"wires":[["227859f9d8ac82ae"]]},{"id":"227859f9d8ac82ae","type":"change","z":"9f91b407.d238f8","name":"Set Payload to LowTemp","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.main.temp","tot":"msg"},{"t":"set","p":"topic","pt":"msg","to":"lowTemps","tot":"str"},{"t":"set","p":"messages","pt":"msg","to":"currentLow","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":1180,"wires":[["3bcd7c047a214fcd"]]},{"id":"3bcd7c047a214fcd","type":"join-wait","z":"9f91b407.d238f8","name":"","paths":"[\"currentLow\", \"future24Hours\"]","pathsToExpire":"","useRegex":false,"warnUnmatched":false,"pathTopic":"messages","pathTopicType":"msg","correlationTopic":"","correlationTopicType":"msg","timeout":"3","timeoutUnits":"1000","exactOrder":"true","firstMsg":"true","mapPayload":"true","disableComplete":false,"persistOnRestart":false,"x":740,"y":1180,"wires":[["5d22c6d19e3ce766"],[]],"info":"Waits for current and future forecast to arrive"},{"id":"e77fb078dcb945ae","type":"function","z":"9f91b407.d238f8","name":"Check for Low 24 Hour Temp","func":"const lows = [];\nconst lowTime = [];\n\n// Check first 24 hours: 6 ranges (first range is first 6 hours, 1-6 are 3 hour ranges) for less than freezing temps\nmsg.payload.topic = \"lowTemps\";\n\nfor (x = 0; x <= 6; x++) {\nif (parseFloat(msg.payload.list[x].main.temp_min) <= 32) {\nlows.push(msg.payload.list[x].main.temp_min);\n\nlowTime.push(msg.payload.list[x].dt_txt);\n\n}\n}\n\n/* Add to payload first time freezing temp and lowest of range along with formatted times */\nmsg.payload.firstFreezeTemp = lows[0];\nmsg.payload.firstFreezeTime = formatTime(lowTime[0]);\nmsg.payload.twentyFourHourLow = Math.min(...lows).toString();\nmsg.payload.twentyFourHourLowTime = formatTime(lowTime[lows.indexOf(parseFloat(msg.payload.twentyFourHourLow), 0)]);\nmsg.messages = \"future24Hours\";\nmsg.payload.topic = \"lowTemps\";\nreturn msg; \n\n\n\nfunction formatTime(dateString) {\n \nvar options = {\n\tweekday: 'long',\n month: \"2-digit\",\n day: 'numeric',\n year: '2-digit',\n hour: 'numeric',\n minute: 'numeric',\n hour12: true\n};\ndateString = dateString.split(\" \").join(\"-\").split(\":\").join(\"-\").split(\"-\");\n\nvar date = new Date(dateString[0], dateString[1] - 1, dateString[2],dateString[3],dateString[4]);\n\nreturn date.toLocaleString('en-US', options);\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":500,"y":1260,"wires":[["3bcd7c047a214fcd"]]},{"id":"32f47ba8af8bbd3c","type":"debug","z":"9f91b407.d238f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1170,"y":1160,"wires":[]},{"id":"5d22c6d19e3ce766","type":"function","z":"9f91b407.d238f8","name":"Build Warning Message","func":"\nmsg.payload = {};\nmsg.payload.data = {}\nmsg.payload.data.message = \"\";\n\n/* testing\nmsg.messages.currentLow = \"31\";\nmsg.messages.future24Hours.twentyFourHourLow = \"\";\nmsg.messages.future24Hours.twentyFourHourLow = \"28\";\n*/\n\nif (parseFloat(msg.messages.currentLow) <= 32) { \n\n if (!isEmpty(msg.messages.future24Hours.twentyFourHourLow)) {\n \n msg.payload.data.message = \"Freeze Warning: It is currently \" + msg.messages.currentLow + \"\\u00B0F. Temperature will continue to be below freezing in next 24 hours and will be \" + msg.messages.future24Hours.twentyFourHourLow + \"\\u00B0F on \" + msg.messages.future24Hours.twentyFourHourLowTime;\n \n } else {\n msg.payload.data.message = \"Freeze Warning: It is currently \" + msg.messages.currentLow + \"\\u00B0F.\";\n \n }\n return msg; \n\n}\n\nif (!isEmpty(msg.messages.future24Hours.twentyFourHourLow)) {\n msg.payload.data.message = \"Freeze Warning: It will be \" + msg.messages.future24Hours.firstFreezeTemp + \"\\u00B0F on \" + msg.messages.future24Hours.firstFreezeTime + \", getting down to \" + msg.messages.future24Hours.twentyFourHourLow + \"\\u00B0F on \" + msg.messages.future24Hours.twentyFourHourLowTime;\n return msg; \n}\n\n\nreturn msg; \n\nfunction isEmpty(str) {\n return (!str || str.length === 0 );\n}\n\n\nfunction formatTime(dateString) {\n \nvar options = {\n\tweekday: 'long',\n month: \"2-digit\",\n day: 'numeric',\n year: '2-digit',\n hour: 'numeric',\n minute: 'numeric',\n hour12: true\n};\ndateString = dateString.split(\" \").join(\"-\").split(\":\").join(\"-\").split(\"-\");\n\nvar date = new Date(dateString[0], dateString[1] - 1, dateString[2],dateString[3],dateString[4]);\n\nreturn date.toLocaleString('en-US', options);\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":950,"y":1180,"wires":[["c632ba8fb423ed30","32f47ba8af8bbd3c"]]},{"id":"c632ba8fb423ed30","type":"switch","z":"9f91b407.d238f8","name":"","property":"payload.data.message","propertyType":"msg","rules":[{"t":"nempty"},{"t":"eq","v":"","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":810,"y":1280,"wires":[["2e6f4746c075230f","696430b5064f374e"],[]]},{"id":"2e6f4746c075230f","type":"api-call-service","z":"9f91b407.d238f8","name":"Notify Home Assistant","server":"","version":1,"debugenabled":false,"service_domain":"notify","service":"persistent_notification","entityId":"","data":"{\"message\":\"\"}","dataType":"json","mergecontext":"","output_location":"payload","output_location_type":"none","mustacheAltTags":false,"x":1060,"y":1280,"wires":[[]]},{"id":"696430b5064f374e","type":"debug","z":"9f91b407.d238f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.data.message","targetType":"msg","statusVal":"","statusType":"auto","x":1040,"y":1340,"wires":[]}]