Power usage monitor using neopixel ring and oled screen

Many years ago I used to have a power monitor that changed colours depending on how much power was being consumed from the grid. It was pretty cool but sadly died some time ago, so I wanted to do something similar. I had a neopixel ring doing nothing as such, so thought it would make a nice base for my power usage monitor.

The features are:

  • On initial startup, it shows a message on the screen saying that it’s fetching data
  • If power is being consumed from the grid, the left hand arc of 12 LEDs light in colours ranging from yellow to red depending on how much is being consumed.
  • If power is being generated, the right hand arc of 12 LEDs light in colours ranging from blue to green, depending on how much is being generated
  • Each LED represents one kW of power (rounded to the nearest kW - eg 1,350W = 1kW = 1 LED) to a maximum of 12.
  • If power is being consumed from the grid, then the OLED shows how much is being consumed
  • If power is not being consumed from the grid, then the OLED shows how much solar power is being generated
  • To make this bedroom friendly, at a defined time at night both the neopixel ring and OLED screen are switched off (technically the neopixel turns the LEDs down to 0%, and the OLED displays a blank screen. This is because the neopixel is powered directly from the 5V pin of the esp device so it is, let’s say, challenging to actually turn off the ring without using a relay. Even if you put the esp into deep sleep, the ring will still be powered. The OLED is also a special case as, unlike with a LCD panel it does not have a backlight to turn off so making it display a black screen provides the desired result!)
  • At a defined time, the neopixel ring and OLED screen are turned back on again. This time can be varied based on day of week - for example I’d prefer it to come on later in the morning on the weekend.

The code itself is located at SSD1306 OLED panel for Neopixel stand by TheRealNinkasi - Thingiverse
Normally I would post the code here, but it is quite big and even just trying to post it by itself I get “An error occurred: Body is limited to 32000 characters; you entered 36658.” I’ll split is up and post it here, but the whole file is it at Thingiverse.

Notes:

  1. This is not a tutorial on how to get this data into home assistant, but just some information on a way to display it. FWIW Personally I use a Rainforest dongle and mqtt to capture grid usage from our smart meter, and solar generation info comes directly from my Fronius inverter.
  2. If you use an esp32 device that supports bluetooth, you could also use this as a ble scanner eg for room presence monitoring. This does however use up a lot of resources, and could easily make the device unstable due to memory issues causing random rebooting. I have however put some sample code in there, commented out, to give an indication of what you can do.
  3. I found that the ESP32-WROOM-32U board I had purchased from Aliexpress had WiFi issues when powered from the USB-C port - just a warning there. The resolution was to power it directly from the 5V pin.
  4. Feel free to change the colour scheme for the LEDs
  5. Feel free to change the number of LEDs that light up based on power - for example, if you have a smaller solar system, you may want to change the increments so each LED represents 500W
  6. On wakeup in the morning the system does not show anything until something changes that triggers the “on_value_range” - I might update the code at some point to allow for this, but it’s not a huge priority for me… :wink:
  7. The code does have references to my specific sensors - you will need to go through it of course to change to suit your specific system.
  8. If printing the case, I’d suggest the base can be printed in standard (ie 2mm) resolution, the other parts should be in high (ie 1mm) resolution. Speaking of which, the case I printed using designs that are on thingiverse - actual locations are referred to in the code that I’ve tried to make as descriptive as possible.
  9. I have set the default brightness to 30% - depending on your environment, and how far in you push the ring into the case, you may want this brighter or dimmer. A future update may be the addition of a light sensor so I can vary the brightness based on ambient light.
  10. Yes, if you look not that closely you’ll see a small piece of tape on my stand. This was my first trial print and it had a small black smudge from a prior print, so the tape is currently performing the dual purpose of covering the mark and keeping the ring straight. This is only a first draft anyway - I plan to print it again, possibly providing space for motion and light sensors. When I’m happy, I’ll just use a small dab of glue to keep it all in place.

Hardware required:

  • An esp32 or esp8266 of some form. I like the Wemos D1 mini, although if you later plan to potentially add in extra sensors (eg proximity, motion, temperature, etc) then the more powerful esp32 is definitely the way to go.
  • A neopixel ring. In my case I got a 24 led version - there are larger and smaller out there, but that seemed to be the Golidlocks size ie not too big or too small.
  • Optional - a 0.96 inch oled display (SSD1306 128x64) - the ring is used to give an approximation of the amount of power being consumed from the grid and/or being generated by your solar panels if you have them. The oled display is a nice to have as it can be used to provide more detail. Note that past experience has shown me that these displays are not always the same physical size, so you may need to tweak the 3D case if you use what I put together.

