Seeed Studio XIAO 7.5" ePaper Panel - Battery Status?

I bought the XIAO 7.5" ePaper Panel and have it setup and running nicely with Home Assistant. The one thing I can’t find is how to get the battery status? I’d like to monitor it (preferably in HA) so I know when it needs to be plugged in. I’ve done a bunch of searches, but haven’t found anything yet.

Thanks for any help or pointing me in the right direction.

Hi there,

SO you are correct , Home Assistant (HA) integration with Seeed’s XIAO 7.5" ePaper Panel doesn’t expose battery info by default. But the capability is there — it depends on how the firmware running on the XIAO is configured, and how it’s reporting battery voltage back to HA (e.g. via MQTT, ESPHome, or BLE).

You can add the voltage divider externally and then Analog read say (A3) along this line, and there are some threads here also on this topic.

For an S3,

Use a Resistor Divider from VBAT to an Analog-Capable Pin

Example:

  • Connect VBAT → 100kΩ → Analog Pin (e.g., A0)
  • Connect Analog Pin → 100kΩ → GND

This gives a 2:1 division, so a 4.2V battery reads as ~2.1V at the analog pin.

#define BATTERY_PIN A0  // or GPIO number

void setup() {
  Serial.begin(115200);
  analogReadResolution(12); // 12-bit ADC: 0–4095
}

void loop() {
  int raw = analogRead(BATTERY_PIN);
  float voltage = (raw * 3.3 / 4095.0) * 2.0; // adjust 2.0 if using a different divider
  Serial.printf("Battery Voltage: %.2f V\n", voltage);
  delay(10000);
}

For ESPHome add this YamL

sensor:
  - platform: adc
    pin: GPIO1  # or wherever your voltage divider feeds
    name: "Battery Voltage"
    update_interval: 60s
    attenuation: 11db  # for full range
    filters:
      - multiply: 2.0  # scale up for divider
    unit_of_measurement: "V"

the original question’s answer is "You will not see battery voltage unless their firmware explicitly uses an external voltage divider into an analog pin. Nothing is prewired on the Xiao ESP32-S3-based ePaper board for that.

HTH
GL :slight_smile: PJ :v:

FYI :crossed_fingers:

Board Built-in VBAT Monitor? Notes
XIAO nRF52840 :white_check_mark: analogRead(P0_31) or PIN_VBAT Has onboard VBAT divider
XIAO ESP32-S3 :x: None built-in Must use external divider
XIAO SAMD21 :x: None built-in External divider needed
XIAO ESP32C3 :x: None built-in External divider required

The old BSP for the Nrf52840 Xiao was able to read the battery voltage, check out the old threads on it, I have a demo of it there also.
non-embed and certain mbed BSP’s as well :pinched_fingers:

Thanks for the response! It’s using the ESP32C3, but your point is the same. I was hoping to not have to open the case and mod it, but it sounds like that’s the only way. Maybe they’ll do it with the next release of the product. Knowing the battery status is something I’d think most people would want.

I knew this was a pre-release product when I bought it, so no big deal. It’s not a deal breaker and it will do what I need it to do (display some Home Assistant information). I’ll just have to remember to plug it in every now and then. :grin:

John

1 Like

Hi there,

Yep, You got it… funny though the Wio_terminal they have has a Battery I2C PMIC chip in it, so you can extract all sorts of SOC info like on a cell phone. Battery total capacity and life , fast and slow charge , etc. It surprises me every time these “Battery Powered” or “Wearable” terms are thrown around like one guy I suspect on here at a Ditty Party :sweat_smile: :scream:

Good battery management is almost an art form for these MCU’s along with Deep Sleep as the holly grail.

I’m betting REV 2 will have something for us…battery hawks :+1:

If Seeed is listening and does make the change for v2, I’d love to know what the change is so I can do it to my v1. I’m sure I can find and figure it out from the posts on here, but my free time is limited right now and this will be low on my list of things to research for now. :wink:

