node.log("Master Bedroom Climate: Processing Started") // pull in the necessary information const states = global.get('homeassistant.homeAssistant.states') const allowed = states['input_boolean.master_bedroom_climate_protocol'].state const ac = global.get('masterBedroom.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.master_bedroom_daytime_temp'].state const nightTemp = states['input_number.master_bedroom_night_temp'].state const bedTemp = states['input_number.master_bedroom_bedtime_temp'].state const showerMode = states['input_boolean.shower_mode'].state const nightVolume = states['input_number.master_bedroom_echo_dot_night_volume'].state const fanMode = states['input_select.scheduled_climate_mode_master_bedroom_fan'].state const acMode = states['input_select.scheduled_climate_mode_master_bedroom_aircon'].state const sleeping = states['input_boolean.master_bedroom_sleeping'].state const hotDay = states['input_boolean.hot_day'].state const heatWarning = states["binary_sensor.heat_warning"].state const showerCooldown = states["timer.shower_mode_cooldown"].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.master_bedroom_cooling_on'].state const echoDotDND = 'switch.basement_echo_dot_do_not_disturb_switch' node.log("Master Bedroom Climate: Constants Set") // Define some entity IDs const masterBedroomAircon = ["climate.master_bedroom_aircon"] const masterBedroomFan = ["fan.master_bedroom_fan"] const peopleIDs = ["input_boolean.tony_awake", "input_boolean.tina_awake"] // 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 setFan = [] let setCool = [] let setSleep = [] let setPeople = [] let setDisplay = [] let time = [] let echoDotService = [] let setBriefing = [] let setBriefingDelay = [] let type = msg.type let topic = msg.topic let isWakeup = context.get("isWakeup") node.log("Master Bedroom Climate: Variables Defined") // Sleep Switch Handling if (type === 'sleep' && payload === 'off') { setDisplay = 'turn_on' echoDotService = 'turn_off' setPeople = 'turn_on' if (coolingActive === 'on') { time = 'night' } else { time = 'day' } } else if (type === 'sleep' && payload === 'on') { setDisplay = 'turn_off' echoDotService = 'turn_on' time = 'bedtime' } else { time = msg.time } if (topic === 'mrbedroom-wakeup') { setSleep = 'turn_off' } // Setup TTS briefing if (topic === 'mrbedroom-wakeup') { setBriefing = "master_bedroom_wakeup_briefing" setBriefingDelay = 60000 } else if (type === 'sleep' && payload === 'off') { setBriefing = "master_bedroom_wakeup_briefing" setBriefingDelay = 15000 } // Day Time if (time === 'day') { if (type === 'auto') { setCool = 'turn_off' } if (earlyNight === 'off') { setFan = "turn_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 (fanMode === 'Fan') { setFan = 'turn_on' } else { setFan = 'turn_off' } if (acMode === 'AC') { setHvac = 'cool' } else if (acMode === '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.master_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 (acMode === 'AC') { setHvac = 'cool' } else if (acMode === 'Fan') { setHvac = 'fan_only' } else { setHvac = 'off' } // Decide fan on/off if (type === 'sleep' && payload === 'off') { setFan = 'turn_off' } else if (fanMode === 'Fan') { setFan = 'turn_on' } // Bed Time } else if (time === 'bedtime') { setPeople = 'turn_off' if (ac === 'on') { setTemp = bedTemp setEco = 'none' if (acMode === 'AC') { setHvac = 'cool' } else if (acMode === 'Fan') { setHvac = "fan_only" } else { setHvac = "off" } } if (fanMode === 'Fan') { setFan = 'turn_on' } else { setFan = 'turn_off' } } node.log("Master Bedroom Climate: Decision Logic Complete") // Define message payloads let sendFan = { "payload": { "action": `fan.${setFan}`, "target": { "entity_id": masterBedroomFan }, "data": {} } } let sendCool = { "payload": { "action": `input_boolean.${setCool}`, "target": { "entity_id": ["input_boolean.master_bedroom_cooling_on"] }, "data": {} } } let sendSleep = { "payload": { "action": `input_boolean.${setSleep}`, "target": { "entity_id": ["input_boolean.master_bedroom_sleeping"] }, "data": {} } } let sendPeople = { "payload": { "action": `input_boolean.${setPeople}`, "target": { "entity_id": peopleIDs }, "data": {} } } let sendDisplay = { "payload": { "action": `switch.${setDisplay}`, "target": { "entity_id": ["switch.master_bedroom_aircon_display"] }, "data": {} } } let notify = { "topic": topic, "nighttemp": nightTemp, "acmode": acMode, "fanmode": fanMode } let sendBriefing = { "payload": { "action": `script.${setBriefing}`, }, "delay": setBriefingDelay } let sendHvac = { "payload": { "action": "climate.set_hvac_mode", "target": { "entity_id": masterBedroomAircon }, "data": { "hvac_mode": setHvac } } } let sendTemp = { "payload": { "action": "climate.set_temperature", "target": { "entity_id": masterBedroomAircon }, "data": { "temperature": setTemp } } } let sendEco = { "payload": { "action": "climate.set_preset_mode", "target": { "entity_id": masterBedroomAircon }, "data": { "preset_mode": setEco } } } let sendAcFan = { "payload": { "action": "climate.set_fan_mode", "target": { "entity_id": masterBedroomAircon }, "data": { "fan_mode": "auto" } } } let sendEchoDotDND = { "payload": { "action": `switch.${echoDotService}`, "target": { "entity_id": ["switch.basement_echo_dot_do_not_disturb_switch"] }, "data": {} } } node.log("Master Bedroom Climate: Message Payloads Defined") // Log the parameters that were chosen, for debugging purposes node.log("----- Master Bedroom Climate: Set Parameters -----") node.log(`setTemp: ${setTemp}`) node.log(`setEco: ${setEco}`) node.log(`setHvac: ${setHvac}`) node.log(`setFan: ${setFan}`) node.log(`setCool: ${setCool}`) node.log(`setSleep: ${setSleep}`) node.log(`setPeople: ${setPeople}`) node.log(`setDisplay: ${setDisplay}`) node.log(`setBriefing: ${setBriefing}`) node.log(`setBriefingDelay: ${setBriefingDelay}`) node.log(`time: ${time}`) node.log(`type: ${type}`) node.log(`topic: ${topic}`) node.log("----- Master 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, null, sendCool, null, null]) node.log("Master Bedroom Climate: Cooling Context Set") } // Automated responses if (type === 'auto' && allowed === 'on' && meltdown === 'off' && vacation === 'off') { node.log("Master Bedroom Climate: Auto") if (sleeping === 'on' && topic != 'mrbedroom-wakeup') { node.status({ fill: "red", shape: "ring", text: "Blocked (sleep mode)" }) node.log("Master Bedroom Climate: Blocked (sleep mode)") } else { if (topic === 'mrbedroom-cooling' && ac === 'on') { node.status({ fill: "green", shape: "dot", text: "Cooling Schedule" }) node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null, null]) node.log("Master Bedroom Climate: Auto/Cooling") } else if (topic === 'mrbedroom-bedtime') { node.send([null, null, sendPeople, null, null]) node.status({ fill: "green", shape: "dot", text: "Bedtime" }) node.log("Master Bedroom Climate: Auto/Bedtime") if (ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null, null, null]) node.log("Master Bedroom Climate: Auto/Bedtime/AC") } if (fanMode === 'fan') { node.send([null, sendFan, null, null, null]) node.log("Master Bedroom Climate: Auto/Bedtime/Fan") } } else if (topic === 'mrbedroom-fan' && fanMode === 'Fan') { node.status({ fill: "green", shape: "dot", text: "Fan Schedule" }) node.send([null, sendFan, null, null, null]) node.log("Master Bedroom Climate: Auto/Fan") } else if (topic === 'mrbedroom-wakeup') { node.send([null, null, null, null, sendBriefing]) node.status({ fill: "green", shape: "dot", text: "Wakeup Schedule" }) node.log("Master Bedroom Climate: Auto/Wakeup") if (sleeping === 'off') { context.set("isWakeup", false) node.send([null, sendFan, null, null, null]) node.log("Master Bedroom Climate: Auto/Wakeup/Sleep Off") if (ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null, null, null]) node.log("Master Bedroom Climate: Auto/Wakeup/AC On") } } else if (sleeping === 'on') { context.set("isWakeup", true) node.send([null, null, sendSleep, null, null]) node.log("Master Bedroom Climate: Auto/Wakeup/Sleep On") } } } // Manual Responses } else if (type === 'manual') { node.log("Master Bedroom Climate: Manual") if (time === 'night') { node.status({ fill: "blue", shape: "dot", text: "Manual Night" }) node.send([null, sendFan, null, null, null]) node.log("Master Bedroom Climate: Manual/Night") if (ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null, null, null]) node.log("Master Bedroom Climate: Manual/Night/AC") } } else if (time === 'day') { node.status({ fill: "blue", shape: "dot", text: "Manual Day" }) node.send([null, sendFan, null, null, null]) node.log("Master Bedroom Climate: Manual/Day") if (ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null, null, null]) node.log("Master Bedroom Climate: Manual/Day/AC") } } else if (time === 'bedtime') { node.status({ fill: "blue", shape: "dot", text: "Manual Bedtime" }) node.send([null, sendFan, null, null, null]) node.log("Master Bedroom Climate: Manual/Bedtime") if (ac === 'on') { node.send([[sendHvac, sendTemp, sendEco, sendAcFan], null, null, null, null]) node.log("Master Bedroom Climate: Manual/Bedtime/AC") } } context.set("isWakeup", false) // Sleep Switch Responses } else if (type === 'sleep') { if (payload === 'off') { node.send([null, null, sendPeople, null, null]) } node.log("Master Bedroom Climate: Sleep") if (time === 'bedtime') { node.status({ fill: "blue", shape: "dot", text: "Sleep" }) node.send([null, sendFan, [sendEchoDotDND,sendPeople], null, null]) node.log("Master Bedroom Climate: Sleep/Bedtime") if (ac === 'on') { node.send([[sendDisplay, sendHvac, sendTemp, sendEco, sendAcFan], null, null, null, null]) node.log("Master Bedroom Climate: Sleep/Bedtime/AC") } } else { node.status({ fill: "blue", shape: "dot", text: "Wakeup" }) node.send([null, sendFan, sendEchoDotDND, null, null]) node.log("Master Bedroom Climate: Sleep/Day") if (ac === 'on') { node.send([[sendDisplay, sendHvac, sendTemp, sendEco, sendAcFan], null, null, null, null]) node.log(`Master Bedroom Climate: Sleep/${convertToTitleCase(time)}/AC`) } if (time === 'day' && isWakeup === false) { node.send([null, null, null, null, sendBriefing]) } } context.set("isWakeup", false) } else if (meltdown === 'on') { node.status({ fill: "red", shape: "ring", text: "Blocked (Meltdown Protocol)" }) node.log("Master Bedroom Climate: Blocked (Meltdown Protocol)") } else if (vacation === 'on') { node.status({ fill: "red", shape: "ring", text: "Blocked (Vacation Mode)" }) node.log("Master Bedroom Climate: Blocked (Vacation Mode)") } else { node.status({ fill: "red", shape: "ring", text: "Blocked (Automation Disabled)" }) node.log("Master Bedroom Climate: Blocked (Automation Disabled)") } node.log("Master Bedroom Climate: Processing Complete")