Inspiration

My dad has been building power infrastructure for his house which aims to save him money on his electricity bills. After installing four solar panels and a battery, he came to me with a problem. His battery would fill overnight during the cheap tariff period, but the excess output (anything the house doesn't need) from his solar panels would have nowhere to go! He needed a way to limit the charge of his battery on sunny days, but to still charge to full on cloudy days. EcoFlow has this feature behind a paywall but some quick calculations we did wrote this off as more costly than the savings it would generate. This gave me a relatively simple problem to solve with an IoT device!

What it does

  • Solar prediction: a compact regression model trained on historical weather and solar pv generation data predicts the next 24 hours of solar output. Inference runs locally on the Pi Zero W (ARMv6, 512 MB RAM).
  • Weather input: hourly forecasts from the OpenMeteo API feed the model.
  • Battery scheduling: during tariff windows, the expected house load is compared against predicted solar, the battery is configured to charge to cover any shortfall, then reset to its baseline when the tariff ends.
  • EV conditional charging: reads an EV's battery level, home location, and plug state from Home Assistant to control an IoT enabled charger, switching it off once the target charge (currently 95%) is reached.
  • Control panel: a physical panel (currently on a breadboard) with three "appliance" toggle switches (though only one of these is currently configured, being the one representing the home being inhabited) that feed into the estimate for home energy consumption. Shows the state for each these appliances with an LED.

Some metrics I collected from the program: | Metric | Value | |---|---| | Model size on disk | 282B | | Model data size on disk | 99KB | | Inference latency (Pi Zero W) | 1.51ms | | RAM footprint | 3664KB |

How I built it

The first thing I did after scribbling down some requirements was connect my Raspberry Pi Zero W to a breakout board, which I connected to a breadboard, then quickly built a simple circuit for the appliance switches. I then wrote the state machine logic for the switches and LED indicators, and documented the process I had to follow to build and deploy the binary to the pi. I then automated this process a vscode build/run task, which must have saved hours of time. I then added the stubs to communicate with the devices, although I still wasn't fully sure how I would be interfacing with said devices as I hadn't set them up with Home Assistant yet, and I didn't know if that was possible or not. At this point I was waiting on access to the home setup so I built as much as I could that didn't require it: fetching weather data; a .env file for credentials/other info best kept off a public repo; and the ML inference with some mock solar output data. By this point I was able to access the EcoFlow App, from which (after some unsuccessful testing of the API) I manually copied hourly solar data from ~50 days into a spreadsheet, and reformatted it into a data CSV which I combined with historic weather data to feed into my model. I also wrote a separate program using linfa (which can be thought of as Rust's scikit-learn) to train a model on my laptop and changed the build automation so that this model could be transferred to the pi to be read by the manager. I then made the decision to switch a single-threaded approach. This was because my model ran and trained far faster than I had expected at the start of the project, so I didn't need a background thread to handle interrupts while an inference thread was running (since the control panel's latency would be at worst a couple of seconds, and the odds of the user pressing at this time were very slim). This allowed me to remove a lot of now redundant logic (Mutex + Arc attributes). By this point I was able to access the EcoFlow data through Home Assistant, and I knew that it was possible to add every other local device to its ecosystem. This allowed me to implement the methods to interact with these endpoints, and also to build the scheduling logic of the system. From here it was just ironing out some small bugs that weren't caught in the limited runtime contexts up to this point and creating a "benchmark" branch which gathers some basic information about the performance of the system, and here we arrive at the present.

Challenges I ran into

The main challenge I faced was integrating the IoT ecosystems into Home Assistant. Every company likes to have its own system for IoT, and it's currently up to open source communities like that of Home Assistant to hack these together into a centralised platform. Perhaps in the future when more people start to integrate these devices centrally, being natively integrated with a centralised platform like Home Assistant could be a selling point for IoT companies, but for now it is still quite a tedious process even for someone technically minded. Using Rust was also a challenge initially. I had decided on Rust for a variety of reasons, but whenever I develop a Rust application after some time without using the language, I find it to be quite laborious at the beginning. One of Rust's massive advantages over other languages is that it forces you to think about programming in a certain way order for it to even compile. This presents a steep curve at the start, but it has a strong influence against technical debt and makes the final 20% of development not feel like an extra 100% like is the case in other languages.

Accomplishments that I'm proud of

My main accomplishment has been the speed with which I produced this software. I made my first logbook entry and first commit 9 days ago, and since then I've gone from not even knowing how I would interact with the devices from the Pi to a fully working system. I am also proud of the fact that I came back to Rust after 9 months without programming in it, and it still feels as natural as it did when I was developing programs regularly with it.

What I learned

I rounded out a lot of my knowledge of Rust. I think the most impactful practice I got was the process of actually having to weigh up thread usage and asynchronicity, whereas when I was learning Rust I was not as hardware constrained so I just relied on async runtimes like Tokio. I also learned a very valuable lesson in Machine Learning, which was that bigger and more complicated models don't always yield the improvement in results you think they might! My Linear Regression model was almost equal in performance to any of the lightweight neural networks I tried (albeit on a limited dataset), while of course being way faster and more compact.

What's next for Home Power Manager

I am currently on an electronics bootcamp, so I will be extending this work significantly. The main feature I will be adding is an EV charge target using a variable resistor (and ADC), and instead of having all this on a breadboard I will be putting it on a carrier board to directly connect to the Pi. I will also be using buildroot to create a custom embedded linux OS for this, rather than relying on Raspbian. This was something I didn't have the time for but I really feel like I'd benefit from the knowledge of how to do this.

Built With

Share this project:

Updates

Submission history