Building a CO2 Energy Sensor

Building a CO2 Energy Sensor

Mikey Harper · · 7 min read
share:

What else better to do over the weekend than to come up new smart home devices! And this is exactly what I have done, building a light which provides me an update on the current carbon intensity of the electricity supply. I am quite happy with the end result, and this blog explains the motivation behind the idea, along with code for anyone who wants to replicate it. I hope it helps!

The Challenge: Varying CO2 Emmissions

As we shift increasingly to using renewable energy resources, there becomes an increasing issue of not only how much electricity needs to be produced, but importantly when.

Renewable energy like solar and wind operate very differently to “traditional” power stations such as coal and gas. There is much less control over exactly when they will produce energy and how much will be produced. This is highlighted below, showing the UK’s wind generation for March 2021. At its peak, wind was providing 13GW of electricity, which is enough energy to power 13 million homes! However, just a few days earlier, the output had been only a few GW.

UK Wind Generation March 2021

As a result of such large variations, the carbon intensity of the grid changes. When there is a lot of renewable energy available, the intensity is low, but if the sun isn’t shining, or wind isn’t blowing, then the carbon intensity is generally higher.

The figure below shows the Carbon intensity of the national grid over the past month.

Carbon Trends for November December

The Idea

There are a few resources out there which inform users of potential carbon emissions from their consumption. For example:

However, part of the problem with these approaches is they mostly rely on you opening an app or visiting a website. Sure, this might work for technical enthusiast like myself, but will it really work for people such as my wife? My feeling with this project was that occupants of houses want to have a minimum tolerance for changing their behaviour: if they want to put the dishwasher on, they are very unlikely to want to go out of their way, check a graph and make a decision about when to run it. What we need is a simple visual prompt for people to be able to make a decision.

So I came up with a basic side lamp idea, which could provide a visual cue to people. This can sit relatively unobtrusively, but equally is relatively easy to get an understanding of the current CO2 outputs. If you see red or yellow, it should hopefully make you think twice of whether you need to use the electricity now, or whether it could be deferred to another time!

The Setup

There are three main components to this project:

  • The data
  • The hardware: ESP Home
  • Linking them up with Home Assistant

Note, this tutorial is very Home Assistant focussed. It would probably be achievable coding this all in native Arduino code, so the solution might look a bit messy. But if like me you are competent in the tools above and don’t want to learn extra code innecessarily, this should help!

The data stream

Firstly, we need a reliable and up-to-date dataset which provides us with the carbon emissions for the UK. For where I am based in the United Kingdom, two options for this:

  • co2signal: offers a Home Assistant integration. This provides data for most of Europe, and many other parts of the world. The Electricity map gives you a good place to check. You’ll need an account to use this, but have a free tier.
  • Carbon Intensity API this project is specifically for the UK, but offers a free API which gives carbon estimates. It also goes down a regional level if needed, although I didn’t use this for this work.

Both these methodologies offer slightly different carbon emissions, as they have to calculate this themselves, however they are similar enough to not worry about. I ultimately decided to use the Carbon Intensity API. It offered a more extensive suite of APIs, and there was no limit on the calls made: I found that the co2signal would occasionally rate limit my calls resulting in an error. However, as Carbon Intensity offers no official integration, I instead decided to do the API calls instead.

I came up with the following code for querying the API and bringing the data into Home Assistant. The code does a single API call every 1800 seconds (30 minutes). Template sensors are then used to extract the required values from the full JSON objet returned from the API call, which creates the sensors sensor.carbon_intensity_value, the gCO2e/kWh expressed as a numeric value, and sensor.carbon_intensity_index, a rating of the CO2 score, expressed from very low, low, moderate and high and very high. You can add this to your sensors.yaml within you Home Assistant configuration:

# Carbon Intensity for UK: Headline Figure
- platform: rest
name: Carbon Intensity Full
resource: https://api.carbonintensity.org.uk/intensity
json_attributes: data
scan_interval: 1800
- platform: template
sensors:
carbon_intensity_value:
friendly_name: 'Carbon Intensity Value'
value_template: '{{ state_attr("sensor.carbon_intensity_full", "data")[0].intensity.actual}}'
icon_template: 'mdi:molecule-co2'
unit_of_measurement: "CO2e/kWh"
carbon_intensity_index:
friendly_name: 'Carbon Intensity Index'
value_template: '{{ state_attr("sensor.carbon_intensity_full", "data")[0].intensity.index}}'