Code part 1:

# Compiled and tested on esphome 2024.7.2 and HA 2024.7.3

# Notes:
#  
# A 24 LED neopixel string may draw too much power and cause stability issues if powered from the 5V pin
# If you find this is the case, you can try a different power supply with higher amps or power the neopixels separately
# You can of course use an esp8266 eg a Wemos D1 mini, but they generally do not have bluetooth support
# plus restrict the number of GPIOs available for external sensors
#
# Does not need a case, but if you have a 3D printer
# there are a number of options to choose from, such as https://www.thingiverse.com/thing:2868939
# My modified design to include an OLED display is here: https://www.thingiverse.com/thing:6710772
#
# Note there are potential WiFi issues with some esp32 boards. If having disconnects, check out this thread:
# https://community.home-assistant.io/t/something-is-very-wrong-with-the-wifi-on-the-esp32-boards-i-ordered-from-aliexpress-is-there-any-way-to-salvage-these-and-fix-the-wifi/477631/29?u=crypter
# Simplest thing is to power the esp32 board directly from the vin pins rather than use the usb-c port

# Check https://randomnerdtutorials.com/esp32-pinout-reference-gpios/ for what pins to use
# Roughly speaking, GPIO4, 13, 16-33 are fine

substitutions:
  devicename: ws2812b24-32
  friendname: ws2812b24-32
# ESP32 Wroom DevKit
  board: esp32dev
  inpin: GPIO13 # connected to IN of ws2812b24 ring. Choosing this pin as it is directly in line with gnd and vin ie 5V power
  bright: 30% # default colour brightness for the neopixels

# This is for the SSD1306 OLED Display https://esphome.io/components/display/ssd1306.html
# Note that adding in extra sensors/displays will draw more power concurrently with the neopixels causing stability issues
  sdapin: GPIO22
  sckpin: GPIO23

esphome:
  name: $devicename
  friendly_name: $friendname
  project:
    name: "ninkasi.solarstatus"
    version: "1.0.1"
  comment: Solar Status Display
# Can take a little while before the display shows anything as "on_value_range" only triggers when something changes
# As such, can always display something in the meantime
  on_boot:
    priority: 600
    then:
      - display.page.show: page0
      - logger.log: "Just started - lets display the welcome screen!"

esp32:
  board: $board

# Enable Home Assistant API
api:
  encryption:
    key: !secret esphome_encryption_key

ota:
  password: !secret ota_password
  platform: esphome

wifi:
  networks:
  - ssid: !secret wifIoT_ssid
    password: !secret wifIoT_password
    priority: 2
# Backup SSID just in case
  - ssid: !secret wifi_ssid
    password: !secret wifi_password
    priority: 1
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "$devicename Fallback Hotspot"
    password: !secret ota_password

# Enable logging
# Change to avoid "Components should block for at most 20-30ms" warning messages in the log - an issue since 2023.7.0
# Not really a breaking change - it's an issue I suspect due to the device being slow and this error previously
# simply not being reported
logger:
  logs:
    component: ERROR


# Note - I wanted the neopixel lights to turn off at night
# Found that although I could do it, using 'on_value_range' they would turn back on should the state change
# As power was being run from VCC, the lights would stay on even if put into deep sleep
# Instead, as I admit a hack, I run a 'blank' automation effect - this remains active until turned off
# ie any requests to change the LED colours are simply ignored. See the display and script sections.
time:
  - platform: homeassistant
    timezone: "Australia/Melbourne"
    id: homeassistant_time
    on_time:
      - seconds: 0
        minutes: 0
        hours: 21
        then:
          - logger.log: "Time to turn the screens off"
          - script.execute: screenoff
      - seconds: 0
        minutes: 0
        hours: 8
        days_of_week: MON-FRI
        then:
          - logger.log: "Time to turn the screens on - weekday"
          - script.execute: screenon
      - seconds: 0
        minutes: 0
        hours: 10
        days_of_week: SAT-SUN
        then:
          - logger.log: "Time to turn the screens on - weekend"
          - script.execute: screenon

