Domoticz - MikroTik presence management

Innen: IT documentation


Summary

In this method the base of presence will be a mobile device of the user. If the device connected to the home network then we consider that the user is at home.

A MikroTik router script is watching that the mac address of the device is present in the network and report this to the Domoticz Home Automation System. A Domoticz Lua script manages the arrives and the leaves and related events.

Features

  • Multiple users usage.
  • Turn on specified light(s) (or any swiches) after sunset when somebody arrives.
  • Turn off specified light(s) and set the heating to tempering mode when there is nobody at home.
  • Set the heating to normal mode (previous temperature values per thermostat) when somebody arrives.

Prerequisites

  • Have to know the mac address of the mobile device(s). Probable you can turn off the Randomized MAC on your devices at the home wifi network.
  • Have to create an integer user variable, what is going to store that the system is presence (1) or absence (0) mode.
  • Have to create two integer user variable per user, these are going to store that thes user is present or not, and the previous state, that the change can be perceptible.
  • Have to create an Float user variable per thermostat, in what the temperature value of presence mode will be stored.
  • Have to create a dummy "thermostat setpoint" device in the Domoticz, this is going to control the temperature of absence.
  • Have to create a selector switch device with Off, Presence, Auto, Absence levels. This device will define the mode of the operation, like:
    • Off: the script will be inactive
    • Presence: always presence mode, regardless of the position of the mobile devices
    • Auto: If at least one devide is at home, the mode is presence
    • Absence: always absence mode, regardless of the position of the mobile devices.

MikroTik

The MikroTik router can trigger a script when DHCP leases change, so enough that the current script run at this event. Although may occur in communication between MikroTik-Domoticz an error, so it is worth the script running by scheluded too. We can set in the Telemetry varaiable that how many seconds to be force refresh, although there was no change. Recommended that the schelude time and the value of the Telemetry variable be equal.

Put the datas of the users into the below script logically like mac address of mobile device and the domoticz user variable belonging to user and the domoticz api URL.

After save the script as "Domoticz_Presence", the script policy is enought if it is read only (read, policy, test)

## Domoticz presence handle MikroTik script

# @author moszat <moszat@onlinesoft.org>
# @copyright 2022 moszat
# @license GPL 3
# @version 1.1

# See the https://doc.onlinesoft.org/index.php?title=Domoticz_-_MikroTik_presence_management

## Parameters

:local DomoticzURL "http://192.168.1.10:8080/json.htm"
:local Telemetry 600s
:local items {
{
   pres="USER1_PRESENCE";
   mac="AA:BB:CC:DD:EE:FF";
};
{
   pres="USER2_PRESENCE";
   mac="00:11:22:33:44:55";
};
}

## Assistant variables

:local searchMac
:local ctime [/system clock get time]
:local forceupdate false
:global PRESENCE

# Set the global variable if not exsist

if ( [:typeof $PRESENCE]!="array" ) do={

   :set $PRESENCE ({})

}

# Init last update time

if ( [:len ($PRESENCE->"lastupdate")]=0 || ($PRESENCE->"lastupdate")>$ctime ) do={

   :set ($PRESENCE->"lastupdate") 00:00:00

}

## Logic

:set $forceupdate ((($PRESENCE->"lastupdate")+$Telemetry)<$ctime)

if ( $forceupdate ) do={

    :set ($PRESENCE->"lastupdate") $ctime

}

:foreach item in=$items do={

   :set searchMac [/ip dhcp-server lease find mac-address=($item->"mac") ]
  
   if ( ([:len $searchMac]>0) != ($PRESENCE->"$($item->"pres")") || $forceupdate ) do={
   
      :set ($PRESENCE->"$($item->"pres")") ([:len $searchMac]>0)

      if ($PRESENCE->"$($item->"pres")") do={

         /tool fetch mode=http url=$DomoticzURL http-data="type=command&param=updateuservariable&vname=$($item->"pres")&vtype=INTEGER&vvalue=1" output=none

      } else={

        /tool fetch mode=http url=$DomoticzURL http-data="type=command&param=updateuservariable&vname=$($item->"pres")&vtype=INTEGER&vvalue=0" output=none

      }
   }
}

Assign the script to the DHCP server (in our example: LAN)

/ip dhcp-server add address-pool=LAN bootp-support=none disabled=no interface=LAN lease-script="/system script run Domoticz_Presence" name=LAN

Schedule the script

