Software

Solar Power Oled display ESP32 with EspHome & Home Assistant

esphome:
  name: "heltec"
  friendly_name: Heltec

esp32:
  board: heltec_wifi_kit_32_V3
  variant: esp32s3
  framework:
    type: arduino
    version: 2.0.9
    platform_version: 6.3.0

# Enable logging
logger:

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

ota:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.0.125
    gateway: 192.168.0.1
    subnet: 255.255.255.0
    dns1: 8.8.8.8
    dns2: 192.168.0.1
  power_save_mode: none
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Heltec-V3"
    password: !secret wifi_hotspot_password

captive_portal:

sensor:
  - platform: homeassistant
    id: consumo_istantaneo
    entity_id: sensor.sonoff_10013bca72_power
    internal: true

  - platform: homeassistant
    id: daily_import
    entity_id: sensor.daily_import
    internal: true

  - platform: homeassistant
    id: esportata
    entity_id: sensor.daily_export
    internal: true

  - platform: homeassistant
    id: surplus_energia_w
    entity_id: sensor.surplus_energia_w
    internal: true

  - platform: homeassistant
    id: sonoff_10016fc351_power # potenza_fotovoltaico
    entity_id: sensor.sonoff_10016fc351_power
    internal: true

  - platform: homeassistant
    id: energia_consumata
    entity_id: sensor.sonoff_10013bca72_energy
    internal: true

  - platform: homeassistant
    id: energia_prodotta
    entity_id: sensor.sonoff_10016fc351_energy
    internal: true

  - platform: homeassistant
    id: percentage_power_charger_1
    entity_id: sensor.percentage_power_charger_1
    internal: true

  - platform: homeassistant
    id: percentage_power_charger_2
    entity_id: sensor.percentage_power_charger_2
    internal: true

  - platform: homeassistant
    id: percentage_power_charger_3
    entity_id: sensor.percentage_power_charger_3
    internal: true

  - platform: homeassistant
    id: temperatura_interna
    entity_id: sensor.sonoff_100148c86e_temperature
    internal: true

  - platform: homeassistant
    id: temperatura_esterna
    entity_id: sensor.sonoff_100148c86e_outdoor_temp
    internal: true

switch:
  - platform: gpio
    name: "Switch_Heltec"
    pin: GPIO45

output:
  - platform: ledc
    pin: GPIO46
    id: pwm_heltec
    frequency: 50Hz

light:
  - platform: monochromatic
    output: pwm_heltec
    name: "PWM_Heltec"    

time:
  - platform: homeassistant
    id: homeassistant_time
  - platform: sntp
    id: sntp_time
    timezone: CET-1CEST,M3.5.0,M10.5.0/3
  - platform: sntp
    id: sntp_zone_time
    timezone: Europe/Rome

i2c:
  - id: bus_a
    sda: GPIO17
    scl: GPIO18
    scan: false
#    frequency: 700khz
  - id: bus_b
    sda: 41
    scl: 42
    scan: false
#    frequency: 700khz

#spi:
#  clk_pin: GPIO9
#  mosi_pin: GPIO10
#  miso_pin: GPIO11
  
image:
  - file: "solar_power.bmp"
    id: solar_icon
    resize: 65x50

graph:
  - id: solar_power_graph
    duration: 24h
    x_grid: 120min
    y_grid: 50  # Watt
    width: 128
    height: 64
    traces:
      - sensor: sonoff_10016fc351_power
        line_type: SOLID
        line_thickness: 2


interval:
  - interval: 4s
    then:
      - display.page.show_next: my_display
      - component.update: my_display

display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    reset_pin: GPIO21
    i2c_id: bus_a
    address: 0x3C
    contrast: 50%
    id: my_display
    pages:
      - id: page1
        lambda: |-
          it.printf(0, 0, id(icon_font), TextAlign::TOP_LEFT, "󰟑󰌪");
          it.printf(it.get_width() / 2, 0, id(arial), TextAlign::TOP_CENTER, "Travis90x");
          it.image(10, 16, id(solar_icon));
          it.strftime(it.get_width(), it.get_height() - 48, id(arial), TextAlign::BASELINE_RIGHT, "%a", id(homeassistant_time).now());
          it.strftime(it.get_width(), it.get_height() - 36, id(arial), TextAlign::BASELINE_RIGHT, "%d", id(homeassistant_time).now());
          it.strftime(it.get_width(), it.get_height() -24, id(arial), TextAlign::BASELINE_RIGHT, "%b", id(homeassistant_time).now());
          it.strftime(it.get_width(), it.get_height() -12, id(arial), TextAlign::BASELINE_RIGHT, "%Y", id(homeassistant_time).now());
          it.strftime(it.get_width(), it.get_height(), id(arial), TextAlign::BASELINE_RIGHT, "%H:%M", id(homeassistant_time).now());
