Rather than me try to explain how this works, feel free to take a look at this written by a member of the home assistant community:
http://nbviewer.jupyter.org/github/robm ... rial.ipynb
The script is partly its own script, but most of it resides in the global_data.lua file as a helper script. The actual probabilities in my script are literally random numbers Ive used for testing - swapping my devices for yours wont work Im afraid.
Main code:
Code: Select all
--**********************************
-- DESCRIPTION:
-- This script aims to use probability to determine whether a room is occupied. It is based upon the
-- home assistant script that operates in a smiliar way. Devices effect the probability in two ways
-- either when they are on, or if they were last seen between certain times. The script requires the following:
-- VARIABLES:
-- room name: The name of the room, set the name of the switch the script triggers
-- prior: The prior probability of the event. At any point in time (ignoring all external influences)
-- how likely is this event to occur?
-- threshold: The probability at which the sensor should trigger to on.
--devicesToCheckOn : An array containing the following:
-- Name: Name of the entity to monitor.
-- true_prob (Required): The probability of the observation occurring, given the event is true.
-- false_prob (Optional): The probability of the observation occurring, given the event is false.
--deviceTimesToCheckLastSeen : An array containing the following:
-- Name: Name of the entity to monitor.
-- true_prob (Required): The probability of the observation occurring, given the event is true.
-- false_prob (Optional): The probability of the observation occurring, given the event is false.
-- startmin: the start of the range that will trigger this rule
-- endmin: the end of the range that will trigger this rule
-- E.G if startmin is 0 and endmin 5 then switch seen in the last 5 minutes triggers the probability
-- Why have timer rules?
-- We do this to increase accuracy. The probability model works MUCH better with more inputs
--What are the outputs?
-- None, the script triggers a switch that takes the name 'room_name Occupied' - ie 'Living Room Occupied' this will need to be created.
-- Why do you have so many devices as triggers?
-- the triggers have to be set to anything that can effect the probability so a VERY long list. Because of this I would recommend
-- starting the script name with 'Z' so it triggers last.
--**********************************
return {
on = {
devices = {
'Conservatory Motion Sensor',
'Kitchen Motion Sensor',
'Bedroom Motion Sensor',
'Living Room Motion Sensor (Main)',
'Upstairs Hall Motion Sensor (Bottom)',
'Downstairs TV',
'Living Room Motion Sensor (Desk)'},
timer = {
'every minute'
}
},
data = {
counter = { initial = 0 }
},
execute = function(domoticz, device)
--**********************************
--
-- Living Room
--
--**********************************
--set the room name
local room_name = "Living Room"
-- Set Devices that we want to check the last seen for
local deviceTimesToCheckLastSeen= {
{ ['name'] = 'Conservatory Motion Sensor', ['true_prob'] = 0.5,['false_prob'] = 0.3,['startmin'] = 0,['endmin'] = 5 },
{ ['name'] = 'Conservatory Motion Sensor', ['true_prob'] = 0.5,['false_prob'] = 0.3,['startmin'] = 5,['endmin'] = 15 }
}
-- Set Devices that we want to check are on
local devicesToCheckOn = {
{ ['name'] = 'Conservatory Motion Sensor', ['true_prob'] = 0.5,['false_prob'] = 0.3 },
{ ['name'] = 'Kitchen Motion Sensor', ['true_prob'] = 0.75,['false_prob'] = 0.5 },
{ ['name'] = 'Bedroom Motion Sensor', ['true_prob'] = 0.2,['false_prob'] = 0.7 },
{ ['name'] = 'Living Room Motion Sensor (Main)', ['true_prob'] = 1,['false_prob'] = 0 },
{ ['name'] = 'Living Room Motion Sensor (Desk)', ['true_prob'] = 1,['false_prob'] = 0 },
{ ['name'] = 'Upstairs Hall Motion Sensor (Bottom)', ['true_prob'] = 0.75,['false_prob'] = 0.1 },
{ ['name'] = 'Downstairs TV', ['true_prob'] = 0.75,['false_prob'] = 0.25 }
}
-- Set the starting probability
local prior = 0.5
-- Set the activation threshold
local threshold = 0.85
domoticz.helpers.occupied(domoticz, devicesToCheckOn, deviceTimesToCheckLastSeen, room_name, prior,threshold)
end -- end dzvents
}
Code: Select all
return {
helpers = {
bayes = function(prior, true_prob, false_prob)
numerator = prior * true_prob
denominator = numerator + false_prob * (1- prior)
prior = numerator / denominator
return prior
end,
occupied = function(domoticz, devicesToCheckOn, deviceTimesToCheckLastSeen, room_name,prior,threshold)
local text_for_log= ""
--Start by looping through all the motion sensors
for i, deviceToCheck in pairs(devicesToCheckOn) do
old_prior = prior
if domoticz.devices(deviceToCheck['name']).state == 'On' then
prior = domoticz.utils.round(domoticz.helpers.bayes(prior, deviceToCheck['true_prob'], deviceToCheck['false_prob']),3)
text_for_log = text_for_log .."\n" .. deviceToCheck['name'] .. " On: " .. "Old prior was: " .. old_prior .. ". New prior is : " .. prior
end
end
--Start by looping through all the devies with time settings
for i, deviceToCheck in pairs(deviceTimesToCheckLastSeen) do
local device_last_seen = domoticz.devices(deviceToCheck['name']).lastUpdate.minutesAgo
if device_last_seen >= deviceToCheck['startmin'] and device_last_seen < deviceToCheck['endmin'] then
old_prior = prior
prior = domoticz.utils.round(domoticz.helpers.bayes(prior, deviceToCheck['true_prob'], deviceToCheck['false_prob']),3)
text_for_log = text_for_log .."\n" ..("Motion between " .. deviceToCheck['startmin'] .. " and " .. deviceToCheck['endmin'] .. " minutes, old prior was: " .. old_prior .. ".New prior: " .. prior)
end
end
--update the text (I use a switch, the current setting is to log)
--domoticz.devices(room_name .. " Bayesian").updateText(text_for_log)
print(text_for_log)
--finally decide if the room is occupied
if prior >= threshold then
domoticz.devices(room_name .. " Occupied").switchOn().checkFirst()
else
domoticz.devices(room_name .. " Occupied").switchOff().checkFirst()
end
end
}
}