# Bluetooth stuff
# Be aware this can eat up a LOT of memory, so if your device starts off with not much
# then this could introduce instability ie reboots
# For example, my esp32 averaged around the 200kb free mark normally. Enabling ble_tracker and it averaged around tohe 40kb mark, at times
# dropping below 20kb.

#esp32_ble_tracker:
#  scan_parameters:
#    interval: 1100ms
#    window: 1100ms
    # We currently use the defaults to ensure Bluetooth
    # can co-exist with WiFi In the future we may be able to
    # enable the built-in coexistence logic in ESP-IDF
#    active: false

#bluetooth_proxy:
#  active: true

#binary_sensor:
  ## Presence based on MAC address
#  - platform: ble_presence
#    mac_address: DE:AD:BE:EF:00:00
#    name: "Example"
#    min_rssi: -75dB

  ## Presence based on iBeacon UUID
#  - platform: ble_presence
#    ibeacon_uuid: '1100008E-80FF-80FF-8080-DEADBEEFE1E1,'
#    name: "Watch UUID"
#    min_rssi: -75dB
   # Enabled through HA app on phone, turning on BLE Transmitter

i2c:
  sda: $sdapin
  scl: $sckpin

font:
  - file: "gfonts://Roboto"
    id: font_15
    size: 15
  - file: "gfonts://Roboto"
    id: font_25
    size: 25
  - file: "gfonts://Roboto"
    id: font_36
    size: 36

display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    id: mydisplay
    pages:
      - id: page0 # This page is just shown on initial startup 
        lambda: |-
          it.printf(it.get_width()/2, 15, id(font_25), TextAlign::TOP_CENTER, "Fetching");
          it.printf(it.get_width()/2, 35, id(font_25), TextAlign::TOP_CENTER, "Data....");
      - id: page1 # This page is shown when generating solar power and NOT consuming power from the grid
        lambda: |-
          it.print(it.get_width()/2, 0, id(font_15), TextAlign::TOP_CENTER, "SOLAR");
          it.printf(it.get_width()/2, 15, id(font_36), TextAlign::TOP_CENTER, "%.1fkW" , id(power_solar_inst).state/1000);
      - id: page2 # This page is shown when consuming power from the grid 
        lambda: |-
          it.print(it.get_width()/2, 0, id(font_15), TextAlign::TOP_CENTER, "GRID");
          it.printf(it.get_width()/2, 15, id(font_36), TextAlign::TOP_CENTER, "%.1fkW" , id(power_grid_inst).state/1000);
      - id: page3 # This is a blank page to show at night
        lambda: |-
          it.fill(COLOR_OFF);

light:
  - platform: neopixelbus
    variant: WS2812
    pin: $inpin
    num_leds: 24
    type: GRB
    name: ring24
    id: ring24
    effects:
      - addressable_rainbow:
      - automation: # This is called when we want to turn off the neopixel lights AND stop them from coming back on until the effect is turned off
          name: Blank
          sequence:
            - light.addressable_set:
                id: ring24
                red: 0%
                green: 0%
                blue: 0%
            - delay: 500ms
            - light.addressable_set:
                id: ring24
                red: 0%
                green: 0%
                blue: 0%

text_sensor:
  - platform: template
    name: "Uptime (formatted)"
    lambda: |-
      uint32_t dur = id(uptime_s).state;
      int dys = 0;
      int hrs = 0;
      int mnts = 0;
      if (dur > 86399) {
        dys = trunc(dur / 86400);
        dur = dur - (dys * 86400);
      }
      if (dur > 3599) {
        hrs = trunc(dur / 3600);
        dur = dur - (hrs * 3600);
      }
      if (dur > 59) {
        mnts = trunc(dur / 60);
        dur = dur - (mnts * 60);
      }
      char buffer[17];
      sprintf(buffer, "%ud %02uh %02um %02us", dys, hrs, mnts, dur);
      return {buffer};
    icon: mdi:clock-start
    update_interval: 60s

