Philips’ Hue Sensor Automation

I wrote about my first pass at the Philips’ Hue API to customise the motion sensor functionality back in December. At the time, I tested out my approach to force a third time slot [use of a nightlight setting for part of the the night] using a simple mobile app in Objective C. The approach isn’t that fancy: it’s basically 3 API PUT calls: two to rules, and then a third to a resourcelink all basically doing the same thing: inverting references to scenes [one for full brightness, and the other for the nightlight setting].

At the time I thought it would be handy to use a Raspberry Pi using cron jobs to toggle it off and on, and the long and short of it, that’s what I’ve gone with. It’s a simple Python script [using the Requests module, which is great, to make the API calls], and it’s working really well so far.

A couple of observations. First, I found an article on the Hue discussion forum – which I only found when I got a weird error and which, unfortunately I can’t find any more – that has what’s probably a more purist way of using the API to create extra slots. While it’s smarter than what I’m doing, unfortunately [and the author of the post does point this out] it has the effect of stopping the mobile app from working to set the sensor.

Secondly, my approach is pretty brittle. Between writing the app and implementing the Python script the state had changed in the bridge: there was a new scene [not one we added – at least intentionally] which was causing the API calls to fail.

Currently, my script is doing exactly what my mobile app did, which is creating the PUT payload for the API calls from files, and ‘hoping’ that they work. What the Philips’ mobile app does is to GET the various API resources and then PUT them back. I’ll do this when the current implementation breaks as it’s more trouble than it’s worth for now.

I was telling someone at work [a proper developer] about my results with proxying via ZAP, which I had to revisit to figure out why my original implementation had stopped working, and he couldn’t believe the fact that the app is making around 55 API calls to effect a change in the sensor setup. Based on the diffs I looked at, It seems to pretty blindly do the GETting and PUTting where no changes have been made.

I managed to completely corrupt the setup on the bridge by playing the ‘I wonder what will happen if I do this?’ game: I deleted the scene that was breaking my API calls. I ended up having to do a factory reset – about a five minute job for me, but worth bearing in mind if you are playing with this stuff and have a more sophisticated configuration.

Automating Philips Hue Motion Sensor Functionality

OK, this turned out to be a *lot* more complicated than I thought. Here’s what I wanted to do: we have a Hue motion sensor in the bathroom which I’ve set up to do nothing during the day, and then come on at night. Nothing too controversial there. But I wanted to have a 3rd option: for a certain section of the night – say after midnight – to come on at a nightlight setting.

There’s a ‘3 times a charm formula‘ from the Hue Labs which sounded promising, but that only allows you to set the idle time after motion activation. So I started looking at the API. There were a few obvious options I tried which didn’t work [like simply setting the brightness – over-written by whatever scene you have set in the accessory setup].

This article set me on the right track for what I needed to do insofar as rule settings. By toggling changes on the smartphone app and then looking at the results in the Clip API debugger I narrowed down the changes to two rules called ‘MotionSensor 5.night-on’ and ‘MotionSensor 5.night-dark-on’. [Obviously the number is dependent on the identifier the sensor is registered under.]

This isn’t enough on its own. I gave up on this after my first pass, waiting for a rainy day to come back to it – today.

I ended up using OWASP ZAP to proxy the Hue app traffic, to see what it was doing when you submit a change to the sensor configuration. That’s quite interesting actually: I was initially a bit puzzled at what looked like a mountain of traffic on first pass, but what in part turns out to be a very zealous keep-alive – roughly twice a second.

Long and short of it is that resetting the scene config using the app overwrites a ‘resourcelink’ with new scene specific values, as well as updating the rules.

I’ve roughed this out with my own iOS app just to check that it works in a way that I can transplant to another setup [a cron job on a Raspberry Pi would be a reasonable candidate]. To toggle on the ‘dim at night after midnight’ setting I make 3 API calls. You’ll need to fiddle around with the clip tool to get the equivalents for your hub – specifically, your sensor number will be different. For me, these are:

  • Rule: MotionSensor 5.night-on
  • Rule: MotionSensor 5.night-dark-on
  • Resourcelink: MotionSensor 5

For the rules, I Post the same ‘actions’ payload to both of the corresponding endpoints. It looks like:

{"actions": [
                {
                        "address": "/groups/YourActionNumber/action",
                        "method": "PUT",
                        "body": {
                                "scene": "YourDimSceneIDHere"
                        }
                },
                {
                        "address": "/sensors/YourStateNumber/state",
                        "method": "PUT",
                        "body": {
                                "status": 1
                        }
                }
        ]
}

Then for the resourcelink, I post:

{
    "name": "MotionSensor 5",
    "description": "MotionSensor 5 behavior",
    "type": "Link",
    "classid": 10020,
    "owner": "OwnerIDHere",
    "recycle": false,
    "links": [
              "/sensors/5",
              "/sensors/6",
              "/sensors/19",
              "/groups/5",
              "/rules/4",
              "/rules/5",
              "/rules/6",
              [etc.....]
              "/scenes/YourDimSceneIDHere",
              "/scenes/RecoverRoomSceneIDHere"
              ]
}

