Event for Light Ghosts (away from home), will it work ?

Moderator: leecollings

Post Reply
User avatar
deejc
Posts: 168
Joined: Tuesday 22 September 2015 18:50
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.5641
Location: UK
Contact:

Event for Light Ghosts (away from home), will it work ?

Post by deejc »

Hi,
I found an old Lua script from when i had a vera edge, will this work on domoticz without editing ?
be aware this is not My script but someone else's that i was using...

Code: Select all

-- This scene
-- . needs a virtual switch to know when somebody is home
-- . needs a virtual switch to enable/disable simulation when nobody is home
-- . is triggered 1 hour before sunset, at Vera startup and when virtual switch is turned ON

local at_home_virtual_switch_device = 122
local ghost_virtual_switch_device = 42
local dry_run = false

local sunset_time = os.date("*t", luup.sunset())
local sunset = sunset_time.hour * 60 + sunset_time.min
luup.log("Sunset is at " .. string.format("%02i:%02i:%02i", sunset_time.hour, sunset_time.min, sunset_time.sec))

local offset_times = 0

local ghost_rules = {
    living_room = {
        switch_devices = { 10, 11 },
        dimmer_devices = { 12 },
        dimmer_level = 33, -- 33%
        start_min = sunset - 10, start_max = sunset + 15, -- start between t-10 and t+15 minutes
        end_min = 22*60, end_max = 23*60 -- end between 10pm & 11pm
    },
    bedside_room1 = {
        switch_devices = { 20 },
        start_min = sunset, start_max = sunset + 30, -- start between t and t+30 minutes
        end_min = 20.5*60, end_max = 21*60, -- end between 8:30pm and 9:00pm
        cycles = true,
        cycles_on_min = 30, cycles_on_max = 3 * 60, -- each cycle should leave light ON for 30 to 3 hours
        cycles_off_min = 5, cycles_off_max = 30 -- each cycle should leave light OFF for 5 to 30 minutes
    },
    ceiling_room1 = {
        switch_devices = { 21 },
        start_min = sunset, start_max = sunset + 30, -- start between t and t+30 minutes
        end_min = 20.5*60, end_max = 21.5*60, -- end between 8:30pm and 9:30pm
        cycles = true,
        cycles_on_min = 30, cycles_on_max = 60, -- each cycle should leave light ON for 30 to 1 hour
        cycles_off_min = 15, cycles_off_max = 60 -- each cycle should leave light OFF for 15 to 60 minutes
    },
    bedside_room2 = {
        switch_devices = { 28 },
        start_min = sunset, start_max = sunset + 30, -- start between t and t+30 minutes
        end_min = 21*60, end_max = 23*60, -- end between 9:00pm and 11:00pm
    }
}

function ghostDeviceIdToName(device_id)
    return luup.devices[device_id].description .. " " .. luup.rooms[luup.devices[device_id].room_num] .. " (#" .. device_id .. ")"
end

function generateGhosts()
    -- Reinitialize ghost list
    if ghosts then
        terminateAllGhosts() -- terminate all current ghosts if any
    end
    ghosts = {}
    sorted_ghosts = {}

    -- Calc ghosts start/end
    luup.log("Generating ghosts...")
    math.randomseed(os.time())
    for rule_name, rule in pairs(ghost_rules) do
        local starts = math.random(rule['start_min'] * 60, rule['start_max'] * 60) + (offset_times * 60)
        local ends = math.random(rule['end_min'] * 60, rule['end_max'] * 60) + (offset_times * 60)

        local ghost_i = 1
        local ghost_starts = starts
        local ghost_ends = ends
        while ghost_starts < ends do
            local ghost_name = rule_name .. " #" .. ghost_i
            if rule['cycles'] then
                ghost_ends = math.min(ghost_starts + math.random(rule['cycles_on_min'] * 60, rule['cycles_on_max'] * 60), ends)
            end
            ghosts["" .. ghost_starts .. "/" .. ghost_name] = { name = ghost_name, rule_name = rule_name, starts = ghost_starts, duration = ghost_ends - ghost_starts }
            if rule['cycles'] then
                ghost_starts = ghost_ends + math.random(rule['cycles_off_min'] * 60, rule['cycles_off_max'] * 60)
            else
                ghost_starts = ghost_ends
            end
            ghost_i = ghost_i + 1
        end
    end

    -- Sort ghosts by start time
    for ghost_id in pairs(ghosts) do
        table.insert(sorted_ghosts, ghost_id)
    end
    table.sort(sorted_ghosts)