1 Like

Hi there,

Yes , So it’s the penny wise and pound foolish with this , a swing and a miss IMO. You see from the schematic :face_with_open_eyes_and_hand_over_mouth: :fist_right: they left us hanging :grin:

the Charge chip ETA9740E8A is also having a 4 LED FUEL Gauge it a LIPO 3A Switching Charger, 2.4A Boost and Fuel Gauge in One ESOP8 with Single Inductor

See , Seeed can always do better :grin: :+1:
From the Data sheet HERE
and the Included reference design 2 resistors and 4 LED’s is what’s missing IMO for the absolute Minimum for a display product like this.
Oh’ and 4 tiny holes… :pinched_fingers:

Curious to get one and crack it open See if just adding a jumper or three :sweat_smile: from the pins on the ESOP8 package to the Xiao socket pins for D6, D7 & D9 “available” …
WoW, someone missed the boat? :canoe:

If they were not , they are NOW!

In Rev 2… I would also try a nrf52840 Sense, Low Sleep power, Let the IMU get in on the action, Wake from sleep & gesture controls… NO BUTTONS :+1:
Use a Plus variety and Enable an ADD-ON Grove EXTernal Sensor capability , We can do Way better…Add an Interrupt pin for the PMIC
maybe as well.

HTH
GL :slight_smile: PJ :v:

1 Like

Hi There
Based on msfujino’s work], I tried to measure the battery, but unfortunately, there are no more ADC ports available for the C3.
So I looked for another compatible xiao and I found the C6.

I soldered the resistors directly onto the battery terminals under the driver board.

Then I soldered a cable to GPIO6 on the back of the C6 (I forgot to take a photo).

Finally, I put everything back in its place and reconnected the resistors.


I had to modify the code a little bit to make it work with the C6, but now it’s perfect.
I’m currently running tests to calibrate the battery, but with deep sleep mode it takes a long time.
For the code i use esphome (not optimized)

substitutions:
  device_name: "dashboard-epaper-salon"
  friendly_name: "Dashboard epaper salon"
  compile_process_limit: "1"

esphome:
  name: "${device_name}"
  friendly_name: "${friendly_name}"
  on_boot:
      priority: 200.0
      then:
        - logger.log: "Boot..."
        - component.update: eink_display
        - wait_until:
            condition:
              lambda: 'return id(data_updated) == true;'
              # Wait a bit longer so all the items are received
        - delay: 5s
        - logger.log: "Initial sensor data received: Refreshing display..."
        - lambda: 'id(initial_data_received) = true;'
        - script.execute: update_display

esp32:
  board: seeed_xiao_esp32c6
  framework:
    type: esp-idf

external_components:
  - source:
      type: git
      url: https://github.com/lboue/esphome
      ref: adc_oneshot
    components: [ adc ]
    refresh: 0s # Do not update automatically

# Enable logging
logger:
  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: "mykey"

ota:
  - platform: esphome
    password: "mypassword"

globals:
  - id: wifi_status
    type: int
    restore_value: no
    initial_value: "0"
  - id: first_update_done
    type: bool
    restore_value: no
    initial_value: "false"
  - id: data_updated
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: initial_data_received
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: recorded_display_refresh
    type: int
    restore_value: yes
    initial_value: '0'
  - id: trash_data
    type: std::string
    restore_value: no
    initial_value: ''

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  on_connect:
    then:
      - lambda: |-
          id(wifi_status) = 1;
  on_disconnect:
    then:
      - lambda: |-
          id(wifi_status) = 0;
  ap:
    ssid: "${device_name} Hotspot"
    password: "mypassword"

captive_portal:

web_server:
  port: 80

# -------------------------------------- Keep your code above, change your code below --------------------------------------

# Here is deep sleep part
deep_sleep:
  id: deep_sleep_1
  run_duration: 2min  # Device wake up and run 60s (enough to pull data and update)
  sleep_duration: 58min  # deep sleep for 1h

