7 Commits

51 changed files with 923 additions and 1449 deletions

3
.gitignore vendored
View File

@ -1,2 +1 @@
**.vscode
testing/
/.vscode

View File

@ -1,6 +1,6 @@
const states = global.get('homeassistant.homeAssistant.states')
const allowed = states['input_boolean.basement_studio_heat_allowed'].state
const outsideTemp = global.get('outdoorTemp.tempInt')
const outsideTemp = states['weather.iron_nerd_weather_station'].attributes.temperature
const nightMode = states['input_boolean.night_mode'].state
let power = {}
@ -13,14 +13,14 @@ if (outsideTemp > 32) {
if (nightMode === 'on') {
preset = "frost"
} else {
preset = "activity"
preset = "eco"
}
}
if (allowed === 'on') {
if (power === 'on') {
msg.preset = preset
node.status({fill:'green',shape:'dot',text:`Preset ${preset}`})
node.status({fill:'green',shape:'dot',text:'Preset ' + preset})
node.send(msg,null)
} else {
node.status({fill:'red',shape:'ring',text:'Heater Shutoff'})

View File

@ -1,33 +0,0 @@
const states = global.get('homeassistant.homeAssistant.states')
const allowed = states['input_boolean.basement_studio_heat_allowed'].state
const outsideTemp = global.get('outdoorTemp.tempInt')
const todaysHighTemp = states['sensor.todays_high_temp'].state
const basementTemp = states['sensor.basement_studio_temperature'].state
let power = {}
let reason = {}
if (todaysHighTemp < 55) {
power = 'on'
reason = 'Todays High Temperature'
} else if (outsideTemp < 40) {
power = 'on'
reason = 'Outside Temperature'
} else if (basementTemp < 64) {
power = 'on'
reason = 'Basement Temperature'
} else {
power = 'off'
}
if (allowed === 'on') {
if (power === 'on') {
node.status({fill:'green',shape:'dot',text:`Heater Needed: ${reason}`})
node.send(msg,null)
} else {
node.status({fill:'red',shape:'ring',text:'Heater Not Needed'})
node.send(null,msg)
}
} else {
node.status({fill:'red',shape:'ring',text:'Heat Disabled'})
}

View File

@ -1,72 +0,0 @@
const states = global.get('homeassistant.homeAssistant.states')
const toggle = msg.payload
const ac = global.get('emmaBedroom.aircon.installed', "diskCon")
const lastMode = flow.get("emmaBedroom.lastMode", "diskCon")
const bedTemp = states['input_number.emma_bedroom_bedtime_temp'].state
let setTemp = bedTemp
let setEco = 'none'
let setHvac = 'cool'
let setAcFan = 'High'
let sendHvac = {
"payload": {
"action": "climate.set_hvac_mode",
"target": {
"entity_id": ["climate.emma_bedroom_aircon"]
},
"data": {
"hvac_mode": setHvac
}
}
}
let sendTemp = {
"payload": {
"action": "climate.set_temperature",
"target": {
"entity_id": ["climate.emma_bedroom_aircon"]
},
"data": {
"temperature": setTemp
}
}
}
let sendEco = {
"payload": {
"action": "climate.set_preset_mode",
"target": {
"entity_id": ["climate.emma_bedroom_aircon"]
},
"data": {
"preset_mode": setEco
}
}
}
let sendAcFan = {
"payload": {
"action": "climate.set_fan_mode",
"target": {
"entity_id": ["climate.emma_bedroom_aircon"]
},
"data": {
"fan_mode": setAcFan
}
}
}
let reset = {
"topic": "Reset"
}
if (toggle === 'on') {
node.status({fill:"red",shape:"dot",text:"DANGER MODE ACTIVE"})
if (ac === 'on') {
node.send([[sendHvac,sendTemp,sendEco,sendTemp],null])
}
} else {
node.status({fill:"green",shape:"dot",text:"Danger Mode Off"})
node.send([null,reset])
}

View File

@ -1,25 +0,0 @@
const topic = msg.topic
const nightTemp = msg.nighttemp
const acMode = msg.acmode
let coolMsg = {
"payload": `Emma bedroom AC temp has been set to ${nightTemp} °F as scheduled`,
"topic": 'Emma AC Mode: Cooling'
}
let fanOnlyMsg = {
"payload": 'Mildly chilly outside, AC running fan only.',
"topic": "Emma AC Mode: Fan Only"
}
if (topic === 'emmabedroom-cooling') {
if (acMode === 'AC') {
node.status({fill:"green",shape:"dot",text:"AC Cooling"})
return coolMsg
} else if (acMode === 'Fan') {
node.status({fill:"green",shape:"dot",text:"AC Fan Only"})
return fanOnlyMsg
}
} else {
node.status({fill:"red",shape:"ring",text:"Notification not sent"})
return null
}

View File

@ -1,420 +0,0 @@
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")

View File

@ -1,30 +0,0 @@
const lastMode = flow.get("emmaBedroom.lastMode", "diskCon")
const linkSource = msg._linkSource
let setTime = []
let setType = []
let setTopic = []
if (lastMode === 'day') {
setTime = 'day'
setType = 'manual'
setTopic = 'manual-day'
} else if (lastMode === 'night') {
setTime = 'night'
setType = 'manual'
setTopic = 'manual-night'
} else if (lastMode === 'bedtime') {
setTime = 'bedtime'
setType = 'manual'
setTopic = 'manual-bedtime'
}
let reset = {
"type": setType,
"time": setTime,
"topic": setTopic,
"_linkSource": linkSource
}
node.send(reset)
node.status({ fill: "green", shape: "dot", text: `Mode reset to ${setTopic}`})

View File

@ -1,20 +0,0 @@
const states = global.get("homeassistant.homeAssistant.states")
const sleeping = states["input_boolean.emma_sleeping"].state
const earlyNight = states["binary_sensor.early_night_mode"].state
const giveMeDarkness = states["input_boolean.give_me_darkness"].state
const nightMode = states["input_boolean.night_mode"].state
const goodnight = states["input_boolean.goodnight"].state
const coolingActive = states['input_boolean.emma_bedroom_cooling_on'].state
let lastMode = []
if (sleeping === 'on' || nightMode === 'on' || goodnight === 'on') {
lastMode = 'bedtime'
} else if (earlyNight === 'on' || giveMeDarkness === 'on' || coolingActive === 'on') {
lastMode = 'night'
} else {
lastMode = 'day'
}
flow.set("emmaBedroom.lastMode", lastMode, "diskCon")
node.status({ fill: "green", shape: "dot", text: `Last Mode Set: ${lastMode}`})

View File

@ -1,18 +0,0 @@
const airconState = msg.payload.state
const airconAttributes = msg.payload.attributes
const airconPreset = airconAttributes['preset_mode']
const airconEco = airconAttributes['eco_mode']
const airconTargetTemp = airconAttributes['temperature']
const airconFanMode = airconAttributes['fan_mode']
const airconDisplay = airconAttributes['screen_display']
msg.payload = {
"airconState": airconState,
"airconPreset": airconPreset,
"airconEco": airconEco,
"airconTargetTemp": airconTargetTemp,
"airconFanMode": airconFanMode,
"airconDisplay": airconDisplay
}
return msg

View File

@ -8,15 +8,10 @@ const brightness = states['switch.adaptive_lighting_kallen_bedroom'].attributes.
const fadeNight = states['input_number.wakeup_lights_fade_night'].state
const hotDay = states['input_boolean.hot_day'].state
const heatWarning = states['binary_sensor.heat_warning'].state
const fanState = states['fan.kallen_bedroom_fan'].state
const fanAvailable = fanState !== 'unavailable'
const fanSeparate = states['binary_sensor.kallen_fan_separate_schedule'].state
const schedMode = states['input_select.scheduled_climate_mode_kallen_bedroom'].state
const topic = msg.topic
const toggle = msg.toggle || ''
const roomName = 'Kallen Bedroom'
const toggle = msg.toggle
node.log("Kallen Bedroom: Constants Set")
let setFan = []
@ -24,40 +19,27 @@ let setWhiteNoise = []
let setVolume = []
let setLights = []
let setWake = []
node.log(`${roomName}: Variables Defined`)
node.log("Kallen Bedroom: Variables Defined")
if (schedMode === 'White Noise') {
setFan = 'turn_off'
if (toggle === 'off' && (hotDay === 'on' || heatWarning === 'on')) {
setFan = 'turn_on'
} else if ((toggle === 'on' || topic === 'kallen-fan') && schedMode === 'Fan') {
setFan = 'turn_on'
} else {
if (fanAvailable) {
if (toggle === 'off' && (hotDay === 'on' || heatWarning === 'on')) {
setFan = 'turn_on'
} else if ((toggle === 'on' || topic === 'kallen-fan') && schedMode === 'Fan') {
setFan = 'turn_on'
} else {
setFan = 'turn_off'
}
} else {
if (schedMode === 'Fan') {
node.log(`${roomName}: Fan is unavailable, forcing White Noise mode`)
}
setFan = 'turn_off'
}
}
if ((schedMode === 'White Noise' && toggle === 'on') || (schedMode === 'Fan' && !fanAvailable)) {
setWhiteNoise = 'turn_on'
} else if (topic === 'kallen-fan' && !fanAvailable && schedMode !== 'N/A') {
if (schedMode === 'White Noise' && toggle === 'on') {
setWhiteNoise = 'turn_on'
} else {
setWhiteNoise = 'turn_off'
}
if (topic === 'boolean' && toggle === 'on') {
if (toggle === 'on') {
setVolume = parseFloat(nightVolume)
setLights = 'turn_on'
setWake = 'turn_off'
} else if (topic === 'boolean' && toggle === 'off') {
} else {
setVolume = parseFloat(dayVolume)
setWake = 'turn_on'
}
@ -67,11 +49,12 @@ let fadeFinal = Math.round(fadeMult)
let brtFinal = Math.round(brightness)
node.log(`${roomName}: Decision Logic Complete`)
node.log("Kallen Bedroom: Decision Logic Complete")
let sendFan = {
"payload": {
"action": `fan.${setFan}`,
"domain": "fan",
"service": setFan,
"target": {
"entity_id": ["fan.kallen_bedroom_fan"]
},
@ -81,7 +64,8 @@ let sendFan = {
let sendWhiteNoise = {
"payload": {
"action": `input_boolean.${setWhiteNoise}`,
"domain": "input_boolean",
"service": setWhiteNoise,
"target": {
"entity_id": ["input_boolean.white_noise_kallen_bedroom"]
},
@ -91,7 +75,8 @@ let sendWhiteNoise = {
let sendVolume = {
"payload": {
"action": "media_player.volume_set",
"domain": "media_player",
"service": "volume_set",
"target": {
"entity_id": ["media_player.kallen_bedroom_google_speaker"]
},
@ -103,7 +88,8 @@ let sendVolume = {
let sendLights = {
"payload": {
"action": `light.${setLights}`,
"domain": "light",
"service": setLights,
"target": {
"entity_id": ["light.kallen_bedroom_lights"]
},
@ -113,7 +99,8 @@ let sendLights = {
let sendWake = {
"payload": {
"action": `input_boolean.${setWake}`,
"domain": "input_boolean",
"service": setWake,
"target": {
"entity_id": ["input_boolean.kallen_awake"]
},
@ -130,34 +117,33 @@ let sleepMsg = {
"payload": "sleep"
}
node.log(`${roomName}: Message Payloads Defined`)
node.log("Kallen Bedroom: Message Payloads Defined")
node.log(`----- ${roomName}: Set Parameters -----`)
node.log(`${roomName}: fanAvailable: ${fanAvailable}`)
node.log(`${roomName}: setFan: ${setFan}`)
node.log(`${roomName}: setWhiteNoise: ${setWhiteNoise}`)
node.log(`${roomName}: setVolume: ${setVolume}`)
node.log(`${roomName}: setLights: ${setLights}`)
node.log(`${roomName}: setWake: ${setWake}`)
node.log(`----- ${roomName}: End Parameters -----`)
node.log("----- Kallen Bedroom: Set Parameters -----")
node.log("setFan: " + setFan)
node.log("setWhiteNoise: " + setWhiteNoise)
node.log("setVolume: " + setVolume)
node.log("setLights: " + setLights)
node.log("setWake: " + setWake)
node.log("----- Kallen Bedroom: End Parameters -----")
if (vacationMode === 'off' && overnight === 'off' && kallenLoc === 'home') {
if (topic === 'kallen-fan' && fanSeparate === 'on') {
node.status({fill:"green",shape:"dot",text:"Fan"})
node.log(`${roomName}: Early Fan`)
node.log("Kallen Bedroom: Early Fan")
node.send([null,[sendFan,sendWhiteNoise],null])
} else if (topic === 'boolean' && toggle === 'off') {
} else if (toggle === 'off') {
node.status({fill:"green",shape:"dot",text:"Wakeup"})
node.log(`${roomName}: Wake`)
node.log("Kallen Bedroom: Wake")
node.send([wakeMsg,[sendFan,sendWhiteNoise,sendVolume,sendWake],null])
} else if (topic === 'boolean' && toggle === 'on') {
} else if (toggle === 'on') {
node.status({fill:"green",shape:"dot",text:"Sleep"})
node.log(`${roomName}: Sleep`)
node.log("Kallen Bedroom: Sleep")
node.send([null,[sendFan,sendWhiteNoise,sendVolume,sendLights,sendWake],sleepMsg])
}
} else {
node.status({fill:"red",shape:"ring",text:"Blocked"})
node.log(`${roomName}: Flow Blocked`)
node.log("Kallen Bedroom: Flow Blocked")
}
node.log(`${roomName}: Processing Complete`)
node.log("Kallen Bedroom: Processing Complete")

View File

@ -1,7 +1,7 @@
const states = global.get('homeassistant.homeAssistant.states')
const toggle = msg.payload
const ac = global.get('masterBedroom.aircon.installed', "diskCon")
const lastMode = flow.get("masterBedroom.lastMode", "diskCon")
const ac = global.get('mb_aircon_installed', "diskCon")
const lastMode = flow.get("lastMode", "diskCon")
const bedTemp = states['input_number.master_bedroom_bedtime_temp'].state
let setTemp = bedTemp
@ -12,7 +12,8 @@ let setFan = 'turn_off'
let sendFan = {
"payload": {
"action": `fan.${setFan}`,
"domain": "fan",
"service": setFan,
"target": {
"entity_id": ["fan.master_bedroom_fan"]
},
@ -22,7 +23,8 @@ let sendFan = {
let sendHvac = {
"payload": {
"action": "climate.set_hvac_mode",
"domain": "climate",
"service": "set_hvac_mode",
"target": {
"entity_id": ["climate.master_bedroom_aircon"]
},
@ -34,7 +36,8 @@ let sendHvac = {
let sendTemp = {
"payload": {
"action": "climate.set_temperature",
"domain": "climate",
"service": "set_temperature",
"target": {
"entity_id": ["climate.master_bedroom_aircon"]
},
@ -46,7 +49,8 @@ let sendTemp = {
let sendEco = {
"payload": {
"action": "climate.set_preset_mode",
"domain": "climate",
"service": "set_preset_mode",
"target": {
"entity_id": ["climate.master_bedroom_aircon"]
},
@ -58,7 +62,8 @@ let sendEco = {
let sendAcFan = {
"payload": {
"action": "climate.set_fan_mode",
"domain": "climate",
"service": "set_fan_mode",
"target": {
"entity_id": ["climate.master_bedroom_aircon"]
},

View File

@ -4,7 +4,7 @@ const acMode = msg.acmode
const fanMode = msg.fanmode
let coolMsg = {
"payload": `Master bedroom AC temp has been set to ${nightTemp} °F as scheduled`,
"payload": 'Master bedroom AC temp has been set to ' + nightTemp + '°F as scheduled',
"topic": 'AC Mode: Cooling'
}
let fanOnlyMsg = {

View File

@ -3,8 +3,8 @@ node.log("Master Bedroom Climate: Processing Started")
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 ac = global.get('mb_aircon_installed', "diskCon")
const temp = global.get("tempStr")
const payload = msg.payload
const vacation = states['input_boolean.vacation_mode'].state
const dayTemp = states['input_number.master_bedroom_daytime_temp'].state
@ -25,21 +25,6 @@ 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 = []
@ -198,9 +183,10 @@ node.log("Master Bedroom Climate: Decision Logic Complete")
let sendFan = {
"payload": {
"action": `fan.${setFan}`,
"domain": "fan",
"service": setFan,
"target": {
"entity_id": masterBedroomFan
"entity_id": ["fan.master_bedroom_fan"]
},
"data": {}
}
@ -208,7 +194,8 @@ let sendFan = {
let sendCool = {
"payload": {
"action": `input_boolean.${setCool}`,
"domain": "input_boolean",
"service": setCool,
"target": {
"entity_id": ["input_boolean.master_bedroom_cooling_on"]
},
@ -218,7 +205,8 @@ let sendCool = {
let sendSleep = {
"payload": {
"action": `input_boolean.${setSleep}`,
"domain": "input_boolean",
"service": setSleep,
"target": {
"entity_id": ["input_boolean.master_bedroom_sleeping"]
},
@ -228,9 +216,10 @@ let sendSleep = {
let sendPeople = {
"payload": {
"action": `input_boolean.${setPeople}`,
"domain": "input_boolean",
"service": setPeople,
"target": {
"entity_id": peopleIDs
"entity_id": ["input_boolean.tony_awake","input_boolean.tina_awake"]
},
"data": {}
}
@ -238,7 +227,8 @@ let sendPeople = {
let sendDisplay = {
"payload": {
"action": `switch.${setDisplay}`,
"domain": "switch",
"service": setDisplay,
"target": {
"entity_id": ["switch.master_bedroom_aircon_display"]
},
@ -255,16 +245,18 @@ let notify = {
let sendBriefing = {
"payload": {
"action": `script.${setBriefing}`,
"domain": "script",
"service": setBriefing
},
"delay": setBriefingDelay
}
let sendHvac = {
"payload": {
"action": "climate.set_hvac_mode",
"domain": "climate",
"service": "set_hvac_mode",
"target": {
"entity_id": masterBedroomAircon
"entity_id": ["climate.master_bedroom_aircon"]
},
"data": {
"hvac_mode": setHvac
@ -274,9 +266,10 @@ let sendHvac = {
let sendTemp = {
"payload": {
"action": "climate.set_temperature",
"domain": "climate",
"service": "set_temperature",
"target": {
"entity_id": masterBedroomAircon
"entity_id": ["climate.master_bedroom_aircon"]
},
"data": {
"temperature": setTemp
@ -286,9 +279,10 @@ let sendTemp = {
let sendEco = {
"payload": {
"action": "climate.set_preset_mode",
"domain": "climate",
"service": "set_preset_mode",
"target": {
"entity_id": masterBedroomAircon
"entity_id": ["climate.master_bedroom_aircon"]
},
"data": {
"preset_mode": setEco
@ -298,9 +292,10 @@ let sendEco = {
let sendAcFan = {
"payload": {
"action": "climate.set_fan_mode",
"domain": "climate",
"service": "set_fan_mode",
"target": {
"entity_id": masterBedroomAircon
"entity_id": ["climate.master_bedroom_aircon"]
},
"data": {
"fan_mode": "auto"
@ -310,7 +305,8 @@ let sendAcFan = {
let sendEchoDotDND = {
"payload": {
"action": `switch.${echoDotService}`,
"domain": "switch",
"service": echoDotService,
"target": {
"entity_id": ["switch.basement_echo_dot_do_not_disturb_switch"]
},
@ -323,19 +319,19 @@ 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("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.
@ -426,7 +422,26 @@ if (type === 'auto' && allowed === 'on' && meltdown === 'off' && vacation === 'o
node.send([null, null, sendPeople, null, null])
}
node.log("Master Bedroom Climate: Sleep")
if (time === 'bedtime') {
if (time === 'night') {
node.status({ fill: "blue", shape: "dot", text: "Wakeup (Hot Day)" })
node.send([null, sendFan, sendEchoDotDND, null, null])
node.log("Master Bedroom Climate: Sleep/Night")
if (ac === 'on') {
node.send([[sendDisplay, sendHvac, sendTemp, sendEco, sendAcFan], null, null, null])
node.log("Master Bedroom Climate: Sleep/Night/AC")
}
} else if (time === 'day') {
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/Day/AC")
}
if (isWakeup === false) {
node.send([null, null, null, null, sendBriefing])
}
} else 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")
@ -434,17 +449,6 @@ if (type === 'auto' && allowed === 'on' && meltdown === 'off' && vacation === 'o
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') {

View File

@ -1,4 +1,4 @@
const lastMode = flow.get('masterBedroom.lastMode', "diskCon")
const lastMode = flow.get('lastMode', "diskCon")
const linkSource = msg._linkSource
let setTime = []
@ -27,4 +27,4 @@ let reset = {
}
node.send(reset)
node.status({ fill: "green", shape: "dot", text: `Mode reset to ${setTopic}`})
node.status({ fill: "green", shape: "dot", text: "Mode reset to " + setTopic})

View File

@ -16,5 +16,5 @@ if (sleeping === 'on' || nightMode === 'on' || goodnight === 'on') {
lastMode = 'day'
}
flow.set("masterBedroom.lastMode", lastMode, "diskCon")
node.status({ fill: "green", shape: "dot", text: `Last Mode Set: ${lastMode}`})
flow.set("lastMode", lastMode, "diskCon")
node.status({ fill: "green", shape: "dot", text: "Last Mode Set: " + lastMode})

View File

@ -1,6 +1,6 @@
const states = global.get('homeassistant.homeAssistant.states')
const ac = global.get('masterBedroom.aircon.installed', "diskCon")
const temp = global.get('outdoorTemp.tempStr')
const ac = states['input_boolean.master_bedroom_aircon_installed'].state
const temp = global.get('tempStr')
const threshold = states['input_number.master_bedroom_aircon_run_threshold'].state
const dayTemp = states['input_number.master_bedroom_daytime_temp'].state
const nightTemp = states['input_number.master_bedroom_night_temp'].state

View File

@ -1,6 +1,6 @@
const states = global.get('homeassistant.homeAssistant.states')
const ac = global.get('masterBedroom.aircon.installed', "diskCon")
const temp = global.get('outdoorTemp.tempStr')
const ac = states['input_boolean.master_bedroom_aircon_installed'].state
const temp = global.get('tempStr')
const threshold = states['input_number.master_bedroom_aircon_run_threshold'].state
const nightTemp = states['input_number.master_bedroom_night_temp'].state
const bedTemp = states['input_number.master_bedroom_bedtime_temp'].state
@ -10,11 +10,11 @@ if (ac === 'on') {
if (temp >= threshold) {
if (sleeping === 'on') {
msg.set = bedTemp
node.status({fill:"green",shape:"dot",text:`Shower Mode On: ${bedTemp}`})
node.status({fill:"green",shape:"dot",text:"Shower Mode On: " + bedTemp})
return msg
} else {
msg.set = nightTemp
node.status({fill:"green",shape:"dot",text:`Shower Mode On: ${nightTemp}`})
node.status({fill:"green",shape:"dot",text:"Shower Mode On: " + nightTemp})
return msg
}
} else {

View File

@ -7,22 +7,17 @@ const payload = msg.payload
const newDuration = duration * 60
if (payload === 'on') {
if (lux <= threshold && lights === 'off') {
node.status({fill:'green',shape:'dot',text:'Turning lights on'})
node.send([msg,msg,null])
} else {
if (lights === 'on') {
node.status({fill:'red',shape:'ring',text:'Lights already on'})
node.send([null,msg,null])
if (lux <= threshold || lights === 'on') {
node.status({fill:'green',shape:'dot',text:'Lights On'})
node.send([msg,null])
} else {
node.status({fill:'red',shape:'ring',text:'Too bright'})
}
}
} else if (payload === 'off') {
if (lights === 'on') {
msg.duration = newDuration
node.status({fill:"green",shape:"dot",text:parseInt(duration) + ' minutes'})
node.send([null,null,msg])
node.send([null,msg])
} else {
node.status({fill:"red",shape:"ring",text:"Lights already off"})
}

View File

@ -1,6 +1,5 @@
const states = global.get('homeassistant.homeAssistant.states')
const lights = states['light.mud_room_overhead'].state
const selScene = states['input_text.mud_room_selected_scene'].state
const duration = states['input_number.mud_room_lights_off_delay'].state
const lux = parseInt(states['sensor.mud_room_illuminance'].state)
const threshold = parseInt(states['input_number.mud_room_lux_threshold'].state)
@ -8,22 +7,17 @@ const payload = msg.payload
const newDuration = duration * 60
if (payload === 'on') {
if (lux <= threshold && (lights === 'off' || selScene === 'Nightlight')) {
node.status({fill:'green',shape:'dot',text:'Turning lights on'})
node.send([msg,msg,null])
} else {
if (lights === 'on') {
node.status({fill:'red',shape:'ring',text:'Lights already on'})
node.send([null,msg,null])
if (lux <= threshold || lights === 'on') {
node.status({fill:'green',shape:'dot',text:'Lights On'})
node.send([msg,null])
} else {
node.status({fill:'red',shape:'ring',text:'Too bright'})
}
}
} else if (payload === 'off') {
if (lights === 'on') {
msg.duration = newDuration
node.status({fill:"green",shape:"dot",text:parseInt(duration) + ' minutes'})
node.send([null,null,msg])
node.send([null,msg])
} else {
node.status({fill:"red",shape:"ring",text:"Lights already off"})
}

View File

@ -1,30 +0,0 @@
const states = global.get('homeassistant.homeAssistant.states')
const schoolToday = states['input_boolean.kallen_school_today'].state
const kallen = states['person.kallen_stork'].state
const morning = states['binary_sensor.morning'].state
let basement = {
"payload": {
"action": "script.goodnight_in_basement"
}
}
let firstFloor = {
"payload": {
"action": "script.goodnight_on_first_floor"
}
}
let secondFloor = {
"payload": {
"action": "script.goodnight_on_second_floor"
}
}
if (schoolToday === 'on' && kallen === 'home' && morning === 'on') {
node.send([[basement,secondFloor]])
node.status({fill:'yellow',shape:'dot',text:'Kallen waiting for school bus'})
} else {
node.send([[basement,firstFloor,secondFloor]])
node.status({fill:'green',shape:'dot',text:'All scripts sent'})
}

View File

@ -1,25 +0,0 @@
const states = global.get('homeassistant.homeAssistant.states')
const schoolToday = states['input_boolean.kallen_school_today'].state
const kallen = states['person.kallen_stork'].state
const morning = states['binary_sensor.morning'].state
const masterBedroomSleeping = states['input_boolean.master_bedroom_sleeping'].state
const payload = msg.payload
let presence = {}
if (payload === 'home') {
presence = 'on'
} else if (payload != 'unavailable' && payload != 'unknown') {
presence = 'off'
}
if (schoolToday === 'on' && kallen != 'home' && morning === 'on') {
if (presence === 'off' && masterBedroomSleeping === 'on') {
node.send(msg)
node.status({fill:'green',shape:'dot',text:'Kallen left, first floor lights off'})
} else {
return null
}
} else {
return null
}

View File

@ -1,20 +0,0 @@
const statusCode = msg.statusCode
const issueNumber = msg.payload.number
const issueTitle = msg.payload.title
const url = msg.payload.html_url
const user = msg.user
let notification = {
"title": "Issue Submitted",
"message": `${user.firstName} ${user.lastName} submitted a new issue: #${issueNumber} - ${issueTitle}`,
"actions": [
{
"action": "URI",
"uri": url,
"title": "View Issue"
}
]
}
node.send(notification)
node.status({fill:'green',shape:'dot',text:`Issue #${issueNumber} notification sent`})

View File

@ -1,33 +0,0 @@
const needsReponseLabel = flow.get("needsReponseLabel", "diskCon")
const typeBugLabel = flow.get("typeBugLabel", "diskCon")
const typeEnhancementLabel = flow.get("typeEnhancementLabel", "diskCon")
const typeAdjustmentLabel = flow.get("typeAdjustmentLabel", "diskCon")
const title = msg.text
const type = msg.type
const user = msg.user
let labels = [needsReponseLabel]
let formatType = {}
if (type === 'Bug Report') {
labels.push(typeBugLabel)
formatType = "[Bug]"
} else if (type === 'New Idea') {
labels.push(typeEnhancementLabel)
formatType = "[Feature Request]"
} else if (type === 'Adjustment') {
labels.push(typeAdjustmentLabel)
formatType = "[Adjustment Request]"
}
let newTitle = `${formatType}: ${title}`
msg.payload = {
"title": newTitle,
"body": `This issue was submitted by ${user.firstName} ${user.lastName}, using the automated form on the main Home Assistant dashboard`,
"assignees":["tm24fan8"],
"labels": labels
}
node.status({fill:'green',shape:'dot',text:'API data prepped'})
return msg

View File

@ -1,21 +0,0 @@
const states = global.get('homeassistant.homeAssistant.states')
const text = states['input_text.report_system'].state
const type = states['input_select.report_type'].state
const resetText = 'Type your report here'
const resetType = 'Bug Report'
msg.text = text
msg.type = type
msg.reset_text = resetText
msg.reset_type = resetType
if (type === "New Idea") {
node.status({fill:"green",shape:"dot",text:"New Idea"})
} else if (type === "Bug Report") {
node.status({fill:"green",shape:"dot",text:"Bug Report"})
} else if (type === "Adjustment") {
node.status({fill:"green",shape:"dot",text:"Adjustment"})
}
return msg

View File

@ -1,9 +0,0 @@
const needsReponseLabel = 213
const typeBugLabel = 196
const typeEnhancementLabel = 198
const typeAdjustmentLabel = 208
flow.set("needsReponseLabel", needsReponseLabel, "diskCon")
flow.set("typeBugLabel", typeBugLabel, "diskCon")
flow.set("typeEnhancementLabel", typeEnhancementLabel, "diskCon")
flow.set("typeAdjustmentLabel", typeAdjustmentLabel, "diskCon")

View File

@ -6,7 +6,7 @@ if (msg.lights === 'on') {
node.status({fill:"green",shape:"dot",text:"Lights Controlled"})
return[null,msg]
} else {
node.status({fill:"red",shape:"ring",text:`N/A in ${msg.room}`})
node.status({fill:"red",shape:"ring",text:"N/A in " + msg.room})
return null
}
} else {

View File

@ -68,7 +68,8 @@ if (payload === 'start') {
// Prepare message payloads
let sendTimerStart = {
"payload": {
"action": "timer.start",
"domain": "timer",
"service": "start",
"target": {
"entity_id": timerEntity
},
@ -80,7 +81,8 @@ let sendTimerStart = {
let sendTimerCancel = {
"payload": {
"action": "timer.cancel",
"domain": "timer",
"service": "cancel",
"target": {
"entity_id": timerEntity
},
@ -90,7 +92,8 @@ let sendTimerCancel = {
let sendBoolFinished = {
"payload": {
"action": "input_boolean." + servFinished,
"domain": "input_boolean",
"service": servFinished,
"target": {
"entity_id": boolFinished
},
@ -100,7 +103,8 @@ let sendBoolFinished = {
let sendDateTimeFinished = {
"payload": {
"action": "input_datetime.set_datetime",
"domain": "input_datetime",
"service": "set_datetime",
"target": {
"entity_id": dateTimeEntity
},

View File

@ -10,6 +10,13 @@ const segLivingRoom2 = [10,11,12,13,14,15,16,17,18,19]
const segLivingRoom3 = [20,21,22,23,24,25,26,27,28,29]
const segLivingRoom4 = [30,31,32,33,34,35,36,37,38,39]
// Preset effect segments for living room LED strip
const effectSegLivingRoom1 = [].concat(segLivingRoom1, segLivingRoom3)
const effectSegLivingRoom2 = [].concat(segLivingRoom2, segLivingRoom4)
// Full strip for living room LED strip
const livingRoomFull = [].concat(halfLivingRoom1, halfLivingRoom2)
// Half and half for basement LED strip
const halfBasement1 = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
const halfBasement2 = [16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]
@ -20,18 +27,65 @@ const segBasement2 = [8,9,10,11,12,13,14,15]
const segBasement3 = [16,17,18,19,20,21,22,23]
const segBasement4 = [24,25,26,27,28,29,30,31]
// Preset effect segments for basement LED strip
const effectSegBasement1 = [].concat(segBasement1, segBasement3)
const effectSegBasement2 = [].concat(segBasement2, segBasement4)
// Full strip for basement LED strip
const basementFull = [].concat(halfBasement1, halfBasement2)
// Adaptive Lighting switches
const adaptiveFirstFloor = [
"switch.adaptive_lighting_living_room",
"switch.adaptive_lighting_dining_room_lamp",
"switch.adaptive_lighting_tina_lamp"]
const adaptiveBasement = [
"switch.adaptive_lighting_basement_studio"
]
// Define light arrays for backup scenes
const lightsTinaDesk = ['light.tina_desk_strip','light.tina_lamp_top','light.tina_lamp_side']
const lightsBasement = ['light.basement_tall_lamp','light.basement_short_lamp','light.basement_stairwell','light.basement_led_strip_1']
const lightsLivingRoom = ['light.living_room_color_1','light.living_room_color_2','light.living_room_color_3','light.living_room_led_strip']
const lightsDiningRoom = ['light.dining_room_lamp']
const lightsStairwell = ['light.stairwell_led_strip']
// Write flow variables
flow.set("halfLivingRoom1", halfLivingRoom1, "diskCon")
flow.set("halfLivingRoom2", halfLivingRoom1, "diskCon")
flow.set("halfLivingRoom2", halfLivingRoom2, "diskCon")
flow.set("segLivingRoom1", segLivingRoom1, "diskCon")
flow.set("segLivingRoom2", segLivingRoom2, "diskCon")
flow.set("segLivingRoom3", segLivingRoom3, "diskCon")
flow.set("segLivingRoom4", segLivingRoom4, "diskCon")
flow.set("effectSegLivingRoom1", effectSegLivingRoom1, "diskCon")
flow.set("effectSegLivingRoom2", effectSegLivingRoom2, "diskCon")
flow.set("livingRoomFull", livingRoomFull, "diskCon")
flow.set("halfBasement1", halfBasement1, "diskCon")
flow.set("halfBasement2", halfBasement1, "diskCon")
flow.set("halfBasement2", halfBasement2, "diskCon")
flow.set("segBasement1", segBasement1, "diskCon")
flow.set("segBasement2", segBasement2, "diskCon")
flow.set("segBasement3", segBasement3, "diskCon")
flow.set("segBasement4", segBasement4, "diskCon")
flow.set("effectSegBasement1", effectSegBasement1, "diskCon")
flow.set("effectSegBasement2", effectSegBasement2, "diskCon")
flow.set("basementFull", basementFull, "diskCon")
flow.set("adaptiveFirstFloor", adaptiveFirstFloor, "diskCon")
flow.set("adaptiveBasement", adaptiveBasement, "diskCon")
flow.set('lightsTinaDesk', lightsTinaDesk, 'diskCon')
flow.set('lightsBasement', lightsBasement, 'diskCon')
flow.set('lightsLivingRoom', lightsLivingRoom, 'diskCon')
flow.set('lightsDiningRoom', lightsDiningRoom, 'diskCon')
flow.set('lightsStairwell', lightsStairwell, 'diskCon')
flow.set('alertFirstFloor', false)
flow.set('alertBasement', false)

View File

@ -1,36 +1,368 @@
// Set constants
const states = global.get('homeassistant.homeAssistant.states')
const occupied = states["binary_sensor.basement_occupied"].state
const quiet = states["input_boolean.studio_quiet"].state
const deskState = states["light.tina_desk_lights"].state
const livingRoomState = states["light.living_room_lights"].state
const diningRoomState = states["light.dining_room_lamp"].state
const basementState = states["light.basement_studio_lights"].state
const where = msg.payload.event.where
const type = msg.payload.event.type
const stateTinaDesk = states["light.tina_desk_lights"].state
const stateLivingRoom = states["light.living_room_lights"].state
const stateDiningRoom = states["light.dining_room_lamp"].state
const stateStairwell = states["light.stairwell_led_strip"].state
const stateBasement = states["light.basement_studio_lights"].state
const adaptLivingRoom = states["switch.adaptive_lighting_living_room"].state
const adaptDiningRoom = states["switch.adaptive_lighting_dining_room_lamp"].state
const adaptBasement = states["switch.adaptive_lighting_basement_studio"].state
const nightLivingRoom = states["switch.adaptive_lighting_sleep_mode_living_room"].state
const nightDiningRoom = states["switch.adaptive_lighting_sleep_mode_dining_room_lamp"].state
const nightBasement = states["switch.adaptive_lighting_sleep_mode_basement_studio"].state
const currentSceneBasement = states["input_text.basement_studio_selected_scene"].state
const currentSceneLivingRoom = states["input_text.living_room_selected_scene"].state
const currentSceneTinaDesk = states["input_text.tina_desk_selected_scene"].state
const currentSceneDiningRoom = states["input_text.dining_room_lamp_selected_scene"].state
const effectBasement = msg.payload.event.basement
const effectFirstFloor = msg.payload.event.first_floor
const effectColor = msg.payload.event.color
const effectDivide = msg.payload.event.divide
const duration = msg.payload.event.duration
const delay = duration * 1000
const adaptiveSwitchFirstFloor = flow.get("adaptiveFirstFloor", "diskCon")
const adaptiveSwitchBasement = flow.get("adaptiveBasement", "diskCon")
const lightsTinaDesk = flow.get('lightsTinaDesk', 'diskCon')
const lightsBasement = flow.get('lightsBasement', 'diskCon')
const lightsLivingRoom = flow.get('lightsLivingRoom', 'diskCon')
const lightsDiningRoom = flow.get('lightsDiningRoom', 'diskCon')
const alertFirstFloor = flow.get('alertFirstFloor')
const alertBasement = flow.get('alertBasement')
let firstFloorLights = []
let basementLights = []
// Set flow contexts to be used later in the reset node
flow.set("currentSceneBasement", currentSceneBasement)
flow.set("currentSceneLivingRoom", currentSceneLivingRoom)
flow.set("currentSceneTinaDesk", currentSceneTinaDesk)
flow.set('currentSceneDiningRoom', currentSceneDiningRoom)
flow.set("adaptLivingRoom", adaptLivingRoom)
flow.set("adaptBasement", adaptBasement)
flow.set("nightLivingRoom", nightLivingRoom)
flow.set("nightBasement", nightBasement)
flow.set('nightDiningRoom', nightDiningRoom)
flow.set("stateTinaDesk", stateTinaDesk)
flow.set("stateLivingRoom", stateLivingRoom)
flow.set("stateDiningRoom", stateDiningRoom)
flow.set("stateStairwell", stateStairwell)
flow.set("stateBasement", stateBasement)
if (deskState === 'on') {
firstFloorLights.push('light.tina_desk_strip','light.tina_lamp_top','light.tina_lamp_side')
// Define empty arrays for basement LED strip zones
let basement1 = []
let basement2 = []
let basementFull = []
// Define empty arrays for living room LED strip zones
let livingRoom1 = []
let livingRoom2 = []
let livingRoomFull = []
// Color names are set by default, however certain effects can override them below
let colorName1 = effectColor
let colorName2 = "white"
// Define empty object for LIFX effect settings
let lifxData = {}
let effectLifx = msg.payload.event.lifx
// Setup the proper zones to use for the effect
if (effectDivide === 'half') {
basement1 = flow.get("halfBasement1", "diskCon")
basement2 = flow.get("halfBasement2", "diskCon")
livingRoom1 = flow.get("halfLivingRoom1", "diskCon")
livingRoom2 = flow.get("halfLivingRoom2", "diskCon")
} else if (effectDivide === 'quarter') {
basement1 = flow.get("effectSegBasement1", "diskCon")
basement2 = flow.get("effectSegBasement2", "diskCon")
livingRoom1 = flow.get("effectSegLivingRoom1", "diskCon")
livingRoom2 = flow.get("effectSegLivingRoom2", "diskCon")
} else if (effectDivide === 'full') {
basementFull = flow.get("basementFull", "diskCon")
livingRoomFull = flow.get("livingRoomFull", "diskCon")
}
if (livingRoomState === 'on') {
firstFloorLights.push('light.living_room_color_1','light.living_room_color_2','light.living_room_color_3','light.living_room_led_strip')
if (effectFirstFloor === true) {
flow.set('alertFirstFloor', true)
}
if (diningRoomState === 'on') {
firstFloorLights.push('light.dining_room_lamp')
if (effectBasement === true) {
flow.set('alertBasement', true)
}
if (basementState === 'on') {
basementLights.push('light.basement_tall_lamp','light.basement_short_lamp','light.basement_stairwell','light.basement_led_strip_1')
// Set/change colors if necessary
if (effectColor === 'police') {
colorName1 = 'red'
colorName2 = 'blue'
}
flow.set("deskState", deskState)
flow.set("livingRoomState", livingRoomState)
flow.set("diningRoomState", diningRoomState)
flow.set("basementState", basementState)
// Define parameters for different LIFX effects
if (effectLifx === 'move') {
lifxData = {
"speed": 0.5,
"direction": "right",
"power_on": false
}
} else if (effectLifx === 'ping') {
effectLifx = 'pulse'
colorName2 = colorName1
lifxData = {
"power_on": false,
"mode": "ping",
"period": 1,
"cycles": duration,
"color_name": "white",
"brightness": 255
}
} else if (effectLifx === 'blink') {
effectLifx = 'pulse'
colorName2 = colorName1
lifxData = {
"power_on": false,
"mode": "blink",
"period": 0.5,
"cycles": duration * 2,
"color_name": "white",
"brightness": 255
}
}
// let segLivingRoom = [].concat(segLivingRoom1, segLivingRoom2)
// Define messages
let sendBasementStripFX = {
"payload": {
"domain": "lifx",
"service": "effect_" + effectLifx,
"target": {
"entity_id": ["light.basement_led_strip_1"]
},
"data": lifxData
}
}
let sendBasementStrip1 = {
"payload": {
"domain": "lifx",
"service": "set_state",
"target": {
"entity_id": ["light.basement_led_strip_1"]
},
"data": {
"zones": basement1,
"color_name": colorName1,
"brightness": 255
}
}
}
let sendBasementStrip2 = {
"payload": {
"domain": "lifx",
"service": "set_state",
"target": {
"entity_id": ["light.basement_led_strip_1"]
},
"data": {
"zones": basement2,
"color_name": colorName2,
"brightness": 255,
"power": true
}
}
}
let sendBasementLights = {
"payload": {
"domain": "light",
"service": "turn_on",
"target": {
"entity_id": [
"light.basement_tall_lamp",
"light.basement_short_lamp",
"light.basement_stairwell"
]
},
"data": {
"color_name": colorName1,
"brightness": 255
}
}
}
let sendLivingRoomStripFX = {
"payload": {
"domain": "lifx",
"service": "effect_" + effectLifx,
"target": {
"entity_id": ["light.living_room_led_strip"]
},
"data": lifxData
}
}
let sendLivingRoomStrip1 = {
"payload": {
"domain": "lifx",
"service": "set_state",
"target": {
"entity_id": ["light.living_room_led_strip"]
},
"data": {
"zones": livingRoom1,
"color_name": colorName1,
"brightness": 255
}
}
}
let sendLivingRoomStrip2 = {
"payload": {
"domain": "lifx",
"service": "set_state",
"target": {
"entity_id": ["light.living_room_led_strip"]
},
"data": {
"zones": livingRoom2,
"color_name": colorName2,
"brightness": 255,
"power": true
}
}
}
let sendLivingRoomLights = {
"payload": {
"domain": "light",
"service": "turn_on",
"target": {
"entity_id": [
"light.living_room_color_1",
"light.living_room_color_2",
"light.living_room_color_3",
"light.stairwell_led_strip"
]
},
"data": {
"color_name": colorName1,
"brightness": 255
}
}
}
let sendTinaDeskLights = {
"payload": {
"domain": "light",
"service": "turn_on",
"target": {
"entity_id": ["light.tina_desk_lights"]
},
"data": {
"color_name": colorName1,
"brightness": 255
}
}
}
let sendDiningRoomLamp = {
"payload": {
"domain": "light",
"service": "turn_off",
"target": {
"entity_id": ["light.dining_room_lamp"]
},
"data": {}
}
}
let sendAdaptiveFirstFloor = {
"payload": {
"domain": "switch",
"service": "turn_off",
"target": {
"entity_id": adaptiveSwitchFirstFloor
},
"data": {}
}
}
let sendAdaptiveBasement = {
"payload": {
"domain": "switch",
"service": "turn_off",
"target": {
"entity_id": adaptiveSwitchBasement
},
"data": {}
}
}
let backupLivingRoom = {
"payload": {
"domain": "scene",
"service": "create",
"data": {
"scene_id": "living_room_alert_restore",
"snapshot_entities": lightsLivingRoom
}
}
}
let backupTinaDesk = {
"payload": {
"domain": "scene",
"service": "create",
"data": {
"scene_id": "tina_desk_alert_restore",
"snapshot_entities": lightsTinaDesk
}
}
}
let backupBasement = {
"payload": {
"domain": "scene",
"service": "create",
"data": {
"scene_id": "basement_alert_restore",
"snapshot_entities": lightsBasement
}
}
}
let sendReset = {
"delay": delay
}
let sendDebug = {
"topic": "debug",
"colorName1": colorName1,
"colorName2": colorName2,
"lifxData": lifxData,
"effectLifx": effectLifx,
"basement1": basement1,
"basement2": basement2
}
// Send backup messages
if (stateLivingRoom === 'on' && alertFirstFloor === false) {
node.send([backupLivingRoom,null,null,null,null,null])
}
if (stateTinaDesk === 'on' && alertFirstFloor === false) {
node.send([backupTinaDesk,null,null,null,null,null])
}
if (stateBasement === 'on' && alertBasement === false) {
node.send([backupBasement,null,null,null,null,null])
}
// Send effect messages
if (effectBasement === true) {
node.send([null,null,null,null,[sendAdaptiveBasement,sendBasementLights,sendBasementStripFX,sendBasementStrip1,sendBasementStrip2,sendDebug],null])
}
if (effectFirstFloor === true) {
node.send([null,[sendAdaptiveFirstFloor,sendLivingRoomLights,sendLivingRoomStripFX,sendLivingRoomStrip1,sendLivingRoomStrip2],sendTinaDeskLights,sendDiningRoomLamp,null,null])
}
// Send the reset message to start the timer
node.send([null,null,null,null,null,sendReset])
node.status({fill:'green',shape:'dot',text:'Alert Sent'})

326
lightfx/reset.js Normal file
View File

@ -0,0 +1,326 @@
// Set constants
const states = global.get('homeassistant.homeAssistant.states')
const currentSceneBasement = flow.get('currentSceneBasement')
const currentSceneLivingRoom = flow.get('currentSceneLivingRoom')
const currentSceneTinaDesk = flow.get('currentSceneTinaDesk')
const currentSceneDiningRoom = flow.get('currentSceneDiningRoom')
const adaptLivingRoom = flow.get('adaptLivingRoom')
const adaptBasement = flow.get('adaptBasement')
const nightLivingRoom = flow.get('nightLivingRoom')
const nightBasement = flow.get('nightBasement')
const nightDiningRoom = flow.get('nightDiningRoom')
const stateTinaDesk = flow.get('stateTinaDesk')
const stateLivingRoom = flow.get('stateLivingRoom')
const stateDiningRoom = flow.get('stateDiningRoom')
const stateBasement = flow.get('stateBasement')
const stateStairwell = flow.get('stateStairwell')
const scenesLivingRoom = states["input_select.living_room_scenes"].attributes.options
const scenesBasement = states["input_select.basement_studio_scenes"].attributes.options
const scenesTinaDesk = states["input_select.tina_desk_scenes"].attributes.options
const scenesDiningRoom = states["input_select.dining_room_lamp_scenes"].attributes.options
const definedLivingRoom = scenesLivingRoom.includes(currentSceneLivingRoom)
const definedBasement = scenesBasement.includes(currentSceneBasement)
const definedTinaDesk = scenesTinaDesk.includes(currentSceneTinaDesk)
const definedDiningRoom = scenesDiningRoom.includes(currentSceneDiningRoom)
// Define variables
let setSceneLivingRoom = []
let setSceneTinaDesk = []
let setSceneBasement = []
let setSceneDiningRoom = []
let setServiceLivingRoom = []
let setServiceTinaDesk = []
let setServiceDiningRoom = []
let setServiceBasement = []
let restoreLivingRoom = {}
let restoreTinaDesk = {}
let restoreBasement = {}
// Decide what to restore for each room
if (stateLivingRoom === 'on') {
setServiceLivingRoom = 'turn_on'
if (definedLivingRoom === true) {
restoreLivingRoom = 'defined'
setSceneLivingRoom = currentSceneLivingRoom
} else if (nightLivingRoom === 'on') {
restoreLivingRoom = 'night'
setSceneLivingRoom = 'Adaptive'
} else if (adaptLivingRoom === 'on') {
restoreLivingRoom = 'adaptive'
setSceneLivingRoom = 'Adaptive'
} else {
restoreLivingRoom = 'backup'
setSceneLivingRoom = 'living_room_alert_restore'
}
} else {
restoreLivingRoom = 'off'
setServiceLivingRoom = 'turn_off'
setSceneLivingRoom = 'Adaptive'
}
if (stateTinaDesk === 'on') {
setServiceTinaDesk = 'turn_on'
if (definedTinaDesk === true) {
restoreTinaDesk = 'defined'
setSceneTinaDesk = currentSceneTinaDesk
} else {
restoreTinaDesk = 'adaptive'
setSceneTinaDesk = 'Reset'
}
} else {
restoreTinaDesk = 'off'
setServiceTinaDesk = 'turn_off'
}
if (stateDiningRoom === 'on') {
setServiceDiningRoom = 'turn_on'
if (nightDiningRoom === 'on') {
setSceneDiningRoom = 'Nightlight'
} else {
setSceneDiningRoom = 'Adaptive'
}
} else {
setServiceDiningRoom = 'turn_off'
}
if (stateBasement === 'on') {
setServiceBasement = 'turn_on'
if (definedBasement === true) {
restoreBasement = 'defined'
setSceneBasement = currentSceneBasement
} else if (nightBasement === 'on') {
restoreBasement = 'night'
setSceneBasement = 'Adaptive'
} else if (adaptBasement === 'on') {
restoreBasement = 'adaptive'
setSceneBasement = 'Adaptive'
} else {
restoreBasement = 'backup'
setSceneBasement = 'basement_alert_restore'
}
} else {
restoreBasement = 'off'
setServiceBasement = 'turn_off'
setSceneBasement = 'Adaptive'
}
// Define messages
let sendSceneLivingRoom = {
"payload": {
"domain": "input_select",
"service": "select_option",
"target": {
"entity_id": ["input_select.living_room_scenes"]
},
"data": {
"option": setSceneLivingRoom
}
}
}
let sendSceneTinaDesk = {
"payload": {
"domain": "input_select",
"service": "select_option",
"target": {
"entity_id": ["input_select.tina_desk_scenes"]
},
"data": {
"option": setSceneTinaDesk
}
}
}
let sendSceneBasement = {
"payload": {
"domain": "input_select",
"service": "select_option",
"target": {
"entity_id": ["input_select.basement_studio_scenes"]
},
"data": {
"option": setSceneBasement
}
}
}
let sendSceneDiningRoomLamp = {
"payload": {
"domain": "input_select",
"service": "select_option",
"target": {
"entity_id": ["input_select.dining_room_lamp_scenes"]
},
"data": {
"option": setSceneDiningRoom
}
}
}
let sendNightLivingRoom = {
"payload": {
"domain": "switch",
"service": "turn_on",
"target": {
"entity_id": ["switch.adaptive_lighting_sleep_mode_living_room"]
},
"data": {}
}
}
let sendNightTinaDesk = {
"payload": {
"domain": "switch",
"service": "turn_on",
"target": {
"entity_id": ["switch.adaptive_lighting_sleep_mode_tina_desk"]
},
"data": {}
}
}
let sendNightBasement = {
"payload": {
"domain": "switch",
"service": "turn_on",
"target": {
"entity_id": ["switch.adaptive_lighting_sleep_mode_basement_studio"]
},
"data": {}
}
}
let sendStateLivingRoom = {
"payload": {
"domain": "light",
"service": setServiceLivingRoom,
"target": {
"entity_id": ["light.living_room_lights"]
},
"data": {}
}
}
let sendStateTinaDesk = {
"payload": {
"domain": "light",
"service": setServiceTinaDesk,
"target": {
"entity_id": ["light.tina_desk_lights"]
},
"data": {}
}
}
let sendStateDiningRoom = {
"payload": {
"domain": "light",
"service": setServiceDiningRoom,
"target": {
"entity_id": ["light.dining_room_lamp"]
},
"data": {}
}
}
let sendStateBasement = {
"payload": {
"domain": "light",
"service": setServiceBasement,
"target": {
"entity_id": ["light.basement_studio_lights"]
},
"data": {}
}
}
let sendRestoreLivingRoom = {
"payload": {
"domain": "scene",
"service": "turn_on",
"target": {
"entity_id": setSceneLivingRoom
},
"data": {}
}
}
let sendRestoreTinaDesk = {
"payload": {
"domain": "scene",
"service": "turn_on",
"target": {
"entity_id": setSceneTinaDesk
},
"data": {}
}
}
let sendRestoreBasement = {
"payload": {
"domain": "scene",
"service": "turn_on",
"target": {
"entity_id": setSceneBasement
},
"data": {}
}
}
let sendStairwellScript = {
"payload": {
"domain": "script",
"service": "stairwell_led_strip",
"data": {}
}
}
let sendStairwellOff = {
"payload": {
"domain": "light",
"service": "turn_off",
"target": {
"entity_id": ["light.stairwell_led_strip"]
},
"data": {}
}
}
// Send messages
if (restoreLivingRoom === 'backup') {
node.send([sendRestoreLivingRoom,null,null,null])
} else if (restoreLivingRoom === 'off') {
node.send([sendStateLivingRoom,null,null,null])
} else {
node.send([sendSceneLivingRoom,null,null,null])
}
if (restoreTinaDesk === 'backup') {
node.send([null,sendRestoreTinaDesk,null,null])
} else if (restoreTinaDesk === 'off') {
node.send([null,sendStateTinaDesk,null,null])
} else {
node.send([null,sendSceneTinaDesk,null,null])
}
node.send([null,null,[sendStateDiningRoom,sendSceneDiningRoomLamp],null])
if (restoreBasement === 'backup') {
node.send([null,null,null,sendRestoreBasement])
} else if (restoreBasement === 'off') {
node.send([null,null,null,sendStateBasement])
} else {
node.send([null,null,null,sendSceneBasement])
}
if (stateStairwell === 'on') {
node.send([sendStairwellScript,null,null,null])
} else {
node.send([sendStairwellOff,null,null,null])
}
flow.set('alertFirstFloor', false)
flow.set('alertBasement', false)
node.status({fill:'green',shape:'dot',text:'Scenes Reset'})

View File

@ -5,9 +5,6 @@ const tinawork = msg.tinawork
if (tinawork === 'on' && workEndZone === 'on') {
node.status({fill:"green",shape:"dot",text:"Activated"})
return[msg,null]
} else if (tinawork === 'on' && workEndZone === 'off') {
node.status({fill:"yellow",shape:"dot",text:"Not time to leave yet"})
return null
} else if (tinawork === 'off') {
node.status({fill:"yellow",shape:"dot",text:"No Work Today"})
return null

View File

@ -9,22 +9,17 @@ const newDuration = duration * 60
if (sleeping === 'off') {
if (payload === 'on') {
if (lux <= threshold && lights === 'off') {
node.status({fill:'green',shape:'dot',text:'Turning lights on'})
node.send([msg,msg,null])
} else {
if (lights === 'on') {
node.status({fill:'red',shape:'ring',text:'Lights already on'})
node.send([null,msg,null])
if (lux <= threshold || lights === 'on') {
node.status({fill:'green',shape:'dot',text:'Lights On'})
node.send([msg,null])
} else {
node.status({fill:'red',shape:'ring',text:'Too bright'})
}
}
} else if (payload === 'off') {
if (lights === 'on') {
msg.duration = newDuration
node.status({fill:"green",shape:"dot",text:parseInt(duration) + ' minutes'})
node.send([null,null,msg])
node.send([null,msg])
} else {
node.status({fill:"red",shape:"ring",text:"Lights already off"})
}

View File

@ -9,22 +9,17 @@ const newDuration = duration * 60
if (sleeping === 'off') {
if (payload === 'on') {
if (lux <= threshold && lights === 'off') {
node.status({fill:'green',shape:'dot',text:'Turning lights on'})
node.send([msg,msg,null])
} else {
if (lights === 'on') {
node.status({fill:'red',shape:'ring',text:'Lights already on'})
node.send([null,msg,null])
if (lux <= threshold || lights === 'on') {
node.status({fill:'green',shape:'dot',text:'Lights On'})
node.send([msg,null])
} else {
node.status({fill:'red',shape:'ring',text:'Too bright'})
}
}
} else if (payload === 'off') {
if (lights === 'on') {
msg.duration = newDuration
node.status({fill:"green",shape:"dot",text:parseInt(duration) + ' minutes'})
node.send([null,null,msg])
node.send([null,msg])
} else {
node.status({fill:"red",shape:"ring",text:"Lights already off"})
}

View File

@ -12,22 +12,17 @@ const newDuration = duration * 60
if (peopleSleeping === false && nightMode === 'off') {
if (payload === 'on') {
if (lux <= threshold && lights === 'off') {
node.status({fill:'green',shape:'dot',text:'Turning lights on'})
node.send([msg,msg,null])
} else {
if (lights === 'on') {
node.status({fill:'red',shape:'ring',text:'Lights already on'})
node.send([null,msg,null])
if (lux <= threshold || lights === 'on') {
node.status({fill:'green',shape:'dot',text:'Lights On'})
node.send([msg,null])
} else {
node.status({fill:'red',shape:'ring',text:'Too bright'})
}
}
} else if (payload === 'off') {
if (lights === 'on') {
msg.duration = newDuration
node.status({fill:"green",shape:"dot",text:parseInt(duration) + ' minutes'})
node.send([null,null,msg])
node.send([null,msg])
} else {
node.status({fill:"red",shape:"ring",text:"Lights already off"})
}

View File

@ -1,94 +0,0 @@
const states = global.get('homeassistant.homeAssistant.states')
const masterBedroomSleeping = states['input_boolean.master_bedroom_sleeping'].state
const emmaSleep = states['input_boolean.emma_sleeping'].state
const tonyAwake = states['input_boolean.tony_awake'].state
const xiaDesktopUser = states['sensor.xia_desktop_current_username'].state
const xiaDesktopIdle = states['binary_sensor.tina_desktop_idle'].state
const tonyLocation = states['person.tony_stork'].state
const tinaLocation = states['person.christina_stork'].state
const overnight = states['binary_sensor.overnight'].state
const payload = msg.payload
const topic = msg.topic
// Set some default values
let who = 'Alexa Everywhere' // Default to playing on all Echo Dots unless told otherwise
let tinaAvailable = false
let tonyAvailable = false
let enable = false
let reason = {}
// Determine who is available to respond
if (tonyAwake === 'on' && tonyLocation === 'home') {
tonyAvailable = true
}
if (xiaDesktopUser === 'irish' && xiaDesktopIdle === 'off' && tinaLocation === 'home') {
tinaAvailable = true
}
// If both of us are still asleep, or I am asleep and she is at work, play the alert only in the master bedroom
if (tinaAvailable === false && tonyAvailable === false) {
who = 'Master Bedroom'
}
// Determine if the alert should be sent
if (emmaSleep === 'on') {
if (overnight === 'on' && masterBedroomSleeping === 'on') {
enable = true
reason = 'Overnight is on, and master bedroom is sleeping'
} else if (overnight === 'off') {
enable = true
reason = 'Overnight is off'
}
}
// Define the alert message
let alertTTS = {
"topic": who,
"payload": "Emma has opened her door, please check on her. I repeat, Emma has opened her door, please check on her. This is urgent, Emma is awake. PDS toddler warning, a large and extremely dangerous toddler is on the ground in your area.",
"type": "critical"
}
// Add some logs for debugging
node.log(`--------------- Emma Door Alert --------------`)
node.log(`Emma Door Alert - topic: ${topic}`)
node.log(`Emma Door Alert - payload: ${payload}`)
node.log(`Emma Door Alert - masterBedroomSleeping: ${masterBedroomSleeping}`)
node.log(`Emma Door Alert - emmaSleep: ${emmaSleep}`)
node.log(`Emma Door Alert - tonyAwake: ${tonyAwake}`)
node.log(`Emma Door Alert - xiaDesktopUser: ${xiaDesktopUser}`)
node.log(`Emma Door Alert - xiaDesktopIdle: ${xiaDesktopIdle}`)
node.log(`Emma Door Alert - tonyLocation: ${tonyLocation}`)
node.log(`Emma Door Alert - tinaLocation: ${tinaLocation}`)
node.log(`Emma Door Alert - overnight: ${overnight}`)
node.log(`Emma Door Alert - tonyAvailable: ${tonyAvailable}`)
node.log(`Emma Door Alert - tinaAvailable: ${tinaAvailable}`)
node.log(`Emma Door Alert - who: ${who}`)
node.log(`Emma Door Alert - enable: ${enable}`)
node.log(`Emma Door Alert - reason: ${reason}`)
node.log(`----------------------------------------------`)
// Send the alert if conditions are met
if (topic === 'door' && payload === 'on') {
if (enable === true) {
node.status({fill:'green',shape:'dot',text:`Sending alert to ${who}`})
node.send([alertTTS,msg,null])
} else {
node.status({fill:'red',shape:'ring',text:'Door Opened, but no alert sent'})
}
} else if (topic === 'timer') {
node.status({fill:'green',shape:'dot',text:'Timer Finished'})
node.send([alertTTS,msg,null])
} else if (topic === 'cancel') {
node.status({fill:'green',shape:'dot',text:'Cancel Button Pressed'})
node.send([null,null,msg])
} else if (topic === 'door' && payload === 'off') {
node.status({fill:'green',shape:'dot',text:'Door Closed'})
}

View File

@ -1,50 +0,0 @@
const livingRoom = ["Living Room", "Living Room Echo Dot"]
const basementAlexa = ["Basement", "Basement Echo Dot"]
const basementGoogle = ["Basement Google", "basement_google"]
const kallenBedroom = ["Kallen Bedroom", "Kallen Bedroom Speaker"]
const emmaBedroom = ["Emma Bedroom", "Emma Bedroom Speaker"]
const kidsBedrooms = ["Kids Bedrooms"]
const allBedrooms = ["All Bedrooms"]
const masterBedroom = ["Master Bedroom", "Master Bedroom Echo Dot"]
const commonAreas = ["Common Areas"]
const alexaEverywhere = ["alexa_everywhere", "Alexa Everywhere"]
const room = msg.topic
const voice = msg.voice || global.get("jarvis_voice", "diskCon")
const type = msg.type || "normal"
if (livingRoom.includes(room)) {
msg.topic = "living_room"
} else if (basementAlexa.includes(room)) {
msg.topic = "basement"
} else if (basementGoogle.includes(room)) {
msg.topic = "basement_google"
} else if (kallenBedroom.includes(room)) {
msg.topic = "kallen_bedroom"
} else if (emmaBedroom.includes(room)) {
msg.topic = "emma_bedroom"
} else if (kidsBedrooms.includes(room)) {
msg.topic = "kids_bedrooms"
} else if (allBedrooms.includes(room)) {
msg.topic = "all_bedrooms"
} else if (masterBedroom.includes(room)) {
msg.topic = "master_bedroom"
} else if (commonAreas.includes(room)) {
msg.topic = "common"
} else if (alexaEverywhere.includes(room)) {
msg.topic = "alexa_everywhere"
} else if (room === "Everywhere") {
msg.topic = "everywhere"
}
msg.voice = voice
msg.type = type
let statusMsg = {
"status": {
"fill": "green",
"shape": "dot",
"text": `${msg.voice} speaking in ${room}`
}
}
node.send([msg,statusMsg])

View File

@ -1,36 +0,0 @@
// Get the user ID list from global context
const users = global.get("userIDList", "diskCon") || {}
// Initialize variables
let userTrigger = "none"
let statusTxt = ""
// Extract user ID from the message
if (msg.payload?.context?.user_id) {
userTrigger = msg.payload.context.user_id
} else if (msg.data?.context?.user_id) {
userTrigger = msg.data.context.user_id
}
// Validate userTrigger and set status message
if (userTrigger === "none" || !users[userTrigger]) {
statusTxt = "User not found"
node.error(`User ID '${userTrigger}' not found in user list.`)
return null // Stop execution if user is not found
} else {
const user = users[userTrigger]
statusTxt = `User: ${user.firstName}`
msg.user = { ...user } // Avoid mutating the original msg
}
// Create the status message
const statusMsg = {
status: {
fill: "green",
shape: "dot",
text: `${statusTxt} at ${new Date().toLocaleString()}`
}
}
// Send the message and status message to the output nodes
node.send([msg, statusMsg])

View File

@ -1,22 +0,0 @@
let userIDList = {
"c3909d27048140729f002aaef0391775": {
"shortName": "tony",
"firstName": "Tony",
"lastName": "Stork",
"hassUser": "tonystork"
},
"f387a983651a4321a7411ff8cf36f949": {
"shortName": "tina",
"firstName": "Christina",
"lastName": "Stork",
"hassUser": "christinastork"
},
"879b4c04e32841b3ad1d2763a11b4e70": {
"shortName": "kallen",
"firstName": "Kallen",
"lastName": "Stork",
"hassUser": "kallenstork"
}
}
global.set("userIDList",userIDList,"diskCon")

View File

@ -127,7 +127,8 @@ node.log("Time-based Automations: Decision Logic Complete")
// ---------- Service Calls ----------
let sendLights = {
"payload": {
"action": "light.turn_off",
"domain": "light",
"service": "turn_off",
"target": {
"entity_id": lightsOff
},
@ -137,7 +138,8 @@ let sendLights = {
let sendSleepOff = {
"payload": {
"action": "switch.turn_off",
"domain": "switch",
"service": "turn_off",
"target": {
"entity_id": adaptiveSleep
},
@ -147,7 +149,8 @@ let sendSleepOff = {
let sendBooleanOff = {
"payload": {
"action": "input_boolean.turn_off",
"domain": "input_boolean",
"service": "turn_off",
"target": {
"entity_id": booleanOff
},
@ -157,7 +160,8 @@ let sendBooleanOff = {
let sendAdaptive = {
"payload": {
"action": "switch.turn_" + setAdaptive,
"domain": "switch",
"service": "turn_" + setAdaptive,
"target": {
"entity_id": switchAdaptive
},
@ -167,7 +171,8 @@ let sendAdaptive = {
let sendSceneResetMain = {
"payload": {
"action": "input_text.set_value",
"domain": "input_text",
"service": "set_value",
"target": {
"entity_id": selScenesMain
},
@ -179,7 +184,8 @@ let sendSceneResetMain = {
let sendSceneResetDesk = {
"payload": {
"action": "input_text.set_value",
"domain": "input_text",
"service": "set_value",
"target": {
"entity_id": selScenesTinaDesk
},
@ -191,7 +197,8 @@ let sendSceneResetDesk = {
let sendHoliday = {
"payload": {
"action": "switch.turn_" + setHoliday,
"domain": "switch",
"service": "turn_" + setHoliday,
"target": {
"entity_id": switchHoliday
},
@ -201,7 +208,8 @@ let sendHoliday = {
let sendTimer = {
"payload": {
"action": "timer.start",
"domain": "timer",
"service": "start",
"target": {
"entity_id": timerEntity
},
@ -213,7 +221,8 @@ let sendTimer = {
let sendTimerCancel = {
"payload": {
"action": "timer.cancel",
"domain": "timer",
"service": "cancel",
"target": {
"entity_id": timerEntity
},
@ -223,7 +232,8 @@ let sendTimerCancel = {
let sendNotifyPhone = {
"payload": {
"action": "script.text_notify",
"domain": "script",
"service": "text_notify",
"data": {
"who": "all",
"title": notifyTitle,
@ -236,7 +246,8 @@ let sendNotifyPhone = {
let sendNotifyTV = {
"payload": {
"action": "script.tv_notify",
"domain": "script",
"service": "tv_notify",
"data": {
"who": "all",
"title": notifyTitle,
@ -252,7 +263,8 @@ let sendNotifyTV = {
let sendFirstFloorScene = {
"payload": {
"action": "script.evening_on_first_floor",
"domain": "script",
"service": "evening_on_first_floor",
"data": {
"sunset_lights": 1
}
@ -261,7 +273,8 @@ let sendFirstFloorScene = {
let sendSecondFloorScene = {
"payload": {
"action": "script.evening_on_second_floor",
"domain": "script",
"service": "evening_on_second_floor",
"data": {
"sunset_lights": 1
}
@ -270,7 +283,8 @@ let sendSecondFloorScene = {
let sendDeskScene = {
"payload": {
"action": "input_select.select_option",
"domain": "input_select",
"service": "select_option",
"target": {
"entity_id": ["input_select.tina_desk_scenes"]
},

View File

@ -1,44 +0,0 @@
let tomorrow = msg.tomorrow
let today = msg.today
let number = {}
let work_tomorrow = {}
// Check if calendar data exists
if (!msg.payload || msg.payload.length === 0) {
msg.payload = [{
date: "No Data",
eventStart: "No Data",
eventEnd: "No Data",
summary: "No Data",
location: "No Data",
isRecurring: "No Data",
allDay: "No Data",
calendarName: "No Data",
countdown: "No Data",
uid: { date: "No Data" }
}]
work_tomorrow = "false"
number = 0
} else {
if (tomorrow > 0) {
work_tomorrow = "true"
if (today == 0) {
number = 0
} else {
number = 1
}
} else {
work_tomorrow = "false"
number = 0
}
}
msg.work_tomorrow = work_tomorrow
node.status({fill:"green",shape:"dot",text:`Number ${number}`})
if (number == 0) {
node.send([msg,null])
} else {
node.send([null,msg])
}

View File

@ -1,69 +0,0 @@
const severeWarningEvents = ["Severe Thunderstorm Warning", "Destructive Severe Thunderstorm Warning", "Considerable Destructive Severe Thunderstorm Warning"]
const tornadoWarningEvents = ["Tornado Warning", "Radar Indicated Tornado Warning", "Confirmed Tornado Warning", "Tornado Emergency"]
let alerts = msg.payload
// Helper function to safely access nested properties
const getNestedProperty = (obj, path, defaultValue = undefined) => {
return path.reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : defaultValue), obj)
}
// Filter function
const filterAlerts = (alerts, condition) => {
return alerts.filter(alert => {
try {
return condition(alert)
} catch (e) {
node.warn(`Error processing alert: ${e.message}`)
return false
}
})
}
// Filtering logic
const ts = filterAlerts(alerts, alert => {
const event = getNestedProperty(alert, ['raw', 'properties', 'event'])
return severeWarningEvents.includes(event)
})
const tstp = filterAlerts(alerts, alert => {
const event = getNestedProperty(alert, ['raw', 'properties', 'event'])
const tornadoDetection = getNestedProperty(alert, ['raw', 'properties', 'parameters', 'tornadoDetection'], [])
return severeWarningEvents.includes(event) && tornadoDetection.includes("POSSIBLE")
})
const cdst = filterAlerts(alerts, alert => {
const event = getNestedProperty(alert, ['raw', 'properties', 'event'])
return event === "Considerable Destructive Severe Thunderstorm Warning"
})
const tornado = filterAlerts(alerts, alert => {
const event = getNestedProperty(alert, ['raw', 'properties', 'event'])
return tornadoWarningEvents.includes(event)
})
const confirmed_tornado = filterAlerts(alerts, alert => {
const event = getNestedProperty(alert, ['raw', 'properties', 'event'])
return event === "Confirmed Tornado Warning"
})
// Output messages
let tstormMsg = {
"payload": {
"alerts": ts,
"count": ts.length,
"tornado_possible": tstp.length,
"considerable_destructive": cdst.length
}
}
let tornadoWarnMsg = {
"payload": {
"alerts": tornado,
"count": tornado.length,
"confirmed": confirmed_tornado.length
}
}
node.send([tstormMsg, tornadoWarnMsg])
node.status({ fill: 'green', shape: 'dot', text: `${alerts.length} alerts processed at ${new Date().toLocaleString()}`})

View File

@ -1,150 +0,0 @@
const severeWarningEvents = ["Severe Thunderstorm Warning","Destructive Severe Thunderstorm Warning","Considerable Destructive Severe Thunderstorm Warning"]
const tornadoWarningEvents = ["Tornado Warning","Radar Indicated Tornado Warning","Confirmed Tornado Warning","Tornado Emergency"]
const tornadoWatchEvents = ["Tornado Watch"]
const severeThunderstormWatchEvents = ["Severe Thunderstorm Watch"]
const area = msg.area
const mqttTopic = "weather/alerts/" + area
const allTopic = mqttTopic + "/alerts"
const tstormTopic = mqttTopic + "/severe_thunderstorm_warning"
const tornadoWarnTopic = mqttTopic + "/tornado_warning"
const tornadoWatchTopic = mqttTopic + "/tornado_watch"
const severeThunderstormWatchTopic = mqttTopic + "/severe_thunderstorm_watch"
let alerts = msg.payload.features
let tornado_possible = false
let considerable_destructive = false
let confirmed = false
// Filter for Severe Thunderstorm Warnings
let ts = alerts.filter(function(alert) {
if (alert.properties &&
severeWarningEvents.includes(alert.properties.event)) {
return true
}
})
// Filter for Severe Thunderstorm Warnings with tornado detection
// that have a tornado possible parameter
let tstp = alerts.filter(function(alert) {
if (alert.properties &&
severeWarningEvents.includes(alert.properties.event) &&
alert.properties.parameters &&
alert.properties.parameters.tornadoDetection &&
alert.properties.parameters.tornadoDetection.length > 0) {
let tornadoPossible = alert.properties.parameters.tornadoDetection[0]
return tornadoPossible === "POSSIBLE"
}
})
if (tstp.length > 0) {
tornado_possible = true
}
// Filter for considerable destructive severe thunderstorm warnings
let cdst = alerts.filter(function(alert) {
if (alert.properties &&
alert.properties.event === "Considerable Destructive Severe Thunderstorm Warning") {
return true
}
})
if (cdst.length > 0) {
considerable_destructive = true
}
// Filter for Tornado Warnings
let tornado = alerts.filter(function(alert) {
if (alert.properties &&
tornadoWarningEvents.includes(alert.properties.event)) {
return true
}
})
let confirmed_tornado = alerts.filter(function(alert) {
if (alert.properties &&
alert.properties.event === "Confirmed Tornado Warning") {
return true
}
})
if (confirmed_tornado.length > 0) {
confirmed = true
}
// Filter for Tornado Watches
let tornado_watch = alerts.filter(function(alert) {
if (alert.properties &&
tornadoWatchEvents.includes(alert.properties.event)) {
return true
}
})
// Filter for Severe Thunderstorm Watches
let severe_thunderstorm_watch = alerts.filter(function(alert) {
if (alert.properties &&
severeThunderstormWatchEvents.includes(alert.properties.event)) {
return true
}
})
// If there are any alerts, return them
let allAlerts = {
"payload": msg.payload.features,
"topic": allTopic
}
let tstormMsg = {
"payload": {
"alerts": ts,
"count": ts.length,
"tornado_possible": tornado_possible,
"considerable_destructive": considerable_destructive
},
"topic": tstormTopic
}
let tornadoWarnMsg = {
"payload": {
"alerts": tornado,
"count": tornado.length,
"confirmed": confirmed
},
"topic": tornadoWarnTopic
}
let tornadoWatchMsg = {
"payload": {
"alerts": tornado_watch,
"count": tornado_watch.length
},
"topic": tornadoWatchTopic
}
let severeThunderstormWatchMsg = {
"payload": {
"alerts": severe_thunderstorm_watch,
"count": severe_thunderstorm_watch.length
},
"topic": severeThunderstormWatchTopic
}
// Create status message for node
let statusMsg = {
"status": {
"fill": "green",
"shape": "dot",
"text": `${alerts.length} alerts processed at ${new Date().toLocaleString()}`
}
}
// Send messages to output nodes
node.send([allAlerts,tstormMsg,tornadoWarnMsg,tornadoWatchMsg,severeThunderstormWatchMsg,statusMsg])