# Alert Sudden Rise in Temperature

**URL:** <https://discourse.nodered.org/t/alert-sudden-rise-in-temperature/76074>\
**Category:** General\
**Tags:** home-assistant\
**Created:** [3 March 2023 18:14 UTC](https://discourse.nodered.org/t/alert-sudden-rise-in-temperature/76074 "2023-03-03T18:14:52Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jgvary](https://avatars.discourse-cdn.com/v4/letter/j/dfb087/32.png) [@jgvary](https://discourse.nodered.org/u/jgvary)\
**Post date:** [3 March 2023 18:14 UTC](https://discourse.nodered.org/t/alert-sudden-rise-in-temperature/76074/1 "2023-03-03T18:14:52Z")

</div>

I am trying to create a flow that will alert me of a sudden rise in temperature for my temperature sensors around the house.

He is what I have currently and suggestions or advice?

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/b/2b3569f0b920d9325cc62a1fec09079f71a08311.png)

```auto
[{"id":"405f829e0a28b82e","type":"api-call-service","z":"892eaa13311e821a","name":"Notify John","server":"c33123cf.c144e","version":5,"debugenabled":false,"domain":"notify","service":"mobile_app_pixel_7_pro","areaId":[],"deviceId":[],"entityId":[],"data":"{ \"message\": payload }","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"data"}],"queue":"none","x":1230,"y":2400,"wires":[[]]},{"id":"de1b06b9e93f77a9","type":"server-state-changed","z":"892eaa13311e821a","name":"Rapid Temp Increase","server":"c33123cf.c144e","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"temperature","entityidfiltertype":"substring","outputinitially":true,"state_type":"num","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"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":140,"y":2360,"wires":[["5050be2bd911b8eb"]]},{"id":"53898adb1b4cd249","type":"comment","z":"892eaa13311e821a","name":"Rapid Temp Alert for Fire","info":"","x":150,"y":2280,"wires":[]},{"id":"5050be2bd911b8eb","type":"switch","z":"892eaa13311e821a","name":"Allow Numbers Only","property":"payload","propertyType":"msg","rules":[{"t":"istype","v":"number","vt":"number"}],"checkall":"true","repair":false,"outputs":1,"x":380,"y":2360,"wires":[["5a7e3e9d47f5fe84","5e22ad2c0d3a084e"]]},{"id":"b801bf0cadd6db71","type":"debug","z":"892eaa13311e821a","name":"debug 24","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":940,"y":2460,"wires":[]},{"id":"5a7e3e9d47f5fe84","type":"smooth","z":"892eaa13311e821a","name":"","property":"payload","action":"mean","count":"20","round":"","mult":"multi","reduce":false,"x":580,"y":2320,"wires":[["7c790a11a863ba6b"]]},{"id":"7c790a11a863ba6b","type":"function","z":"892eaa13311e821a","name":"function 3","func":"var t = msg.topic\nmsg.topic = msg.topic.replace(/[^a-zA-Z0-9]/g, \" \")\nmsg.topic = msg.topic.replace(/(^\\w|\\s\\w)/g, m => m.toUpperCase())\nflow.set(t, msg.payload.toFixed(0))\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":880,"y":2320,"wires":[[]]},{"id":"5e22ad2c0d3a084e","type":"function","z":"892eaa13311e821a","name":"function 4","func":"var t = msg.topic // set topic variable\nvar avetemp = parseFloat(flow.get(t))// retrieve the value of the flow variable based on topic\nvar possibleTexts = [\"Bedroom\", \"Laundry\", \"Utility\", \"Garage\", \"Office\", \"Family\", \"Hallway\", \"Door\", \"Bathroom\", \"Kitchen\"]; // array of strings to check for in msg.topic\nvar delta = 10 // Different in Temp \nvar deltatemp = Math.round(avetemp+delta) // Calc Delta Temp\nvar curtemp = parseFloat(msg.payload.toFixed(0)) // Get Current Temp from Payload\nvar alert = \"Temperature High\" // Set Alert Text\nmsg.topic = msg.topic.replace(/[^a-zA-Z0-9]/g, \" \") // Change msg.topic replace non alphanumeric with \" \"\nmsg.topic = msg.topic.replace(/(^\\w|\\s\\w)/g, m => m.toUpperCase()) // Change msg.topic to First Letter Upper Case\n\n\n\n// Check if msg topic includes allowed areas and if current temp exceeds average temp + delta\nif (possibleTexts.some(topic => msg.topic.includes(topic)) && (curtemp > avetemp + delta)) {\n msg = { topic: msg.topic, payload: \"The \" + msg.topic + \" \" + alert + \" \" + curtemp, avetemp:avetemp, currenttemp: curtemp, deltatemp: deltatemp };\n node.status({\n text: msg.topic + \", \" + msg.payload + \" Average Temp: \" + avetemp + ' ' + \"Current Temp: \" + curtemp\n });\n\n return msg\n}\nelse\n\n node.status({\n text: msg.topic + \" Normal\"\n });\n\nflow.set(\"status\", msg)\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":2400,"wires":[["b801bf0cadd6db71","405f829e0a28b82e"]]},{"id":"9ad1cd94e76fe6c5","type":"comment","z":"892eaa13311e821a","name":"Averaging Mean Temps by Topic","info":"","x":590,"y":2260,"wires":[]},{"id":"c7fc45f4e2dbe4d8","type":"comment","z":"892eaa13311e821a","name":"Set Flow Variable Average Temp by Topic","info":"","x":920,"y":2260,"wires":[]},{"id":"695b806a96e554a9","type":"comment","z":"892eaa13311e821a","name":"Check if Current Temp rose high then 10 degrees over average","info":"","x":610,"y":2460,"wires":[]},{"id":"c33123cf.c144e","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}]

```

---

<div class="post-metadata">

**Author:** ![Paul-Reed](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/paul-reed/32/66906_2.png) [@Paul-Reed](https://discourse.nodered.org/u/Paul-Reed)\
**Post date:** [3 March 2023 18:18 UTC](https://discourse.nodered.org/t/alert-sudden-rise-in-temperature/76074/2 "2023-03-03T18:18:44Z")

</div>

Is this a Home Assistant flow??

---

<div class="post-metadata">

**Author:** ![raspberry](https://avatars.discourse-cdn.com/v4/letter/r/35a633/32.png) [@raspberry](https://discourse.nodered.org/u/raspberry)\
**Post date:** [3 March 2023 19:11 UTC](https://discourse.nodered.org/t/alert-sudden-rise-in-temperature/76074/3 "2023-03-03T19:11:28Z")

</div>

What would you consider "sudden"?

One approach would be to calculate a simple moving average (SMA) of the input temperatures over a window that is reasonable for your application (10 data points, for example). Any new temperature value over that moving average becomes an alert.

This is a simple moving average function you can implement, where new temperature is carried on msg.payload

```auto
var windowSize = 10; // How many values to include in the moving average

// If the SMA array of temperatures does not exist yet, create it
if (typeof flow.get("SMA") === "undefined" || flow.get("SMA") === null) {
    flow.set("SMA", []);
}

var SMA = flow.get("SMA");

// If the SMA array of temepratures is less than the window size,
// add the new temperature to the array
if (SMA.length < windowSize) {
    SMA.push(msg.payload);
    

// If the SMA array of temepratures is full (ie equal to the array size),
// we need to shift the array and add the new value to the end
} else {
    SMA = SMA.slice(1, windowSize); // slice from the second value to the end
    SMA.push(msg.payload); // add the most recent value to the end
}

flow.set("SMA", SMA);
msg.SMA = SMA;
msg.movingAverage = getAvg(SMA);

return msg;

function getAvg(values) {
  const total = values.reduce((acc, c) => acc + c, 0);
  return total / values.length;
}

```

To see this in an example, try this simple case:

```auto
[{"id":"045defddf411d517","type":"tab","label":"Flow 4","disabled":false,"info":"","env":[]},{"id":"b5407a90dfb28991","type":"inject","z":"045defddf411d517","name":"new temperature (5)","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"5","payloadType":"num","x":210,"y":200,"wires":[["e6f623bb0499d6e0"]]},{"id":"e6f623bb0499d6e0","type":"function","z":"045defddf411d517","name":"Calculate moving average","func":"var windowSize = 10; // How many values to include in the moving average\n\n\n// If the SMA array of temperatures does not exist yet, create it\nif (typeof flow.get(\"SMA\") === \"undefined\" || flow.get(\"SMA\") === null) {\n flow.set(\"SMA\", []);\n}\n\nvar SMA = flow.get(\"SMA\");\n\n// If the SMA array of temepratures is less than the window size,\n// add the new temperature to the array\nif (SMA.length < windowSize) {\n SMA.push(msg.payload);\n \n\n// If the SMA array of temepratures is full (ie equal to the array size),\n// we need to shift the array and add the new value to the end\n} else {\n SMA = SMA.slice(1, windowSize); // slice from the second value to the end\n SMA.push(msg.payload); // add the most recent value to the end\n}\n\nflow.set(\"SMA\", SMA);\nmsg.SMA = SMA;\nmsg.movingAverage = getAvg(SMA);\n\nreturn msg;\n\nfunction getAvg(values) {\n const total = values.reduce((acc, c) => acc + c, 0);\n return total / values.length;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":500,"y":200,"wires":[["a51b91ccc7338706","9186a52879445e34","214aaa75b89b7d78"]]},{"id":"a51b91ccc7338706","type":"debug","z":"045defddf411d517","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"SMA","targetType":"msg","statusVal":"","statusType":"auto","x":440,"y":120,"wires":[]},{"id":"3791a9a1a579584e","type":"inject","z":"045defddf411d517","name":"new temperature (4)","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"4","payloadType":"num","x":210,"y":240,"wires":[["e6f623bb0499d6e0"]]},{"id":"5393a07bd24d56d3","type":"inject","z":"045defddf411d517","name":"new temperature (3)","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"3","payloadType":"num","x":210,"y":280,"wires":[["e6f623bb0499d6e0"]]},{"id":"033b3e7803b5d7d0","type":"inject","z":"045defddf411d517","name":"new temperature (50)","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"100","payloadType":"num","x":200,"y":320,"wires":[["e6f623bb0499d6e0"]]},{"id":"9186a52879445e34","type":"debug","z":"045defddf411d517","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"movingAverage","targetType":"msg","statusVal":"","statusType":"auto","x":480,"y":160,"wires":[]},{"id":"214aaa75b89b7d78","type":"function","z":"045defddf411d517","name":"Notify if over threshold","func":"// An alert is triggered if we are so many degrees over the moving average\n\nvar threshold = 5;\nvar delta = msg.payload - msg.movingAverage;\n\nif (delta > threshold) {\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":820,"y":200,"wires":[["57e518c035641989"]]},{"id":"57e518c035641989","type":"template","z":"045defddf411d517","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Warning!!","output":"str","x":1040,"y":200,"wires":[["97ba9c6bc2b22fc6"]]},{"id":"97ba9c6bc2b22fc6","type":"debug","z":"045defddf411d517","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1210,"y":200,"wires":[]}]

```

---

<div class="post-metadata">

**Author:** ![jgvary](https://avatars.discourse-cdn.com/v4/letter/j/dfb087/32.png) [@jgvary](https://discourse.nodered.org/u/jgvary)\
**Post date:** [3 March 2023 19:33 UTC](https://discourse.nodered.org/t/alert-sudden-rise-in-temperature/76074/4 "2023-03-03T19:33:40Z")

</div>

Yes, Node red Home Assistant

---

<div class="post-metadata">

**Author:** ![E1cid](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/e1cid/32/77971_2.png) [@E1cid](https://discourse.nodered.org/u/E1cid)\
**Post date:** [3 March 2023 20:31 UTC](https://discourse.nodered.org/t/alert-sudden-rise-in-temperature/76074/6 "2023-03-03T20:31:24Z")

</div>

I would probably make sure the high readings do not get sent to smooth node. I would also put a trigger node on the alert with a reset if temp falls back with in x seconds.  
e.g.

```auto
[{"id":"688d7d9f0dc577b4","type":"inject","z":"65617ffeb779f51c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"utility","payload":"$round(($random()*10)+10, 2)","payloadType":"jsonata","x":110,"y":2020,"wires":[["5050be2bd911b8eb"]]},{"id":"5050be2bd911b8eb","type":"switch","z":"65617ffeb779f51c","name":"Allow Numbers Only","property":"payload","propertyType":"msg","rules":[{"t":"istype","v":"number","vt":"number"}],"checkall":"true","repair":false,"outputs":1,"x":140,"y":2100,"wires":[["5e22ad2c0d3a084e"]]},{"id":"5fff03092525e600","type":"inject","z":"65617ffeb779f51c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"bedroom","payload":"$round(($random()*10)+10, 2)","payloadType":"jsonata","x":130,"y":2180,"wires":[["5050be2bd911b8eb"]]},{"id":"ea2dcac5e3a4c953","type":"inject","z":"65617ffeb779f51c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"bedroom","payload":"30","payloadType":"num","x":130,"y":2220,"wires":[["5050be2bd911b8eb"]]},{"id":"846c7c996ffe47e7","type":"inject","z":"65617ffeb779f51c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"utility","payload":"30","payloadType":"num","x":100,"y":2060,"wires":[["5050be2bd911b8eb"]]},{"id":"5e22ad2c0d3a084e","type":"function","z":"65617ffeb779f51c","name":"function 4","func":"const possible_topics = [\"Bedroom\", \"Laundry\", \"Utility\", \"Garage\", \"Office\", \"Family\", \"Hallway\", \"Door\", \"Bathroom\", \"Kitchen\"]; // array of strings to check for in msg.topic\nconst output = [null,null];\nmsg.topic = msg.topic.replace(/[^a-zA-Z0-9]/g, \" \") // Change msg.topic replace non alphanumeric with \" \"\nmsg.topic = msg.topic.replace(/(^\\w|\\s\\w)/g, m => m.toUpperCase()) // Change msg.topic to First Letter Upper Case\n\nif(possible_topics.includes(msg.topic)){\n const path = \"sensor_temps.\" + msg.topic;\n let avetemp = parseFloat(flow.get(path))// retrieve the value of the flow variable based on topic\n let delta = 10 // Different in Temp \n let deltatemp = Math.round(avetemp+delta) // Calc Delta Temp\n let curtemp = parseFloat(msg.payload.toFixed(0)) // Get Current Temp from Payload\n let alert = \"Temperature High\" // Set Alert Text\n\n // Check if msg topic includes allowed areas and if current temp exceeds average temp + delta\n if(curtemp > avetemp + delta) {\n msg = { topic: msg.topic, payload: \"The \" + msg.topic + \" \" + alert + \" \" + curtemp, avetemp:avetemp, currenttemp: curtemp, deltatemp: deltatemp };\n node.status({\n text: msg.topic + \", \" + msg.payload + \" Average Temp: \" + avetemp + ' ' + \"Current Temp: \" + curtemp\n });\n output[1] = msg;\n }else{\n node.status({\n text: msg.topic + \" Normal\"\n });\n output[0] = msg;\n }\n flow.set(\"status\", msg)\n}\nreturn output;\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":2100,"wires":[["5a7e3e9d47f5fe84"],["9670aba09026a741"]]},{"id":"5a7e3e9d47f5fe84","type":"smooth","z":"65617ffeb779f51c","name":"","property":"payload","action":"mean","count":"20","round":"","mult":"multi","reduce":false,"x":520,"y":2080,"wires":[["39429f2becf83487","7841bfe8fd6a4e21"]]},{"id":"9670aba09026a741","type":"trigger","z":"65617ffeb779f51c","name":"","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"10","extend":true,"overrideDelay":false,"units":"s","reset":"","bytopic":"topic","topic":"topic","outputs":1,"x":490,"y":2200,"wires":[["b801bf0cadd6db71"]]},{"id":"39429f2becf83487","type":"debug","z":"65617ffeb779f51c","name":"debug 237","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":730,"y":2040,"wires":[]},{"id":"7841bfe8fd6a4e21","type":"change","z":"65617ffeb779f51c","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_temps[msg.topic]","tot":"flow"},{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":2080,"wires":[["9670aba09026a741"]]},{"id":"b801bf0cadd6db71","type":"debug","z":"65617ffeb779f51c","name":"debug 24","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":680,"y":2200,"wires":[]}]

```

I would also store the average temps in a single object, as in the example.

---

<div class="post-metadata">

**Author:** ![jgvary](https://avatars.discourse-cdn.com/v4/letter/j/dfb087/32.png) [@jgvary](https://discourse.nodered.org/u/jgvary)\
**Post date:** [3 March 2023 22:50 UTC](https://discourse.nodered.org/t/alert-sudden-rise-in-temperature/76074/7 "2023-03-03T22:50:48Z")

</div>

Yes, Node red Home Assistant.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [4 May 2023 15:35 UTC](https://discourse.nodered.org/t/alert-sudden-rise-in-temperature/76074/9 "2023-05-04T15:35:57Z")

</div>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.
