Maker.io main logo

IoT Battery Monitor

238

2024-12-03 | By Adafruit Industries

License: See Original Project 3D Printing ESP32 Adafruit Feather

Courtesy of Adafruit

Guide by Ruiz Brothers and 1 other contributor

Overview

 

Build an internet connected battery charger and monitor with ‎Feather ESP32-S2 Reverse TFT, CircuitPython, and Adafruit IO.‎

The on-board MAX17048 LiPoly battery monitor chip reads the ‎batteries voltage and is displayed on the Feather ESP32's built-in ‎color TFT display. Use the on-board button to cycle between icons ‎and text.‎

The project uses Adafruit IO actions to receive an SMS text or email ‎when the battery is fully charged.‎

monitor_1

Enclosure

The 3D printed enclosure snap fits together and features a tray for ‎holding a 1200mAh battery. The enclosure can swivel forwards and ‎back allowing for an adjustable viewing angle.‎

Use a JST extension cable to easily swap out batteries without ‎having to unplug from the Feather.‎

enclosure_2

Parts

Battery Options

  • ‎1 x 100mAh Lithium-Ion Polymer Battery - 3.7v‎

  • ‎1 x 150mAh Lithium-Ion Polymer Battery - 3.7v‎

  • ‎1 x 350mAh Lithium-Ion Polymer Battery - 3.7v‎

  • ‎1 x 400mAh Lithium-Ion Polymer Battery - 3.7v

  • ‎1 x 420mAh Lithium-Ion Polymer Battery - 3.7v‎

  • ‎1 x 500mAh Lithium-Ion Polymer Battery - 3.7v

  • ‎1 x 1200mAh Lithium-Ion Polymer Battery - 3.7v‎

  • ‎1 x 2000mAh Lithium-Ion Polymer Battery - 3.7v

‎ ‎Hardware

The following hardware is necessary for the case assembly.‎

  • ‎4x M2.5 x 6mm long machine screws‎

  • ‎2x M2 x 6mm long FF standoffs‎

Text editor powered by tinymce.‎

CAD Files

‎3D Printed Parts‎

STL files for 3D printing are oriented to print "as-is" on FDM style ‎machines. Parts are designed to 3D print without any support ‎material using PLA filament. Original design source may be ‎downloaded using the links below.‎

cad_3

Download STLs.zip

Download CAD source

CAD Assembly

The Feather ESP32-S2 Reverse TFT Feather board is secured to the ‎enclosure's back cover using both M2 and M2.5 fasteners. The back ‎cover snap fits onto the front cover. The front cover is secured to the ‎battery tray using M2.5 fastener. ‎

3d_printing_CAD

Build Volume

The parts require a 3D printer with a minimum build volume.‎

  • ‎68mm (X) x 62mm (Y) x 20mm (Z)‎

build_4

Design Source Files

The project assembly was designed in Fusion 360. This can be ‎downloaded in different formats like STEP, STL and more.‎

Electronic components like Adafruit boards, displays, connectors ‎and more can be downloaded from the Adafruit CAD parts GitHub ‎Repo.‎

design_5

Text editor powered by tinymce.‎

CircuitPython

CircuitPython is a derivative of MicroPython designed to simplify ‎experimentation and education on low-cost microcontrollers. It ‎makes it easier than ever to get prototyping by requiring no upfront ‎desktop software downloads. Simply copy and edit files on ‎the CIRCUITPY drive to iterate.‎

CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your ‎board.‎

Download the latest version of CircuitPython for this board via ‎circuitpython.org

Click the link above to download the latest CircuitPython UF2 file.

Save it wherever is convenient for you.‎

click_6

board_7

Plug your board into your computer, using a known-good data-sync ‎cable, directly, or via an adapter if needed.‎

Double-click the reset button (highlighted in red above), and you ‎will see the RGB status LED(s) turn green (highlighted in green ‎above). If you see red, try another port, or if you're using an adapter ‎or hub, try without the hub, or different adapter or hub.‎