/system scheduler add interval=10m name=Domoticz_Presence on-event="/system script run Domoticz_Presence" policy=read,policy,test start-date=jan/01/2022 start-time=00:00:00

Domoticz

After you create the user variables and the device, like at prerequisites, in the Domoticz, you can create the below Lua script at Domoticz events. The script trigger will be "User Variable".

Change the variables' and the devices' name according to your enviorment as descripted by script comment.

--[[

Domoticz presence handle Lua script

@author moszat <moszat@onlinesoft.org>
@copyright 2022 moszat
@license GPL 3
@version 2.0

See the https://doc.onlinesoft.org/index.php?title=Domoticz_-_MikroTik_presence_management

--]]

commandArray = {}

-- Parameters

-- PRESENCEVAR	The variable in what the current state of the house be stored (integer, 1 = presence, 0 = absence)

local PRESENCEVAR = 'PRESENCE'

-- Users' data
--
-- USERS[NAME]         User's name (free string)
-- USERS[TRIGGERVAR]   The variable what the external system is triggered. (integer, 1 = presence, 0 = absence)
-- USERS[STOREVAR]     The variable in what the previous state be stored (integer)

local USERS = {
    { 
        ["NAME"]        = "John Doe", 
        ["TRIGGERVAR"]  = "USER1_PRESENCE", 
        ["STOREVAR"]    = "USER1_PRESENCE_PREV" 
    },
    {
        ["NAME"]        = "Jane Doe", 
        ["TRIGGERVAR"]  = "USER2_PRESENCE", 
        ["STOREVAR"]    = "USER2_PRESENCE_PREV" 
    }
}

-- Light control
--
-- SWITCHESOFF  Switches what switch off when there is no presence (device names)
-- SWITCHESON   Switches what switch on when an arriving is occurred (device names)

local SWITCHESOFF   = { 'Bedroom switch', 'Livingroom switch', 'Childrenroom switch', 'Larder switch', 'Bathroom switch', 'Garden switch'}
local SWITCHESON    = { 'Garden switch' }

-- Heating contol
--
-- PRESENCEDEVICE           A dummy selector device for set to presence mode
-- ABSENCEDEVICE            A dummy thermostat setpoint device for set to absence temperature
-- THERMOSTATS[DEVICENAME]  Thermostat setpoint device name
-- THERMOSTATS[STOREVAR]    The variable in what the normal degree be stored in absence mode

local PRESENCEDEVICE = 'Presence'
local ABSENCEDEVICE = 'Thermostat Absence'
local THERMOSTATS = {
    
    {
      ['DEVICENAME']        = 'Kitchen thermostat - Setpoint',
      ['STOREVAR']          = 'TEMP_KITHCEN',
    },
    {
      ['DEVICENAME']        = 'Livingroom thermostat - Setpoint',
      ['STOREVAR']          = 'TEMP_LIVINGROOM',
    },
    {
      ['DEVICENAME']        = 'Bedroom thermostat - Setpoint',
      ['STOREVAR']          = 'TEMP_BEDROOM',
    },
    {
      ['DEVICENAME']        = 'Childrenroom thermostat - Setpoint',
      ['STOREVAR']          = 'TEMP_CHILDRENROOM',
    }, 
    
}

-- Assistant variables

local ARRIVING = false
local PRESENCE = false
local STOREDPRESENCE = false

-- Logic

if ( uservariables[PRESENCEVAR] == nil ) then
		
	print( PRESENCEVAR .. ' value does not exist' )
	return commandArray
		
end

if ( otherdevices[PRESENCEDEVICE] == nil ) then
		
	print( PRESENCEDEVICE .. ' device does not exist' )
	return commandArray
		
end

if ( otherdevices[PRESENCEDEVICE] == 'Off' ) then
		
	print( 'Presence handle is off. Exiting..' )
	return commandArray
		
end

if ( tonumber(uservariables[PRESENCEVAR]) == 0) then
    
    STOREDPRESENCE = false
    
else
    
    STOREDPRESENCE = true
    
end

commandArray['SetSetPoint:' .. otherdevices_idx[ABSENCEDEVICE]] = tostring(otherdevices[ABSENCEDEVICE])

-- Users' presence changed

