# Humidity and Temperature Monitor with E-Ink Display

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/070/824/medium800/temperature___humidity_laurel-272961_1920.jpg?1549495826 From Pixabay: Free for commercial use  No attribution required)

Depending on your climate (and HVAC system) dried herbs can go moldy. A big cause of mold is too high of humidity. That's the reasons for all those silica gel packets in items you get. If you store a lot of dried herbs or anything that requires a controlled humidity (and/or temperature) environment, this project can help by monitoring the temperature and humidity in a container and warn you if they go out of the desired range.

In a previous guide:&nbsp;[Storage Humidity and Temperature Monitor](https://learn.adafruit.com/storage-humidity-and-temperature-monitor), we built a simple monitoring project. Specifically, for a small jar. It was really simple, using a Trinket M0 to drive it, a SI7021 breakout to take measurements, and a TPL5111 breakout to manage power. The onboard DotStar and a piezo buzzer were used to indicate status. The code was written in C.

That was built in late 2017. Fast forward (at least it seems fast) to February 2019 (a bit over a year later) and it was time to revisit the design.

The SI7021 is a reliable, robust sensor that the author as used in various projects. All we require is temperature and humidity measurements, and the I2C interface is simple to work with. We'll keep that.

In place of a Trinket M0 we'll use a Feather M4 Express. That's a big jump in power, but this board is reasonably priced and is the author's go-to board for most projects. A huge advantage is the onboard battery charging circuit. This will allow the battery to be charged without having to disconnect and remove it. The Feather also has far more I/O pins than the Trinket. This makes possible the next change.

With the Feather, we can do something better for status indication. It was decided to use an eInk display (which uses SPI and 5 digital I/O lines). The 1.54" square 3-color display was selected. An eInk display is a huge benefit on a device like this. It wakes up approximately every hour to take readings, update the display, and possibly raise an alarm. It's not powered the rest of the time. Using eInk provides a persistent display that remains "on" and informative all the time without requiring power. The downside of eInk is that screen refresh is a slow process. But when you only need to update every hour, that's not a problem.

The previous project used the TPL5110 breakout which directly controls power to the circuit. Since the Feather has an enable pin to control power, the TPL5111 breakout is used in this version.

We keep the piezo buzzer as an out-of-range signal, and add a pushbutton switch to provide input for cancelling the alarm as well as entering and exiting edit mode (we'll talk about that later).

Finally, since the Feather M4 was selected, it was made a project goal to write the software in CircuitPython rather than C.

## Required Parts
Featured
### Adafruit Feather M4 Express - Featuring ATSAMD51

[Adafruit Feather M4 Express - Featuring ATSAMD51](https://www.adafruit.com/product/3857)
It's what you've been waiting for, the Feather M4 Express featuring ATSAMD51. This Feather is fast like a swift, smart like an owl, strong like a ox-bird (it's half ox, half bird, OK?) This feather is powered by our new favorite chip, the **ATSAMD51J19** -&nbsp; with...

In Stock
[Buy Now](https://www.adafruit.com/product/3857)
[Related Guides to the Product](https://learn.adafruit.com/products/3857/guides)
![Angled shot of a Adafruit Feather M4 Express. ](https://cdn-shop.adafruit.com/640x480/3857-10.jpg)

Featured
### Adafruit TPL5111 Low Power Timer Breakout

[Adafruit TPL5111 Low Power Timer Breakout](https://www.adafruit.com/product/3573)
With some development boards, low power usage is an afterthought. Especially when price and usability are the main selling points. So what should you do when it's time to turn around and make that project of yours run on a battery or solar? Sure you&nbsp;_could_&nbsp;try to hot-air...

In Stock
[Buy Now](https://www.adafruit.com/product/3573)
[Related Guides to the Product](https://learn.adafruit.com/products/3573/guides)
![Angled shot of a TPL5111 Low Power Timer Breakout Board.](https://cdn-shop.adafruit.com/640x480/3573-04.jpg)

Featured
### Adafruit Si7021 Temperature & Humidity Sensor Breakout Board

[Adafruit Si7021 Temperature & Humidity Sensor Breakout Board](https://www.adafruit.com/product/3251)
It's summer and you're sweating and your hair's all frizzy and all you really want to know is why the weatherman said this morning that today's relative humidity would max out at a perfectly reasonable 42% when it feels more like 77%. Enter the&nbsp; **Si7021 Temperature +...**

In Stock
[Buy Now](https://www.adafruit.com/product/3251)
[Related Guides to the Product](https://learn.adafruit.com/products/3251/guides)
![Angled shot of black, rectangular temperature and humidity sensor breakout.](https://cdn-shop.adafruit.com/640x480/3251-05.jpg)

Featured
### Lithium Ion Polymer Battery - 3.7v 1200mAh

[Lithium Ion Polymer Battery - 3.7v 1200mAh](https://www.adafruit.com/product/258)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 1200mAh for a total of about 4.5 Wh. If you need a larger battery, <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/258)
[Related Guides to the Product](https://learn.adafruit.com/products/258/guides)
![Lithium Ion Polymer Battery 3.7v 1200mAh with JST 2-PH connector](https://cdn-shop.adafruit.com/640x480/258-02.jpg)

Featured
### Piezo Buzzer

[Piezo Buzzer](https://www.adafruit.com/product/160)
Piezo buzzers are used for making beeps, tones and alerts. This one is petite but loud! Drive it with 3-30V peak-to-peak square wave. To use, connect one pin to ground (either one) and the other pin to a square wave out from a timer or microcontroller. For the loudest tones, stay around 4 KHz,...

In Stock
[Buy Now](https://www.adafruit.com/product/160)
[Related Guides to the Product](https://learn.adafruit.com/products/160/guides)
![Bread-board friendly Piezo Buzzer](https://cdn-shop.adafruit.com/640x480/160-01.jpg)

You'll need your choice of SPST momentary pushbutton switch. The one below is a lovely option for breadboarding.

Featured
### Metal Ball Tactile Button (6mm) x 10 pack

[Metal Ball Tactile Button (6mm) x 10 pack](https://www.adafruit.com/product/3347)
Add some steely elegance to your project with these **Metal Ball Tactile Buttons**. They've got a nice industrial shine to them along&nbsp;with a light blue underbelly. Not only do they look good, but they're also good if you have an actuator that will be pressing the...

In Stock
[Buy Now](https://www.adafruit.com/product/3347)
[Related Guides to the Product](https://learn.adafruit.com/products/3347/guides)
![Angled closeup of single 6mm metal ball tactile button.](https://cdn-shop.adafruit.com/640x480/3347-00.jpg)

### Part: Resistor
quantity: 1
120K 1/4w resistor
[Resistor](https://www.digikey.ca/product-detail/en/stackpole-electronics-inc/CF14JT120K/CF14JT120KCT-ND/1830401)

### 0.1uF ceramic capacitors - 10 pack

[0.1uF ceramic capacitors - 10 pack](https://www.adafruit.com/product/753)
As any engineer will tell you, 0.1uF ceramic capacitors are the magic fairy dust of electronics - sprinkle them over your circuit schematics for good luck! But seriously, a 0.1uF capacitor right next to the VCC pin of your chips will improve stability by filtering out power supply spikes and...

Out of Stock
[Buy Now](https://www.adafruit.com/product/753)
[Related Guides to the Product](https://learn.adafruit.com/products/753/guides)
![10 pack of 0.1uF through hole ceramic capacitors ](https://cdn-shop.adafruit.com/640x480/753-02.jpg)

### Part: Prototyping perf-board
quantity: 1
An assortment of perfboard for prototyping
[Prototyping perf-board](https://www.amazon.com/ELEGOO-Prototype-Soldering-Compatible-Arduino/dp/B072Z7Y19F)

# Humidity and Temperature Monitor with E-Ink Display

## Hardware

![](https://cdn-learn.adafruit.com/assets/assets/000/070/686/medium800/temperature___humidity_wiring.png?1549395455)

Above is the wiring diagram. The schematic is at the bottom of this page and makes a little more sense in some ways. Let's look at the pieces of the circuit around the Feather, one piece at a time.

## Power

The circuit is powered by a LiPo battery. A 1200mAh model was selected based on size and charge lifetime.

Power is controlled by a TPL5111 breakout which controls the Feather's **Enable** input. While it can be used as is, with the onboard potentiometer (to set the sleep duration) is hard to get exact. The alternative is to use an external resistor which is what we do. To do this, we need to cut the _Trim_ trace under the TPL5111 breakout. The other (_LED_) trace can be cut as well to save power and since the "on" LED won't be of much use.

Now let's talk about the startup sequence of the system.&nbsp; The first thing the code does at the earliest opportunity is set the DONE signal to the TPL5111 low so as to not turn off the power and start the timing sequence. The problem is that the SAMD51 output floats high. That along with the fact that the TPL5111 starts up faster than CircuitPython can configure and set the **DONE** output low means it will shut down before getting started (because it sees a high **DONE** signal). To avoid that we need to delay that **DONE** signal registering as **True/high**. For that we turn to our friend the capacitor.&nbsp;

By using a small capacitor between the **DONE** pin and ground, the pin won't be reach a voltage that registers as **True** for a short length of time: the amount of time that the capacitor takes to charge. A little trial and error showed that 100nF did the job. It delays **DONE** long enough for the code to configure the output and set it to **False/low**. This lets the TPL5111 stay in on mode until the **DONE** line is explicitly set to **True/high** by the code.

## Measurement

The Si7021 is simple: power, ground and the pair of I2C signals. Nothing unusual about the connection. Actual wiring is a bit more involved. The sensor breakout has to be inside the container (a jar in the target build), preferably in an airtight way since a sealed environment is desired.

## Display

The display is connected simply as well: power, ground, the SPI clock and data lines, as well as various control and status lines as shown. Note that we're not using the SD card in this project.

## Miscellaneous

The remaining pieces are a push button switch and a piezo. Note that this is a buzzer that is driven by a square wave (via a PWM) and not one that makes sound when power is applied.

![](https://cdn-learn.adafruit.com/assets/assets/000/070/839/medium800/temperature___humidity_wiring_schem.png?1549503113)

# Humidity and Temperature Monitor with E-Ink Display

## Code

![](https://cdn-learn.adafruit.com/assets/assets/000/070/840/medium800/temperature___humidity_circuitpython_blinka-small.png?1549505679)

Using a SAMD51 based board gives plenty of memory and speed for writing in CircuitPython. Because of that it was decided from the start to write the code in CircuitPython.

## Getting Familiar

CircuitPython is a programming language based on Python, one of the fastest growing programming languages in the world. It is specifically designed to simplify experimenting and learning to code on low-cost microcontroller boards. Here are some guides which cover the basics:

- [Welcome to CircuitPython!](https://learn.adafruit.com/welcome-to-circuitpython)
- [Adafruit&nbsp;Feather M4 Express](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51)

Be sure you have the latest CircuitPython loaded onto your board per the second guide.

CircuitPython is easiest to use within the Mu Editor. If you haven't previously used Mu,&nbsp;[this guide will get you started](https://learn.adafruit.com/welcome-to-circuitpython/installing-mu-editor).

## Download Library Files

Plug your Feather M4 Express board into your computer via a USB cable. Please be sure the cable is a good power+data cable so the computer can talk to the Feather board.

A new disk should appear in your computer's file explorer/finder called **CIRCUITPY**. This is the place we'll copy the code and code library. If you can only get a drive named&nbsp; **CPLAYBOOT** , load CircuitPython per the guide above.

Create a new directory on the&nbsp; **CIRCUITPY** drive named **lib**.

Download the latest CircuitPython driver package to your computer using the green button below. **Match the library you get to the version of CircuitPython you are using**. Save to your computer's hard drive where you can find it.

[Go to GitHub to get the latest CircuitPython library bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/)
With your file explorer/finder, browse to the bundle and open it up. Copy the following folder from the library bundle to your&nbsp; **CIRCUITPY** &nbsp; **lib** &nbsp;directory you made earlier:

- **adafruit\_bus\_device**
- **adafruit\_epd**
- **adafruit\_si7021.mpy**

All of the other necessary code is baked into CircuitPython!

Your **CIRCUITPY** drive should look like the snapshot below.

![](https://cdn-learn.adafruit.com/assets/assets/000/070/891/medium800/temperature___humidity_Screenshot_2019-02-07_17.26.46.png?1549578530)

## Download Code

Below is the code for this project. Select **download** &nbsp; **project zip** &nbsp;below and save it to your computer's hard drive where you can find it.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Jar_Minder_v2/code.py

# Humidity and Temperature Monitor with E-Ink Display

## Code Operation

## Startup

As mentioned earlier, we want to configure and set the **DONE** signal low as soon as possible after the the runtime hands control to our code.

```auto
import digitalio
import board

done = digitalio.DigitalInOut(board.A4)
done.direction = digitalio.Direction.OUTPUT
done.value = False
```

Once that's done, the usual imports and setup can be done. There are no surprises here: display, sensor, buzzer, and switch are set up as you would expect. The display setup is covered in [it's tutorial guide](https://learn.adafruit.com/adafruit-eink-display-breakouts). Likewise, see the [guide for the sensor](https://learn.adafruit.com/adafruit-si7021-temperature-plus-humidity-sensor).

```auto
import time
import pulseio
import busio
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il0373 import Adafruit_IL0373
import adafruit_si7021
import font

spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = digitalio.DigitalInOut(board.D11)
dc = digitalio.DigitalInOut(board.D10)
srcs = digitalio.DigitalInOut(board.D9)
rst = digitalio.DigitalInOut(board.D6)
busy = digitalio.DigitalInOut(board.D12)
display = Adafruit_IL0373(152, 152, rst, dc, busy, srcs, ecs, spi)

i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_si7021.SI7021(i2c)

ON = 2**15
OFF = 0

buzzer = pulseio.PWMOut(board.D5, variable_frequency=True)
buzzer.duty_cycle = OFF

silence_button = digitalio.DigitalInOut(board.A5)
silence_button.direction = digitalio.Direction.INPUT
silence_button.pull = digitalio.Pull.UP
```

## Settings

Various aspects of the system's behavior are controlled by a collection of settings. These are read from the **settings.txt** file on the **CIRCUITPY** drive.&nbsp;Once read they are stored in a dictionary which is initialized with default values after the hardware is set up.

```auto
settings = {}
settings['temperature_range'] = (15, 30)
settings['humidity_range'] = (60, 70)
settings['title'] = 'Jar Minder'
settings['alarm_frequency'] = 4000
settings['alarm_number_of_beeps'] = 3
settings['alarm_seconds_beep_on'] = 0.5
settings['alarm_seconds_between_beeps'] = 0.5
settings['alarm_seconds_between_alarms'] = 5.0
settings['alarm_timeout'] = 60.0
```

`temperature_range` takes the low and high bounds of the acceptable temperature range: two integers separated by a dash.

`humidity_range` is similar for the humidity range.

`title` is a string (at most 19 characters with no surrounding quotes) that is shown at the top of the display.

`alarm_frequency` is the frequency of alarm beeps as an int.

`alarm_number_of_beeps` is the number of beeps in an alarm as an int.

`alarm_seconds_beep_on` the amount of time each alarm beep sounds (seconds, a float).

`alarm_seconds_between_beeps` the amount of time between alarm beeps (seconds, a float).

`alarm_seconds_between_alarms` the amount of time between groups of alarm beeps (seconds, a float).

`alarm_timeout` how long (ins seconds) to continue sounding the alarm (float) after which the device will go to sleep.

Here's an example of the setting file:

```auto
temperature_range:15-30
humidity_range:60-70
title:Jar Minder
alarm_frequency:4000
alarm_number_of_beeps:3
alarm_seconds_beep_on:0.5
alarm_seconds_between_beeps:0.5
alarm_timeout:60.0
```

The code that reads the setting file is pretty simple:

```auto
def to_int_tuple(a):
    """Convert an array of strings to a tuple of ints.
    :param [int] a: array of strings to convert
    """

    return tuple([int(x.strip()) for x in a])

with open('settings.txt', 'r') as f:
    for line in f:
        key, value = line.strip().split(':').strip()
        values = value.split('-')
        if key == 'temperature_range':
            setting = to_int_tuple(values)
        elif key == 'humidity_range':
            setting = to_int_tuple(values)
        elif key == 'title':
            setting = value
        elif key == 'alarm_frequency':
            setting = int(value)
        elif key == 'alarm_number_of_beeps':
            setting = int(value)
        elif key == 'alarm_seconds_beep_on':
            setting = float(value)
        elif key == 'alarm_seconds_between_beeps':
            setting = float(value)
        elif key == 'alarm_timeout':
            setting = float(value)
        settings[key] = setting  
```

## Description Text

Along with the settings file, there is a file of text named **description.txt** which contains informative text to be displayed on the screen. It is limited to 4 lines of 19 characters each. This can be used to identify the contents, when it was put in the jar, etc. It gets read and stored for display:

```auto
with open('description.txt', 'r') as f:
    text = [line.strip() for line in f]
```

## Rendering Text

There are a few functions to display text on the display:

```auto
def render_character(x, y, ch, color=Adafruit_EPD.BLACK):
    """Render a character.
    :param int x: horizontal position of the left edge of the character
    :param int y: vertical position of the top edge of the character
    :param str ch: a single character string to be displayed
    :param Adafruit_EPD.* color: BLACK or RED, background is always white
    """

    if x < 144 and y < 144:
        bitmap = font.bitmaps[ord(ch)]
        for row_num in range(8):
            row = bitmap[row_num]
            for column_num in range(8):
                if (row & 1) == 0:
                    display.draw_pixel(x + column_num, y + row_num, Adafruit_EPD.WHITE)
                else:
                    display.draw_pixel(x + column_num, y + row_num, color)
                row >>= 1


def render_string(x, y, s, color=Adafruit_EPD.BLACK):
    """Render a string.
    :param int x: horizontal position of the left edge of the string
    :param int y: vertical position of the top edge of the string
    :param str ch: a string to be displayed
    :param Adafruit_EPD.* color: BLACK or RED, background is always white
    """

    x_pos = x
    for ch in s:
        render_character(x_pos, y, ch, color)
        x_pos += 8


def centered(s):
    """Computer the X position to center a string.
    :param str s: the string to center
    """
    
    return 75 - (4 * len(s))
```

The `centered` function determines where to start a line to center it horizontally. `render_string` iterates through a string, rendering each character by using `render_character`, moving across the screen as it goes. A character is rendered by setting each pixel in its 8x8 grid to white (the background, represented by a 0 bit in the font data) or the foreground color that is passed in (black or red).

Where do these character bitmaps come from? At the start we imported **font.py** which contains the bitmaps for the 127 ASCII characters. It's done as Python code that defines an array of arrays. Each inner array contains 8 bytes: each bit is a pixel in the character bitmap. A small section is shown below, and is based on&nbsp; **font8x8\_basic.h** from&nbsp;[https://github.com/dhepper/font8x8](https://github.com/dhepper/font8x8)&nbsp;(which is in the public domain).

```auto
bitmaps = [
    ...
    [ 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00],   # U+0041 (A)
    [ 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00],   # U+0042 (B)
    [ 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00],   # U+0043 (C)
    [ 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00],   # U+0044 (D)
    [ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00],   # U+0045 (E)
    ...
]
```

## Other Support Functions

There are three other functions.

First is `check_for_push` which monitors the pushbutton for a specified period of time. Every 100mS during that time the button is checked. If it is pushed, `True` is immediately returned. If the time expires `False` is returned.

```auto
def check_for_push(button, duration):
    """Wait for a time, regularly checking for a button push.
    :param DigitalInOut button: the button input to check
    :param float duration: seconds to wait
    Return True if the button is pushed, False if the time passes
    """

    stop_at = time.monotonic() + duration
    while time.monotonic() < stop_at:
        if not button.value:
            return True
        time.sleep(0.1)
    return False
```

Next is `sound_alarm` which is responsible for generating a series of alarm beeps as specified in the settings. The `check_for_push` function is called during each time of the beeps and the time between beeps. As soon as it returns `True`, the alarm sequence is terminated and `sound_alarm` returns `True`.

```auto
def sound_alarm():
    """Sound the alarm based on the settings."""

    buzzer.frequency = settings['alarm_frequency']
    for _ in range(settings['alarm_number_of_beeps']):
        buzzer.duty_cycle = ON
        if check_for_push(silence_button, settings['alarm_seconds_beep_on']):
            buzzer.duty_cycle = OFF
            return True
        buzzer.duty_cycle = OFF
        if check_for_push(silence_button, settings['alarm_seconds_between_beeps']):
            return True
    return False
```

Finally, there is `out_of_range` which takes temperature and humidity readings and checks them against the appropriate range. `True` is returned if either reading is out of range, `False` otherwise.

```auto
def out_of_range(t, h):
    """Check if either temperature and humidity is out of range.
    :param float t: temperature reading
    :param float h: humidity reading
    """

    if t < settings['temperature_range'][0]:
        return True
    if t > settings['temperature_range'][1]:
        return True
    if h < settings['humidity_range'][0]:
        return True
    if h > settings['humidity_range'][1]:
        return True
    return False
```

## Edit Mode

When the system starts up the switch is checked. If it is pressed _edit mode_ is entered. This is indicated by a low beep and the message EDIT MODE on the display. The system stays in edit mode until the switch is pressed again. Another low beep is sounded and the normal mode is entered. The purpose of this is to keep the power on while the user edits the setting and description files/

```auto
if not silence_button.value:
    buzzer.frequency = 440
    buzzer.duty_cycle = ON
    time.sleep(0.5)
    buzzer.duty_cycle = OFF
    display.clear_buffer()
    render_string(39, 64, 'EDIT MODE')
    display.display()
    while not silence_button.value:       # wait for button to be released
        pass
    while silence_button.value:           # wait for button to be pressed
        pass
    buzzer.duty_cycle = ON
    time.sleep(0.5)
    buzzer.duty_cycle = OFF
```

## Main Script

After settings and description are loaded as described above, the display is updated based on readings. First the title and description:

```auto
display.clear_buffer()
render_string(centered(settings['title']), 12, settings['title'])

# Display text
row_index = 64
for line in text:
    if row_index > 112:
        break
    render_string(centered(line), row_index, line)
    row_index += 10
```

Next the sensor is read and the values displayed.

```auto
temperature = int(sensor.temperature)
humidity = int(sensor.relative_humidity)
render_string(8, 32, '{0:2d} C'.format(temperature))
render_string(112, 32, '{0:2d} %'.format(humidity))
```

Once we have the readings, they are checked against their respective ranges and explanatory text assigned. If a reading is in range, this will be an empty string.

```auto
if temperature < settings['temperature_range'][0]:
    temperature_message = 'LOW TEMPERATURE'
elif temperature > settings['temperature_range'][1]:
    temperature_message = 'HIGH TEMPERATURE'
else:
    temperature_message = ''

if humidity < settings['humidity_range'][0]:
    humidity_message = 'LOW HUMIDITY'
elif humidity > settings['humidity_range'][1]:
    humidity_message = 'HIGH HUMIDITY'
else:
    humidity_message = ''
```

If a reading is out of range, the associated text is displayed in red and red bars are displayed at the top and bottom of the screen.

```auto
if temperature_message:
    render_string(centered(temperature_message), 122, temperature_message, Adafruit_EPD.RED)
if humidity_message:
    render_string(centered(humidity_message), 132, humidity_message, Adafruit_EPD.RED)

if temperature_message or humidity_message:
    display.fill_rect(0, 0, 152, 10, Adafruit_EPD.RED)
    display.fill_rect(0, 142, 152, 10, Adafruit_EPD.RED)

display.display()
```

Finally, we handle sounding the alarm. While either reading is out of range and the alarm timeout hasn't expired, the series of alarm beeps is generated each interval specified in the settings. Once the timeout expires or the switch is pressed, the alarm stops and the device powers down by setting the **DONE** signal `True`/high.

```auto
timeout = time.monotonic() + settings['alarm_timeout']

while out_of_range(sensor.temperature, sensor.humidity) and time.monotonic() < timeout:
    if sound_alarm():
        break
    if check_for_push(silence_button, settings['alarm_seconds_between_alarms']):
        break

done.value = True
```

# Humidity and Temperature Monitor with E-Ink Display

## Prototype Construction

This version of the jar monitor is still in the prototype stage with a hand-wired version glued onto a 3D printed lid for a large mouth mason jar.

The Jar Minder prototype mounted on the printed jar lid.

The jar lid is based on&nbsp;[https://www.thingiverse.com/thing:1323393/](https://www.thingiverse.com/thing:1323393/)&nbsp;which is for a small sized mason jar. It was scaled on the X and Y axies to 123% to fit the larger size jars.

![temperature___humidity_IMG_3311.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/807/medium640/temperature___humidity_IMG_3311.jpg?1549487330)

![temperature___humidity_IMG_3312.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/808/medium640/temperature___humidity_IMG_3312.jpg?1549487343)

![temperature___humidity_IMG_3313.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/809/medium640/temperature___humidity_IMG_3313.jpg?1549487351)

![temperature___humidity_IMG_3314.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/810/medium640/temperature___humidity_IMG_3314.jpg?1549487360)

Closeups, including with the display removed.

![temperature___humidity_IMG_3315.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/811/medium640/temperature___humidity_IMG_3315.jpg?1549487401)

![temperature___humidity_IMG_3316.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/812/medium640/temperature___humidity_IMG_3316.jpg?1549487410)

![temperature___humidity_IMG_3317.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/813/medium640/temperature___humidity_IMG_3317.jpg?1549487427)

![temperature___humidity_IMG_3318.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/814/medium640/temperature___humidity_IMG_3318.jpg?1549487433)

For the unassembled prototype, nylon standoffs were superglued to the lid upon which the main board is mounted. Standoffs were bolted to the board, glue applied to their other ends, and the assembly positioned and left to set.

Point-to-point wiring was used, and everything was mounted to a piece of perf-board.&nbsp; The LED and potentiometer traces on the underside of the TPL5111 breakout were cut to disable the LED and allow the use of an external, fixed timing resistor which can be seen along with the DONE capacitor.

The wire below was used to connect the sensor to the Feather.

![temperature___humidity_IMG_3319.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/816/medium640/temperature___humidity_IMG_3319.jpg?1549487885)

![temperature___humidity_IMG_3320.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/817/medium640/temperature___humidity_IMG_3320.jpg?1549487898)

![temperature___humidity_IMG_3322.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/818/medium640/temperature___humidity_IMG_3322.jpg?1549487906)

![temperature___humidity_IMG_3323.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/819/medium640/temperature___humidity_IMG_3323.jpg?1549487914)

# Humidity and Temperature Monitor with E-Ink Display

## Wrap Up

This guide has revisited a previous project using more powerful and feature rich hardware. The switch to a Feather M4 Express has allowed the use of a feature-rich device coded in CircuitPython. The Feather's generous I/O capabilities has made possible the use of an eInk display which gives the ability to display readings as well as informative and warning text. The Feather also provides in-place battery charging which makes the device far more convenient.

## Going Further

There are a few ways to expand the project. First is making a printed enclosure that extends or mounts on the jar lid. Next is making a custom PCB rather than using hand-wired perf-board construction. Another direction is to enhance the display. A larger font would help with legibility, as would some icons.


## Guide Products

### Adafruit Feather M4 Express - Featuring ATSAMD51

[Adafruit Feather M4 Express - Featuring ATSAMD51](https://www.adafruit.com/product/3857)
It's what you've been waiting for, the Feather M4 Express featuring ATSAMD51. This Feather is fast like a swift, smart like an owl, strong like a ox-bird (it's half ox, half bird, OK?) This feather is powered by our new favorite chip, the **ATSAMD51J19** -&nbsp; with...

In Stock
[Buy Now](https://www.adafruit.com/product/3857)
[Related Guides to the Product](https://learn.adafruit.com/products/3857/guides)
### Adafruit 1.54" 152x152 Tri-Color eInk / ePaper Display with SRAM

[Adafruit 1.54" 152x152 Tri-Color eInk / ePaper Display with SRAM](https://www.adafruit.com/product/3625)
Easy e-paper finally comes to microcontrollers, with this breakout that's designed to make it a breeze to add a tri-color eInk display. Chances are you've seen one of those new-fangled 'e-readers' like the Kindle or Nook. They have gigantic electronic paper 'static'...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/3625)
[Related Guides to the Product](https://learn.adafruit.com/products/3625/guides)
### Adafruit TPL5111 Low Power Timer Breakout

[Adafruit TPL5111 Low Power Timer Breakout](https://www.adafruit.com/product/3573)
With some development boards, low power usage is an afterthought. Especially when price and usability are the main selling points. So what should you do when it's time to turn around and make that project of yours run on a battery or solar? Sure you&nbsp;_could_&nbsp;try to hot-air...

In Stock
[Buy Now](https://www.adafruit.com/product/3573)
[Related Guides to the Product](https://learn.adafruit.com/products/3573/guides)
### Adafruit Si7021 Temperature & Humidity Sensor Breakout Board

[Adafruit Si7021 Temperature & Humidity Sensor Breakout Board](https://www.adafruit.com/product/3251)
It's summer and you're sweating and your hair's all frizzy and all you really want to know is why the weatherman said this morning that today's relative humidity would max out at a perfectly reasonable 42% when it feels more like 77%. Enter the&nbsp; **Si7021 Temperature +...**

In Stock
[Buy Now](https://www.adafruit.com/product/3251)
[Related Guides to the Product](https://learn.adafruit.com/products/3251/guides)
### Lithium Ion Polymer Battery - 3.7v 1200mAh

[Lithium Ion Polymer Battery - 3.7v 1200mAh](https://www.adafruit.com/product/258)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 1200mAh for a total of about 4.5 Wh. If you need a larger battery, <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/258)
[Related Guides to the Product](https://learn.adafruit.com/products/258/guides)
### Piezo Buzzer

[Piezo Buzzer](https://www.adafruit.com/product/160)
Piezo buzzers are used for making beeps, tones and alerts. This one is petite but loud! Drive it with 3-30V peak-to-peak square wave. To use, connect one pin to ground (either one) and the other pin to a square wave out from a timer or microcontroller. For the loudest tones, stay around 4 KHz,...

In Stock
[Buy Now](https://www.adafruit.com/product/160)
[Related Guides to the Product](https://learn.adafruit.com/products/160/guides)
### Metal Ball Tactile Button (6mm) x 10 pack

[Metal Ball Tactile Button (6mm) x 10 pack](https://www.adafruit.com/product/3347)
Add some steely elegance to your project with these **Metal Ball Tactile Buttons**. They've got a nice industrial shine to them along&nbsp;with a light blue underbelly. Not only do they look good, but they're also good if you have an actuator that will be pressing the...

In Stock
[Buy Now](https://www.adafruit.com/product/3347)
[Related Guides to the Product](https://learn.adafruit.com/products/3347/guides)
### 0.1uF ceramic capacitors - 10 pack

[0.1uF ceramic capacitors - 10 pack](https://www.adafruit.com/product/753)
As any engineer will tell you, 0.1uF ceramic capacitors are the magic fairy dust of electronics - sprinkle them over your circuit schematics for good luck! But seriously, a 0.1uF capacitor right next to the VCC pin of your chips will improve stability by filtering out power supply spikes and...

Out of Stock
[Buy Now](https://www.adafruit.com/product/753)
[Related Guides to the Product](https://learn.adafruit.com/products/753/guides)

## Related Guides

- [Adafruit Si7021 Temperature + Humidity Sensor](https://learn.adafruit.com/adafruit-si7021-temperature-plus-humidity-sensor.md)
- [Adafruit Feather M4 Express](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51.md)
- [Adafruit 1.54" eInk Display Breakouts](https://learn.adafruit.com/adafruit-1-54-eink-display-breakouts.md)
- [Zelda: Breath of the Wild – 3D Printed Bladesaw](https://learn.adafruit.com/bladesaw.md)
- [DIY Robotic Sky Tracking Astrophotography Mount with CircuitPython](https://learn.adafruit.com/diy-robotic-sky-tracking-astrophotography-mount.md)
- [Fiber Optic Whip](https://learn.adafruit.com/fiber-optic-whip.md)
- [How to Build a Testing Jig](https://learn.adafruit.com/how-to-build-a-testing-fixture.md)
- [Square NeoPixel Display with Black LED Acrylic](https://learn.adafruit.com/sqaure-neopixel-display-with-black-led-acrylic.md)
- [MIT Green Building NeoPixel Tetris](https://learn.adafruit.com/tetris-building.md)
- [Cellular Data for CircuitPython with FONA](https://learn.adafruit.com/cellular-data-for-circuitpython-with-fona.md)
- [How to Make Animated Graphics for Hologram Displays](https://learn.adafruit.com/how-to-make-animated-graphics-for-hologram-displays.md)
- [Adafruit IO IOT Hub with the Adafruit FunHouse](https://learn.adafruit.com/adafruit-io-hub-with-the-adafruit-funhouse.md)
- [Adafruit IO Environmental Monitor for Feather or Raspberry Pi](https://learn.adafruit.com/adafruit-io-air-quality-monitor.md)
- [No-Solder LED Disco Tie with Bluetooth](https://learn.adafruit.com/no-solder-circuit-playground-bluetooth-disco-tie.md)
- [Adafruit Proto Tripler PiCowbell](https://learn.adafruit.com/adafruit-proto-tripler-picowbell.md)
- [CircuitPython BLE Heart Rate Zone Trainer Display](https://learn.adafruit.com/circuitpython-ble-heart-rate-monitor-gizmo.md)
- [SpaceX Helmet](https://learn.adafruit.com/spacex-helmet.md)
- [Adafruit 3.5" 320x480 Color TFT Touchscreen Breakout](https://learn.adafruit.com/adafruit-3-5-color-320x480-tft-touchscreen-breakout.md)