For this board, tap reset and wait for the LED to turn purple, and as ‎soon as it turns purple, tap reset again. The second tap needs to ‎happen while the LED is still purple.‎

If double-clicking doesn't work the first time, try again. Sometimes it ‎can take a few tries to get the rhythm right!‎

A lot of people end up using charge-only USB cables and it is very ‎frustrating! Make sure you have a USB cable you know is good for ‎data sync.‎

You will see a new disk drive appear called FTHRS2BOOT.‎

‎ ‎Drag the adafruit_circuitpython_etc.uf2 file to FTHRS2BOOT.‎

drive_8

drive_9

The BOOT drive will disappear, and a new disk drive ‎called CIRCUITPY will appear.‎

That's it!‎

boot_10

Text editor powered by tinymce.‎

Create Your settings.toml File

CircuitPython works with WiFi-capable boards to enable you to ‎make projects that have network connectivity. This means working ‎with various passwords and API keys. As of CircuitPython 8, there is ‎support for a settings.toml file. This is a file that is stored on ‎your CIRCUITPY drive, that contains all of your secret network ‎information, such as your SSID, SSID password and any API keys for ‎IoT services. It is designed to separate your sensitive information ‎from your code.py file so you are able to share your code without ‎sharing your credentials.‎

CircuitPython previously used a secrets.py file for this purpose. ‎The settings.toml file is quite similar.‎

Your settings.toml file should be stored in the main directory of your ‎CIRCUITPY drive. It should not be in a folder.‎

CircuitPython settings.toml File

This section will provide a couple of examples of what ‎your settings.toml file should look like, specifically for CircuitPython ‎WiFi projects in general.‎

The most minimal settings.toml file must contain your WiFi SSID ‎and password, as that is the minimum required to connect to WiFi. ‎Copy this example, paste it into your settings.toml, and update:‎

  • your_wifi_ssid

  • your_wifi_password

Download File

Copy Code
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"

Many CircuitPython network-connected projects on the Adafruit ‎Learn System involve using Adafruit IO. For these projects, you ‎must also include your Adafruit IO username and key. Copy the ‎following example, paste it into your settings.toml file, and update:‎

  • your_wifi_ssid

  • your_wifi_password

  • your_aio_username

  • your_aio_key

Download File

Copy Code
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
ADAFRUIT_AIO_USERNAME = "your_aio_username"
ADAFRUIT_AIO_KEY = "your_aio_key"

Some projects use different variable names for the entries in ‎the settings.toml file. For example, a project might ‎use ADAFRUIT_AIO_ID in the place of ADAFRUIT_AIO_USERNAME. If you run into ‎connectivity issues, one of the first things to check is that the ‎names in the settings.toml file match the names in the code.‎

Not every project uses the same variable name for each entry in the ‎settings.toml file! Always verify it matches the code.‎

settings.toml File Tips

Here is an example settings.toml file.‎

‎Download File

Copy Code
# Comments are supported
CIRCUITPY_WIFI_SSID = "guest wifi"
CIRCUITPY_WIFI_PASSWORD = "guessable"
CIRCUITPY_WEB_API_PORT = 80
CIRCUITPY_WEB_API_PASSWORD = "passw0rd"
test_variable = "this is a test"
thumbs_up = "\U0001f44d"

In a settings.toml file, it's important to keep these factors in mind:‎

  • Strings are wrapped in double quotes; ex: "your-string-here"

  • Integers are not quoted and may be written in decimal with ‎optional sign (+1, -1, 1000) or hexadecimal (0xabcd).‎

    • Floats, octal (0o567) and binary (0b11011) are not supported.‎

  • Use \u escapes for weird characters, \x and \ooo escapes are not ‎available in .toml files

    • Example: \U0001f44d for 👍 (thumbs up emoji) ‎and \u20ac for € (EUR sign)‎

  • Unicode emoji, and non-ASCII characters, stand for themselves ‎as long as you're careful to save in "UTF-8 without BOM" format‎‎

When your settings.toml file is ready, you can save it in your text ‎editor with the .toml extension.‎

settings_11

