node.log("Emma Bedroom Climate: Processing Started"); // pull in the necessary information const states = global.get('homeassistant.homeAssistant.states') const allowed = states['input_boolean.emma_bedroom_climate_protocol'].state const ac = global.get('emmaBedroom.aircon.installed', "diskCon") const temp = global.get("outdoorTemp.tempStr") const payload = msg.payload const vacation = states['input_boolean.vacation_mode'].state const dayTemp = states['input_number.emma_bedroom_daytime_temp'].state const nightTemp = states['input_number.emma_bedroom_night_temp'].state const bedTemp = states['input_number.emma_bedroom_bedtime_temp'].state const schedMode = states['input_select.scheduled_climate_mode_emma_bedroom'].state const sleeping = states['input_boolean.emma_sleeping'].state const hotDay = states['input_boolean.hot_day'].state const heatWarning = states["binary_sensor.heat_warning"].state const earlyNight = states["binary_sensor.early_night_mode"].state const danger = states['binary_sensor.heat_warning'].attributes.danger const meltdown = states['input_boolean.meltdown_protocol'].state const coolingActive = states['input_boolean.emma_bedroom_cooling_on'].state node.log("Emma Bedroom Climate: Constants Set") // Define reusable constants const emmaBedroomAircon = ["climate.emma_bedroom_aircon"] const emmaBedroomWhiteNoise = ["input_boolean.white_noise_emma_bedroom"] const validSchedModesAC = ['AC', 'Fan'] // Helper function to convert a string to title case function convertToTitleCase(str) { if (!str) { return ""; } return str.toLowerCase().replace(/\b\w/g, (s) => s.toUpperCase()); } // init variables let setTemp = [] let setEco = [] let setHvac = [] let setCool = [] let setSleep = [] let setPeople = [] let setDisplay = [] let setWhiteNoise = "turn_off" let time = [] let type = msg.type let topic = msg.topic let isWakeup = context.get("isWakeup") node.log("Emma Bedroom Climate: Variables Defined") // Sleep Switch Handling if (type === 'sleep' && payload === 'off') { setDisplay = 'turn_on' setPeople = 'turn_on' if (coolingActive === 'on') { time = 'night' } else { time = 'day' } } else if (type === 'sleep' && payload === 'on') { setDisplay = 'turn_off' time = 'bedtime' } else { time = msg.time } if (topic === 'emmabedroom-wakeup') { setSleep = 'turn_off' } // Day Time if (time === 'day') { if (type === 'auto') { setCool = 'turn_off' } if (earlyNight === 'off') { if (ac === 'on') { if (danger === 'Extreme') { setTemp = nightTemp setEco = "eco" setHvac = "cool" } else if (hotDay === 'on' || heatWarning === 'on') { setTemp = dayTemp setEco = "eco" setHvac = "cool" } else { setTemp = nightTemp setEco = "eco" setHvac = "off" } } } else if (earlyNight === 'on') { if (ac === 'on') { if (danger === 'Extreme') { setTemp === bedTemp } else { setTemp = nightTemp } if (schedMode === 'AC') { setHvac = 'cool' } else if (schedMode === 'fan') { setHvac = 'fan_only' } else { setHvac = 'off' } if (hotDay === 'on') { setEco = 'none' } else { setEco = 'eco' } } } // Night Time } else if (time === 'night') { // If this is being run at scheduled time, turn on input_boolean.emma_bedroom_cooling_on if (type === 'auto') { setCool = 'turn_on' } // Decide temperature if (type === 'sleep' && payload === 'off') { setTemp = dayTemp } else if (danger === 'Extreme') { setTemp = bedTemp } else { setTemp = nightTemp } // Decide eco mode if (sleeping === 'on') { setEco = 'none' } else { setEco = 'eco' } // Decide HVAC mode if (schedMode === 'AC') { setHvac = 'cool' } else if (schedMode === 'Fan') { setHvac = 'fan_only' } else { setHvac = 'off' } // Bed Time } else if (time === 'bedtime') { setPeople = 'turn_off' if (ac === 'on') { setTemp = bedTemp setEco = 'none' if (schedMode === 'AC') { setHvac = 'cool' } else if (schedMode === 'Fan') { setHvac = "fan_only" } else if (schedMode === 'White Noise') { setWhiteNoise = 'turn_on' if (ac === 'on') { setHvac = 'off' } } else { setHvac = "off" } } } node.log("Emma Bedroom Climate: Decision Logic Complete") // Define message payloads let sendCool = { "payload": { "action": `input_boolean.${setCool}`, "target": { "entity_id": ["input_boolean.emma_bedroom_cooling_on"] }, "data": {} } } let sendSleep = { "payload": { "action": `input_boolean.${setSleep}`, "target": { "entity_id": ["input_boolean.emma_sleeping"] }, "data": {} } } let sendPeople = { "payload": { "action": `input_boolean.${setPeople}`, "target": { "entity_id": ["input_boolean.emma_awake"] }, "data": {} } } let sendDisplay = { "payload": { "action": `switch.${setDisplay}`, "target": { "entity_id": ["switch.emma_bedroom_aircon_display"] }, "data": {} } } let sendWhiteNoise = { "payload": { "action": `input_boolean.${setWhiteNoise}`, "target": { "entity_id": emmaBedroomWhiteNoise }, "data": {} } } let notify = { "topic": topic, "nighttemp": nightTemp, "schedMode": schedMode } let sendHvac = { "payload": { "action": "climate.set_hvac_mode", "target": { "entity_id": emmaBedroomAircon }, "data": { "hvac_mode": setHvac } } } let sendTemp = { "payload": { "action": "climate.set_temperature", "target": { "entity_id": emmaBedroomAircon }, "data": { "temperature": setTemp } } } let sendEco = { "payload": { "action": "climate.set_preset_mode", "target": { "entity_id": emmaBedroomAircon }, "data": { "preset_mode": setEco } } } let sendAcFan = { "payload": { "action": "climate.set_fan_mode", "target": { "entity_id": emmaBedroomAircon }, "data": { "fan_mode": "auto" } } } node.log("Emma Bedroom Climate: Message Payloads Defined") // Send some parameters to flow context for use in other nodes if (setHvac.length > 0) { flow.set('emmaBedroom.airconHvacMode',setHvac,'diskCon') } if (setEco.length > 0) { flow.set('emmaBedroom.airconPreset',setEco,'diskCon') } if (setTemp.length > 0) { flow.set('emmaBedroom.airconTargetTemp',setTemp,'diskCon') } if (setDisplay.length > 0) { flow.set('emmaBedroom.airconDisplay',setDisplay,'diskCon') } flow.set('emmaBedroom.airconFanMode','auto','diskCon') // Log the parameters that were chosen, for debugging purposes node.log("----- Emma Bedroom Climate: Set Parameters -----") node.log(`setTemp: ${setTemp}`) node.log(`setEco: ${setEco}`) node.log(`setHvac: ${setHvac}`) node.log(`setCool: ${setCool}`) node.log(`setSleep: ${setSleep}`) node.log(`setPeople: ${setPeople}`) node.log(`setDisplay: ${setDisplay}`) node.log(`time: ${time}`) node.log(`type: ${type}`) node.log(`topic: ${topic}`) node.log("----- Emma Bedroom Climate: End Parameters -----") // If this was an automated trigger, set the cooling context for the bedroom accordingly. if (type === 'auto' && time != 'bedtime') { node.send([null, sendCool, null]) node.log("Emma Bedroom Climate: Cooling Context Set") } if (type === 'auto' && allowed === 'on' && meltdown === 'off' && vacation === 'off') { node.log("Emma Bedroom Climate: Auto") if (sleeping === 'on' && topic != 'emmabedroom-wakeup') { node.status({ fill: "red", shape: "ring", text: "Blocked (sleep mode)" }) node.log("Emma Bedroom Climate: Blocked (sleep mode)") } else { if (topic === 'emmabedroom-cooling' && ac === 'on') { node.status({ fill: "green", shape: "dot", text: "Cooling Schedule" }) node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null]) node.log("Emma Bedroom Climate: Auto/Cooling") } else if (topic === 'emmabedroom-bedtime') { node.send([null, sendPeople, null]) node.status({ fill: "green", shape: "dot", text: "Bedtime" }) node.log("Emma Bedroom Climate: Auto/Bedtime") if (validSchedModesAC.includes(schedMode) && ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null]) node.log("Emma Bedroom Climate: Auto/Bedtime/AC") } else if (schedMode === 'White Noise') { node.send([null, sendWhiteNoise, null]) node.log("Emma Bedroom Climate: Auto/Bedtime/White Noise") } } else if (topic === 'emmabedroom-wakeup') { node.status({ fill: "green", shape: "dot", text: "Wakeup Schedule" }) node.log("Emma Bedroom Climate: Auto/Wakeup") if (sleeping === 'off') { context.set("isWakeup", false) node.send([null, sendWhiteNoise, null]) node.log("Emma Bedroom Climate: Auto/Wakeup/Sleep Off") if (ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null]) node.log("Emma Bedroom Climate: Auto/Wakeup/AC On") } } else if (sleeping === 'on') { context.set("isWakeup", true) node.send([null, sendSleep, null]) node.log("Emma Bedroom Climate: Auto/Wakeup/Sleep On") } } } // Manual Responses } else if (type === 'manual') { node.log("Emma Bedroom Climate: Manual") if (time === 'night') { node.status({ fill: "blue", shape: "dot", text: "Manual Night" }) node.log("Emma Bedroom Climate: Manual/Night") if (ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null]) node.log("Emma Bedroom Climate: Manual/Night/AC") } } else if (time === 'day') { node.status({ fill: "blue", shape: "dot", text: "Manual Day" }) node.send([null, sendWhiteNoise, null]) node.log("Emma Bedroom Climate: Manual/Day") if (ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null]) node.log("Emma Bedroom Climate: Manual/Day/AC") } } else if (time === 'bedtime') { node.status({ fill: "blue", shape: "dot", text: "Manual Bedtime" }) node.log("Emma Bedroom Climate: Manual/Bedtime") if (validSchedModesAC.includes(schedMode) && ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null]) node.log("Emma Bedroom Climate: Manual/Bedtime/AC") } else if (schedMode === 'White Noise') { node.send([null, sendWhiteNoise, null]) node.log("Emma Bedroom Climate: Manual/Bedtime/White Noise") } } context.set("isWakeup", false) // Sleep Switch Responses } else if (type === 'sleep') { if (payload === 'off') { node.send([null, [sendPeople, sendWhiteNoise], null]) } node.log("Emma Bedroom Climate: Sleep") if (time === 'bedtime') { node.status({ fill: "blue", shape: "dot", text: "Sleep" }) node.send([null, [sendPeople, sendWhiteNoise], null]) node.log("Emma Bedroom Climate: Sleep/Bedtime") if (ac === 'on') { node.send([[sendDisplay, sendHvac, sendTemp, sendEco, sendAcFan], null, null]) node.log("Emma Bedroom Climate: Sleep/Bedtime/AC") } } else { node.status({ fill: "blue", shape: "dot", text: "Wakeup" }) node.send([null, sendWhiteNoise, null]) node.log("Emma Bedroom Climate: Sleep/Day") if (ac === 'on') { node.send([[sendDisplay, sendHvac, sendTemp, sendEco, sendAcFan], null, null]) node.log(`Emma Bedroom Climate: Sleep/${convertToTitleCase(time)}/AC`) } } context.set("isWakeup", false) } else if (meltdown === 'on') { node.status({ fill: "red", shape: "ring", text: "Blocked (Meltdown Protocol)" }) node.log("Emma Bedroom Climate: Blocked (Meltdown Protocol)") } else if (vacation === 'on') { node.status({ fill: "red", shape: "ring", text: "Blocked (Vacation Mode)" }) node.log("Emma Bedroom Climate: Blocked (Vacation Mode)") } else { node.status({ fill: "red", shape: "ring", text: "Blocked (Automation Disabled)" }) node.log("Emma Bedroom Climate: Blocked (Automation Disabled)") } node.log("Emma Bedroom Climate: Processing Complete")