end

function wakeGhost(ghost_id)
    if (luup.variable_get("urn:upnp-org:serviceId:VSwitch1", "Status", at_home_virtual_switch_device) == "1") then
        luup.log("Not waking up ghost " .. ghost_id .. ", somebody is home")
    else
        if (luup.variable_get("urn:upnp-org:serviceId:VSwitch1", "Status", ghost_virtual_switch_device) == "0") then
            luup.log("Not waking up ghost " .. ghost_id .. ", virtual switch has been turned OFF")
        else
            local ghost = ghosts[ghost_id]
            if ghost then
                luup.log("Waking up ghost " .. ghost_id)
                rule = ghost_rules[ghost['rule_name']]
                if rule['switch_devices'] then
                    for i, device_id in ipairs(rule['switch_devices']) do
                        if luup.variable_get("urn:upnp-org:serviceId:SwitchPower1", "Status", device_id) == "1" then
                            luup.log("Ghost " .. ghost_id .. " is NOT switching " .. ghostDeviceIdToName(device_id) .. " ON, it's already ON!")
                        else
                            luup.log("Ghost " .. ghost_id .. " is switching " .. ghostDeviceIdToName(device_id) .. " ON")
                            if not ghost['switch_devices_to_turn_off'] then
                                ghost['switch_devices_to_turn_off'] = {}
                            end
                            table.insert(ghost['switch_devices_to_turn_off'], device_id)
                            if not dry_run then
                                luup.call_action("urn:upnp-org:serviceId:SwitchPower1", "SetTarget", { newTargetValue = "1" }, device_id)
                            end
                        end
                    end
                end
                if rule['dimmer_devices'] then
                    for i, device_id in ipairs(rule['dimmer_devices']) do
                        if luup.variable_get("urn:upnp-org:serviceId:SwitchPower1", "Status", device_id) == "1" then
                            luup.log("Ghost " .. ghost_id .. " is NOT switching " .. ghostDeviceIdToName(device_id) .. " ON, it's already ON!")
                        else
                            local dimmer_level = rule['dimmer_level'] or 25
                            luup.log("Ghost " .. ghost_id .. " is switching " .. ghostDeviceIdToName(device_id) .. " ON to " .. dimmer_level .."%")
                            if not ghost['dimmer_devices_to_turn_off'] then
                                ghost['dimmer_devices_to_turn_off'] = {}
                            end
                            table.insert(ghost['dimmer_devices_to_turn_off'], device_id)
                            if not dry_run then
                                luup.call_action("urn:upnp-org:serviceId:Dimming1", "SetLoadLevelTarget", { newLoadlevelTarget = "" .. dimmer_level }, device_id)
                            end
                        end
                    end
                end
                luup.log("Schedule ghost termination in " .. ghost['duration'] .. " seconds")
                luup.call_delay("terminateGhost", ghost['duration'], ghost_id)
            else
                luup.log("Ghost " .. ghost_id .. " already killed, do nothing")
            end
        end
    end
end

function terminateAllGhosts()
    for i, ghost_id in ipairs(sorted_ghosts) do
        ghost = ghosts[ghost_id]
        terminateGhost(ghost_id)
    end
end