Accessing ‎Your settings.toml Information ‎in code.py

In your code.py file, you'll need to import the os library to access ‎the settings.toml file. Your settings are accessed with ‎the os.getenv() function. You'll pass your settings entry to the function ‎to import it into the code.py file.‎

Download File

Copy Code
import os

print(os.getenv("test_variable"))

codepy_12

In the upcoming CircuitPython WiFi examples, you'll see how ‎the settings.toml file is used for connecting to your SSID and ‎accessing your API keys.‎

Text editor powered by tinymce.‎

Code the Battery Monitor

Once you've finished setting up your Feather ESP32-S2 Reverse TFT ‎with CircuitPython, you can access the code and necessary libraries ‎by downloading the Project Bundle.‎

To do this, click on the Download Project Bundle button in the ‎window below. It will download to your computer as a zipped folder.‎

‎Download Project Bundle

Copy Code
# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT

import ssl
import os
import socketpool
import wifi
import board
import digitalio
import displayio
import vectorio
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import bitmap_label
import adafruit_imageload
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
import adafruit_max1704x
import adafruit_requests
from simpleio import map_range
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff

# states
send_io = True
bat_clock = ticks_ms()
bat_timer = 60 * 1000
first_run = True
# settings.toml imports
aio_username = os.getenv('AIO_USERNAME')
aio_key = os.getenv('AIO_KEY')
# connect to wifi
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
io = IO_HTTP(aio_username, aio_key, requests)
try:
    # get feed
    battery_feed = io.get_feed("battery-monitor")
except AdafruitIO_RequestError:
    # if no feed exists, create one
    battery_feed = io.create_new_feed("battery-monitor")
# default group
group = displayio.Group()
# text only group
textOnly_group = displayio.Group()
board.DISPLAY.root_group = group
# palette for vector graphics
palette = displayio.Palette(5)
palette[0] = 0xFF0000
palette[1] = 0xFFFF00
palette[2] = 0x00FF00
palette[3] = 0x0000FF
palette[4] = 0x000000
# battery rectangle
rect = vectorio.Rectangle(pixel_shader=palette, width=72, height=45, x=140, y=70, color_index = 0)
group.append(rect)
text_bg = vectorio.Rectangle(pixel_shader=palette, width=115, height=70,
                             x=120, y=60, color_index = 4)