The sensor and rule set you’re linking to will be specific to your own setup.

I’ve no idea what that ‘recover scene’ is. I’m guessing it’s something that’s created when you configure a sensor in the first instance, and is some sort of default state.

There’s a corresponding 3 API calls which I need to make to toggle back to the scene for ‘bright pre-midnight’, replacing the scene ID accordingly.

At the point I gave up – where I was just making the rule changes – I could tell that it wasn’t right by loading up the config in the app. The partial configuration – without the resourcelink change – manifest itself simply as ‘do nothing’ for the nighttime slot. Resetting this restored the full config. I guess there’s always the danger that if you run wild and free with setting values incorrectly, you might invalidate the ruleset to the point where unpicking it could be a problem. All I can say is that the above approach works for me, but test carefully!

Making Your WordPress Site Harder to Break Into

If you are using an infrastructure-as-a-service offering to host your WordPress site, you might find the following suggestions useful. If you have web access to site administration, e.g., via CPanel, there’s not much more you can do beyond:

  • Install WordFence.
  • Pick a very long password for your admin account. Have a look at secondary authentication options [described below].
  • Keep your software up to date.
  • Have a long hard look at all of those plugins you’re using, and try to cut them to the bone.

Here are a few Linux specific things to consider:

  • Install fail2ban.
  • Install the fail2ban WordPress plugin.
  • Change the default port you are running sshd on from 22 to something above 1024. You might want to check the IANA port listing to avoid colliding with other daemons you may be running on your box. This is pretty painless to do. You could do the same for all of your other network services [obviously excluding your web site and mail transfer agent, if you’re using one].
  • Consider running TCP wrappers on your ssh daemon access. Be careful not to lock yourself out if you don’t have a fixed IP address from your service provider. I use BT: a bit of googling suggested a couple of likely address ranges [81. and 86.], but my get out of jail card is a static IP I can use with a VPN service, which I’ve also configured.
  • Consider restricting access to mysqld to localhost. You may have already done this during install. I have to admit I was pretty careless when I was installing the database in terms of notetaking so I just added a TCP wrapper to be on the safe side.
  • Have an extremely long password for your admin account. Mine is basically half a mile long in 8 point text.
  • Have a look at some secondary authentication [or at least Captcha style robot identification] mechanism on the login form. I’ve experimented with Duo in the past. Make sure you understand the implications of changing your mobile phone if you are using one of the app based mechanisms.
  • Consider chrooting your website. I don’t but I may.
  • Have a look at some of the security scanners, like ZAP. Again, be careful not to lock yourself out with fail2ban.

The rest of these are host specific. A good starting point is to run

nmap -n localhost

to confirm what network services you are running. For instance, I found that my Linux distro had an FTP server running out of the box which I didn’t know about. In my case it was as simple as

pgrep ftp

to get the process id, then

ps -ef | grep <process_number>

[substituting appropriately] to find what the process was, and then finally

apt-get remove <package_name>

For any other servers you need to run, there’s a pretty good chance that there is fail2ban config that you can use off the shelf.

Why I felt I needed to pay more attention…

A few months ago, based on the daily activity reports I get from WordFence, I started blocking ranges of addresses using iptables. So if I got repeated brute force attempt on my admin password from say 192.187.111.146 [this is a real example], I’d block the the entire range by doing:

iptables -A INPUT -s 192.187.0.0/16 -j DROP

This was pretty tedious, but I only needed to do it around once a week. For some reason [presumably it’s some sort of off the shelf attack script], the attack counts from specific IPs always seemed to top out at exactly 1460 hits. Last week, I got my daily email which showed someone had hit the site 49k times that day. By the time I got home and did some digging in the logs, it was totalling more than 80k for the week. I suddenly realised that my manual blocking was way too blunt a tool, so last weekend I wrote a log scanning  script launched by cron every 30 minutes. It pattern matches on the login form in the Apache log file and sends me an email if an individual IP tops out at over a certain threshold. The longer term plan was that I’d call another script that would automatically insert the block rule in iptables. There would be a bit of messing around with state management [seek to a point in the log file based on the timestamp to not go over the same ground twice or something] and it would have to be run as root, but it would be better than nothing. I happened to mention this to someone at work who told me about fail2ban, which is doing the same thing [but better than I could have implemented it].

I also had a dig around at ssh logs, and discovered that some kind soul was trying to brute force the root password, and was up to 8k attempts for the week. Subsequent digging showed that the same thing was happening with my Imap server, but on a smaller scale.

While what I’ve suggested here isn’t necessarily bullet proof, it’s a reasonable start. Bear in mind that the types of attacks I’m seeing are commensurate with the value of my site, which in commercial terms is zero. And oh, the irony, when my server gets brought to its knees next week by someone with serious intent :).