Mqtt: if I understand correctly

I have three computers in the house which each support Bluetooth:

  • An old laptop (chimera) running Ubuntu 15 which is my openHAB server and Mosquitto server (MQTT broker) among other things (file server, VPN, Plex, etc). This machine is on the top floor of the house

  • A first gen Raspberry Pi (garage) in the garage which is wired to a dual relay for triggering the garage door openers and to a couple of reed switches that detect whether or not the garage doors are open. It has a bluetooth dongle attached and it is located on the ground floor of the house.

  • Another first gen Raspberry Pi (hydra) in the basement which is wired to the sensors the previous owner had installed on the doors and windows of the house. It too has a bluetooth dongle attached.

Having bluetooth sensing on each of the three floors guarantees that the whole house gets coverage.

I followed the tutorial here to get bluetooth support on all three machines and install access to bluetooth through Python. I used the inquiry.py script to discover the addresses of my and my wife’s phones and then adapted the
detect.py script to work with a script I already wrote for reporting the door and window sensor outputs over MQTT to do the same for whether or not the bluetooth address is detected nearby or not.

So all three devices are sensing and reporting whether or not the BT devices are present and only if all three report that the devices are not present does openHAB mark that person as away. If both people are way the house goes into “away” mode. However, a person has to be away for more than five minutes before the away states become active to prevent the house from flipping back and forth when going to get the mail.

The rules and Items are as follows. I make heavy use of lambdas and group filters in my rules which makes them short but they might seem daunting for someone not used to writing rules.

Items:

Group:Switch:OR(ON,OFF) gPresent     "Present" <present>
Group:Switch:OR(ON,OFF) gRichPresent "Rich Present" <present> (gPresent)
Group:Switch:OR(ON,OFF) gJennPresent "Jenn Present" <present> (gPresent)

Switch   S_V_RichChimeraBT   <bluetooth> (gRichPresent) { mqtt="<[mosquitto:presence_sensors/bluetooth/chimeraRich:state:default]" }
Switch   S_V_RichGarageaBT   <bluetooth> (gRichPresent)  { mqtt="<[mosquitto:presence_sensors/bluetooth/garageRich:state:default]" }
Switch   S_V_RichHydraBT   <bluetooth> (gRichPresent)     { mqtt="<[mosquitto:presence_sensors/bluetooth/hydraRich:state:default]" }

Switch  S_V_JennChimeraBT   <bluetooth> (gJennPresent)  { mqtt="<[mosquitto:presence_sensors/bluetooth/chimeraJenn:state:default]" }
Switch  S_V_JennGarageBT   <bluetooth> (gJennPresent)    { mqtt="<[mosquitto:presence_sensors/bluetooth/garageJenn:state:default]" }
Switch  S_V_JennHydraBT   <bluetooth> (gJennPresent)      { mqtt="<[mosquitto:presence_sensors/bluetooth/hydraJenn:state:default]" }

Rules:

import org.openhab.core.library.types.*
import org.openhab.core.library.items.*
import org.openhab.model.script.actions.*
import org.joda.time.*
import org.eclipse.xtext.xbase.lib.*
import java.util.Map
import java.util.HashMap

val Map<SwitchItem, Timer> timers = newHashMap

val Functions$Function3 home = [ String name, SwitchItem homeSwitch, Map<SwitchItem, Timer> timers |
        logInfo("Presence", name + " was detected at home")
        var t = timers.get(homeSwitch)
        if(t != null) {
                t.cancel
                timers.put(homeSwitch, null)
        }
        homeSwitch.sendCommand(ON)
]

val Functions$Function4 away = [ String name, SwitchItem trigger, SwitchItem homeSwitch, Map<SwitchItem, Timer> timers |
        val timer = timers.get(homeSwitch)
        if(timer == null){
                logInfo("Presence", name + " is not home, setting timer before updating home state")
                timers.put(homeSwitch, createTimer(now.plusMinutes(5), [|
                        if(trigger.state == OFF) {
                                logInfo("Presence", name + " is still away after five minutes")
                                homeSwitch.sendCommand(OFF)
                        } else {
                                logInfo("Presence", name + " came back before timer went off")
                        }
                        timers.put(homeSwitch, null)
                ]))
        } else {
                logInfo("Presence", "Timer for " + name + " is already set")
        }
]

rule "Rich Presence Changed"
when
        Item gRichPresent changed or
        System started
then
        logInfo("Presence", "Rich Group state = " + gRichPresent.state)
        gRichPresent?.members.forEach(s|logDebug("Presence", s.name + " state = " + s.state))

        if(gRichPresent?.members.filter(s|s.state == ON).size > 0) home.apply("Rich", RichHome, timers)
        else away.apply("Rich", gRichPresent, RichHome, timers)
end

rule "Jenn Presence Changed"
when
        Item gJennPresent changed or
        System started
then
        logInfo("Presence", "Jenn Group state = " + gJennPresent.state)
        gJennPresent?.members.forEach(s|logDebug("Presence", s.name + " state = " + s.state))

        if(gJennPresent?.members.filter(s|s.state == ON).size > 0) home.apply("Jenn", JennHome, timers)
        else away.apply("Jenn", gJennPresent, JennHome, timers)
end
2 Likes