#  it.strftime(it.get_width(), it.get_height() - 30, id(arial), TextAlign::BASELINE_RIGHT, "%H:%M", id(sntp_zone_time).now());
#  it.strftime(it.get_width(), it.get_height() - 15, id(arial), TextAlign::BASELINE_RIGHT, "%H:%M", id(sntp_time).now());

      - id: page2
        lambda: |-
          it.printf(0, 0, id(icon_font), TextAlign::TOP_LEFT, "󰥛");
          it.printf(it.get_width() / 2, 0, id(arial), TextAlign::TOP_CENTER, "ENERGIA");
          it.printf(it.get_width(), it.get_height() - 37, id(arial), TextAlign::BASELINE_RIGHT, "Consumata %.1f KWh", id(energia_consumata).state); 
          it.printf(it.get_width(), it.get_height() -25, id(arial), TextAlign::BASELINE_RIGHT, "Prelevata %.1f KWh", id(daily_import).state / 1000);   
          it.printf(it.get_width(), it.get_height() -13, id(arial), TextAlign::BASELINE_RIGHT, "Prodotta %.1f KWh", id(energia_prodotta).state);      
          it.printf(it.get_width(), it.get_height() -1, id(arial), TextAlign::BASELINE_RIGHT, "Ceduta %.1f Wh", id(esportata).state);

      - id: page3
        lambda: |-
          it.printf(it.get_width(), it.get_height() -28, id(arial), TextAlign::BASELINE_RIGHT, "Consumo %.1f W", id(consumo_istantaneo).state);
          it.printf(it.get_width(), it.get_height() -15, id(arial), TextAlign::BASELINE_RIGHT, "Fotovoltaico %.2f W", id(sonoff_10016fc351_power).state);
          it.printf(it.get_width(), it.get_height() -2, id(arial), TextAlign::BASELINE_RIGHT, "Surplus %.2f W", id(surplus_energia_w).state);

      - id: page4
        lambda: |-
          it.printf(0, 0, id(icon_font), TextAlign::TOP_LEFT, "󰥛");
          it.printf(it.get_width() / 2, 0, id(arial), TextAlign::TOP_CENTER, "Surplus to PWM");
          it.printf(it.get_width(), it.get_height() -35, id(arial), TextAlign::BASELINE_RIGHT, "0-100W @ %.0f%%", id(percentage_power_charger_1).state);   
          it.printf(it.get_width(), it.get_height() -20, id(arial), TextAlign::BASELINE_RIGHT, "100-200W @ %.0f%%", id(percentage_power_charger_2).state);   
          it.printf(it.get_width(), it.get_height() -5, id(arial), TextAlign::BASELINE_RIGHT, "200-300W @ %.0f%%", id(percentage_power_charger_3).state);

      - id: page5
        lambda: |-
          it.printf(2, 0, id(icon_font), TextAlign::TOP_LEFT, "󰖙");
          it.graph(0, 0, id(solar_power_graph));
#          it.printf(it.get_width() / 2, 0, id(icon_font), TextAlign::TOP_RIGHT, "SOLARE %.2f W 󰖙 ", id(sonoff_10016fc351_power).state);

      - id: page6
        lambda: |-
          it.printf(0, 0, id(icon_font), TextAlign::TOP_LEFT, "󰽕");
          it.printf(it.get_width(), it.get_height() -20, id(arial), TextAlign::BASELINE_RIGHT, "Temp. interna: %.1f°C", id(temperatura_interna).state);
          it.printf(it.get_width(), it.get_height() -5, id(arial), TextAlign::BASELINE_RIGHT, "Temp. esterna: %.1f°C", id(temperatura_esterna).state);

font:
  - file: 'arial.ttf'
    id: arial
    size: 12
    glyphs:
      ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z','à', 'è', 'é', 'ì', 'ò','ù', '/', '#']
  - file: 'materialdesignicons-webfont.ttf' 
    id: icon_font
    size: 17
    glyphs:
      ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z','à', 'è', 'é', 'ì', 'ò','ù', '/', '#', '󰌪', '󰽔', '󰟑', '󰮧', '󰂒', '󰽕', '󰕊', '󱩟', '󰖛', '󰖜', '󰤟', '󰤢', '󰤥', '󰤨', '󰤫', '󰖙', '󰖔', '󰖐', '󰖖', '󰼵', '󰼴', '󰖞', '󰖑', '󰼱', '󰖕', '󰽡', '󰽢', '󰽣', '󰽤', '󰽥', '󰽦', '󰽧', '󰽨', '󰀟', '󰀠', '󰀳', '󰀸', '󰁆', '󰁅', '󰁍', '󰁔', '󰁝', '󰁎', '󰁕', '󰁞', '󰄪', '󰖟', '󰖚', '󰖨', '󰖩', '󰥭', '󰥛']

en_GBEnglish (UK)