Circadian/Adaptive Lighting NodeRed

I am also using global variables but I also export those to sensors in HA and I use those sensors in templates in automations…

[{"id":"e812678d.651e28","type":"subflow","name":"Circadian Calculator","info":"","category":"time and astro","in":[{"x":80,"y":80,"wires":[{"id":"aa4b86d8.b17118"}]}],"out":[{"x":890,"y":100,"wires":[{"id":"40de744.1e2ca8c","port":0}]},{"x":890,"y":160,"wires":[{"id":"15b473ec45fa7fc4","port":0}]},{"x":930,"y":260,"wires":[{"id":"6f365d7d05905955","port":0}]},{"x":930,"y":320,"wires":[{"id":"c26bdcca.eb483","port":0}]}],"env":[],"meta":{},"color":"#FFCC66","inputLabels":["Trigger"],"outputLabels":["Brightness Value","Brightness Percent","Mireds","Kelvin"]},{"id":"5de89261.4fb97c","type":"switch","z":"e812678d.651e28","name":"curve switch","property":"payload.times_of_day.active.name","propertyType":"msg","rules":[{"t":"eq","v":"night","vt":"str"},{"t":"eq","v":"morning","vt":"str"},{"t":"eq","v":"day","vt":"str"},{"t":"eq","v":"evening","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":250,"y":220,"wires":[["ba17c1e6.e6f58","840431b7.eeefc"],["e5bb5a04.a33948","d4d99259.d0d7e"],["7c0f0774.90adf8","6ac1af7.dddb15"],["23b260f9.19f78","a907f5f4.0bf488"]]},{"id":"ba17c1e6.e6f58","type":"spline-curve","z":"e812678d.651e28","name":"night curve","output_key":"","input_key":"payload.times_of_day.active.perc","points":[{"x":0,"y":0.3},{"x":0.333,"y":0.037},{"x":0.477,"y":0},{"x":0.783,"y":0},{"x":1,"y":0}],"x":490,"y":80,"wires":[["40de744.1e2ca8c","15b473ec45fa7fc4"]]},{"id":"e5bb5a04.a33948","type":"spline-curve","z":"e812678d.651e28","name":"morning curve","output_key":"","input_key":"payload.times_of_day.active.perc","points":[{"x":0,"y":0.01},{"x":0.132,"y":0.01},{"x":0.269,"y":0.027},{"x":0.449,"y":0.124},{"x":0.676,"y":0.334},{"x":1,"y":0.75}],"x":500,"y":120,"wires":[["40de744.1e2ca8c","15b473ec45fa7fc4"]]},{"id":"23b260f9.19f78","type":"spline-curve","z":"e812678d.651e28","name":"evening curve","output_key":"","input_key":"payload.times_of_day.active.perc","points":[{"x":0,"y":0.85},{"x":0.036,"y":0.78},{"x":0.176,"y":0.63},{"x":1,"y":0.3}],"x":500,"y":200,"wires":[["40de744.1e2ca8c","15b473ec45fa7fc4"]]},{"id":"7c0f0774.90adf8","type":"spline-curve","z":"e812678d.651e28","name":"daylight curve","output_key":"","input_key":"payload.times_of_day.active.perc","points":[{"x":0,"y":0.744},{"x":0.03,"y":0.838},{"x":0.097,"y":0.941},{"x":0.183,"y":1},{"x":0.86,"y":0.995},{"x":0.943,"y":0.931},{"x":1,"y":0.85}],"x":500,"y":160,"wires":[["40de744.1e2ca8c","15b473ec45fa7fc4"]]},{"id":"840431b7.eeefc","type":"spline-curve","z":"e812678d.651e28","name":"night curve","output_key":"","input_key":"payload.times_of_day.active.perc","points":[{"x":0,"y":0.5},{"x":0.067,"y":0.368},{"x":0.133,"y":0.265},{"x":0.27,"y":0.171},{"x":0.333,"y":0.16},{"x":0.506,"y":0.124},{"x":0.606,"y":0}],"x":490,"y":240,"wires":[["c26bdcca.eb483","6f365d7d05905955"]]},{"id":"d4d99259.d0d7e","type":"spline-curve","z":"e812678d.651e28","name":"morning curve","output_key":"","input_key":"payload.times_of_day.active.perc","points":[{"x":0,"y":0},{"x":0.42,"y":0.018},{"x":0.54,"y":0.051},{"x":0.587,"y":0.101},{"x":0.817,"y":0.675},{"x":1,"y":0.85}],"x":500,"y":280,"wires":[["c26bdcca.eb483","6f365d7d05905955"]]},{"id":"a907f5f4.0bf488","type":"spline-curve","z":"e812678d.651e28","name":"evening curve","output_key":"","input_key":"payload.times_of_day.active.perc","points":[{"x":0,"y":0.85},{"x":0.787,"y":0.598},{"x":1,"y":0.5}],"x":500,"y":360,"wires":[["c26bdcca.eb483","6f365d7d05905955"]]},{"id":"6ac1af7.dddb15","type":"spline-curve","z":"e812678d.651e28","name":"daylight curve","output_key":"","input_key":"payload.times_of_day.active.perc","points":[{"x":0,"y":0.85},{"x":0.123,"y":0.927},{"x":0.5,"y":1},{"x":0.92,"y":0.904},{"x":1,"y":0.85}],"x":500,"y":320,"wires":[["c26bdcca.eb483","6f365d7d05905955"]]},{"id":"40de744.1e2ca8c","type":"range","z":"e812678d.651e28","minin":"0","maxin":"1","minout":"1","maxout":"254","action":"clamp","round":true,"property":"payload","name":"","x":710,"y":100,"wires":[[]]},{"id":"c26bdcca.eb483","type":"range","z":"e812678d.651e28","minin":"0","maxin":"1","minout":"2700","maxout":"6500","action":"clamp","round":true,"property":"payload","name":"","x":730,"y":320,"wires":[[]]},{"id":"aa4b86d8.b17118","type":"sun-position","z":"e812678d.651e28","name":"","positionConfig":"31826811.22a458","rules":[],"onlyOnChange":"true","topic":"","outputs":1,"start":"","startType":"none","startOffset":0,"startOffsetType":"num","startOffsetMultiplier":60000,"end":"","endType":"none","endOffset":0,"endOffsetType":"num","endOffsetMultiplier":60000,"x":210,"y":80,"wires":[["717191f7a71b0df4"]]},{"id":"15b473ec45fa7fc4","type":"range","z":"e812678d.651e28","minin":"0","maxin":"1","minout":"1","maxout":"100","action":"clamp","round":true,"property":"payload","name":"","x":710,"y":160,"wires":[[]]},{"id":"6f365d7d05905955","type":"range","z":"e812678d.651e28","minin":"0","maxin":"1","minout":"370","maxout":"154","action":"clamp","round":true,"property":"payload","name":"","x":720,"y":260,"wires":[[]]},{"id":"717191f7a71b0df4","type":"function","z":"e812678d.651e28","name":"Times of Day","func":"var newmsg = JSON.parse(JSON.stringify(msg));\nnewmsg.payload.times_of_day = {};\n\nconst processTimeOfDay = function(nme, obj, name_start, name_end) {\n    var ret = {};\n    ret.name  = nme;\n    ret.start = obj.times[name_start].ts;\n    ret.end   = obj.times[name_end].ts;\n    ret.perc  = (obj.ts - ret.start) / (ret.end - ret.start);\n    \n    \n    // to cover range starting before midnight and ending after it.\n    if (ret.start > ret.end)\n    {\n        var a;\n\n        // before midnight\n        if (ret.start < obj.ts) \n        {\n            a = new Date(ret.end);\n            a.setUTCDate(a.getUTCDate() + 1);\n            ret.end = a.getTime();\n             \n             \n        }\n        else if (ret.end > obj.ts) \n        {\n            a = new Date(ret.start);\n            a.setUTCDate(a.getUTCDate() - 1);\n            ret.start = a.getTime();\n\n        }\n\n    }\n    \n    ret.perc  = (obj.ts - ret.start) / (ret.end - ret.start);\n    \n    obj.times_of_day[nme] = ret;\n    if (ret.start <= obj.ts && obj.ts < ret.end ) obj.times_of_day.active = ret;\n}\n\n\nprocessTimeOfDay('night', newmsg.payload, \"astronomicalDusk\", \"astronomicalDawn\");\nprocessTimeOfDay('morning', newmsg.payload, \"astronomicalDawn\", \"goldenHourDawnEnd\");\nprocessTimeOfDay('day', newmsg.payload, \"goldenHourDawnEnd\", \"sunsetStart\");\nprocessTimeOfDay('evening', newmsg.payload, \"sunsetStart\", \"astronomicalDusk\");\n\n\nreturn newmsg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":230,"y":140,"wires":[["5de89261.4fb97c"]]},{"id":"31826811.22a458","type":"position-config","name":"Home Location","isValide":"true","longitude":"0","latitude":"0","angleType":"deg","timeZoneOffset":"99","timeZoneDST":"0","stateTimeFormat":"3","stateDateFormat":"12"},{"id":"365094a5.72bb5c","type":"subflow:e812678d.651e28","z":"7ea0620.a243ca","name":"","env":[],"x":480,"y":130,"wires":[["5f4a2fbe.d6b89"],["2bd57efd76cfcedf"],["eb1275669172038f","30bf6ebc.f4da52","e54896f13be9148d"],[]]},{"id":"a7bca137.c0d2f","type":"comment","z":"7ea0620.a243ca","name":"Update","info":"","x":90,"y":40,"wires":[]},{"id":"5f4a2fbe.d6b89","type":"function","z":"7ea0620.a243ca","name":"global brightness","func":"var new_brightness = (msg.payload == 254) ? 255 : msg.payload;\nif (new_brightness != global.get('nr_circadian_brightness')){\n    global.set('nr_circadian_brightness',new_brightness);\n//     return { payload: new_brightness }\n}\nreturn { payload: new_brightness }\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":730,"y":40,"wires":[["2a30dc124d3af143"]]},{"id":"30bf6ebc.f4da52","type":"function","z":"7ea0620.a243ca","name":"global kelvin","func":"var new_kelvin = Math.round(1000000/msg.payload)\nif (new_kelvin != global.get('nr_circadian_kelvin')) {\n    global.set('nr_circadian_kelvin',new_kelvin);\n    return {payload: new_kelvin}\n    }\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":220,"wires":[["3c129db64c31287f"]]},{"id":"934e0600896a7adb","type":"link out","z":"7ea0620.a243ca","name":"Mireds","mode":"link","links":["43c2e1ab9d4c3a33","46442d133be6f963","9d3d2931ff09f30e","a52970d03d1f30a5","a897dbf21ffb2b4c"],"x":1195,"y":160,"wires":[]},{"id":"b1ee887a5f59e581","type":"link out","z":"7ea0620.a243ca","name":"Brightness","mode":"link","links":["e376d76995dda48c","4c8de271d9d32579","df433767e85260dc","3055458e27486427","4ccd12c7e9fa28f9","d72d56acc2f72b41","b1137e5488a33dda","ffa6896cb76348d5","19af89da0660a8f1","5c549b4f7506d662"],"x":1195,"y":40,"wires":[]},{"id":"eb1275669172038f","type":"function","z":"7ea0620.a243ca","name":"global mireds","func":"var new_mireds = msg.payload\nif (new_mireds != global.get('nr_circadian_mireds')) {\n    global.set('nr_circadian_mireds',new_mireds);\n    return {payload: new_mireds}\n    }\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":160,"wires":[["720badcc22d0246e"]]},{"id":"2bd57efd76cfcedf","type":"function","z":"7ea0620.a243ca","name":"global brightness %","func":"var new_brightness_pct = msg.payload;\nif (new_brightness_pct != global.get('nr_circadian_brightness_pct')) {\n    global.set('nr_circadian_brightness_pct',new_brightness_pct);\n    return {payload: new_brightness_pct}\n    }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":730,"y":100,"wires":[["e2ac2146b3a99484"]]},{"id":"53a933a438c1326b","type":"change","z":"7ea0620.a243ca","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"color_temp","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1070,"y":160,"wires":[["934e0600896a7adb"]]},{"id":"ba7018086eca537b","type":"change","z":"7ea0620.a243ca","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"brightness","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1070,"y":40,"wires":[["b1ee887a5f59e581"]]},{"id":"f6a0b62593cc81c1","type":"interval-multiples-timer","z":"7ea0620.a243ca","interval":"60000","payload":"","topic":"","name":"Every minute","x":86,"y":120,"wires":[["f7382c3f63fec06f"]],"outputLabels":["timestamp"]},{"id":"b49e0a964008e7ba","type":"inject","z":"7ea0620.a243ca","name":"At startup","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":"5","topic":"","payload":"","payloadType":"date","x":96,"y":160,"wires":[["f7382c3f63fec06f"]]},{"id":"f7382c3f63fec06f","type":"api-current-state","z":"7ea0620.a243ca","name":"Circadian On?","server":"c879ac61.99cd1","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.circadian_lighting","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"date"}],"for":0,"forType":"num","forUnits":"minutes","x":280,"y":136,"wires":[["365094a5.72bb5c"],[]]},{"id":"3c129db64c31287f","type":"ha-sensor","z":"7ea0620.a243ca","name":"Kelvin","entityConfig":"f5e1d08b.a8cd58","version":0,"state":"nr_circadian_kelvin","stateType":"global","attributes":[],"inputOverride":"allow","outputProperties":[],"x":890,"y":220,"wires":[[]]},{"id":"720badcc22d0246e","type":"ha-sensor","z":"7ea0620.a243ca","name":"color_temp","entityConfig":"e80bd956.f2e098","version":0,"state":"nr_circadian_mireds","stateType":"global","attributes":[],"inputOverride":"allow","outputProperties":[],"x":910,"y":160,"wires":[["53a933a438c1326b"]]},{"id":"2a30dc124d3af143","type":"ha-sensor","z":"7ea0620.a243ca","name":"brightness","entityConfig":"476cda43.0f4c94","version":0,"state":"nr_circadian_brightness","stateType":"global","attributes":[],"inputOverride":"block","outputProperties":[],"x":910,"y":40,"wires":[["ba7018086eca537b"]]},{"id":"e2ac2146b3a99484","type":"ha-sensor","z":"7ea0620.a243ca","name":"brightness_pct","entityConfig":"5cd0d7153aaad741","version":0,"state":"nr_circadian_brightness_pct","stateType":"global","attributes":[],"inputOverride":"block","outputProperties":[],"x":920,"y":100,"wires":[[]]},{"id":"e54896f13be9148d","type":"function","z":"7ea0620.a243ca","name":"Kelvin to RGB","func":"var tmpKelvin = Math.round(1000000 / msg.payload)\n\nif (tmpKelvin < 1000) {tmpKelvin = 1000}\nif (tmpKelvin > 40000) {tmpKelvin = 40000}\ntmpKelvin = tmpKelvin / 100\n\n// First: red\nif (tmpKelvin <= 66)\n    { r = 255 }\nelse\n{\n    // Note: the R-squared value for this approximation is .988\n    var tmpCalc = tmpKelvin - 60\n    tmpCalc = 329.698727446 * (tmpCalc ^ -0.1332047592)\n    var r = Math.round(tmpCalc)\n    if (r < 0) {r = 0}\n    if (r > 255) {r = 255}\n}\n\n// Second: green\nif (tmpKelvin <= 66) \n{\n    // Note: the R-squared value for this approximation is .996\n    tmpCalc = tmpKelvin\n    tmpCalc = 99.4708025861 * Math.log(tmpCalc) - 161.1195681661\n    var g = Math.round(tmpCalc)\n    if (g < 0) {g = 0}\n    if (g > 255) {g = 255}\n} else\n{\n    // Note: the R-squared value for this approximation is .987\n    tmpCalc = tmpKelvin - 60\n    tmpCalc = 288.1221695283 * (tmpCalc ^ -0.0755148492)\n    g = Math.round(tmpCalc)\n    if (g < 0) { g = 0 }\n    if (g > 255) { g = 255 }\n}\n\n// Third: blue\nif (tmpKelvin >= 66)\n    { var b = 255 }\nelse if (tmpKelvin <= 19)\n    { b = 0 }\nelse \n    {\n    // Note: the R-squared value for this approximation is .998\n        tmpCalc = tmpKelvin - 10\n        tmpCalc = 138.5177312231 * Math.log(tmpCalc) - 305.0447927307\n    }\nb = Math.round(tmpCalc)\nif (b < 0) { b = 0 }\nif (b > 255) { b = 255 }\n\nif ([r,g,b] != global.get('nr_circadian_rgb')) {\n    global.set('nr_circadian_rgb', [r,g,b]);\n    return { payload: [r, g, b] }\n    }\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":280,"wires":[["412288630f9120b7"]]},{"id":"be1c8e1a66aec806","type":"change","z":"7ea0620.a243ca","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"rgb_color","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1070,"y":280,"wires":[["eb72c612dcb6c962"]]},{"id":"eb72c612dcb6c962","type":"link out","z":"7ea0620.a243ca","name":"RGB","mode":"link","links":["c1cff865a0ee9d10"],"x":1195,"y":280,"wires":[]},{"id":"412288630f9120b7","type":"ha-sensor","z":"7ea0620.a243ca","name":"RGB","entityConfig":"10179c1c0d06ea3c","version":0,"state":" ","stateType":"str","attributes":[{"property":"rgb_color","value":"payload","valueType":"msg"}],"inputOverride":"allow","outputProperties":[],"x":890,"y":280,"wires":[["be1c8e1a66aec806"]]},{"id":"c879ac61.99cd1","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"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},{"id":"f5e1d08b.a8cd58","type":"ha-entity-config","server":"c879ac61.99cd1","deviceConfig":"7e438167417be2db","name":"Circadian kelvin","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"Circadian Kelvin"},{"property":"icon","value":"mdi:brightness-6"},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":"K"},{"property":"state_class","value":""}],"resend":true,"debugEnabled":false},{"id":"e80bd956.f2e098","type":"ha-entity-config","server":"c879ac61.99cd1","deviceConfig":"f5ff2695a5677b41","name":"Circadian color_temp","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"Circadian color_temp"},{"property":"icon","value":"mdi:brightness-6"},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":true,"debugEnabled":false},{"id":"476cda43.0f4c94","type":"ha-entity-config","server":"c879ac61.99cd1","deviceConfig":"d03039723c3f87fe","name":"Circadian brightness","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"Circadian Brightness"},{"property":"icon","value":"mdi:brightness-auto"},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":true,"debugEnabled":false},{"id":"5cd0d7153aaad741","type":"ha-entity-config","server":"c879ac61.99cd1","deviceConfig":"c260472dc44e142d","name":"Circadian brightness_pct","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"Circadian Brightness %"},{"property":"icon","value":"mdi:brightness-percent"},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":"%"},{"property":"state_class","value":""}],"resend":true,"debugEnabled":false},{"id":"10179c1c0d06ea3c","type":"ha-entity-config","server":"c879ac61.99cd1","deviceConfig":"3619f11c08848aa5","name":"Circadian RGB","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"Circadian RGB"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":true,"debugEnabled":false},{"id":"7e438167417be2db","type":"ha-device-config","name":"nr_circadian_kelvin","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""},{"id":"f5ff2695a5677b41","type":"ha-device-config","name":"nr_circadian_color_temp","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""},{"id":"d03039723c3f87fe","type":"ha-device-config","name":"nr_circadian_brightness","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""},{"id":"c260472dc44e142d","type":"ha-device-config","name":"nr_circadian_brightness_pct","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""},{"id":"3619f11c08848aa5","type":"ha-device-config","name":"nr_circadian_rgb","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""}]

alias: Automatic Lighting - Office
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.my_pc_is_active
    id: PC Active
    to: "on"
  - platform: state
    entity_id:
      - binary_sensor.office_occupancy
    id: Motion on
    to: "on"
  - platform: state
    entity_id:
      - binary_sensor.my_pc_is_active
    id: PC Idle
    to: "off"
    for:
      hours: 0
      minutes: 0
      seconds: 0
  - platform: state
    entity_id:
      - binary_sensor.office_occupancy
    to: "off"
    id: Motion off
    for:
      seconds: "{{ states('input_number.office_lights_auto_off_time') }}"
condition: []
action:
  - choose:
      - conditions:
          - condition: or
            conditions:
              - condition: trigger
                id: PC Active
              - condition: trigger
                id: Motion on
        sequence:
          - if:
              - condition: not
                conditions:
                  - condition: state
                    entity_id: sensor.windows_11_monitorpowerstate
                    state: PowerOn
            then:
              - service: light.turn_on
                data: {}
                target:
                  entity_id: light.pc_monitor
          - if:
              - condition: state
                entity_id: light.office_lights
                state: "off"
            then:
              - service: light.turn_on
                data:
                  brightness: "{{ states('sensor.circadian_brightness') }}"
                  color_temp: "{{ states('sensor.circadian_color_temp') }}"
                target:
                  entity_id: light.office_lights
      - conditions:
          - condition: and
            conditions:
              - condition: state
                entity_id: binary_sensor.my_pc_is_active
                state: "off"
              - condition: state
                entity_id: binary_sensor.office_occupancy
                state: "off"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              area_id: office
    default: []
mode: restart