The Hardware

For my light, I used ESPHome, which is one of the best Home Assistant integrations available for building Arduino based sensors. Instead of having to write the Arduino code yourself, you can instead focus on writing relatively simple YAML files which enable us to build some basic logic around.

For the setup here, I only have three components:

  1. The ESP8266 chip. I use a Wemo D1 mini here [link to AliExpress]
  2. The addressible LEDs: WS2812B are my go-to for any LEDs, but there is no real need for the addressible LEDs in this project [link to AliExpress]
  3. The Display [link to AliExpress]
  4. Some container: I had a light bulb drinking cup knocking around which seemed like the perfect object!

Circuit diagram

The following code sets up the code. Note, that a lot of the code is for the display.

esphome:
name: carbonintensity
platform: ESP8266
board: d1_mini
wifi:
ssid: !secret SSID
password: !secret SSIDPassword
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
light:
- platform: fastled_clockless
chipset: WS2812B
pin: D4
num_leds: 4
rgb_order: GRB
name: "FastLED WS2811 Light"
id: "CarbonIntensity"
# Code for display
sensor:
- platform: homeassistant
name: "Grid CO2 Sensor From Home Assistant"
entity_id: sensor.carbon_intensity_value
id: co2intensity
internal: True
text_sensor:
- platform: homeassistant
name: "CO2 Rating"
entity_id: sensor.carbon_intensity_index
id: co2label
internal: True
# Example configuration entry
i2c:
sda: D1
scl: D2
scan: False
font:
- file: "Roboto.ttf"
id: my_font
size: 25
- file: "Roboto.ttf"
id: my_font_2
size: 12
display:
- platform: ssd1306_i2c
model: "SH1106 128x64"
reset_pin: D0
address: 0x3C
lambda: |-
// Print inside temperature (from homeassistant sensor)
it.printf(60, 30, id(my_font), TextAlign::BASELINE_RIGHT , "%.0f", id(co2intensity).state);
it.printf(60, 30, id(my_font_2), TextAlign::BASELINE_LEFT , "g CO2e kwh");
it.printf(60, 60, id(my_font_2), TextAlign::BASELINE_CENTER, "Rating: %s", id(co2label).state.c_str());

You’ll note several things from the above: firstly, the device extracts the data from Home Assistant, and secondly, there is no logic controlling the colour of the light with ESPHome. It would probably be possible for the Wemo D1 to manage both of these, but the design ethos for ESPHome is that the majority of the thinking is done by the Home Assistant device itself.

Automating the Light changes

We have two options for making the light change colour.

Changing Colour based on value

alias: Carbon Intensity Bulb Update
description: ''
trigger:
- platform: state
entity_id: sensor.carbon_intensity_value
condition: []
action:
- service: light.turn_on
data_template:
entity_id: light.fastled_ws2811_light
hs_color: >
{% if states('sensor.carbon_intensity_value') == 'unavailable'%}[300,100]
{% elif states('sensor.carbon_intensity_value') | float < 300 %}
[ {{ (-0.45 * states('sensor.carbon_intensity_value')|int + 135)|int }} , 100 ]
{%else%}[1,100] {% endif %}
mode: single

Change Colour Based on Category

As mentioned earlier, the Carbon Intensity API provides us with an index which scores the colour. We can instead use this to assign the colour. A benefit of this is that it makes it easier to set unique colours which stand out for the categories, but we will lose the smooth colour gradients across the groups. Ultimately this was my preferred route so it is what I used.

Colour categories for carbon intensity levels

service: light.turn_on
data_template:
entity_id: light.fastled_ws2811_light
hs_color: >
{% if states('sensor.carbon_intensity_index') == 'very low' %}[120,100]
{% elif states('sensor.carbon_intensity_index') == 'low' %}[80,100]
{% elif states('sensor.carbon_intensity_index') == 'moderate' %}[50,100]
{% elif states('sensor.carbon_intensity_index') == 'high' %}[20,100]
{% elif states('sensor.carbon_intensity_index') == 'very high' %}[0,100]
{%else%}[300,100] {% endif %}

Potential Improvements

As shown in the apps,