Skip to content

Instantly share code, notes, and snippets.

@ConnorGriffin
Last active April 27, 2018 21:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ConnorGriffin/be4b380f105578bcf5fbd98af401d831 to your computer and use it in GitHub Desktop.
Save ConnorGriffin/be4b380f105578bcf5fbd98af401d831 to your computer and use it in GitHub Desktop.
Home Assistant Node-RED Scripts
var homeStatus = msg.payload.data.state
var homeStatusMinutes = Math.floor((msg.payload.timeSinceChangedMs/1000)/60)
var notHome = (homeStatus == "not_home" && homeStatusMinutes >= 10)
var ecobeeStatus = flow.get("ecobeeStatus")
var holdMode = ecobeeStatus.data.attributes.hold_mode
var climateMode = ecobeeStatus.data.attributes.climate_mode
var operationMode = ecobeeStatus.data.attributes.operation_mode
// Set the holdMatch criteria based on whether we're home or not, this is so we don't cancel temp or vacation holds
if (notHome) {
var holdMatch = (holdMode == "away" || holdMode == "home" || holdMode == "temp" || !holdMode)
} else {
var holdMatch = (holdMode == "away" || holdMode == "home" || !holdMode)
}
// Set the possible return payloads
var away = {
"payload": {
"switchAction": "hold",
"data": {"hold_mode": "away"}
}
}
var home = {
"payload": {
"switchAction": "hold",
"data": {"hold_mode": "home"}
}
}
var resume = {
"payload": {
"switchAction": "resume",
"data": {"resume_all": true}
}
}
// Doesn't evaluate if ecobee is off or in vacation mode, or we're home and in a temp hold
if (operationMode != "off" && holdMatch) {
if (notHome) {
if (holdMode != "away" && climateMode != "Away") {
// Set an Away hold if confort setting isn't Away, and we haven't set an away hold
return away
} else if (holdMode && climateMode == "Away") {
// Resume operation if comfort setting is Away and there is a home/away hold
return resume
}
// Do nothing if holdMode is null and climateMode is Away (already away)
// Do nothing if holdMode is away and climateMode is not Away (away hold already set)
} else {
// If we are home
if (holdMode != "home" && climateMode == "Away") {
// If we're home during a standard away time, set a home hold
return home
} else if (holdMode && climateMode != "Away") {
// If we're home during any hold where the comfort setting would normally be a home/sleep setting, resume schedule
return resume
}
// Do nothing if we're home during a home/sleep time with no hold set
}
}
// Return a switchAction of null if nothing happens, just for debugging
return {"payload": {"switchAction": null,}}
var occupied = flow.get("occupied")
var lightOn = flow.get("lightOn")
var override = flow.get("override")
var currentBrightness = flow.get("light").data.attributes.brightness
var lightSchedule = [
{
"pct": 100,
"start": "10:00",
"end": "16:00"
},
{
"pct": 70,
"start": "18:00",
"end": "18:00"
},
// Between 6 PM and 10 PM, linearly scale from 100 to 10% brightness, then do the inverse from 6 AM to 10 AM
{
"pct": 10,
"start": "21:00",
"end": "06:00"
}
]
// If the room is occupied and the light is on, use the schedule
if (occupied && lightOn && !override) {
// Get the current minutes from 00:00 (ex: 5:00 would be 300)
var d = new Date()
var hh = d.getHours()
var mm = d.getMinutes()
var currentMs = hh * 60 + mm
/*
if next start hours is less than current start hours, subtract difference from 24?
current time: 7
next start: 6
start - current + 24
Calculate the difference between the end and start of the next two schedules
Calcuate the difference between the brightness levels
Calculate how far into that difference we are, determine what brightness to set based on this
*/
// Iterate through each schedule item
for (i = 0; i < lightSchedule.length; i++) {
// Get the minutes for the current schedule
var scheduleStartMs = lightSchedule[i].start.split(":")[0] * 60 + parseInt(lightSchedule[i].start.split(":")[1])
var scheduleEndMs = lightSchedule[i].end.split(":")[0] * 60 + parseInt(lightSchedule[i].end.split(":")[1])
// Change calculation if schedule end carries into the next day
if (scheduleEndMs < scheduleStartMs) {
if (currentMs < scheduleEndMs) {
var currentMs = -currentMs + 24 * 60
}
var scheduleEndMs = scheduleEndMs + 24 * 60
}
if (currentMs >= scheduleStartMs && currentMs <= scheduleEndMs) {
// If we're actually in the schedule, return the set percentage
var targetPercent = lightSchedule[i].pct
break // Don't evaluate any more schedules
} else {
// Get the nextSchedule item, go to 0 (wrap around) if we're on the last schedule
if (i+1 == lightSchedule.length) {
var nextSchedule = lightSchedule[0]
} else {
nextSchedule = lightSchedule[i+1]
}
// Get the minutes for the next schedule start time
var nextScheduleStartMs = nextSchedule.start.split(":")[0] * 60 + parseInt(nextSchedule.start.split(":")[1])
// If the next schedule starts before the current schedule ends, calculate the minutes based on going into tomorrow (4:00 becomes 28:00)
if (nextScheduleStartMs < scheduleEndMs || scheduleEndMs < scheduleStartMs) {
var nextScheduleStartMs = nextScheduleStartMs + 24 * 60
}
// if we are between the two schedules, calculate the brightness percentage
if (currentMs >= scheduleEndMs && currentMs <= nextScheduleStartMs) {
var timeDiff = nextScheduleStartMs - scheduleEndMs
var brightDiff = lightSchedule[i].pct - nextSchedule.pct
var brightPerMin = brightDiff / timeDiff
var targetPercent = lightSchedule[i].pct - (timeDiff - (timeDiff - (currentMs - scheduleEndMs))) * brightPerMin
break
}
//console.log(nextScheduleStartMs)
}
}
}
if (targetBrightness) {
var setBrightnessDiff = Math.abs((targetPercent * 2.55) - currentBrightness)
// Don't do anything if the diffence is less than 5 (2%)
if (setBrightnessDiff > 5) {
flow.set("lastSetBrightness",targetPercent)
return {
"payload": {
"entity_id": "light.ge_14294_inwall_smart_dimmer",
"data": {
"brightness_pct": targetPercent
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment