In these last days I have implemented three new features of Phase 2 that will make DomPi more useful to my family: determine who is at home, welcome the family when we arrive home and send an alert if the average temperature of the apartment is either too high or too low. Let´s have a look at them!

 

Previous Posts

PiIoT - DomPi: ApplicationPiIoT - DomPi: IntroPiIoT - DomPi 02: Project Dashboard and first steps in the Living room
PiIoT - DomPi 03: Living room, light control via TV remotePiIoT - DomPi 04: Movement detection and RF2.4Ghz commsPiIoT - DomPi 05: Ready for use Living Room and parents and kids´ bedrooms
PiIoT - DomPi 06: Setting up the Command Center - RPI3PiIoT - DomPi 07: Setting up the Command Center (2)PiIoT - DomPi 08: Setting up the Command Center (3) openHAB, mosquitto, RF24
PiIoT - DomPi 09: Presence EmulatorPiIoT - DomPi 10: Garage node (slave)PiIoT - DomPi 11: Ready to use. Garage node (master & slave)
PiIoT - DomPi 12: Ready to use. Control Panel and Garden NodePiIoT - DomPi 13: Ready to use. DomPi Phase 1

 

Project Status

Project Status

Presence Identification

This feature allows DomPi know, not only know if there is somebody at home, but also who is there. The best solution as of now to implement this, is to check whose mobile phone is at home. I know this has some drawbacks like, what if the phone is off or if we left it at home... To partially sort out this problem, DomPi also leverages the motion sensors to limit the impact of it and make it more reliable. Let´s have a look at all this.

 

At the beginning, I thought of using the command line (via the executeCommandLine function from openHAB) and then parsing the output of the "ping" in the RPI. While I was working on this, I have come across an existing binding in openHAB that has made the development much easier and faster It is the Network Health Binding, some more details here. This binding connects an item in openHAB with the status of any device or host in general. You could for example check the "network health" of your RPI to communicate with www.google.com or www.element14.com for instance. For DomPi, I am controlling the network connectivity to the IP´s of our mobile phones. Let´s review the installation and initial config of the binding and have a look then at the implementation.

 

Installation and initial config

As with any binding, you just need to download the binding in itself (the best approach is to download all of the addons from here as commented in previous posts) and copy the relevant binding (in my case the .jar file is: org.openhab.binding.ntp-1.8.3) into the openhab/addons folder. To perform some fine tune, you just need to modify some of the lines in the openhab.cfg file:

# Cache the state for n minutes so only changes are posted (optional, defaults to 0 = disabled)
# Example: if period is 60, once per hour the online states are posted to the event bus;
#          changes are always and immediately (refresh interval) posted to the event bus.
# The recommended value is 60 minutes.
networkhealth:cachePeriod=60

# refresh interval in milliseconds (optional, default to 60000)
#networkhealth:refresh=60000

 

At the end, I modified the line 5 here and uncommented. By allowing the cache, the binding gets the status of the devices as always, and only updates the item if there is a change in the status. This means, there will only be updates if the phones go out or in range. With no cache, there would be updates posted to the openHAB bus every refresh interval (60s as per line 7). I don´t need to overload the bus with this information, but also if you add persistance, there would be a huge volume to store all of these updates in the HDD... In any case, the binding will update the devices status every hour. All in all, with the cache enabled, openHAB will let me know if the devices go from ON to OFF or viceversa and also every hour it will send an update. I kept the networkhealth refresh (line 8) with the default value.

 

Implementation in DomPi

Potentially, you can connect directly an item to the binding and just display in openHAB its status. Something like this:

Switch Papa_tlf_nh "Papa Network Binding"  <present> (gStatus, gPresencia_casa_nh) nh="192.168.1.140" }

 

This would display a switch showing if the mobile phone is in range or not. However, this would not be optimum. It seems that my mobile phone goes into sleep mode with the Wifi, probably to save up battery. I have not stress-tested but I guess while on sleep mode, it will not reply to pings. The solution I have implemented is to apply a double level of switches: one as above connected directly to the binding and yet another one controlled by an openHAB rule.

 

The rule will get the updated status from the first level switch. When it is in range, it will directly update the second level. However, when it is out of range, it maybe that the phone is on sleep mode. Therefore, it will wait 8 minutes. If within this time, DomPi has not seen the phone in range, it determines that the user/phone is out from home. The description of the second level switch is this:

Switch Papa_tlf "Papa" <present>    (gStatus, gPresencia_casa)

 

And the rule is here:

rule "Presence Identification - Father"
when 
    Item Papa_tlf_nh changed
then
    //If the temporary item Papa_tlf_nh has changed to ON, 
    //we directly update the final item Papa_tlf and cancel the relevant timer if exists
    if (Papa_tlf_nh.state==ON) {
        postUpdate(Papa_tlf, ON)
        if (timer_presenceID_papa!= null) {
            timer_presenceID_papa.cancel
            timer_presenceID_papa = null
        }
    } else if (Papa_tlf_nh==OFF) {
        //If it is OFF, it can be that the phone is saving battery on Wifi
        //Let´s allow 8 minutes since the last time it was updated before putting presence to OFF
        if (timer_presenceID_papa == null) {
            //if there was no timer until now, create it
            timer_presenceID_papa = createTimer(now.plusSeconds(480)) [|
                //Allow 8 minutes and modify Papa_tlf item 
                if (Papa_tlf_nh==OFF) postUpdate(Papa_tlf, OFF)
                if (timer_presenceID_papa!= null) {
                    timer_presenceID_papa.cancel
                    timer_presenceID_papa = null
                }
            ]
        }
    }
end

 

The drawback of this implementation is that I need a rule per phone to control. In the end I am just planning to monitor two phones so it won´t be a big issue. However, I need to review openHAB's capabilities as I am sure I can condense all the devices to monitor into a single rule. I will look into this when optimizing the code, after the Challenge unfortunately... You can see some snapshots below with this feature. The line Quien esta en casa? => Who is at home? summarizes in the Main Menu how many people are there. It is a clickable item that takes you to the right hand side submenu with the details.

 

Presence_IDPresence_ID

 

Welcome Home feature

With this, I intend to execute some actions when somebody has arrived home. At this stage, the action is to turn on the lights of the living room and the parents´ bedroom and in the next development it will also turn on the TV and switch it to the TV channel we usually watch. This can be very useful to us, as you can have some light at the end of the corridor without having to walk till there. Also the light in our room takes time to be fully lit, so it is good as well to turn it on some minutes in advance. I have written the code and split it in four openHAB rules.

 

How it works

It all starts by determining when the apartment is empty. Since it is after the flat is empty when it makes sense to wait for the family and welcome them warmly or at least "lightly". The first rule is quite straightforward:

//This rule determines if there is presence at home
rule "Detect any presence at home"
when
     Item Nodo09MotionDetected changed from OFF to ON or
     Item Papa_tlf changed from OFF to ON or
     Item Mama_tlf changed from OFF to ON
then
     if (Someone_at_home.state!=ON) postUpdate(Someone_at_home, ON)
end

 

If there is movement, or DomPi discovers any phone at home, then we determine that there is a family member. This assumption has to be fine tuned in the future: what about if we forgot the mobile phones, etc. It may happen that there is motion detected because a burglar broke in... We should not welcome him or her This is controlled by another rule, that checks the status of the Alarm Switch, if it is on, then we won´t trigger the welcome feature:

 

rule "Welcome home family"
/*If someone has arrived home and there was nobody before inside, let´s do:
 *         Turn on light in the living room if luminosity is low
 *         Turn on light in the parents bedroom if luminosity is low
 *         Improvements: turn on TV and say hello
 */

when
    Item Someone_at_home changed from OFF to ON
then
    if (Nodo09AlarmSwitch.state==OFF) {
        //Reconfirm that the alarm switch is off - it can be that rule "Detect any presence at home"
        //has changed Someone_at_home, but alarm is active
        say("Welcome at home!!")    //Let´s be nice to the family even if no lights needs to be turned on ;)
        if (gLuminos.state<50) {
            //Average luminosity is low, lets turn on the lights
            postUpdate(Lampara_2, ON)        //Parents light
            postUpdate(Lampara_3, ON)        //Living room light
        }
    } else if (Nodo09AlarmSwitch.state==ON) postUpdate(Someone_at_home, OFF)
end //We avoid welcoming burglars!

 

As you can see in lines 15 to 18, before turning on the lights, it checks the average luminosity in the apartment, taking into account only the luminosity from the sensors in the flat: kids, parents and living rooms. If the average is below 50%, it turns on the lights. I will adjust this value after some days testing it.

 

The last two rules determine whether the family came back home or left home. They will update the item Someone_at_home accordingly:

//This rule determines if there is nobody at home and if so updates item
rule "Did family leave home"
when
    Item Someone_at_home changed from OFF to ON 
    //Thread launched as soon as we determine someone is at home. 
    //It will start to check the conditions to determine that there is noone at home