sensor:
#  - platform: ble_rssi
#    mac_address: DE:AD:BE:EF:00:00
#    name: "Example RSSI"
#  - platform: ble_rssi
#    ibeacon_uuid: '1100008E-80FF-80FF-8080-DEADBEEFE1E1'
#    name: "Watch UUID RSSI"
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    id: wifisignal
    update_interval: 60s
    unit_of_measurement: dBm
    accuracy_decimals: 0
    device_class: signal_strength
    state_class: measurement
    entity_category: diagnostic
  - platform: copy # Reports the WiFi signal strength in %
    source_id: wifisignal
    id: wifipercent
    name: "WiFi Signal Percent"
    filters:
      - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
    unit_of_measurement: "Signal %"
    entity_category: "diagnostic"
  - platform: uptime
    id: uptime_s
    name: "$devicename Uptime"
    update_interval: 60s          
  - platform: template
    name: $devicename free memory
    lambda: return heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
    icon: "mdi:memory"
    entity_category: diagnostic
    state_class: measurement
    unit_of_measurement: "b"
    update_interval: 60s

# initially had the following using the sensor data then splitting it into 24
# but wanted more control - showing grid power being used concurrently with solar
# generation, as well as change the colours depending on how much power was being
# generated

# Note that the LEDs will only update when the power status changes to trigger the on_value_range
# This means that on initial booting, it might take a while before any LEDs light

Code Part 2


  - platform: homeassistant
    id: power_grid_inst
    entity_id: sensor.instantaneousdemand
    accuracy_decimals: 1
    on_value_range:
      - above: -1
        below: 1
        then:
          - logger.log: "Fantastic. Naff all power being consumed from the grid"
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing the blank then leave it alone
              else:
                - display.page.show: page1 # otherwise show the solar screen as no grid power being consumed    
      - above: 1
        below: 1499
        then:
          - logger.log: "Grid below 1.5kW, so light 1 LED"
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 23
              range_to: 23
              red: 100%
              green: 100%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing the blank then leave it alone
              else:
                - display.page.show: page2 # otherwise show how much power being consumed from the grid    
      - above: 1500
        below: 2499
        then:
          - logger.log: "Grid between 1.5 and 2.5kW, so light 2 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 22
              range_to: 23
              red: 100%
              green: 64.7%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 2500
        below: 3499
        then:
          - logger.log: "Grid between 2.5 and 3.5kW, so light 3 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 21
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 3500
        below: 4499
        then:
          - logger.log: "Grid between 3.5 and 4.5kW, so light 4 LEDs"          
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 20
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 4500
        below: 5499
        then:
          - logger.log: "Grid between 4.5 and 5.5kW, so light 5 LEDs"        
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 19
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 5500
        below: 6499
        then:
          - logger.log: "Grid between 5.5 and 6.5kW, so light 6 LEDs"         
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 18
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 6500
        below: 7499
        then:
          - logger.log: "Grid between 6.5 and 7.5kW, so light 7 LEDs"       
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 17
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 7500
        below: 8499
        then:
          - logger.log: "Grid between 7.5 and 8.5kW, so light 8 LEDs"      
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 16
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 8500
        below: 9499
        then:
          - logger.log: "Grid between 8.5 and 9.5kW, so light 9 LEDs"        
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 15
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 9500
        below: 10499
        then:
          - logger.log: "Grid between 9.5 and 10.5kW, so light 10 LEDs"        
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 14
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 10500
        below: 11499
        then:
          - logger.log: "Grid between 10.5 and 11.5kW, so light 11 LEDs"        
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 13
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
      - above: 11500
        then:
          - logger.log: "Grid above 11.5kW, so light 12 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 12
              range_to: 23
              red: 100%
              green: 0%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3
              else:
                - display.page.show: page2    
  - platform: homeassistant
    id: power_solar_inst
    entity_id: sensor.symo_15_0_3_m_1_ac_power  
    accuracy_decimals: 1
    on_value_range:
      - below: 1
        then:
          - logger.log: "Solar below 1W so no LEDs"
          - light.addressable_set: 
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation
      - above: 1
        below: 1499
        then:
          - logger.log: "Solar between 0.1 and 1.5kW, so light 1 LED"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 0       
              red: 0%
              green: 0%
              blue: 100%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation 
      - above: 1500
        below: 2499
        then:
          - logger.log: "Solar between 1.5 and 2.5kW, so light 2 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 1
              red: 0%
              green: 10%
              blue: 90%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation 
      - above: 2500
        below: 3499
        then:
          - logger.log: "Solar between 2.5 and 3.5kW, so light 3 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 2
              red: 0%
              green: 20%
              blue: 80%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation
      - above: 3500
        below: 4499
        then:
          - logger.log: "Solar between 3.5 and 4.5kW, so light 4 LEDs"      
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 3
              red: 0%
              green: 30%
              blue: 70%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation 
      - above: 4500
        below: 5499
        then:
          - logger.log: "Solar between 4.5 and 5.5kW, so light 5 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 4
              red: 0%
              green: 40%
              blue: 60%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation 
      - above: 5500
        below: 6499
        then:
          - logger.log: "Solar between 5.5 and 6.5kW, so light 6 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 5
              red: 0%
              green: 50%
              blue: 50%       
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation 
      - above: 6500
        below: 7499
        then:
          - logger.log: "Solar between 6.5 and 7.5kW, so light 7 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 6
              red: 0%
              green: 60%
              blue: 40%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation
      - above: 7500
        below: 8499
        then:
          - logger.log: "Solar between 7.5 and 8.5kW, so light 8 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 7
              red: 0%
              green: 70%
              blue: 30%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation
      - above: 8500
        below: 9499
        then:
          - logger.log: "Solar between 8.5 and 9.5kW, so light 9 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 8
              red: 0%
              green: 80%
              blue: 20%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation 
      - above: 9500
        below: 10499
        then:
          - logger.log: "Solar between 9.5 and 10.5kW, so light 10 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 9
              red: 0%
              green: 90%
              blue: 10%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation
      - above: 10500
        below: 11499
        then:
          - logger.log: "Solar between 10.5 and 11.5kW, so light 11 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 10
              red: 0%
              green: 90%
              blue: 10%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation 
      - above: 11500
        then:
          - logger.log: "Solar above 11.5kW, so light 12 LEDs"
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 0%
              blue: 0%
          - light.addressable_set:
              id: ring24
              range_from: 0
              range_to: 11
              red: 0%
              green: 100%
              blue: 0%
              color_brightness: $bright
          - if:
              condition:
                display.is_displaying_page:
                  id: mydisplay
                  page_id: page3
              then:
                - display.page.show: page3 # if screen showing blank, leave it alone 
              else:  
                - if:
                    condition:
                      display.is_displaying_page:
                        id: mydisplay
                        page_id: page2
                    then:
                      - display.page.show: page2 # if screen showing grid consumption, leave it alone             
                    else:
                      - display.page.show: page1 # Show solar generation
