ESP32-WROVER with 18650 Battery Holder

Thanks to this post I learned about an interesting ESP32 board with a compartment for a 18650 battery and this can be used as a backup power source in case of a power outage, and also monitor the battery charge level, know the remaining time until it is completely discharged and recharged. I took the ESP32 with battery here

Connection diagram for a divider with 220 kOhm resistors to reduce the voltage to 2.4 V with a fully charged battery at 4.175 V

I also made sensors that show not only the battery level, but also the remaining charging time to 100% and discharging to 0%.


I used a divider of two 220 kom resistors and lowered the voltage to 2.4 V to fall into the range from 150 to 2450. I took it from the table in the documentation esp32 on ADC voltage.

Next, I measured the voltage with a multimeter at full discharged and charged battery and used a filter, which obtained correct voltage readings with a small error of -/+ 0.05V. The fully measured battery had a voltage of 4.175V, and in the sensor the value was 2.151, this is a figure in parrots and I converted it to the real value thus 4.175/2.151 = 1.940957694095769 ~ 1.941

filters:
      - multiply: 1.941

Working code. If you have your own thoughts on this matter, I will only be glad if you post your version of the code.

#####################################################################################
###################################### Variables ####################################
substitutions:
  name: feeder-pettix-s36

#####################################################################################
################################# Basic configuration ###############################
esphome:
  name: $name
  friendly_name: Feeder Pettix S36
  comment: Feeder Pettix S36

#####################################################################################
####################################### Platform ####################################
esp32:
  board: esp32dev
  framework:
    type: arduino

#####################################################################################
################################ WiFi and access point ##############################
#Wi-Fi credentials for connecting the board to the home network
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: off
  reboot_timeout: 5min

#If there is no connection with WiFi, then the access point will rise
  ap:
    ssid: ESP Feeder Pettix S36
    password: !secret ap_esp_password
    ap_timeout: 1 min
    manual_ip:
      static_ip: 192.168.4.1
      gateway: 192.168.4.1
      subnet: 255.255.255.0

#The mdns component forces the node to announce itself on the local network using the DNS Multicast Protocol (mDNS), by default for mDNS disabled: false
mdns:
  disabled: false

#The captive portal component in ESPHome is a backup mechanism in case the connection to the configured Wi-Fi fails
captive_portal:

#Web server
web_server:
  port: 80

#Logging
logger:
  baud_rate: 0

#Enable Home Assistant API
api:

#Over-the-Air Update (OTA)
ota:
  password: "esphome"


#####################################################################################
################################## Sensor ###########################################
sensor:
#ADC sensor for battery level sensor
  - platform: adc
    name: ADC
    icon: mdi:flash
    id: idADC
    pin: GPIO32
    attenuation: 11db
    update_interval: 60s
    accuracy_decimals: 3
    internal: false #Hide - true \show - false

#Battery level sensor
  - platform: copy
    name: Battery Level
    icon: mdi:battery
    id: idBatteryLevel
    source_id: idADC
    unit_of_measurement: '%'
    accuracy_decimals: 0
    filters:
      - calibrate_linear:
          #The battery voltage should not be lower than 3V and higher than 4.2V. To get into the range 0-2500 you need to use a divider to reduce the voltage to 2.4V and specify attenuation: 11db
          #A divider of resistors 220 and 220 kom is used
          - 1.545 -> 0
          - 2.151 -> 100

#Battery voltage sensor. The readings are reliable with an error
  - platform: copy
    name: "Battery Voltage"
    icon: mdi:flash
    id: idBatteryVoltage
    source_id: idADC
    accuracy_decimals: 3
    filters:
      - multiply: 1.941


#####################################################################################
##################################### Text sensor ###################################
text_sensor:
#IP
  - platform: wifi_info
    ip_address:
      name: IP
      icon: mdi:ip-network

#ESPHome Version
  - platform: version
    name: "ESPHome Version"
    hide_timestamp: true

#Uptime
  - platform: template
    name: "Uptime"
    icon: mdi:clock-start
    id: idUptimeESP
    entity_category: diagnostic

  - platform: template
    name: "Time"
    icon: mdi:clock-digital
    id: idTime
    update_interval: 10s
    lambda: |-
      auto time_text = id(homeassistant_time).now().strftime("%H:%M:%S / %d-%m-%Y");
      return { time_text };

#Remaining time until charging 100%
  - name: "Charging time up to 100%"
    id: idChargingTime
    platform: template
    update_interval: 10s
    lambda: |-
      auto time = id(homeassistant_time).now();
      if (!time.is_valid())
      {
        return {};
      }
      auto diff = time.timestamp;
      if (id(idBatteryLevel).state != 100)
      {
        auto result = ((diff /  id(idBatteryLevel).state) * (100 - id(idBatteryLevel).state)) / 86400;
        result = result < 0 ? 0 : result;
        auto hours = static_cast<int>(result) / 3600;
        auto minutes = (static_cast<int>(result) % 3600) / 60;
        return to_string(hours) + "h " + to_string(minutes) + "m";
      }
      else
      {
        auto result = diff / 86400;
        result = result < 0 ? 0 : result;
        auto hours = static_cast<int>(result) / 3600;
        auto minutes = (static_cast<int>(result) % 3600) / 60;
        return to_string(hours) + "h " + to_string(minutes) + "m";
      }


#Remaining time until discharge at 0%
  - name: "Discharge time to 0%"
    id: idDischargeTime
    platform: template
    update_interval: 10s
    lambda: |-
      auto time = id(homeassistant_time).now();
      if (!time.is_valid())
      {
        return {};
      }
      auto diff = time.timestamp;
      if (id(idBatteryLevel).state != 0)
      {
        auto result = ((diff / (100 - id(idBatteryLevel).state)) * id(idBatteryLevel).state) / 86400;
        result = result < 0 ? 0 : result;
        auto hours = static_cast<int>(result) / 3600;
        auto minutes = (static_cast<int>(result) % 3600) / 60;
        return to_string(hours) + "h " + to_string(minutes) + "m";
      }
      else
      {
        auto result = diff / 86400;
        result = result < 0 ? 0 : result;
        auto hours = static_cast<int>(result) / 3600;
        auto minutes = (static_cast<int>(result) % 3600) / 60;
        return to_string(hours) + "h " + to_string(minutes) + "m";
      }



#####################################################################################
####################################### Button ######################################
button:
  - platform: restart
    name: "Restart"
    icon: mdi:restart


#####################################################################################
######################################## Time #######################################
time:
  - platform: homeassistant
    id: homeassistant_time

3 Likes