if ( otherdevices[PRESENCEDEVICE] == 'Auto' ) then 

    for key, value in pairs (USERS) do
        
    	if ( uservariables[value['TRIGGERVAR']] == nil ) then
    		
    		print( value['TRIGGERVAR'] .. ' value does not exist' )
    	
    	elseif ( uservariables[value['STOREVAR']] == nil ) then
    		
    		print( value['STOREVAR'] .. ' value does not exist' )
    		
        elseif ( uservariables[value['TRIGGERVAR']] ~=   uservariables[value['STOREVAR']] ) then 
        
            if ( tonumber(uservariables[value['TRIGGERVAR']]) == 1 ) then
            
                print ( value['NAME'] .. ' is arriving ... ')
                ARRIVING = true
            
            else
            
                print ( value['NAME'] .. ' is leaving ... ')
            
            end
        
            commandArray['Variable:' .. value['STOREVAR'] ] = tostring(uservariables[value['TRIGGERVAR']])
    
        end
    
        if ( tonumber(uservariables[value['TRIGGERVAR']]) == 1 ) then
    
            PRESENCE = true
        
        end
    
    end

elseif ( otherdevices[PRESENCEDEVICE] == 'Presence' ) then

    PRESENCE = true
    print( 'Forced presence is on.' )

elseif ( otherdevices[PRESENCEDEVICE] == 'Absence' ) then

    PRESENCE = false
    print( 'Forced absence is on.' )

end

-- Arriving occurred

if ( ARRIVING == true ) then

    -- LIGHT set on

    if ( timeofday['Nighttime'] ) then

        for key, value in pairs (SWITCHESON) do
    
    		if ( otherdevices[value] == nil ) then
    			
    			print( otherdevices[value] .. ' device does not exist' )
    			
            elseif ( otherdevices[value] == 'Off') then 
    
    			commandArray[value] = 'On'
    			print ( value .. ' set on')
    
    		end
            
        end
        
    end
    
end

-- Presence / Absence handle

if ( PRESENCE ~= STOREDPRESENCE ) then
    
    
    if ( PRESENCE ) then
        
        -- Set Presence
        
        -- Writes back the new state to PRESENCEVAR user variable
        
        commandArray['Variable:' .. PRESENCEVAR ] = '1'
        print ('Presence set on')
        
        -- HEATING set presence mode

        for key, value in pairs (THERMOSTATS) do
			
			if ( uservariables[value['STOREVAR']] == nil ) then
				
				print( value['STOREVAR'] .. ' value does not exist' )
				
			elseif ( otherdevices[value['DEVICENAME']] == nil ) then
			
				print( value['DEVICENAME'] .. ' device does not exist' )
				
			else
            
            	commandArray['SetSetPoint:' .. otherdevices_idx[value['DEVICENAME']]] = tostring(uservariables[value['STOREVAR']])
            	print ( value['DEVICENAME'] .. ' set ' .. uservariables[value['STOREVAR']])
				
			end
             
        end
        
    else
        
        -- Set Absence
        
        -- Writes back the new state to PRESENCEVAR user variable
        
        commandArray['Variable:' .. PRESENCEVAR ] = '0'
	    print ('Presence set off')
	    
	    -- LIGHTIG set absence mode

        for key, value in pairs (SWITCHESOFF) do
    
    		if (  otherdevices[value] == nil ) then
    			
    			print( otherdevices[value] .. ' device does not exist' )
    		
            elseif ( otherdevices[value] == 'On') then 
    			
                commandArray[value] = 'Off'
                print ( value .. ' set off')
    			
            end
            
        end
        
        -- HEATING set absence mode
	
    	if ( otherdevices[ABSENCEDEVICE] == nil ) then
    		
    		print( ABSENCEDEVICE .. ' device does not exist' )
    		
    	else
    
    		for key, value in pairs (THERMOSTATS) do
    
    			if ( uservariables[value['STOREVAR']] == nil ) then
    
    				print( value['STOREVAR'] .. ' value does not exist' )
    
    			elseif ( otherdevices[value['DEVICENAME']] == nil ) then
    
    				print( value['DEVICENAME'] .. ' device does not exist' )
    
    			else
    
    				commandArray['Variable:' .. value['STOREVAR']] = otherdevices[value['DEVICENAME']]
    				commandArray['SetSetPoint:' .. otherdevices_idx[value['DEVICENAME']]] = tostring(otherdevices[ABSENCEDEVICE])
    				print ( value['DEVICENAME'] .. ' set ' .. otherdevices[ABSENCEDEVICE] ) 
    
    			end
    
		    end
		
    	end

    end

end

return commandArray