script:
  - id: update_display
    then:
      - lambda: 'id(data_updated) = false;'
      - component.update: eink_display
      - logger.log: "Display updated."
      - lambda: 'id(recorded_display_refresh) += 1;'

# Connect to Home Assistant to get time
# Check whether the display needs to be refreshed every minute,
# based on whether new data is received or motion is detected. (Thanks @paviro!)
time:
  - platform: homeassistant
    id: homeassistant_time
    on_time:
      - seconds: 0
        minutes: /1
        then:
          - if:
              condition:
                lambda: 'return id(data_updated) == true;'
              then:
                - if:
                    condition:
                      binary_sensor.is_on: motion_detected
                    then:
                      - logger.log: "Sensor data updated and activity in home detected: Refreshing display..."
                      - script.execute: update_display
                    else:
                      - logger.log: "Sensor data updated but no activity in home - skipping display refresh."
              else:
                - logger.log: "No sensors updated - skipping display refresh."
                - script.execute: update_display

button:
  - platform: shutdown
    name: "Shutdown"
  - platform: restart
    name: "Restart"
  - platform: template
    name: "Refresh Screen"
    entity_category: config
    on_press:
      - script.execute: update_display

# Check if motion is detected in the living room.
binary_sensor:
  - platform: homeassistant
    entity_id: binary_sensor.dashboard_epaper_motion_detected
    id: motion_detected

sensor:
  # Create sensors for monitoring Weatherman remotely.
  # https://forum.seeedstudio.com/t/battery-voltage-monitor-and-ad-conversion-for-xiao-esp32c/267535
  # https://forum.seeedstudio.com/t/seeed-studio-xiao-7-5-epaper-panel-battery-status/292932/2
  # https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/#check-the-battery-voltage
  - platform: adc
    pin: GPIO6  # or wherever your voltage divider feeds
    name: "Battery Voltage"
    id: battery_voltage
    update_interval: 60s
    #attenuation: 11db  # for full range
    #filters:
    #  - multiply: 2.0  # scale up for divider
    unit_of_measurement: "V"

  - platform: template
    name: "Battery %"
    id: battery_percent
    lambda: return id(battery_voltage).state;
    accuracy_decimals: 0
    unit_of_measurement: "%"
    icon: mdi:battery-medium
    filters:
      - calibrate_linear:
         method: exact
         datapoints:
#          - 0.00 -> 0.0
#          - 3.30 -> 1.0
#          - 3.39 -> 10.0
#          - 3.70 -> 100.0
    # Voltage (V)  Charge (%)
          - 3.00 -> 0
          - 3.61 -> 5
          - 3.69 -> 10
          - 3.71 -> 15
          - 3.73 -> 20
          - 3.75 -> 25
          - 3.77 -> 30
          - 3.79 -> 35
          - 3.80 -> 40
          - 3.82 -> 45
          - 3.84 -> 50
          - 3.85 -> 55
          - 3.87 -> 60
          - 3.91 -> 65
          - 3.95 -> 70
          - 3.98 -> 75
          - 4.02 -> 80
          - 4.08 -> 85
          - 4.11 -> 90
          - 4.15 -> 95
          - 4.20 -> 100
      - lambda: |-
          if (x <= 100) {
            return x;
          } else {
            return 100;
          }
          if (x <0) {
            return 0;
          }

  - platform: template
    name: "Recorded Real Temperature Last"
    accuracy_decimals: 2
    unit_of_measurement: "C°"
    device_class: "temperature"
    entity_category: "diagnostic"
    id: real_temperature_last_update
    
  - platform: template
    name: "Recorded Display Refresh"
    accuracy_decimals: 0
    unit_of_measurement: "Refreshes"
    state_class: "total_increasing"
    entity_category: "diagnostic"
    lambda: 'return id(recorded_display_refresh);'
  
  - platform: wifi_signal
    name: "WiFi Signal Strength"
    id: wifisignal
    unit_of_measurement: "dBm"
    entity_category: "diagnostic"
    update_interval: 60s

  - platform: homeassistant
    entity_id: sensor.openuv_indice_uv_actuel
    id: weather_uv
    name: "UV"
    on_value:
      then:
        - logger.log: "sensor.openuv_indice_uv_actuel update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_temperature_pool
    id: weather_temperature_pool
    device_class: temperature
    unit_of_measurement: "°C"
    name: "Pool temperature"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_temperature_pool update"                
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_temperature_real
    id: weather_temperature_real
    device_class: temperature
    unit_of_measurement: "°C"
    entity_category: "diagnostic"
    name: "Real temperature"
    on_value:
      then:
        - if:
            condition:
              lambda: return ( id(real_temperature_last_update).state != x );
            then:
              - logger.log:
                  format: "real temperature update %.1f != %.1f"
                  args: [x, id(real_temperature_last_update).state]
              - lambda: 'id(real_temperature_last_update).publish_state(x);'
              - lambda: 'id(data_updated) = true;'
            else:
              - lambda: 'id(real_temperature_last_update).publish_state(x);'
              - logger.log:
                  format: "real temperature not update %.1f == %.1f"
                  args: [x, id(real_temperature_last_update).state]

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_temperature_0
    id: weather_temperature_0
    name: "Temp 0"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_temperature_0 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_temperature_1
    id: weather_temperature_1
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_temperature_1 update"        
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_temperature_2
    id: weather_temperature_2
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_temperature_2 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_temperature_3
    id: weather_temperature_3
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_temperature_3 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    id: famille_calendar_event
    entity_id: calendar.famille
    attribute: "message"
    on_value:
      then:
        - logger.log: "calendar.famille.message update"
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    id: famille_calendar_start_time
    entity_id: calendar.famille
    attribute: "start_time"
    on_value:
      then:
        - logger.log: "calendar.famille.start_time update"
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    id: famille_calendar_end_time
    entity_id: calendar.famille
    attribute: "end_time"
    on_value:
      then:
        - logger.log: "calendar.famille.mesend_timesage update"        
        - lambda: 'id(data_updated) = true;'

text_sensor:
  - platform: wifi_info
    ip_address:
      name: IP Address
    ssid:
      name: Connected SSID
    mac_address:
      name: Mac Address

  - platform: template
    name: "Last Update Time"
    id: last_update_time
    update_interval: 30s
    lambda: return id(homeassistant_time).now().strftime("%d-%m %H:%M");

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: scheduled_events_0
    id: scheduled_events_0
    name: "Scheduled events 0"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.scheduled_events_0 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    entity_category: diagnostic
    attribute: scheduled_events_1
    id: scheduled_events_1
    internal: true
    name: "Scheduled events 1"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.scheduled_events_1 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    entity_category: diagnostic
    attribute: scheduled_events_2
    id: scheduled_events_2
    internal: true
    name: "Scheduled events 2"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.scheduled_events_2 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    entity_category: diagnostic
    attribute: scheduled_events_3
    id: scheduled_events_3
    internal: true
    name: "Scheduled events 3"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.scheduled_events_3 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    entity_category: diagnostic
    attribute: scheduled_events_4
    id: scheduled_events_4
    internal: true
    name: "Scheduled events 4"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.scheduled_events_4 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    entity_category: diagnostic
    attribute: scheduled_events_5
    id: scheduled_events_5
    internal: true
    name: "Scheduled events 5"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.scheduled_events_5 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    entity_category: diagnostic
    attribute: scheduled_events_6
    id: scheduled_events_6
    internal: true
    name: "Scheduled events 6"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.scheduled_events_6 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    entity_category: diagnostic
    attribute: scheduled_events_7
    id: scheduled_events_7
    internal: true
    name: "Scheduled events 7"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.scheduled_events_7 update"
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    id: ha_calendar_event_1
    entity_id: calendar.epaper
    attribute: "message"
  - platform: homeassistant
    id: ha_calendar_start_time_1
    entity_id: calendar.epaper
    attribute: "start_time"
  - platform: homeassistant
    id: ha_calendar_end_time_1
    entity_id: calendar.epaper
    attribute: "end_time"

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    entity_category: diagnostic
    attribute: trash
    id: trash
    internal: true
    name: "Trash status"
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.trash update"        
        - lambda: 'id(trash_data) = x;'
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_condition_now
    id: weather_condition_now
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_condition_now update"        
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_condition_0
    id: weather_condition_0
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_condition_0 update"                
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_timestamp_0
    id: weather_timestamp_0
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_timestamp_0 update"                
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_condition_1
    id: weather_condition_1
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_condition_1 update"                
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_timestamp_1
    id: weather_timestamp_1
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_timestamp_1 update"                
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_condition_2
    id: weather_condition_2
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_condition_2 update"                        
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_timestamp_2
    id: weather_timestamp_2
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_timestamp_2 update"                
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_condition_3
    id: weather_condition_3
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_condition_3 update"                
        - lambda: 'id(data_updated) = true;'
  - platform: homeassistant
    entity_id: sensor.dashboard_epaper_data
    attribute: weather_timestamp_3
    id: weather_timestamp_3
    on_value:
      then:
        - logger.log: "sensor.dashboard_epaper_data.weather_timestamp_3 update"                
        - lambda: 'id(data_updated) = true;'

