Have you ever got that feeling of irritation when you left the kitchen with a favorite snack, set yourself comfortably on a couch, and realized that you left the light on in the other room? Long story short – inaAmbient could save you trouble. And this is not a marketing slogan but a simplistic explanation of the main purpose of this project. I did a smart home automation system from scratch, keeping it cheap, fast, easy to install and use.
Where did that come from
I have the feeling like this project has been going on forever. I started messing around with it somewhere in 2013. Back then, I was fascinated with the Arduino platform and saw the potential to do some more advanced implementations on it. A smart home system seemed like an exciting topic. Not many good systems were available at a reasonable price, so it was worth looking for a way to make one on my own. WiFi transceivers were quite expensive back in the days, so I experimented with nRF24 modules, working on an own transmission protocol to communicate over them. The concept was successful, but I never had enough time to commercialize the solution, so the project was on hold for quite a while. Until technology changed everything, and this market has … not changed much. Back then, I was also prototyping my custom glass touch panels in replacement for conventional light switches, and for this purpose, I bought my first (and, so far – only) 3D printer.
The current architecture features a simple client-server setup without any need for scalability. After all, for the purpose of the application, not more than several clients are expected to be connected to a single server. The server then can be light and does not require much computational power. I based my solution on ESP32 modules (they are a great replacement for old nRF24 modules), acting as clients (worker modules), and the server could be any device able to run either Python or NodeJS scripts (I implemented the server in both technologies, but more about that later), connected to a local network. In my case, I use Raspberry PI v.3 as a server. With two PM2 processes – one serving compiled SPA and one running the server (both NodeJS and Python work well with PM2) with five clients connected, RPI runs at about 1% CPU and 12% RAM usage. Connecting more clients does not seem to keep RPI any busier, but I have not tested the performance to present solid results.
I wanted to control lighting in a bit more complex manner than simple on/off. To achieve that, I designed and soldered (together with a friend) a simple dimmer circuit to be controlled by the ESP32 client module. My prototype dimmer module works nice with resistive loads, but inductive loads make the triacs go wild. I already tried snubber circuits; however, the problem persists, causing the lights to flicker at specific brightness settings. I will need to work out some other method of filtration.
As it lately happens with my projects, I used the Quasar Framework for implementing the user interface. It is a SPA, having only two views (one for uninitialized devices and one for normally operating devices) and a drawer for managing devices’ settings. The interface, in its simplicity, turns out to be very convenient to use. Thanks to Quasar Framework, I have a mobile app covered with Capacitor mode. The UI communicates with the back-end over WebSocket only. Back-end does not use REST communication at all.
Python + uPy vs. Node + C
The biggest challenge with this kind of project was communication between modules, server, and user interface. At larger installations, the number of messages within a short period of time might be massive, and UI needs to reflect the system’s objects’ state changes immediately. WebSocket seemed like the right choice for real-time applications, and it turned out to be right, but (as always) certain problems got in the way.
After a long break from the project, quite recently, over a month, I performed two significant program iterations. At first, I wanted to try out MicroPython, as I did not get a chance to do so earlier. It seemed like a great technology, eliminating all the headaches related to coding limited devices, such as microcontrollers. As a fan of keeping the technology consistent across different parts of a solution, I picked Python for the back-end as well. UI is an independent app, so these choices do not interfere with it. I spent four days implementing the entire thing, from scratch to the working prototype handling eight channels, and ready to take more. MicroPython turned out to be great for prototyping (I managed to easily implement a mechanism for updating the code on all connected devices by sending it through WebSocket, replacing old code on the device with the new one, and rebooting the device – there you go), but not yet production-ready. At least not for my purpose. Many libraries miss crucial (for me) functionalities; they work unstable, threading does not work as expected, etc. It worked, but the performance was not astonishing.
Within a month of implementing the MicroPython + Python version, I decided to rewrite the entire thing to C (for clients) and NodeJS (for server). I kept the logic and basic communication mechanisms unchanged, but I extended the functionality with dimming and added a few more enhancements. This operation took three days, but I assure you – it was worth it. This change resulted in a considerable performance boost, and the current implementation works incredibly fast and stable. As I designed it to work with conventional switches as inputs as well, the response from the controller state change to a channel state change is now immediate.
This project has great potential for commercialization; however, it is not my immediate goal or a priority. I will keep the development going, and soon, perhaps, I will think about releasing an actual product. On the other hand, if some investors want to get this project done and released faster, I am open to discussing and reconsidering my plans for the next months.