then
    if (timer_presenceat_home!= null) {
        timer_presenceat_home.cancel
        timer_presenceat_home = null
    }
    while (Someone_at_home.state==ON) {
        //if there is no motion detected and all of the members from gPresence_casa (Mama and Papa)
        //are in the state OFF, which means they are not at home, then execute the loop inside
        if (Nodo09MotionDetected.state==OFF && (gPresencia_casa.members.filter(s | s.state==OFF).size==0)) {
            //Wait 30 mins and check again if there was any movement
            //this long delay helps to avoid issues if somebody is in the bath, etc
            timer_presenceat_home = createTimer(now.plusSeconds(1800)) [|
                if (Nodo09MotionDetected.state==OFF && (gPresencia_casa.members.filter(s | s.state==OFF).size==0)) {
                    //Still no movement -> modify item
                    postUpdate(Someone_at_home, OFF)
                }
                if (timer_presenceat_home!= null) {
                    timer_presenceat_home.cancel
                    timer_presenceat_home = null
                }
            ]            
        }
        if (Someone_at_home.state==ON) Thread::sleep(120000) //Every 2 mins determines if someone is at home
    }        
end    

rule "Did family come back home"
when 
    Item Someone_at_home changed from ON to OFF
    //Thread launched as soon as we determine nobody is at home
    //It will start checking the conditions to determine that somebody entered home
    //Conditions to determine someone at home:
    //  if there is a mobile phone in the wifi range
        //There is no need to check if any mobile phone appears in range via the Network Binding
        //since there is already a rule ("Detect any presence at home") that would modify the
        //item Someone_at_home to ON
    //  if there is motion detected and 1)the alarm is not active, or 2)alarm is active but 
    //    user turns it off within time limit 
then
    while (Someone_at_home.state==OFF) {
        if (Nodo09MotionDetected.state==ON) {
            if (Nodo09AlarmSwitch.state==OFF) postUpdate(Someone_at_home, ON)
            else {
                //val t_delay = t_delay_trigger_alarm * 1000 + 200
                Thread::sleep(60200)    //Wait the 60 secs plus 200 ms to allow some updates //Change with t_delay_trigger_familyhome 
                if (Nodo09AlarmSwitch.state==OFF) postUpdate(Someone_at_home, ON)
            }
        }
        if (Someone_at_home.state==OFF) Thread::sleep(10000)        //Sleep for 10s before checking again
    }
end

 

Temperature Alarm

This feature notifies me per email if any temperature sensor at home is below 20ºC or above 27 ºC. Many thanks to jkutzsch who gave me the idea back in May, at the very beginning of the Challenge. Finally, I can implement it I have implemented it in a single rule. If the alarm is triggered and the email sent to myself, then the rule launches a timer to wait for 1h before sending again any notification: I want to avoid spamming myself!

/*
 * Rule to send an email warning if temperature at any room is out of a given range
 */
rule "Notify of extreme temperature at home"
//If any room is below 20ºC or above 27ºC send notify per email
when
    Item gTempers received update
then
    //First step to check if the timer is not null, this implies that there was an email already sent and 
    //DomPi is waiting some time (1h-2h) before resending the notification


    if (timer_extreme_temperature_alarm==null) {
        //no timer - we can send the email if required
        //check values of the temperature sensors from home (interiors only)
        gTempers?.members.forEach(tsensor| {
                if (tsensor.state>=27) send_alarm_high_t = true
                if (tsensor.state<=20) send_alarm_low_t = true        
            }
        )
        if ((send_alarm_high_t) || (send_alarm_low_t)) {
            //Send email with the alarm and then create the timer
            var String email_subject =""
            var String email_body =""
            if (send_alarm_high_t) {
                email_subject = "Alta temperatura en Casa. Alarma"
                email_body = "Detectada alta temperatura en casa"
            }
            if (send_alarm_low_t) {
                email_subject = "Baja temperatura en Casa. Alarma"
                email_body = "Detectada baja temperatura en casa"
            }
            sendMail("XXXX@gmail.com", "DomPi - " + email_subject, email_body)
           
            timer_extreme_temperature_alarm = createTimer(now.plusSeconds(3600)) [|
                //Wait 1h and then just remove the timer to allow next notification as required
                if (timer_extreme_temperature_alarm!=null) {
                    timer_extreme_temperature_alarm.cancel
                    timer_extreme_temperature_alarm = null
                }
            ]
        }    
    }    
end

 

Additional improvements

As I continue to run through the existing rules, I find ways to improve on them. Below a summary of the news this week:

  • Show the internal average temperature and humidity in the main menu - before it was not implemented
  • Create a submenu which quickly shows the temperatures and humidity
  • Alarm - new rule created to turn Alarm Status back to OFF after 2 minutes of no movement being detected to avoid having a false alarm sine die...
Main Menu temp humHumidity

 

Nodes´ Dashboard

Nodes Dashboard

 

More items turning into Green!!