# io indicator circle
circle = vectorio.Circle(pixel_shader=palette, radius=8, x=10, y=10, color_index=3)
textOnly_group.append(circle)
# graphics bitmap
bitmap, palette_bit = adafruit_imageload.load(
    "/bat_bg.bmp",
    bitmap=displayio.Bitmap,
    palette=displayio.Palette,
)
# purple is made transparent
palette_bit.make_transparent(0)
tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette_bit)
group.append(tile_grid)
group.append(circle)
# font for graphics
sm_file = "/roundedHeavy-26.bdf"
sm_font = bitmap_font.load_font(sm_file)
# font for text only
lg_file = "/roundedHeavy-46.bdf"
lg_font = bitmap_font.load_font(lg_file)
volt_text = bitmap_label.Label(sm_font, text=" V", x=150, y=33)
group.append(volt_text)
big_volt_text = bitmap_label.Label(lg_font, text=" V")
big_volt_text.anchor_point = (0.5, 0.0)
big_volt_text.anchored_position = (board.DISPLAY.width / 2, 0)
textOnly_group.append(big_volt_text)
percent_text = bitmap_label.Label(sm_font, text=" %", x=150, y=90)
big_percent_text = bitmap_label.Label(lg_font, text=" %", x=board.DISPLAY.width//2, y=90)
big_percent_text.anchor_point = (0.5, 1.0)
big_percent_text.anchored_position = (board.DISPLAY.width / 2, board.DISPLAY.height - 15)
textOnly_group.append(big_percent_text)

# buttons
button0 = digitalio.DigitalInOut(board.D0)
button0.direction = digitalio.Direction.INPUT
button0.pull = digitalio.Pull.UP
button0_state = False
button1 = digitalio.DigitalInOut(board.D1)
button1.direction = digitalio.Direction.INPUT
button1.pull = digitalio.Pull.DOWN
button1_state = False
button2 = digitalio.DigitalInOut(board.D2)
button2.direction = digitalio.Direction.INPUT
button2.pull = digitalio.Pull.DOWN
button2_state = False

# MAX17048 instantiation
monitor = adafruit_max1704x.MAX17048(board.I2C())
monitor.activity_threshold = 0.01

# colors for battery graphic
def get_color(value):
    if value < 30:
        return 0
    elif 30 <= value <= 75:
        return 1
    else:
        return 2

while True:
    # reset button state on release
    if button0.value and button0_state:
        button0_state = False
    if not button1.value and button1_state:
        button1_state = False
    if not button2.value and button2_state:
        button2_state = False
    # toggle sending to adafruit io
    if not button0.value and not button0_state:
        button0_state = True
        send_io = not send_io
        if send_io:
            circle.color_index = 3
        else:
            circle.color_index = 4
    # toggle graphics or text only
    if button1.value and not button1_state:
        button1_state = True
        if board.DISPLAY.root_group == group:
            board.DISPLAY.root_group = textOnly_group
        else:
            board.DISPLAY.root_group = group
    # toggle battery graphic or % text
    if button2.value and not button2_state:
        button2_state = True
        if len(group) > 4:
            group.pop()
            group.pop()
        else:
            group.append(text_bg)
            group.append(percent_text)
    # read MAX17048 every 60 seconds
    if first_run or ticks_diff(ticks_ms(), bat_clock) >= bat_timer:
        first_run = False
        battery_volts = monitor.cell_voltage
        battery_percent = monitor.cell_percent
        print(f"Battery voltage: {battery_volts:.2f} Volts")
        print(f"Battery percentage: {battery_percent:.1f} %")
        print()
        battery_display = map_range(battery_percent, 0, 100, 0, 72)
        battery_x = map_range(battery_percent, 0, 100, 210, 140)
        #  update rectangle to reflect battery charge
        rect.width = int(battery_display)
        rect.x = int(battery_x)
        rect.color_index = get_color(battery_percent)
        volt_text.text = f"{battery_volts:.2f} V"
        percent_text.text = f"{battery_percent:.1f} %"
        big_volt_text.text = f"{battery_volts:.2f} V"
        big_percent_text.text = f"{battery_percent:.1f} %"
        if battery_percent >= 100 and send_io:
            io.send_data(battery_feed["key"], battery_percent)
        bat_clock = ticks_add(bat_clock, bat_timer)

View on GitHub

Upload the Code and Libraries to the Feather ESP32-S2 Reverse TFT

After downloading the Project Bundle, plug your Feather ESP32-S2 ‎Reverse TFT into the computer's USB port with a known good USB ‎data+power cable. You should see a new flash drive appear in the ‎computer's File Explorer or Finder (depending on your operating ‎system) called CIRCUITPY. Unzip the folder and copy the following ‎items to the Feather's CIRCUITPY drive:‎

  • lib folder

  • code.py

  • bat_bg.bmp

  • roundedHeavy-26.bdf‎

  • roundedHeavy-46.bdf‎

Your Feather ESP32-S2 Reverse TFT CIRCUITPY drive should look like ‎this after copying the lib folder, .bdf font files, .bmp image file and ‎the code.py file.‎

file_13

Add Your settings.toml File

As of CircuitPython 8.0.0, there is support for Environment Variables. ‎Environment variables are stored in a settings.toml file. Similar ‎to secrets.py, the settings.toml file separates your sensitive ‎information from your main code.py file. Add your settings.toml file ‎as described in the Create Your settings.toml File page earlier in this ‎guide. You'll need to include your WiFi network SSID and password ‎as CIRCUITPY_WIFI_SSID and CIRCUITPY_WIFI_PASSWORD and your Adafruit IO ‎username and key as AIO_USERNAME and AIO_KEY.‎

‎Download File

Copy Code
CIRCUITPY_WIFI_SSID = "YOUR-SSID-HERE"
CIRCUITPY_WIFI_PASSWORD = "YOUR-SSID-PASSWORD-HERE"
AIO_USERNAME = "YOUR-AIO-USERNAME-HERE"
AIO_KEY = "YOUR-AIO-KEY-HERE"

How the CircuitPython Code Works

At the top of the code are some states that are used in the ‎loop. send_io enables sending the battery charging data to Adafruit ‎IO. bat_timer is the amount of time that the battery monitor is checked ‎and first_run and used to note that the code is running for the first ‎time in the loop.‎

‎Download File

Copy Code
# states
send_io = True
bat_clock = ticks_ms()
bat_timer = 60 * 1000
first_run = True

After the states are the settings.toml imports and WiFi and Adafruit ‎IO connections.‎

‎Download File

Copy Code
# settings.toml imports
aio_username = os.getenv('AIO_USERNAME')
aio_key = os.getenv('AIO_KEY')
# connect to wifi
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
io = IO_HTTP(aio_username, aio_key, requests)
try:
    # get feed
    battery_feed = io.get_feed("battery-monitor")
except AdafruitIO_RequestError:
    # if no feed exists, create one
    battery_feed = io.create_new_feed("battery-monitor")

If your WiFi access point name or password are incorrect, an error ‎will be generated.‎

Graphics

Next are the graphics. There are two display groups: one that ‎includes graphical elements and one that is text only. You can switch ‎between then in the loop depending on your preferences. ‎the bat_bg bitmap file is loaded using the adafruit_image library ‎and its background color is made transparent. vectorio shapes are ‎used to show the battery charge graphic and if you are sending data ‎to Adafruit IO.‎

‎Download File

Copy Code
# default group
group = displayio.Group()
# text only group
textOnly_group = displayio.Group()
board.DISPLAY.root_group = group
# palette for vector graphics
palette = displayio.Palette(5)
palette[0] = 0xFF0000
palette[1] = 0xFFFF00
palette[2] = 0x00FF00
palette[3] = 0x0000FF
palette[4] = 0x000000
# battery rectangle
rect = vectorio.Rectangle(pixel_shader=palette, width=72, height=45, x=140, y=70, color_index = 0)
group.append(rect)
text_bg = vectorio.Rectangle(pixel_shader=palette, width=115, height=70,
                             x=120, y=60, color_index = 4)
# io indicator circle
circle = vectorio.Circle(pixel_shader=palette, radius=8, x=10, y=10, color_index=3)
textOnly_group.append(circle)
# graphics bitmap
bitmap, palette_bit = adafruit_imageload.load(
    "/bat_bg.bmp",
    bitmap=displayio.Bitmap,
    palette=displayio.Palette,
)
# purple is made transparent
palette_bit.make_transparent(0)
tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette_bit)
group.append(tile_grid)
group.append(circle)