font:
  - file: 'fonts/GothamRnd-Book.ttf'
    id: font_18_book
    size: 18
    glyphs: &font-glyphs [1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\/().:;?-_ÉéÈèçàùûô%°,' ',',']
  - file: 'fonts/GothamRnd-Book.ttf'
    id: font_10_book
    size: 10
    glyphs: *font-glyphs
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_108_bold
    size: 108
    glyphs: *font-glyphs
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_title
    size: 54
    glyphs: *font-glyphs
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_30_bold
    size: 30
    glyphs: *font-glyphs
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_18_bold
    size: 18
    glyphs: *font-glyphs
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_16_bold
    size: 16
    glyphs: *font-glyphs
  - file: 'fonts/materialdesignicons-webfont.ttf' # Directory to save ttf file
    id: font_mdi_100_large
    size: 100
    glyphs: &mdi-weather-glyphs # https://pictogrammers.com/library/mdi/
      - "\U000F050F" # Thermometer
      - "\U000F058E" # Humidity
      - "\U000F0D60" # Atmospheric pressure
      - "\U000F04E0" # Sunglasses
      - "\U000F0590" # mdi-weather-cloudy
      - "\U000F0F2F" # mdi-weather-cloudy-alert
      - "\U000F0E6E" # mdi-weather-cloudy-arrow-right
      - "\U000F0591" # mdi-weather-fog
      - "\U000F0592" # mdi-weather-hail
      - "\U000F0F30" # mdi-weather-hazy
      - "\U000F0898" # mdi-weather-hurricane
      - "\U000F0593" # mdi-weather-lightning
      - "\U000F067E" # mdi-weather-lightning-rainy
      - "\U000F0594" # mdi-weather-night
      - "\U000F0F31" # mdi-weather-night-partly-cloudy
      - "\U000F0595" # mdi-weather-partly-cloudy
      - "\U000F0F32" # mdi-weather-partly-lightning
      - "\U000F0F33" # mdi-weather-partly-rainy
      - "\U000F0F34" # mdi-weather-partly-snowy
      - "\U000F0F35" # mdi-weather-partly-snowy-rainy
      - "\U000F0596" # mdi-weather-pouring
      - "\U000F0597" # mdi-weather-rainy
      - "\U000F0598" # mdi-weather-snowy
      - "\U000F0F36" # mdi-weather-snowy-heavy
      - "\U000F067F" # mdi-weather-snowy-rainy
      - "\U000F0599" # mdi-weather-sunny
      - "\U000F0F37" # mdi-weather-sunny-alert
      - "\U000F14E4" # mdi-weather-sunny-off
      - "\U000F059A" # mdi-weather-sunset
      - "\U000F059B" # mdi-weather-sunset-down
      - "\U000F059C" # mdi-weather-sunset-up
      - "\U000F0F38" # mdi-weather-tornado
      - "\U000F059D" # mdi-weather-windy
      - "\U000F059E" # mdi-weather-windy-variant
      - "\U000F044C" # mdi-recycle
      - "\U000F0A79" # mdi-trash-can
      - "\U000F1A5F" # mdi-pool-thermometer
      - "\U000F0734" # mdi-arrow-right-bold
      - "\U000F0020" # mdi-alarm-clock
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: font_mdi_36_medium
    size: 36
    glyphs: *mdi-weather-glyphs
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: font_mdi_16_medium
    size: 16
    glyphs: *mdi-weather-glyphs

