Summer is coming - Are my kid's tablets outside? (WIP)

Well, summer is coming to the northern hemisphere. Without fail my kids will use their tablets outside and on at least one occasion, will forget them overnight.

I figured I can solve this problem automagically. Below is how it’ve done it.
It uses the great Unifi binding by @mgbowman

What you need

  • I’ve got multiple APs in the house (4) and in the garden (2).
  • 3 of the APs can be seen clearly from the garden by most devices. Devices cling on to them whilst in the garden.
  • I specify which are “Questionable” APs and which are “Barred” APs.
  • When an event triggers like night time, rain started or Bedtime scene, the rule will run.
  • Any wifi devices connected to the questionable APs will be kicked and wait for a reconnect.
  • Once reconnected they will be checked again. If they’re still outside or have now moved outside, an alert is sent. Thinking email, app or Alexa.

This is still WIP so any feedback welcome.
This could have been done better with FIND3 but this way you don’t need anything else other than your existing APs and Unifi.

Items

Group g_PhonesAPs
Group g_PhonesBlocked
Group g_QuestionPhones

Switch   CrispinPhone           "Crispin [MAP(unifi.map):%s]"  <boy_2>   (g_PhonesPresent, g_WhosHome, g_QuestionPhones)   { channel="unifi:wirelessClient:home:crispinPhone:online" }
String   CrispinPhoneAP         "Crispin's Phone: AP [%s]"             (g_persist_change, g_PhonesAPs)            { channel="unifi:wirelessClient:home:crispinPhone:ap" }
Switch   CrispinPhoneBlocked    "Crispin Blocked"                      (g_PhonesBlocked)           { channel="unifi:wirelessClient:home:crispinPhone:blocked" }

Switch   DenisePhone           "Denise [MAP(unifi.map):%s]"    <girl_3>  (g_PhonesPresent, g_WhosHome, g_QuestionPhones)     { channel="unifi:wirelessClient:home:denisePhone:online" }
String   DenisePhoneAP         "Denise's Phone: AP [%s]"                (g_persist_change, g_PhonesAPs)         { channel="unifi:wirelessClient:home:denisePhone:ap" }
Switch   DenisePhoneBlocked    "Denise Blocked"                         (g_PhonesBlocked)        { channel="unifi:wirelessClient:home:denisePhone:blocked" }

rule


var questionAPs = newArrayList(
                "AP Garden",
                "AP Shed",
                "AP Utility",
                "AP.Backroom.1"
)
var barredAPs = newArrayList(
                "AP Garden",
                "AP Shed"
)



rule "Question Phones"
when Item KKLL changed
then
    logWarn("KKLL", "Starting")

    g_QuestionPhones?.allMembers.forEach[item |
        val apItem = g_PhonesAPs.members.findFirst[ t | t.name == item.name + "AP" ] as StringItem
        if (apItem === null){
            logError("Question Phones", "Could not find AP Item for " + item.name)
            return;
        }
        logWarn("Question Phones", item.name + " - AP Found:" + apItem.name)
        logWarn("Question Phones", item.name + " - Location:" + apItem.state.toString)
        
        if (questionAPs.contains(apItem.state.toString)){
            logWarn("Question Phones", item.name + " IS LOCATED " + apItem.state.toString)
            val blockedItem = g_PhonesBlocked?.members.findFirst[ t | t.name == item.name + "Blocked" ] as SwitchItem
            if (blockedItem === null){
                logError("Question Phones", "Could not find Blocked Item for " + item.name)
                return;
            }
            blockedItem.sendCommand(ON)
            Thread::sleep(500)
            blockedItem.sendCommand(OFF)
            logWarn("Question Phones", item.name + " was kicked ")
            Thread::sleep(3000)
            logWarn("Question Phones", item.name + " - Location:" + apItem.state.toString)

            //where is it now.
            if (barredAPs.contains(apItem.state.toString)){
                logError("Question Phones", item.name + " is still located in " + apItem.state.toString)
                //this is where you send your error alert.

            }

        }
        // else {
        //     logWarn("Question Phones", item.name + " IS NOT LOCATED " + apItem.state.toString)
        // }

    ]
end 

TODO:

  • I want to remove the sleeps.
  • Need to improve error handling in some of the cases.

Feedback always welcome with this.

C

1 Like

Another notification method could be the telegram action, little complex the setup the first time, but once done its a very simple line in rules; below is what I use as a reminder if the garage door is left open at night:

sendTelegram("bot1", "Garage door is still open")

As far as reducing the sleeps, you could setup a couple of virtual items (not tied to any thing/device) and set an expire on the item matching your sleeps. Instead of doing a Thread::sleep you can do a sendCommand(ON) and activate the timer, I’m not sure it can do 500 msec (not something I’ve tried) but 3 seconds should be possible.

I’ve been wanting to get telegram set up. You happy with the way it works for you?

I was thinking email but I drown in emails and this would just add more.

C

OH is what made me sign up for Telegram and now I push others to it as a communication platform. Spouse and I have a secret chat setup and after showing her how to set the self destruction feature I even shared a picture of a health insurance card for an hour as she needed it to sign some paper work for something.

In the case of OH I setup the bot to be an admin in a channel (like a group chat but only admins can send messages); which could be helpful in your case if you want a kid to be notified they need to bring electronics into the house but prevent them from spamming the chat.
One of my next to do’s with OH and telegram is to setup a rule to send a notification if a door sensor flips to open if no known phone is on my wireless; intrusion notification basically without having to pay monthly fees to some company.

So two options come to mind here…

  1. We could add a “reconnect” channel in the binding vs. you blocking and sleeping 500ms and unblocking - this should be easy to implement.

  2. I’m not sure if this is possible with the UniFi API (I think it is), but what if you could just “disable” those APs in the garden at night? After which you could set a timer to see if the devices are connected or not.

I’m currently finishing up a “site” thing that has 4 “count” channels with the total clients, wired clients, wireless clients and guest clients. I plan on doing the same “count” channels for APs as well (so a “ap” thing is coming soon). This may help in knowing if the devices are connected or not.

1 Like

Within the ubnt software there is a disconnect option. If that could be exposed it could at least get rid of one of my sleeps. I can then issue that and in a timer poll for the reconnect. That would help. :slight_smile:

The devices can still see the ones in the house so they’ll connect via that. The RSSI for the garden and shed ones is such that anything outside will always jump onto that.

If unifi exposed the rssi for a device from other APs then you could use the FIND3 method of locating. That would be great :slight_smile:

Thanks again for the great add-on.

C

Could you not play around with the min RSSI on the APs in the house to prevent the devices from outside connecting if they were in fact left outside?

If not, maybe disabling the APs outside then looking at the RSSI values for the inside AP (signal strength should be weaker if device is outside) could tell you if a device is still outside.

I could.

I think the solution in play now though does a good enough job. It’ll be slightly better with the kick function :wink: No real rush with that though.