Home Energy Dashboard with Elixir and Scenic

By: on April 29, 2020

As of last month, I am able to poll my solar PV inverter for its current yield and other interesting data, which I would ultimately like to display using a Raspberry Pi plus touch screen.

On this home energy dashboard, I would like to be able to cycle through different pages, showing:

  • current solar PV output, weather forecast, placeholders for current grid export and import
  • general inverter info including total yield and operational health
  • a placeholder home page demonstrating future extensibility

The Elixir ecosystem provides a variety of UI technologies, among them wxWidgets, Phoenix LiveView  and Scenic. For my use case, Scenic seems to be an appropriate choice.

In Scenic, a window is called a ViewPort. A ViewPort displays a Scene (using a Driver for the actual rendering and event capturing).

A Scene is a GenServer that:

  • defines and updates a graph of visual elements (i.e. a scene graph)
  • reacts to events such as mouse clicks, key presses, timers and messages from other processes
  • may hold arbitrary internal state / logic as required

Visual elements are either graphical primitives (such as rectangles, lines and text) or components (such as buttons, combo-boxes and input fields). Components are simply Scenes that can be inserted into a graph.

Scenic requires the ViewPort size and initial Scene module to be specified via a configuration file. The official Raspberry Pi touch screen has a resolution of 800 x 480 pixels. Each of the three dashboard Scenes will include a shared navigation component, and thus, we can pick any of the three as the initial Scene.

Each Scene needs to obtain the actual data it is meant to display. Rather than polling the various sources directly, each Scene will read the respective values from shared ETS/DETS tables, which are updated by separate processes. In this way, the Scene refresh rate is decoupled from the various data fetching intervals and inherent delays.

Currently, there are two sources of data — the inverter and the UK Met Office.

The UK Met Office offers programmatic access to hourly weather forecast data via a web api. There is a basic plan that allows up to 360 daily calls free of charge.

In the dashboard application, the weather data is managed by two GenServers. The first GenServer is a named singleton that owns a DETS table and provides simple functions for storing and retrieving forecast data. The second GenServer periodically fetches the latest forecast data and sends it to the first GenServer. Scenes retrieve what they need from the first GenServer.

The inverter data is managed in a similar fashion (based on QSB36) and held in an ETS table.

If you are interested in further details, please have a look at the source code.

Screenshots

The Home Scene is currently an empty placeholder, demonstrating ‘extensibility’. It could, for example, be replaced by a calendar or an amusing cat picture.In the Inverter Info Scene, you can see that the inverter is working fine and that the solar PV installation has generated a total of 3989 kW/h so far.


In the final screenshot, you can see that at around 15:30, the solar PV installation was generating 0.64 kW. The total for the day up to that point was 7.93 kW/h. The columns for grid import and export are empty as I do not have a sensor for those yet. Below the numbers is a graph representing the day. At the top, it shows weather icons and temperatures as per the Met Office forecast. Below that, there is a histogram of the solar PV output in kW/h. Overall, it was a fairly miserable day, but there were some sunny spells, too.

Conclusion and possible next steps

Elixir/OTP is a great match for modelling various ‘sensors’ as independent entities. Scenic is a very slick, easy to use 2D UI library. Scenic, too, utilizes OTP. Should a Scene suffer a runtime error (perhaps due to an offending piece of sensor data), it will simply be restarted (instead of bringing down the whole application).

What’s next?

Share

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*