Dynamic Heating Setpoint Adjustment based on Tibber Electricity Prices
This flow dynamically adjusts the target room temperature (setpoint) for your heating system (e.g., thermostats) based on Tibber dynamic electricity prices and price segments throughout the day.
The system prevents unnecessary heating during expensive periods and allows for slight comfort increases during cheap hours, all fully automated within Node-RED and Home Assistant.
✅ Main Features: Dynamic Temperature Delta Control: Adjusts heating target temperature by -1°C, 0°C, or +1°C, depending on current and forecasted electricity price levels from Tibber.
Price-Based Segmentation: Prices are segmented into "very cheap", "cheap", "normal", "expensive", "very expensive" categories, which influence the target temperature adjustment.
Price-Aware Heating Behavior: In very cheap price windows, target temperature can increase by 1°C for pre-heating or comfort gains. In expensive periods, the temperature is reduced by 1°C to save energy.
Time Constraints for Adjustment Frequency: Temperature shifts only occur if at least 2 hours passed since the last adjustment, to avoid short-cycling.
Setpoint Range Limitations: Ensures that room temperature stays between 17°C and 21°C to prevent over- or underheating.
State Synchronization: Before adjusting, checks if the current thermostat mode is auto to prevent manual overrides from being overwritten.
Home Assistant Sensor Integration: Writes dynamic heating plans and price levels into dedicated Home Assistant sensors (e.g., for Lovelace dashboards or historical analysis).
Failsafe Loop Prevention: Includes built-in logic to avoid infinite loop triggers on each temperature update.
Debugging: Comprehensive debug outputs for each decision step.
[{"id":"7d5bd709feb5c322","type":"inject","z":"3ab217fef43e55c3","name":"TibberTagesPreise 13:30 Uhr ","props":[{"p":"payload"}],"repeat":"","crontab":"30 13 * * *","once":true,"onceDelay":"200","topic":"","payload":"","payloadType":"date","x":230,"y":100,"wires":[["956cf3e2b907108c"]]},{"id":"35d8045edadd6d5d","type":"comment","z":"3ab217fef43e55c3","name":"Heizungssteuerung +1 -1 abhängig vom Strompreis","info":"","x":250,"y":660,"wires":[]},{"id":"b6d358c059be1417","type":"debug","z":"3ab217fef43e55c3","name":"Soll Temp","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":1130,"y":840,"wires":[]},{"id":"8b730d8a1bc924bd","type":"api-current-state","z":"3ab217fef43e55c3","name":"Heizung ist auf Auto ?","server":"xxx","version":3,"outputs":2,"halt_if":"auto","halt_if_type":"str","halt_if_compare":"is","entity_id":"climate.funk_thermostat_eg_arbeitszimmer","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":360,"y":780,"wires":[["70ddd782770ab488"],[]]},{"id":"d10e5b26d96d7f78","type":"api-call-service","z":"3ab217fef43e55c3","name":"","server":"xxx","version":7,"debugenabled":false,"action":"climate.set_temperature","floorId":[],"areaId":[],"deviceId":[],"entityId":["climate.funk_thermostat_eg_arbeitszimmer"],"labelId":[],"data":"{\"temperature\":msg.payload}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[{"property":"data.new_state.attributes.temperature","propertyType":"msg","value":"payload","valueType":"msg"}],"queue":"none","blockInputOverrides":false,"domain":"climate","service":"set_temperature","x":2230,"y":780,"wires":[[]]},{"id":"407e941b160b3e16","type":"debug","z":"3ab217fef43e55c3","name":"Original trigger state","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":460,"y":900,"wires":[]},{"id":"f2514592f0699e11","type":"debug","z":"3ab217fef43e55c3","name":"HEatDelta Price Function ausgang","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":1290,"y":720,"wires":[]},{"id":"70ddd782770ab488","type":"function","z":"3ab217fef43e55c3","name":"HeatDeltaPrice get global kein Delta überschreiben","func":"\n\n// Abrufen der gespeicherten Werte aus der globalen Variable\nvar storedValues = global.get(\"HeatDeltaPrice\");\n\n// Überprüfen, ob Werte vorhanden sind und ob sie das erwartete Format haben\nif (storedValues && typeof storedValues === 'object' && 'payload' in storedValues && 'topic' in storedValues) {\n // Extrahieren der Werte\n var newValue = storedValues.payload;\n var topic = storedValues.topic;\n\n // Hier kannst du die Werte in deiner Funktion verwenden\n // ...\n\n // Optional: Weiterleiten der Werte an den nächsten Node\n msg = {\n _msgid: msg._msgid,\n payload: newValue,\n topic: topic\n };\n\n return msg;\n} else {\n // Handle den Fall, wenn keine Werte in der globalen Variable gefunden wurden\n node.error(\"Gespeicherte Werte nicht im erwarteten Format gefunden\");\n return null; // Oder einen anderen Standardwert oder Fehler zurückgeben\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":870,"y":780,"wires":[["f2514592f0699e11","8a7603d41bd41841"]]},{"id":"ccd2ee6c5bf3eff2","type":"comment","z":"3ab217fef43e55c3","name":"Looping Verhinderung","info":"","x":640,"y":960,"wires":[]},{"id":"2b4842cca38c2f93","type":"switch","z":"3ab217fef43e55c3","name":"Looping condition","property":"oldtemp","propertyType":"msg","rules":[{"t":"jsonata_exp","v":"newtemp = oldtemp + 1","vt":"jsonata"},{"t":"jsonata_exp","v":"newtemp = oldtemp - 1","vt":"jsonata"},{"t":"eq","v":"newtemp","vt":"msg"},{"t":"else"}],"checkall":"true","repair":false,"outputs":4,"x":870,"y":980,"wires":[["80538bc6e884fe28"],["b5b165af113ea9cb"],["f4b8d3baadebfb0d"],["fbc476039cec32ed","be5adf9dfcb7236d"]]},{"id":"80538bc6e884fe28","type":"debug","z":"3ab217fef43e55c3","name":"erhöhung +1","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"newtemp","targetType":"msg","statusVal":"payload","statusType":"auto","x":1140,"y":900,"wires":[]},{"id":"b5b165af113ea9cb","type":"debug","z":"3ab217fef43e55c3","name":"erniedrigung -1","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"newtemp","targetType":"msg","statusVal":"payload","statusType":"auto","x":1150,"y":960,"wires":[]},{"id":"fbc476039cec32ed","type":"debug","z":"3ab217fef43e55c3","name":"Anderer Wert","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"newtemp","targetType":"msg","statusVal":"payload","statusType":"auto","x":1140,"y":1080,"wires":[]},{"id":"929fdbfdb98d07c3","type":"change","z":"3ab217fef43e55c3","name":"Extrahiere Temperaturwert aus trigger state","rules":[{"t":"move","p":"data.event.new_state.attributes.temperature","pt":"msg","to":"newtemp","tot":"msg"},{"t":"move","p":"data.event.old_state.attributes.temperature","pt":"msg","to":"oldtemp","tot":"msg"},{"t":"set","p":"newtemp","pt":"msg","to":"$number(newtemp)","tot":"jsonata"},{"t":"set","p":"oldtemp","pt":"msg","to":"$number(oldtemp)","tot":"jsonata"},{"t":"delete","p":"payload","pt":"msg"},{"t":"delete","p":"data","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":790,"y":900,"wires":[["2b4842cca38c2f93"]]},{"id":"be5adf9dfcb7236d","type":"change","z":"3ab217fef43e55c3","name":"newtemp > payload","rules":[{"t":"move","p":"newtemp","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":890,"y":840,"wires":[["b6d358c059be1417","70ddd782770ab488","8a7603d41bd41841"]]},{"id":"f4b8d3baadebfb0d","type":"debug","z":"3ab217fef43e55c3","name":"gleich geblieben","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"newtemp","targetType":"msg","statusVal":"payload","statusType":"auto","x":1150,"y":1020,"wires":[]},{"id":"a8751ea204a2b033","type":"trigger-state","z":"3ab217fef43e55c3","name":"Heizung ist auf Auto ?","server":"xxx","version":5,"inputs":1,"outputs":2,"exposeAsEntityConfig":"","entities":{"entity":["climate.funk_thermostat_eg_arbeitszimmer"],"substring":[],"regex":[]},"debugEnabled":false,"constraints":[{"targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":"is","comparatorValueDatatype":"str","comparatorValue":"auto"}],"customOutputs":[],"outputInitially":false,"stateType":"str","enableInput":true,"x":360,"y":840,"wires":[["407e941b160b3e16","929fdbfdb98d07c3"],[]]},{"id":"e1f285169ab30f6a","type":"switch","z":"3ab217fef43e55c3","name":"Heizung mindestens 17 ?","property":"payload","propertyType":"msg","rules":[{"t":"gt","v":"16","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1430,"y":780,"wires":[["97811819423e3298","18ce07aae4e4a8d4"],["120f858e583d03f6"]]},{"id":"120f858e583d03f6","type":"debug","z":"3ab217fef43e55c3","name":"Kälter 17?","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1650,"y":840,"wires":[]},{"id":"d340b77ed82e411a","type":"comment","z":"3ab217fef43e55c3","name":"Heizung Büro","info":"","x":120,"y":760,"wires":[]},{"id":"7a020f67f787aa50","type":"server-state-changed","z":"3ab217fef43e55c3","name":"heatdeltaprice","server":"xxx","version":6,"outputs":1,"exposeAsEntityConfig":"","entities":{"entity":["sensor.heatdeltaprice"],"substring":[],"regex":[]},"outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","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":120,"y":800,"wires":[["8b730d8a1bc924bd","a8751ea204a2b033"]]},{"id":"8a7603d41bd41841","type":"SumUltimate","z":"3ab217fef43e55c3","name":"Math Sum","property":"payload","math":"sum","subtractstartfrom":"","x":1210,"y":780,"wires":[["e1f285169ab30f6a","2f948ac552809d71"]]},{"id":"2f948ac552809d71","type":"debug","z":"3ab217fef43e55c3","name":"Math Sum Büro","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1430,"y":840,"wires":[]},{"id":"443f08873ea508c6","type":"inject","z":"3ab217fef43e55c3","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":500,"y":740,"wires":[["70ddd782770ab488","a8751ea204a2b033"]]},{"id":"bbc75fadb8c6ee54","type":"api-current-state","z":"3ab217fef43e55c3","name":"Aktuelle Temperatur abrufen","server":"xxx","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"climate.funk_thermostat_eg_arbeitszimmer","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":0,"forType":"num","forUnits":"minutes","x":1700,"y":780,"wires":[["c252193c0340dbda"]]},{"id":"c252193c0340dbda","type":"switch","z":"3ab217fef43e55c3","name":"Temperatur vergleichen","property":"data.attributes.temperature","propertyType":"msg","rules":[{"t":"neq","v":"payload","vt":"msg"}],"checkall":"true","repair":false,"outputs":1,"x":1970,"y":780,"wires":[["d10e5b26d96d7f78"]]},{"id":"97811819423e3298","type":"debug","z":"3ab217fef43e55c3","name":"Wärmer 17?","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1660,"y":660,"wires":[]},{"id":"18ce07aae4e4a8d4","type":"switch","z":"3ab217fef43e55c3","name":"Heizung maximal 21 ?","property":"payload","propertyType":"msg","rules":[{"t":"lte","v":"21","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1680,"y":720,"wires":[["6ae8ab7f9d22fe91","bbc75fadb8c6ee54"],["05bec1bb589464c3"]]},{"id":"6ae8ab7f9d22fe91","type":"debug","z":"3ab217fef43e55c3","name":"Max 21?","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1930,"y":660,"wires":[]},{"id":"05bec1bb589464c3","type":"debug","z":"3ab217fef43e55c3","name":"wärmer 21?","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1940,"y":720,"wires":[]},{"id":"0771d773ce1cccbd","type":"debug","z":"3ab217fef43e55c3","name":"Delta T neuer Sollwert C°","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1240,"y":60,"wires":[]},{"id":"1fdf3b2283ff2e6c","type":"debug","z":"3ab217fef43e55c3","name":"+1 oder -1","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1190,"y":120,"wires":[]},{"id":"dde53f2629cf8b82","type":"debug","z":"3ab217fef43e55c3","name":"Settings","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1130,"y":220,"wires":[]},{"id":"0e344ceb8ee12df1","type":"function","z":"3ab217fef43e55c3","name":"HeatDeltaPrice save global","func":"// Eingehender Payload mit der Zahl\nvar newValue = msg.payload;\nvar topic = msg.topic; // Hinzugefügt, um das Topic zu erhalten\n\n// Überschreiben Sie die globale Variable mit der neuen Zahl und dem Topic\nglobal.set(\"HeatDeltaPrice\", { topic: topic, payload: newValue });\n\n// Senden Sie den gespeicherten Wert für den nächsten Node weiter (optional)\nmsg = {\n _msgid: msg._msgid,\n payload: newValue,\n topic: topic\n};\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1420,"y":140,"wires":[["35631530894c0f16","740c5dc30bb94a86"]]},{"id":"aa4cc8a2de2ea785","type":"ps-strategy-heat-capacitor","z":"3ab217fef43e55c3","name":"Heat capacitor","timeHeat1C":"50","timeCool1C":"120","maxTempAdjustment":"1","boostTempHeat":0,"boostTempCool":0,"minSavings":"0.05","setpoint":"19","x":900,"y":160,"wires":[["0771d773ce1cccbd"],["1fdf3b2283ff2e6c"],["dde53f2629cf8b82","d6a2e444f2c7363e"],["d788768dd5957df8"]]},{"id":"35631530894c0f16","type":"debug","z":"3ab217fef43e55c3","name":"HeatDeltaPrice save global","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":1750,"y":140,"wires":[]},{"id":"10af73fce7f86af2","type":"debug","z":"3ab217fef43e55c3","name":"powersaver_planning_heizung","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1700,"y":200,"wires":[]},{"id":"d788768dd5957df8","type":"debug","z":"3ab217fef43e55c3","name":"Nur Schedule ohne Preis","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1180,"y":280,"wires":[]},{"id":"9a1f381f266f97a5","type":"ha-sensor","z":"3ab217fef43e55c3","name":"Preis Planung Heizung","entityConfig":"8843bc26e097a60b","version":0,"state":"payload","stateType":"str","attributes":[{"property":"Schedule","value":"payload.schedule","valueType":"msg"}],"inputOverride":"allow","outputProperties":[],"x":1420,"y":200,"wires":[["10af73fce7f86af2"]]},{"id":"740c5dc30bb94a86","type":"ha-sensor","z":"3ab217fef43e55c3","name":"HeatDeltaPrice","entityConfig":"cf8713fca29be2ac","version":0,"state":"payload","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":1680,"y":340,"wires":[[]]},{"id":"d6a2e444f2c7363e","type":"function","z":"3ab217fef43e55c3","name":"calculate schedule","func":"function addMinutes(date, minutes) {\n return new Date(date.getTime() + minutes * 60 * 1000);\n}\n\n// Get variables from the payload\nconst scheduleStartTime = new Date(msg.payload.startAt);\nconst prices = msg.payload.priceData;\nconst fixed_setpoint = msg.payload.config.setpoint;\nconst adjustments = msg.payload.temperatures;\n\n\nlet schedule = []\nlet last_sp = null;\nlet last_price = null;\n\nfor (let i = 0; i < adjustments.length; i++) {\n let startAt = addMinutes(scheduleStartTime, i);\n let hourDiff = Math.floor((startAt.getTime() - scheduleStartTime.getTime()) / (60 * 60 * 1000))\n\n // Skip this adjustment if nothing changed\n if ((prices[hourDiff].value == last_price) && (adjustments[i] == last_sp)) {\n continue;\n }\n last_sp = adjustments[i];\n last_price = prices[hourDiff].value;\n\n // Add data to schedule\n schedule.push({\n \"startAt\": startAt,\n \"price\": prices[hourDiff].value,\n \"adjustment\": adjustments[i],\n \"setpoint\": fixed_setpoint + adjustments[i]\n });\n}\n\n// What is the setpoint now?\nconst now = new Date();\nconst minutes_since_start = Math.floor((now.getTime() - scheduleStartTime.getTime()) / (60 * 1000));\nconst setpoint_now = fixed_setpoint + adjustments[minutes_since_start];\n\nmsg = {\n \"payload\": {\n \"setpoint_now\": setpoint_now,\n \"schedule\": schedule\n }\n}\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1190,"y":180,"wires":[["9a1f381f266f97a5"]]},{"id":"fada96f01c0a5a1c","type":"function","z":"3ab217fef43e55c3","name":"Eigene Heizungssteuerung","func":"function segmentPrice(price, average, veryCheap, cheap, normal, expensive, veryExpensive) {\n if (price <= veryCheap) {\n return { segment: 'very cheap', segmentNumber: 0 };\n } else if (price <= cheap) {\n return { segment: 'cheap', segmentNumber: 1 };\n } else if (price <= normal) {\n return { segment: 'normal', segmentNumber: 2 };\n } else if (price <= expensive) {\n return { segment: 'expensive', segmentNumber: 3 };\n } else {\n return { segment: 'very expensive', segmentNumber: 4 };\n }\n}\n\nfunction controlHeating(msg) {\n const priceData = msg.payload.priceData;\n\n // Sortieren Sie priceData nach startAt in aufsteigender Reihenfolge\n // @ts-ignore\n priceData.sort((a, b) => new Date(a.start) - new Date(b.start));\n\n const prices = priceData.map(data => data.value);\n const maxPrice = Math.max(...prices);\n const minPrice = Math.min(...prices);\n const averagePrice = prices.reduce((a, b) => a + b, 0) / prices.length;\n const priceDiff = maxPrice - minPrice;\n\n const veryCheap = averagePrice - 0.10;\n const cheap = minPrice + priceDiff / 4;\n const normal = minPrice + priceDiff / 2;\n const expensive = minPrice + (3 * priceDiff) / 4;\n const veryExpensive = averagePrice + 0.10;\n\n let schedule = [];\n let priceNow, adjustmentNow, segmentNow, segmentNumberNow, startAtNow;\n let lastAdjustmentChangeHour = null;\n let lastAdjustment = null;\n\n for (let i = 0; i < priceData.length; i++) {\n const priceSegment = segmentPrice(priceData[i].value, averagePrice, veryCheap, cheap, normal, expensive, veryExpensive);\n let adjustment;\n\n const dataTime = new Date(priceData[i].start);\n const hour = dataTime.getHours(); // Extrahieren Sie die Stunde aus dem startAt Wert\n\n if (priceDiff < 0.05 || priceSegment.segment === 'normal') {\n adjustment = 0;\n // node.warn(\"priceDiff: \" + JSON.stringify(priceDiff) + \" priceSegment.segment: \" + JSON.stringify(priceSegment.segment));\n } else if (priceSegment.segment === 'expensive' || priceSegment.segment === 'very expensive') {\n adjustment = -1;\n // node.warn(\"priceSegment.segment: \" + JSON.stringify(priceSegment.segment));\n } else if ((hour >= 21 || hour < 7) && priceSegment.segment === 'very cheap') {\n adjustment = 1;\n // node.warn(\"hour: \" + JSON.stringify(hour) + \" priceSegment.segment: \" + JSON.stringify(priceSegment.segment));\n } else if ((hour >= 7 && hour < 21) && priceSegment.segment === 'very cheap') {\n adjustment = 1; // Setzen Sie die Anpassung auf 1, wenn der Preis \"sehr günstig\" ist und es ist tagsüber\n // node.warn(\"hour: \" + JSON.stringify(hour) + \" priceSegment.segment: \" + JSON.stringify(priceSegment.segment));\n } else if ((hour >= 7 && hour < 21) && priceSegment.segment === 'cheap') {\n adjustment = 1; // Setzen Sie die Anpassung auf 1, wenn der Preis \"günstig\" ist und es ist tagsüber\n // node.warn(\"hour: \" + JSON.stringify(hour) + \" priceSegment.segment: \" + JSON.stringify(priceSegment.segment));\n } else {\n adjustment = 0;\n // node.warn(\"else: 0\");\n }\n\n // Überprüfen Sie, ob die Anpassung sich geändert hat und ob seit der letzten Änderung 2 Stunden vergangen sind\n if (lastAdjustment !== null && adjustment !== lastAdjustment) {\n if (lastAdjustmentChangeHour !== null && Math.abs(hour - lastAdjustmentChangeHour) < 2) {\n // node.warn(\"hour: \" + JSON.stringify(hour) + \" adjustment: \" + JSON.stringify(adjustment) + \" lastAdjustment: \" + JSON.stringify(lastAdjustment));\n adjustment = lastAdjustment; // Setzen Sie die Anpassung auf den letzten Wert zurück, wenn weniger als 2 Stunden vergangen sind\n } else {\n lastAdjustmentChangeHour = hour; // Aktualisieren Sie die Stunde der letzten Anpassungsänderung\n // node.warn(\"Change-lastAdjustmentChangeHour: \" + JSON.stringify(lastAdjustmentChangeHour));\n }\n }\n\n lastAdjustment = adjustment; // Aktualisieren Sie den letzten Anpassungswert\n\n schedule.push({\n startAt: priceData[i].start,\n price: priceData[i].value,\n adjustment: adjustment,\n segment: priceSegment.segment,\n segmentNumber: priceSegment.segmentNumber\n });\n\n const now = new Date();\n if (dataTime.getHours() === now.getHours() && dataTime.getDate() === now.getDate()) {\n priceNow = priceData[i].value;\n adjustmentNow = adjustment;\n segmentNow = priceSegment.segment;\n segmentNumberNow = priceSegment.segmentNumber;\n startAtNow = priceData[i].start;\n }\n }\n\n if (priceNow === undefined) {\n priceNow = prices[0];\n adjustmentNow = schedule[0].adjustment;\n segmentNow = schedule[0].segment;\n segmentNumberNow = schedule[0].segmentNumber;\n startAtNow = schedule[0].startAt;\n }\n\n return { payload: { schedule: schedule, priceNow: priceNow, adjustmentNow: adjustmentNow, segmentNow: segmentNow, segmentNumberNow: segmentNumberNow, startAtNow: startAtNow } };\n}\n\nconst result = controlHeating(msg);\nreturn result;\n\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":960,"y":460,"wires":[["ab7fca649c0b4e89","58b095ec93f2a4e9","506591bcb7927190","3b185f8bc316b4d8","42191e253a522246"]]},{"id":"ab7fca649c0b4e89","type":"debug","z":"3ab217fef43e55c3","name":"Eigene Heizungssteuerung","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1220,"y":360,"wires":[]},{"id":"58b095ec93f2a4e9","type":"ha-sensor","z":"3ab217fef43e55c3","name":"Preis Planung Eigene Heizung","entityConfig":"b8bdeed797577d55","version":0,"state":"payload","stateType":"str","attributes":[{"property":"Schedule","value":"payload.schedule","valueType":"msg"}],"inputOverride":"allow","outputProperties":[],"x":1350,"y":440,"wires":[[]]},{"id":"506591bcb7927190","type":"ha-sensor","z":"3ab217fef43e55c3","name":"Solar Preis Level Now","entityConfig":"3bdbcaf036bbd9d3","version":0,"state":"payload.segmentNow","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":1340,"y":500,"wires":[[]]},{"id":"3b185f8bc316b4d8","type":"function","z":"3ab217fef43e55c3","name":"HeatDeltaPriceSolar save global","func":"// Eingehender Payload mit der Zahl\nvar newValue = msg.payload.adjustmentNow;\nvar topic = \"HeatDeltaPrice\"; // Hinzugefügt, um das Topic zu erhalten\n\n// Überschreiben Sie die globale Variable mit der neuen Zahl und dem Topic\nglobal.set(\"HeatDeltaPrice\", { topic: topic, payload: newValue });\n\n// Senden Sie den gespeicherten Wert für den nächsten Node weiter (optional)\nmsg = {\n _msgid: msg._msgid,\n payload: newValue,\n topic: topic\n};\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1410,"y":400,"wires":[["740c5dc30bb94a86","35631530894c0f16"]]},{"id":"5b6877088ebdf80f","type":"comment","z":"3ab217fef43e55c3","name":"Heizung Steuerung Crad nach Strompreis","info":"","x":940,"y":60,"wires":[]},{"id":"42191e253a522246","type":"ha-number","z":"3ab217fef43e55c3","name":"Solar Preis Level Zahl","version":1,"debugenabled":false,"inputs":1,"outputs":1,"entityConfig":"f1c8c3202d4ed4f7","exposeAsEntityConfig":"","mode":"set","value":"payload.segmentNumberNow","valueType":"msg","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"value"},{"property":"previousValue","propertyType":"msg","value":"","valueType":"previousValue"}],"x":1340,"y":560,"wires":[[]]},{"id":"199603ebd6ea5946","type":"function","z":"3ab217fef43e55c3","name":"TibberPriceReceiver save global","func":"// Eingehender Payload mit dem Array\nvar newArrayTibberPrice = msg.payload && msg.payload.priceData ? msg.payload.priceData : [];\n\n// Überprüfen, ob newArrayTibberPrice vorhanden ist\nif (newArrayTibberPrice.length > 0) {\n // Überschreiben Sie die globale Variable mit dem neuen Array\n global.set(\"TibberPriceReceiver\", newArrayTibberPrice);\n };\n\n// Senden Sie den gespeicherten Array für den nächsten Node weiter (optional)\nmsg.payload = {\n priceData: global.get(\"TibberPriceReceiver\"),\n source: \"Tibber\"\n}\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":530,"y":320,"wires":[["aa4cc8a2de2ea785","fada96f01c0a5a1c"]]},{"id":"ce2916822f74b628","type":"inject","z":"3ab217fef43e55c3","name":"TibberPlanung 30Min Update","props":[],"repeat":"1800","crontab":"","once":false,"onceDelay":"1","topic":"","x":210,"y":320,"wires":[["199603ebd6ea5946"]]},{"id":"17db09e75f9be52d","type":"ps-receive-price","z":"3ab217fef43e55c3","name":"Price Receiver","x":180,"y":260,"wires":[["199603ebd6ea5946","aa4cc8a2de2ea785"]]},{"id":"60ce34d31789a5f6","type":"tibber-query","z":"3ab217fef43e55c3","name":"Get Tibber prices","active":true,"apiEndpointRef":"f037801398711328","x":550,"y":200,"wires":[["17db09e75f9be52d"]]},{"id":"956cf3e2b907108c","type":"template","z":"3ab217fef43e55c3","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\n viewer {\n homes {\n currentSubscription {\n priceInfo {\n today {\n total\n startsAt\n }\n tomorrow {\n total\n startsAt\n }\n }\n }\n }\n }\n}","output":"str","x":360,"y":200,"wires":[["60ce34d31789a5f6"]]},{"id":"9a09d49f6d824add","type":"comment","z":"3ab217fef43e55c3","name":"Dynamischen Strompreis von Tibber abrufen","info":"","x":240,"y":60,"wires":[]},{"id":"xxx","type":"server","name":"Home Assistant User","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":false,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":": ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"default","statusTimeFormat":"h:m","enableGlobalContextStore":false},{"id":"8843bc26e097a60b","type":"ha-entity-config","server":"xxx","deviceConfig":"124a076d640976d6","name":"Preis Planung Heizung","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"powersaver_planning_heizung"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false},{"id":"cf8713fca29be2ac","type":"ha-entity-config","server":"xxx","deviceConfig":"fce00793a931d7b0","name":"HeatDeltaPrice","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"HeatDeltaPrice"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false},{"id":"b8bdeed797577d55","type":"ha-entity-config","server":"xxx","deviceConfig":"147a779b68d208e5","name":"Preis Planung Eigene Heizung","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"Preis Planung Eigene Heizung"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false},{"id":"3bdbcaf036bbd9d3","type":"ha-entity-config","server":"xxx","deviceConfig":"d6ff86710c4729fc","name":"Solar Preis Level","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"Solar Preis Level"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false},{"id":"f1c8c3202d4ed4f7","type":"ha-entity-config","server":"xxx","deviceConfig":"b631fc739fd97695","name":"Solar Preis Level Zahl","version":"6","entityType":"number","haConfig":[{"property":"name","value":"Solar Preis Level Zahl"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"min_value","value":0},{"property":"max_value","value":4},{"property":"step_value","value":1},{"property":"mode","value":"slider"}],"resend":false,"debugEnabled":false},{"id":"f037801398711328","type":"tibber-api-endpoint","queryUrl":"https://api.tibber.com/v1-beta/gql","feedConnectionTimeout":"30","feedTimeout":"60","queryRequestTimeout":"30","name":"Demo"},{"id":"124a076d640976d6","type":"ha-device-config","name":"powersaver_planning_heizung","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""},{"id":"fce00793a931d7b0","type":"ha-device-config","name":"HeatDeltaPrice","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""},{"id":"147a779b68d208e5","type":"ha-device-config","name":"Preis Planung Eigene Heizung","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""},{"id":"d6ff86710c4729fc","type":"ha-device-config","name":"Solar Preis Level","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""},{"id":"b631fc739fd97695","type":"ha-device-config","name":"Solar Preis Level Zahl","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""}]