Then all of the text attributes are created. There are two font files, ‎one for a smaller font and one for a larger font. The larger font is used ‎for the text only graphics group.‎

‎Download File

Copy Code
# font for graphics
sm_file = "/roundedHeavy-26.bdf"
sm_font = bitmap_font.load_font(sm_file)
# font for text only
lg_file = "/roundedHeavy-46.bdf"
lg_font = bitmap_font.load_font(lg_file)
volt_text = bitmap_label.Label(sm_font, text=" V", x=150, y=33)
group.append(volt_text)
big_volt_text = bitmap_label.Label(lg_font, text=" V")
big_volt_text.anchor_point = (0.5, 0.0)
big_volt_text.anchored_position = (board.DISPLAY.width / 2, 0)
textOnly_group.append(big_volt_text)
percent_text = bitmap_label.Label(sm_font, text=" %", x=150, y=90)
big_percent_text = bitmap_label.Label(lg_font, text=" %", x=board.DISPLAY.width//2, y=90)
big_percent_text.anchor_point = (0.5, 1.0)
big_percent_text.anchored_position = (board.DISPLAY.width / 2, board.DISPLAY.height - 15)
textOnly_group.append(big_percent_text)

Buttons and I2C

The three buttons on the Feather are setup as digitalio inputs. The ‎onboard MAX17048 is instantiated over I2C.‎

‎Download File

Copy Code
# buttons
button0 = digitalio.DigitalInOut(board.D0)
button0.direction = digitalio.Direction.INPUT
button0.pull = digitalio.Pull.UP
button0_state = False
button1 = digitalio.DigitalInOut(board.D1)
button1.direction = digitalio.Direction.INPUT
button1.pull = digitalio.Pull.DOWN
button1_state = False
button2 = digitalio.DigitalInOut(board.D2)
button2.direction = digitalio.Direction.INPUT
button2.pull = digitalio.Pull.DOWN
button2_state = False

# MAX17048 instantiation
monitor = adafruit_max1704x.MAX17048(board.I2C())
monitor.activity_threshold = 0.01

Colors

There is a simple function called get_color() that maps the charge ‎percentage of the battery to a color in a palette. This changes the ‎color of the battery from red to yellow to green as it charges up.‎

Download File

Copy Code
# colors for battery graphic
def get_color(value):
    if value < 30:
        return 0
    elif 30 <= value <= 75:
        return 1
    else:
        return 2

The Loop

In the loop, the buttons control the UI appearance and code ‎functionality. Button D0 toggles sending the battery info to Adafruit ‎IO. Button D1 changes between the text only display group and the ‎graphical group. Button D2 changes between representing the ‎battery charge percentage in text or via the battery graphic.‎

‎Download File

Copy Code
# toggle sending to adafruit io
    if not button0.value and not button0_state:
        button0_state = True
        send_io = not send_io
        if send_io:
            circle.color_index = 3
        else:
            circle.color_index = 4
    # toggle graphics or text only
    if button1.value and not button1_state:
        button1_state = True
        if board.DISPLAY.root_group == group:
            board.DISPLAY.root_group = textOnly_group
        else:
            board.DISPLAY.root_group = group
    # toggle battery graphic or % text
    if button2.value and not button2_state:
        button2_state = True
        if len(group) > 4:
            group.pop()
            group.pop()
        else:
            group.append(text_bg)
            group.append(percent_text)

Monitor the Battery

Every minute the MAX17048 is read to check on the battery voltage ‎and charge percentage. The graphics are updated with the data to ‎show on the TFT. If you chose to send the data to IO, the charge ‎percentage is sent to your feed when the battery is fully charged.‎

Download File

Copy Code
# read MAX17048 every 60 seconds
    if first_run or ticks_diff(ticks_ms(), bat_clock) >= bat_timer:
        first_run = False
        battery_volts = monitor.cell_voltage
        battery_percent = monitor.cell_percent
        print(f"Battery voltage: {battery_volts:.2f} Volts")
        print(f"Battery percentage: {battery_percent:.1f} %")
        print()
        battery_display = map_range(battery_percent, 0, 100, 0, 72)
        battery_x = map_range(battery_percent, 0, 100, 210, 140)
        #  update rectangle to reflect battery charge
        rect.width = int(battery_display)
        rect.x = int(battery_x)
        rect.color_index = get_color(battery_percent)
        volt_text.text = f"{battery_volts:.2f} V"
        percent_text.text = f"{battery_percent:.1f} %"
        big_volt_text.text = f"{battery_volts:.2f} V"
        big_percent_text.text = f"{battery_percent:.1f} %"
        if battery_percent >= 100 and send_io:
            io.send_data(battery_feed["key"], battery_percent)
        bat_clock = ticks_add(bat_clock, bat_timer)

Text editor powered by tinymce.‎

Adafruit IO Trigger

Create New Action

You can receive an email when the battery has been fully charged.‎

  • ‎ ‎Go to https://io.adafruit.com and click on Actions

  • Click the New Actions button.‎

  • Choose Yes, use Blockly!‎

trigger_14

Reactive Trigger Setup

  • Click on the Triggers menu, then click on Reactive

  • Drag the Reactive block and snap it to the Trigger section in ‎the Action Root block

  • Click on the Values menu, then click on the Feed block

  • Drag the Feed block and snap it to the Feed section in ‎the Reactive block. Then, select the battery-monitor feed from ‎the dropdown menu

  • Click on the Values menu, then click the A number, whole or ‎decimal block.‎

  • Drag the A number, whole or decimal block and snap it to ‎the Feed or Value section of the Reactive block. Then, type ‎‎"100" into the Feed or Value block.‎

  • Under the Operator section, select ">=" from the dropdown ‎menu.‎

setup_15

Action Setup

  • Click on Actions menu, then click on Email

  • Drag the Email block and snap it to the Action section in the ‎Action Root block.‎

  • Type your preferred text into the subject and body in ‎the Email block.‎

  • Click on Values menu, then click on a Feed block.‎

  • Drag the Feed block into the using section in the Email block. ‎Then, select battery-monitor from the dropdown menu

Click the Save button when you are finished. ‎

action_16

action_17

New Email

You'll now receive an email when the battery is fully charged.‎

email_18

Text editor powered by tinymce.‎

Assembly

Installing Feather

Get the 3D printed back cover, hardware screws, and Feather ready ‎to assemble.‎

Place the Feather over the back cover with the mounting holes lined ‎up and the TFT screen facing up.‎

Use the following hardware to secure the Feather to the back cover.‎

  • ‎2x M2 x 6mm long machine screws‎

  • ‎2x M2.5 x 6mm long machine screws‎

assembly_19

assembly_20

Secure Feather

Install and fasten the hardware screws to secure the Feather ESP32-‎S2 to the 3D printed back cover.‎

Ensure the Feather has been secured in the correct orientation.‎

secure_21

secure_22

Connect JST Extension

Plug in the 2-pin JST extension cable to the battery port on-board ‎the Feather ESP32-S2.‎

connect_23

Install Case & Battery Tray

Slide the 3D printed case in between the battery tray's two ‎mounting tabs.‎

Line up the mounting holes, then insert and fasten two M2.5 x 6mm ‎long machine screws to secure the two parts together.‎

install_24

install_25

Assemble Enclosure

Orient the back cover with the front case and begin to fit the JST ‎extension cable inside the enclosure. ‎

Fit the JST extensions cables socket connector through the notch in ‎the back cover.‎

Press the front case and back cover together to close them shut.‎

press_26

press_27

Install Battery

Connect the battery to the JST extension cable.‎

Place the battery into the 3D printed tray.‎

battery_28

battery_29

Final Build

Congratulations on your build!‎

The Feather ESP32-S2 will power on immediately after connecting ‎the battery. Plug in a USB cable to your Feather to begin charging ‎the battery.‎

Allow the Feather to connect to your WiFi and establish a voltage ‎reading. This may take a minute or two to output to the TFT display.‎

final_30

Text editor powered by tinymce.‎

Usage

Button D0‎

Press the D0 button (top) to enable sending data to Adafruit IO. The ‎blue circle indicates data is sending to Adafruit IO.‎

3d_printing_usage-D0

Button D1‎

Press the D1 button (middle) to toggle between icon view and plain ‎text view.‎

3d_printing_usage-D1

Button D2‎

Press the D2 button (bottom) to toggle between the battery icon ‎and battery percentage text.‎

3d_printing_usage-D2

USB Charging

Use a 5V 1A power supply and USB-C type cable to charge the ‎battery.‎

usb_34

Text editor powered by tinymce.

Mfr Part # 5345
ESP32-S2 FEATHER PCB ANTENNA
Adafruit Industries LLC
159,68 kr.
View More Details
Mfr Part # 1131
JST-PH BATTERY EXT CABLE
Adafruit Industries LLC
12,48 kr.
View More Details
Mfr Part # 5044
CABLE A PLUG TO C PLUG 6.5'
Adafruit Industries LLC
25,28 kr.
View More Details
Add all DigiKey Parts to Cart
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.