spi:
  clk_pin: GPIO19
  mosi_pin: GPIO18

# Define colors
# This design is white on black so this is necessary.
color:
  - id: color_bg
    red: 0%
    green: 0%
    blue: 0%
    white: 0%
  - id: color_text
    red: 0%
    green: 0%
    blue: 0%
    white: 100%

display:
  - platform: waveshare_epaper
    id: eink_display
    cs_pin: GPIO1 #GPIO3
    dc_pin: GPIO21 #GPIO5
    busy_pin: 
      number: GPIO2 #GPIO4
      inverted: true
    reset_pin: GPIO0 #GPIO2
    reset_duration: 2ms
    model: 7.50inv2
    #update_interval: 50s
    update_interval: never
    rotation: 90°
    lambda: |-
      // Map weather states to MDI characters.
      std::map<std::string, std::string> weather_icon_map
        {
          {"cloudy", "\U000F0590"},
          {"cloudy-alert", "\U000F0F2F"},
          {"cloudy-arrow-right", "\U000F0E6E"},
          {"fog", "\U000F0591"},
          {"hail", "\U000F0592"},
          {"hazy", "\U000F0F30"},
          {"hurricane", "\U000F0898"},
          {"lightning", "\U000F0593"},
          {"lightning-rainy", "\U000F067E"},
          {"night", "\U000F0594"},
          {"clear-night", "\U000F0594"},
          {"night-partly-cloudy", "\U000F0F31"},
          {"partlycloudy", "\U000F0595"},
          {"partly-lightning", "\U000F0F32"},
          {"partly-rainy", "\U000F0F33"},
          {"partly-snowy", "\U000F0F34"},
          {"partly-snowy-rainy", "\U000F0F35"},
          {"pouring", "\U000F0596"},
          {"rainy", "\U000F0597"},
          {"snowy", "\U000F0598"},
          {"snowy-heavy", "\U000F0F36"},
          {"snowy-rainy", "\U000F067F"},
          {"sunny", "\U000F0599"},
          {"sunny-alert", "\U000F0F37"},
          {"sunny-off", "\U000F14E4"},
          {"sunset", "\U000F059A"},
          {"sunset-down", "\U000F059B"},
          {"sunset-up", "\U000F059C"},
          {"tornado", "\U000F0F38"},
          {"windy", "\U000F059D"},
          {"windy-variant", "\U000F059E"},
          {"exceptional", "\U000F0898"},
          {"recycle", "\U000F044C"},
          {"trash-can", "\U000F0A79"},
          {"pool-thermometer", "\U000F1A5F"},
          {"arrow-right-bold", "\U000F0734"}
        };

      // Fill background.
      // it.fill(color_bg);

      // Show loading screen before data is received.
      if (id(initial_data_received) == false) {

        it.printf(240, 390, id(font_18_bold), color_text, TextAlign::TOP_CENTER, "ATTENTE DES DONNEES...");
        ESP_LOGD("main", "Wait data...");

      } else {

        ESP_LOGD("main", "0: %s", id(weather_condition_0).state.c_str());
        ESP_LOGD("main", "1: %s", id(weather_condition_1).state.c_str());
        ESP_LOGD("main", "2: %s", id(weather_condition_2).state.c_str());
        ESP_LOGD("main", "3: %s", id(weather_condition_3).state.c_str());
        ESP_LOGD("main", "update time %s", id(homeassistant_time).now().strftime("%d-%m %H:%M").c_str());
        
        // Weather Section
        // it.image(0, 88, id(title_weather)); 
        //it.printf(240, 14, id(font_title), color_text, TextAlign::TOP_CENTER, "MÉTÉO");

        it.printf(100, 14, id(font_mdi_100_large), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_now).state.c_str()].c_str());

        it.printf(300, 14, id(font_108_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_real).state);

        it.printf(105, 148, id(font_18_book), color_text, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_0).state.c_str());
        it.printf(105, 172, id(font_mdi_36_medium), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_0).state.c_str()].c_str());
        it.printf(105, 220, id(font_18_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_0).state);

        it.printf(195, 148, id(font_18_book), color_text, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_1).state.c_str());
        it.printf(195, 172, id(font_mdi_36_medium), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_1).state.c_str()].c_str());
        it.printf(195, 220, id(font_18_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_1).state);

        it.printf(285, 148, id(font_18_book), color_text, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_2).state.c_str());
        it.printf(285, 172, id(font_mdi_36_medium), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_2).state.c_str()].c_str());
        it.printf(285, 220, id(font_18_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_2).state);

        it.printf(375, 148, id(font_18_book), color_text, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_3).state.c_str());
        it.printf(375, 172, id(font_mdi_36_medium), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_3).state.c_str()].c_str());
        it.printf(375, 220, id(font_18_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_3).state);

        it.printf(410, 788, id(font_10_book), color_text, TextAlign::TOP_CENTER, "Mise à jour %s", id(homeassistant_time).now().strftime("%d-%m %H:%M").c_str());
        it.printf(44, 788, id(font_10_book), color_text, TextAlign::TOP_CENTER, "%2.3fV - %3.2f%%", id(battery_voltage).state, id(battery_percent).state);

        // Separator HORIZONTAL
        it.filled_rectangle(10, 244, it.get_width()-20, 2);

        // Pool temp
        it.printf(20, 250, id(font_mdi_36_medium), color_text, TextAlign::TOP_LEFT, "%s", weather_icon_map["pool-thermometer"].c_str());
        it.printf(90, 258, id(font_18_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_pool).state);

        // Separator VERTICAL
        it.filled_rectangle(130, 252, 2, 30);

        // Trash part
        if (strcmp(id(trash).state.c_str(), "trash") == 0) {

          ESP_LOGD("main", "trash match trash");
          it.printf(140, 250, id(font_mdi_36_medium), color_text, TextAlign::TOP_LEFT, "%s", weather_icon_map["trash-can"].c_str());
          it.printf(170, 250, id(font_mdi_36_medium), color_text, TextAlign::TOP_LEFT, "%s", weather_icon_map["arrow-right-bold"].c_str());

        } else if (strcmp(id(trash).state.c_str(), "recycle") == 0) {

          ESP_LOGD("main", "trash match recycle");
          it.printf(140, 250, id(font_mdi_36_medium), color_text, TextAlign::TOP_LEFT, "%s", weather_icon_map["recycle"].c_str());
          it.printf(170, 250, id(font_mdi_36_medium), color_text, TextAlign::TOP_LEFT, "%s", weather_icon_map["arrow-right-bold"].c_str());

        } else {

          ESP_LOGD("main", "trash not match %s", id(trash).state.c_str());

        }

        // Separator VERTICAL
        it.filled_rectangle(210, 252, 2, 30);

      }

2 Likes

why does Seeed NEVER provide battery monitoring… its like they never used electronics before… I think we should start shipping some of our old junk over so they can play with it on their free time… What Da?

1 Like

Nice! I might have to try this at some point. Thanks for sharing.