Ever heard of mqtt? Ever wanted to be able to send your desktop machines notifications just as easily as all those services like pushover do for your phone or tablet?
My answer to both of those questions was 'yes', but of course I didn't immediately come up with the solution (and the little program that implements it) right off the bat.
If your interested in the little bit you've read or figured out, by all means keep reading...
My problem
I'm slooowly getting into the world of home automation (some of that hardware is expensive), and one of the first things I wanted after setting up home assistant was to be notified when something happens. Seems like a reasonable request right?
In a situation like this, you've probably bought one or two (or more) devices your about to place around (and sometimes literally in) your home, so your computer can track the state of those devices, and make decisions based on that data (as well as things like the weather, where you or other people are, etc). It can then use this data (along with rules defined by you) to identify when, say, no-one should be home, -- and why are the indoor motion detectors going off and why is the back window open when no-one is home?
A big part of a system like this (at least, in my opinion) is it's ability to inform you about things that are important, as they happen (as I hope is self-evident in the example above). There are plenty of ways to do this in homeassistant, there's a notification platform for exactly this reason, and in fact at the time of this writing there are 46 different specific notification "components"... But... With options ranging from pushover, instapush, pushbullet, mailgun, , kodi, facebook (one of these is not like the others)... there wasn't one for basic desktop notifications. You know, the system tray on windows, notification center on Mac OS, and... Whatever the latest linux desktop environment uses.
That's what I really wanted: a simple way to push notifications to all my machines when important things happen.
I'm not counting html5 push notifications because (while it is a way to get notifications on the desktop), it requires a browser to be open all the time. It also requires extra work to be used with chrome (work I didn't want to do), your notifications go through mozilla or google, and it requires your home assistant instance to be open to the big bad world wide web (and exposing a server that has lots of information about you and your home, -- even possible live video feeds-- to the internet is always something you should seriously think twice about).
While individually those things might not have been a deal breaker, , with all of them put together I figured I'd look for a better way than html5 push notifications.
So maybe I should update the list of what I wanted:
- Desktop notifications that can be sent automatically.
- Preferably without requiring me to open homeassistant up to the web.
- Doesn't rely on other applications (that I may close because they normally don't have anything to do with notifications).
- Doesn't require much work on my end.
My first thought was to implement this myself, and while it did go against the last item on the list, if I couldn't find anything better it's what I was planning on doing.
Oddly enough, when (in the middle of doing something else) I started trying to come up with things I would want this little notification client / server to be able to do, I came up with this list:
- Authentication (username and password)
- Encryption (ssl)?
- Different endpoints (so this will be useful to more than one situation, instead of just being for homeassistant)
- Access control (unlikely that I'd implement, basic auth and tls would probably have been good enough for my use)
- Clients can be interested in more than one endpoint.
This started to sound like the publish / subscribe pattern; just replace 'endpoint' with 'topic'.
While it was neat to realize the similarities, seeing the pub/sub pattern also made me remember mqtt.
It had been a while since I'd really looked at doing anything with mqtt, so to make sure I remembered things correctly, I skimmed the mqtt specification.
It turns out:
- Mqtt is basically a distributed pub / sub model - clients can subscribe to topics they're interested in as well as publish to any topic (as long as the broker allows this).
- it's actually designed for machine-to-machine communication and the "internet of things" - for what that's worth.
- Mqtt is designed to minimize bandwidth (always a plus).
- It has basic authentication - the standard username and password pairs.
- It has access controls - depending on the broker used, extra access controls can be applied (certain users can only subscribe or publish to certain topics).
- Servers and libraries (at least the ones I found) support ssl out-of-the-box.
- Topics can be specified with wildcards, so clients can, for example, choose to subscribe to every topic after home, without having to list them all.
- There are also different qos (quality of service) levels - a message can be marked as qos 0, which means it just gets flung down a tcp socket with no acknowledgment needed, up to qos 2 ("did you get that?" "Yeah, I got it." "You sure?" "Yes..." "Are you really really sure?").
- mqtt doesn't specify any specific payload format - it can be a json string, bytes, "on", "off, whatever, up to a limit of about 256 mb.
It was basically perfect for what I wanted - as little work for me as possible (mqtt client libraries and servers exist, so no reinventing the wheel), auth and access controls...
Even better... As I had noticed when looking through homeassistant's components, there was an easy way to hook mqtt up to homeassistant, so the publish service (which allows other things like automations or scripts to use a particular feature of another component) would be available for me to use in anything that I wanted to cause a notification.
There's also an mqtt eventstream component, so instead of manually sending notifications in individual automations (ok, bad rimes but it's late when I'm writing this), I could just send each event on the homeassistant event bus over mqtt. This component is intended to be used to bridge home assistant instances - so your main instance has access to all of the information your vacation house instance does (or whatever your second instance is).
It's "intended" purpose doesn't really matter though, because it does just what it says on the tin and directs everything to an mqtt topic of your choice. So a desktop app could subscribe and notify only on ones I'm interested in.
Yeah... About that... (the solution)
So this is where my "just use mqtt, you dummy - don't do extra work" plan sort of hit a wall of... Well... Work.
The mqtt protocol is nice and all, and there are client libraries, but they're just that: libraries.
So I wrote my own little tool called mqn. I still havent decided what that stands for. 'my quick notifier' was suggested to me by a friend, and I like that as much as 'mqtt notifier', or any of the other totally not creative things I've come up with.
My horrible attempts at naming and indecision aside, all this app does is load a config file, connect to the specified mqtt server with the given options, subscribe to any topics that are mentioned in the config file and sit and wait. When it receives a message on any of the listed topics that is a parsable json string, and it has a type of 'notification', a title and a message, it pops up a balloon with that title and message near the system tray.
The only downside to this is that wx (the UI toolkit I'm using) says that the notifications only work on windows. Though I could swear it used to work for other platforms, this is fine for me, for now.
hooking it all up
So mqn worked out just as I'd hoped, after installing mosquitto (what a funny name) on my server, some fiddling with mosquitto-auth-plug and mysql, writing a script to manage it all (I'll probably put that up on git hub soon) I have... Fully working desktop notifications, to as many computers as I need, without sending the notifications through [insert big company name here] (or so I think...).
Now anything that can speak mqtt (or can run a command, which is pretty much everything) can send notifications to my desktops.
I only just pushed this to git hub, and I already have a few ideas I want to add to this, such as making mqn keep track of user activity on a machine and only displaying notifications if that last time of activity is under a certain threshold, machine-named topics (so notifications can be specifically directed), a submenu in the tray icon's pop-up menu to individually mute notifications from certain topics, etc.
What I have now works for me though, and I finally get notifications when someone leaves the damn door open, which is all I really wanted :p.
If you have an issue or (even better) an idea for a pull request with a feature or bugfix, feel free to open either on it's git hub page which is linked above.