Thursday, January 31, 2019

Making a Smart Speaker - Part 6

Calvin has been on my desk for far too long now. I really want to just, you know, finish this project. Obviously, the software will be continuously evolving, but the hardware will be packed away in this nice package and will not be in wires and parts on my desk as it has been for many months. But I think that Calvin's design - as well as his codebase, isn't what I want it to be. Maybe I should start from scratch? Let's design a whole system architecture that allows us to make a whole smart home based on Calvin.

It has long been my intention that Calvin should be at the center of my makeshift smart home. But, the more I think about it, the less I think this should be how it works. In my previous post about Going Down The Home Automation Sinkhole, I mentioned the three key things I wanted to keep in mind regarding smart home design: Extendability, Simplicity, and Locality. All of these are addressed - in my opinion - with the architecture I have in mind. I'll attempt to sketch a proof of concept that involves a NodeJS process (Calvin and others) and an ESP8266 (my smart device of choice).

The first concept we have to embrace is decentralization. If we can have a easy way to broadcast messages across a network to anybody who will listen, then that's fantastic. Luckily there's UDP multicast to the rescue. If my understanding of it is correct, everybody listening on an address and port will get messages sent by someone else belonging to the group. This is fundamental to the next building block of the system.

Obviously, there are events that happen on each device that don't need to be broadcast to everybody on the network. So there needs to be a local message bus different from the global message bus. Notice how I didn't say "separate" because they can't be entirely separate. We'll implement a pub/sub pattern here. Services can ask the local bus to subscribe (or 'bind' is perhaps a more appropriate verb since it's two way) to an event on the global bus. If the global bus has that event published, then it will be duplicated on the local bus and everything listening to it will be notified. If a service emits an event to the local bus and that event is bound to the global bus, it will be broadcast to the global bus as well as the local bus. This is why I think 'bind' is a better verb here, since you're really gluing two parallel buses together at some points.

So now we have the protocol selected and an idea for the application layer. It will be the rock upon which we build Calvin. Or, rather, rebuild him. I've run into some issues with Snowboy's hotword detection working on newer versions of NodeJS, so I need to figure out how to test locally on an older version. The answer is probably nvm, but to be perfectly, honest, nvm is sort of a pain. Maybe this should all be wrapped up in a docker image. That's kind of the point of docker, isn't it? Then we could have the whole thing be cross-platform (assuming there's an acceptable docker image for NodeJS on ARM of the right version.)

But, until I can get a large chunk of time to rework Calvin... he's going to sit on my desk for a good long while. It's heart breaking, I know, but I have a bunch of other stuff to do and other projects I want to get to, and designing a whole home architecture isn't something that you can power through. You have to think about things, otherwise you'll end up with fragmented ideas and adapters left and right.

No comments:

Post a Comment