script:
  - id: screenoff
    then:
      - light.turn_on:
          id: ring24
          effect: blank
      - display.page.show: page3
  - id: screenon
    then:
      - light.turn_on: # Remove the effect from the neopixel ring
          id: ring24
          color_brightness: $bright
          effect: none
      - display.page.show: page0
      - light.addressable_set: # Change
          id: ring24
          range_from: 0
          range_to: 23
          red: 0%
          green: 0%
          blue: 0%

Very cool.

Thanks! It actually took a few days to sort this out enough that I was happy to release it into the wild. Every time I moved one step forward, there always seemed to be something else blocking the way. I had to do a lot of experimenting as well as trawling through the community posts both here as well as at other sites to sort things out.

For example - no matter what I did, the lights just kept wanted to come back on when I wanted it to sleep. I got it to the point where it was almost ok, but every now and then the lights would flicker or come on. I tried putting the esp into deep sleep, but found the wemos d1 I was using at the time would not wake back up again as there is a hard limit on the length of time it can be put into a deep sleep. I then moved over to an esp32 and extended (eg 8+ hours) deep sleep worked for that, but I eventually worked out one of the issues was the lights would stay on due to power coming from the 5V pin. I then realised that simply dropping the brightness to 0% did the same job, so that was finally sorted.

Oh, I also had a much cleaner/shorter code that converted the power to the closest integer between 0 and 12, but although that was a lot neater it also meant that grid power was just red, and solar green - I wasn’t taking advantage of the neopixels being able to show a range of colours. So had to revise that. :wink:

I then had the brilliant idea to include the oled screen, and working out how to blank that display was relatively simple, but I did have to make multiple tweaks to my 3d print so the display would actually fit.

It all was starting to look good, just in time to realise that the esp32 was having intermittent issues that I was able to trace back to two culprits. The wifi was unreliable that I eventually was able to resolve by powering it directly from the pin rather than using the usb-c port, and ble was causing intermittent reboots due to low memory, so had to scrub that idea (but left the code in there, as may work with a better quality esp device).

1 Like