function terminateGhost(ghost_id)
    if (luup.variable_get("urn:upnp-org:serviceId:VSwitch1", "Status", at_home_virtual_switch_device) == "1") then
        luup.log("Not terminating ghost " .. ghost_id .. ", somebody is home")
    else
        local ghost = ghosts[ghost_id]
        if ghost then
            luup.log("Terminating ghost " .. ghost_id)
            if ghost['switch_devices_to_turn_off'] then
                for i, device_id in ipairs(ghost['switch_devices_to_turn_off']) do
                    luup.log("Ghost " .. ghost_id .. " is switching " .. ghostDeviceIdToName(device_id) .. " OFF")
                    if not dry_run then
                        luup.call_action("urn:upnp-org:serviceId:SwitchPower1", "SetTarget", { newTargetValue = "0" }, device_id)
                    end
                end
            end
            if ghost['dimmer_devices_to_turn_off'] then
                for i, device_id in ipairs(ghost['dimmer_devices_to_turn_off']) do
                    luup.log("Ghost " .. ghost_id .. " is switching " .. ghostDeviceIdToName(device_id) .. " OFF")
                    if not dry_run then
                        luup.call_action("urn:upnp-org:serviceId:SwitchPower1", "SetTarget", { newTargetValue = "0" }, device_id)
                    end
                end
            end
        else
            luup.log("Ghost " .. ghost_id .. " already terminated")
        end
    end
end

function scheduleGhosts()
    local current_time = os.date("*t", os.time())
    local seconds_from_midnight = current_time.hour * 3600 + current_time.min * 60 + current_time.sec

    luup.log("Scheduling ghosts...")
    local report = ""
    local ghosts_count = 0
    local scheduled_ghosts_count = 0
    for i, ghost_id in ipairs(sorted_ghosts) do
        ghost = ghosts[ghost_id]

        ghosts_count = ghosts_count + 1

        local starts_in = ghost['starts'] - seconds_from_midnight
        local ends_in = starts_in + ghost['duration']
        local status = ""
        if ends_in < 60 then
            status = "skipped, too late"
        elseif starts_in < 0 then
            status = "started " .. -starts_in .. " seconds ago, run now"
            ghost['duration'] = ghost['duration'] + starts_in
            scheduled_ghosts_count = scheduled_ghosts_count + 1
            wakeGhost(ghost_id)
        else
            status = "scheduled"
            scheduled_ghosts_count = scheduled_ghosts_count + 1
            luup.call_delay("wakeGhost", starts_in, ghost_id)
        end

        -- report
        local start_h = math.floor(ghost['starts'] / 3600)
        local start_m = math.floor((ghost['starts'] - (start_h * 3600)) / 60)
        local start_s = ghost['starts'] - (start_h * 3600) - (start_m * 60)
        local start_str = string.format("%02i:%02i:%02i", start_h, start_m, start_s)
        local duration_h = math.floor(ghost['duration'] / 3600)
        local duration_m = math.floor((ghost['duration'] - (duration_h * 3600)) / 60)
        local duration_s = ghost['duration'] - (duration_h * 3600) - (duration_m * 60)
        local duration_str = string.format("%02i:%02i:%02i", duration_h, duration_m, duration_s)
        local ends = ghost['starts'] + ghost['duration']
        local end_h = math.floor(ends / 3600)
        local end_m = math.floor((ends - (end_h * 3600)) / 60)
        local end_s = ends - (end_h * 3600) - (end_m * 60)
        local end_str = string.format("%02i:%02i:%02i", end_h, end_m, end_s)

        local report_line = string.format("%25s %s => %s (%s): %s", ghost['name'], start_str, end_str, duration_str, status)
        luup.log(report_line)
        report = report .. report_line .. "\n"
    end

    report_file = io.open('/tmp/ghosts.txt', 'w')
    report_file:write('Ghosts generated ' .. os.date("%x %X", os.time()) .. "\n\n")
    report_file:write(report)
end

if (luup.variable_get("urn:upnp-org:serviceId:VSwitch1", "Status", at_home_virtual_switch_device) == "0") then
    if (luup.variable_get("urn:upnp-org:serviceId:VSwitch1", "Status", ghost_virtual_switch_device) == "1") then
        generateGhosts()
        luup.call_delay('scheduleGhosts', 10)
    else
        luup.log("Not generating any ghost, virtual switch is OFF")
    end
else
    luup.log("Not generating any ghost, somebody is home")
end
Domoticz 3.5641 on RPI (Raspbian GNU/Linux 8)
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest