Using I2C in MicroPython 🌡
Tags: esp32, micropython, i2c, sensors
Published: 2022-02-14 19:48:00

The flashy NeoPixel-decorated ESP32-C3 board I've been learning about has no published schematic, so one of the things I've been doing as I play with it, is document how to access the various LEDs, buttons, and pins.

In the [last post](https://dev.to/andypiper/making-a-cheerdot-with-micropython-3ocf), I mentioned that I was curious about the JST-SH connector on the edge of the board.

![ESP32-C3FH4-RGB overview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ecr52azqoj7eibhd66f5.jpeg)
<figcaption>ESP32-C3FH4-RGB overview</figcaption>

![End view showing 4 pin JST-SH connector](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nywskm1ix5qwk5hma63t.jpeg)
<figcaption>End view showing 4 pin JST-SH connector</figcaption>

&nbsp;<br/>

The [MicroPython documentation for the ESP32-C3](https://docs.micropython.org/en/latest/esp32/quickref.html#hardware-i2c-bus) indicates that the default pin assignments for Hardware I2C ports 0 and 1 are 18/19 and 25/26, but attempting to use those pins in the REPL resulted in errors, or no data.

The clue is in the etching on the board itself. Just above the connector, we can see the text `G3V01` - as [one of the commenters on the CNX post about the board](https://www.cnx-software.com/2022/01/07/board-with-25-rgb-leds-is-offered-with-esp32-c3-or-esp32-pico-d4/#comment-589534) points out, this likely means "GND, 3V, I/O 0, I/O 1".

Inserting a JST-SH cable reveals the other part I had a query about:

![JST-SH connector showing Black,Red,Blue,Yellow cables](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r3pnxkb75fgv79wz0srn.jpeg)
<figcaption>JST-SH connector showing Black,Red,Blue,Yellow cables</figcaption>

&nbsp;<br/>

The Adafruit site has a [handy technical guide to StemmaQT / Qwiic connectors](https://learn.adafruit.com/introducing-adafruit-stemma-qt/technical-specs), from which we learn...

> For the STEMMA QT cables, we follow the Qwiic convention:
> 1. Black for GND
> 2. Red for V+
> 3. Blue for SDA
> 4. Yellow for SCL 

SDA and SCL are the important pieces here - these are the I2C data lines. From the labelling `G3V01` and the wire ordering Black / Red / Blue / Yellow we can map SDA to pin 0 and SCL to pin 1. This actually makes sense as I look at the board, where the labels for visible holes for other connections (on the other side of the board from the image above) start from 2. 0 and 1 are for this I2C port, which accepts 4-pin JST-SH / Sparkfun Qwiic / Adafruit StemmaQT peripherals.

---

This is where I admit that it took me the longest time to work all of the above out, even though it sounds so logical and obvious! What can I tell you... I'm not an expert at any of this...

{% twitter https://twitter.com/andypiper/status/1490787623635496965 %}

I actually sat trying `I2C.scan()` in the REPL against various combinations of possibilities for SDA and SCL for quite a long time, either hanging/crashing the board and requiring a reset, or just getting a blank `[]` result... as I said, *now*, it all seems so clear. _Well, I'm on this MicroPython and ESP32-C3 journey to learn, and I'm learning_. 

---

OK, so we've figured out another part of the schematic. My reference card now looks like this (latest version will be [in the GitHub repo](https://github.com/andypiper/fivebyfive/tree/main/reference) in various formats):

![Reference for the ESP32-C3FH4-RGB board](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7lx5206j6flrawswy45.jpeg)
<figcaption>Annotated image of pin assignments</figcaption>

&nbsp;<br/>

This has moved along slightly since the [previous post in the series](https://dev.to/andypiper/making-a-cheerdot-with-micropython-3ocf). Now, let's get some data in.

Although I have a few Adafruit and Sparkfun sensors on hand, I've typically used them with CircuitPython or Python rather than in MicroPython, and it turns out that the Sparkfun Qwiic library is not available for MicroPython. However, in the case of one sensor - the AHT20 temperature sensor - there *is* [a MicroPython library](https://github.com/targetblank/micropython_ahtx0). The example looked fairly straightforward, so I went ahead and installed the library to one of my boards (... I should mention, by now, I have a few of them - they are [reasonably cheap](https://banggood.com/ESP32-C3-Development-Board-RISC-V-WiFi-Bluetooth-IoT-Development-Board-Compatible-with-Python-p-1914005.html), and I'm trying things in MicroPython and in C, and have some other hardware-related ideas as well as this exploration).

This time, for variety and to try out some different tooling, I used Adafruit's `ampy` tool, which can be installed via pip:

```shell
$ pip3 install adafruit-ampy
... ...
$ ampy -p /dev/cu.usbmodem11301 mkdir lib
$ ampy -p /dev/cu.usbmodem11301 put ahtx0.py lib/ahtx0.py
```

This installed the `micropython-ahtx0` library to `lib/` on the board.

![Adafruit AHT20 sensor board attached to ESP32-C3 via JST-SH cable](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlceo212ftq7g2om3uw7.jpeg)
<figcaption>Adafruit AHT20 sensor board attached to ESP32-C3 via JST-SH cable</figcaption>

&nbsp;</br>

The code from there to get a temperature is really, really straightforward (but, the library is ~14 months old, and MicroPython has moved along since then, so I did have to change a few things).

```python
from machine import Pin, SoftI2C
import utime
import ahtx0

i2c = SoftI2C(scl=Pin(1), sda=Pin(0))

sensor = ahtx0.AHT20(i2c)

while True:
    print("\nTemperature: %0.2f C" % sensor.temperature)
    print("Humidity: %0.2f %%" % sensor.relative_humidity)
    utime.sleep(5)
```

(this program is [available in my "Five by Five" repo as `aht20-test.py`](https://github.com/andypiper/fivebyfive/blob/main/micropython/aht20-test.py))

The original example for `micropython-ahtx0` was for a Wemos D1 Mini, and used the hardware `I2C` implementation. Running that on this board on MicroPython 1.18 nightly (we are using nightly builds to make use of the RMT fixes introduced recently) resulted in a warning that hardware `I2C` is deprecated, and to use `SoftI2C` instead. In this case, it's a 1:1 replacement. We now know that the relevant SDA and SCL values are 0 and 1, so we can pass them in, and then, simply read the temperature and humidity every 5 seconds. Works great!

I sent a [Pull Request upstream for the `micropython-ahtx0` code](https://github.com/targetblank/micropython_ahtx0/pull/1) to make the change to `SoftI2C`, as well as to fix an MQTT-related issue in another of the samples - another good deed I've done while learning about this board 😇

Finally, I wanted to play with some other I2C things...

![BCRobotics Qwiic/STEMMA QT Port Expander, wired to Adafruit BH1750 Light Sensor and APDS-9960 Proximity/Gesture/Color Sensor](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/heulpf0c3785l5yov7au.jpeg)
<figcaption>BCRobotics Qwiic/STEMMA QT Port Expander, wired to Adafruit BH1750 Light Sensor and APDS-9960 Proximity/Gesture/Color Sensor</figcaption>

&nbsp;

Here's what happens when we connect this to the board, and scan on the I2C bus:

```python
MicroPython v1.18 on 2022-02-14; ESP32C3 module with ESP32C3
Type "help()" for more information.
>>> from machine import Pin, SoftI2C
>>> i2c = SoftI2C(scl=Pin(1),sda=Pin(0))
>>> i2c.scan()
[35, 56]
>>> 
```

Great! We know that these two peripherals are visible. I've not written code for these yet, and a more general set of drivers may or may not already exist, but this is all part of the fun!

I've been adding the [various things I've learned to my repo as I go along](https://github.com/andypiper/fivebyfive/blob/main/notes.md), including details like the I2C IDs of the devices I have, for when I want to do something with them.

---

I'll close out this part of the series with something a bit different - [Ciro Cattuto](https://twitter.com/ciro) Tweeted about his "Wordle Device" built using this board...

{% twitter https://twitter.com/ciro/status/1492808693070639104 %}

This is really, really cool - running C code to call the Twitter API v2 directly on the board, and display results (there are a LOT of people playing Wordle right now!). I made a quick video running the code on one of mine, and I sent him some PRs to help the project, too! Check it out: look how rapidly those Tweets are coming in!

{% youtube 2UfY--8PEmA %}

I hope you're enjoying this series - I'm learning so much just by really digging deep into the various topics here. So far I've learned a lot about: the ESP32-C3 chip itself, MicroPython, Thonny and plugins, various command line tools, I2C and the Qwiic "standard", some C, Espressif tooling, and FreeRTOS in the Wordle example, and I've sent Pull Requests to different projects, and met some really nice people in the community!

---

Thanks for reading! Thoughts and questions are always welcome! What would **_YOU_** do with a board like this? What would you like me to try out?

You can also [follow me on Twitter](https://twitter.com/andypiper) for more. If you enjoyed this post, you could help to fund my gadget obsession [via a small tip on Ko-Fi](https://ko-fi.com/andypiper) ☕️