Preliminary Instructions: we may update these instructions later (works on my ESP32, but the GSIs had some problems, we are investigating what’s going on and may post additional information).

In this lab we will build a solar-powered “weather station” that reports temperature, humidity, pressure and air quality to the cloud.

1. Prelab

Running electronics from “harvested” power such as solar has many advantages: it’s environmentally friendly and works “off the grid”. Unlike battery operated systems, devices running on harvested energy can theoretically run forever.

Given the high cost of pulling wires to remote (and even not so remote locations e.g. in factories) locations that often exceeds the cost of the sensors themselves, energy harvesting is frequently an attractive alternative.

Operation off the grid is not without challenges:

  1. Usually only a small amount of energy is available, requiring careful book-keeping and low power circuit design.

  2. Frequently harvested power e.g. from solar cells is available only intermittently, requiring a backup power solution.

In this lab we address both problems.

1.1. Lab Power Supply

Study the instructions (first two pages) for using the lab power supply in 122 Hesse.

1.2. Adafruit IO

Create a free account on AdafruitIO[1] and follow these instructions to publish a sine-wave using MQTT (no need for IFTTT).

Save your code for later use in the lab and also submit it to gradescope. Be ready to show the sinusoid on your AdafruitIO account to the GSI.

Add the following line to your boot.py:

machine.WDT(False)

1.3. BME680 Air Quality Sensor

The BME680 is a pepper-corn sized I2C chip that measures temperature, humidity, pressure and air quality. Study the tutorial for the BEM680 on Adafruit and download the CircuitPython[2] driver and example code.

The CircuitPython I2C driver differs from the standard MicroPython I2C. Save the following code as busio.py and upload it to the ESP32.

# `busio` - CircuitPython I2C driver for MicroPython

class I2C:

    def __init__(self, scl, sda, frequency=400000):
        self.init(scl, sda, frequency)

    def init(self, scl, sda, frequency):
        self.deinit()
        from machine import I2C as _I2C
        from machine import Pin as _Pin
        self._i2c = _I2C(id=0, scl=_Pin(scl), sda=_Pin(sda), freq=frequency)

    def deinit(self):
        try:
            del self._i2c
        except AttributeError:
            pass

    def __enter__(self):
        return self

    def __exit__(self, *exc):
        self.deinit()

    def scan(self):
        return self._i2c.scan()

    def readfrom_into(self, address, buffer, *, start=0, end=None):
        if start is not 0 or end is not None:
            if end is None:
                end = len(buffer)
            buffer = memoryview(buffer)[start:end]
        return self._i2c.readfrom_into(address, buffer)

    def writeto(self, address, buffer, *, start=0, end=None, stop=True):
        if isinstance(buffer, str):
            buffer = bytes([ord(x) for x in buffer])
        if start is not 0 or end is not None:
            if end is None:
                return self._i2c.writeto(address, memoryview(buffer)[start:], stop=stop)
            else:
                return self._i2c.writeto(address, memoryview(buffer)[start:end], stop=stop)
        return self._i2c.writeto(address, buffer, stop=stop)

    def writeto_then_readfrom(self, address, buffer_out, buffer_in, *, out_start=0, out_end=None, in_start=0, in_end=None, stop=False):
        return self._i2c.writeto_then_readfrom(address, buffer_out, buffer_in,
                                               out_start=out_start, out_end=out_end,
                                               in_start=in_start, in_end=in_end, stop=stop)

Write a program that prints the sensor measurements every second and store it on your computer for later use in the lab. Also upload it to gradescope.

In the lab we are going to use a special breakout board described here. Note: the pinout differs from the Adafruit tutorial!

1.4. Power Management

1.4.1. Sleep

Following the instructions in power management, write a program that turns on the LED on the Huzzah32 board. After 10 seconds, turn off the LED and put the processor into “sleep” for 15 seconds.

Save your code for later use in the lab and also submit it to gradescope.

1.4.2. Battery Capacity

Calculate the maximum duty cycle \(\eta\) of an application with the following averages:

available

40mA

\(I_{on}\)

200mA

\(I_{off}\)

100µA

\(E_b\)

500mAh

\(\eta\) =

1.5. Circuit Diagram

Draw the circuit diagram including

  • MCU

  • Solar cell

  • Backup battery

  • BME680

Rather than dissipating the harvested power from the solar cell as in previous labs, use it to power the Huzzah32 by connecting it to the VUSB pin.

2. Lab

2.1. BME680 Air Quality Sensor

Solder a header to the BME680. Then connect it to the MCU and verify its operation.

Checkoff:

2.2. Measure ESP32 Supply Current

To measure current draw in on and off (sleep) mode, power the ESP32 from the lab power supply. Program it for 5V output (the voltage regulator on the Huzzah32 board generates the 3.3V used by the MCU from 5V) and connect the positive terminal to VUSB and the negative terminal to GND on the Huzzah32 board. Also connect the Ammeter to measure the supply current.

Then start the program developed in the prelab on the ESP32 that alternates between on and sleep mode. Also turn on the LED while for indication. Make sure the ESP32 connects to WiFi when on (e.g. by placing the appropriate code in boot.py) as this affects the power dissipation. Once the program is running, disconnect the USB cable.

Record the measured supply current during on and sleep mode, respectively. Perform this experiment with the Huzzah32 board alone, and also for the complete circuit including the sensors designed in Section 1.5.

Disconnect the rechargeable battery to the Huzzah32 while performing these tests.

Huzzah32 Only

Complete Weather Station

\(I_{on}\)

\(I_{off}\)

Recalculate the maximum duty cycle \(\eta\) for the actual battery capacity and currents measured.

\(\eta\) =

Checkoff:

2.3. Solar-Powered Weather Station

Reconnect the rechargeable battery. Then combine the programs developed in the prelab and prior labs to measure weather data and upload it to AdafruitIO. Then put the processor into sleep mode for a minute or so (don’t use too long a value or you’ll spend the night in the lab …​).

Once everything working, rename your program main.py and upload it to the ESP32. Disconnect the USB cable and watch the measurement data being recorded on AdafruitIO.

Checkoff (at least one new point on AdafruitIO while the GSI is watching):

Congratulations! Are you learning new tricks in EE49?


1. Alternatively follow the instructions in AWS for a secure IoT solution. In production you always would follow this approach, however, since it is more laborious it is optional in the class.
2. CircuitPython is a derivative of MicroPython for which many drivers, as the one used here, are available. The version of MicroPython we are using has been adapted to be compatible with many CircuitPython drivers.