Skip to main content

Read chlorine

What this example shows​

The module's electrochemical-bridgeBoard.py example starts the board at its default address, 0x30, and prints the gas concentration in ppm every 2.5 s. It is the same example as the Quick Start.

The example uses SENSOR_O3, the preset for the ozone cell. The module calculates ppm from the preset's sensitivity and gain settings; the preset for this board's chlorine cell is SENSOR_CL2.

The example opens I2C bus 0 with SCL on pin 22 and SDA on pin 21. Change them to match your board.

The example code​

The example's comments say the address is set with jumpers on the back of the board and that LMPEN is hardwired to GND. On this board the ADDRESS switch on the top side sets the address (0x30 by default). A 10 kΩ resistor holds LMPEN low and it is wired to the ATtiny404, so you leave it unconnected (see Hardware Details).

# FILE: electrochemical-bridgeBoard.py
# AUTHOR: Fran Fodor @ Soldered
# BRIEF: Single sensor PPM reading example for the ATtiny404 bridge board revision,
# which allows daisy-chaining multiple boards on one I2C bus.
# LAST UPDATED: 2026-07-23

# Connecting diagram:
#
# Qwiic------------------------>Qwiic
#
# Note: on this board revision, LMPEN is hardwired to GND, so there's no
# config_pin to set - it's ignored whenever adc_addr falls in the bridge
# range (0x30-0x37). Set the desired address using the jumpers on the back
# of the board before powering it on.

from machine import I2C, Pin
import time
from ElectrochemicalGasSensor import ElectrochemicalGasSensor, SENSOR_O3

# Initialize I2C
i2c = I2C(0, scl=Pin(22), sda=Pin(21))

# (address = 0x30 + jumper offset, giving a range of 0x30-0x37).
# Any additional boards on the same bus just need a different jumper
# setting, same as twoSensors.py does for legacy boards with 0x49/0x4A/0x4B.
sensor = ElectrochemicalGasSensor(SENSOR_O3, i2c, adc_addr=0x30)

# -------------------------------------------------------------------------
# Setup
# -------------------------------------------------------------------------
print("Electrochemical Gas Sensor - ATtiny Bridge Board Example")

if not sensor.begin():
print("ERROR: Can't init the sensor! Check connections and jumper address!")
while True:
time.sleep_ms(100)

print("Sensor initialized successfully!")

# -------------------------------------------------------------------------
# Main loop
# -------------------------------------------------------------------------
while True:
reading = sensor.getPPM()

# If PPB is more relevant for your sensor, use:
# reading = sensor.getPPB()

print("Sensor reading: {:.5f} PPM".format(reading))

time.sleep_ms(2500)

🔗Open the complete example

Examples/electrochemical-bridgeBoard.py at commit 623e1e6

→

Expected result:

ShellMicroPython
Electrochemical Gas Sensor - ATtiny Bridge Board Example
Sensor initialized successfully!

Then a line every 2.5 s: Sensor reading: , the concentration in ppm with five decimals, and PPM. If the board does not answer, the script prints ERROR: Can't init the sensor! Check connections and jumper address! and stops.

Functions used​

ElectrochemicalGasSensor(sensor_type, i2c=None, adc_addr=0x49, config_pin=None)returns ElectrochemicalGasSensor

Creates the sensor object. Nothing is sent to the board until begin().

ReturnsThe sensor object.

Parameters

TypeNameDescription
SensorConfigsensor_typeThe cell preset. The example passes SENSOR_O3; this board's SGX-4CL2 cell has the preset SENSOR_CL2.
I2Ci2cA ready machine.I2C object; the example passes one. When left out, the module creates I2C(0, scl=Pin(22), sda=Pin(21)) on the esp32 port and on the one other board it recognises by its name (pins 22 and 21 there too); on esp8266, I2C(scl=Pin(5), sda=Pin(4)); on any other board it raises Board not recognized, please pass an I2C object manually.
intadc_addrThe I2C address, 0x49 when left out. For an address from 0x30 to 0x37, the range of this board's ADDRESS switch, begin() talks to the board's ATtiny404; the example passes 0x30, the board's default. For any other address begin() looks for an ADS1115 at that address and the LMP91000 at 0x48 on the bus you pass.
intconfig_pinA GPIO for the LMP91000's MENB input: the module drives it low while it configures the LMP91000 directly, and high otherwise. None when left out. Unused for addresses 0x30 to 0x37.
sensor.begin()returns bool

Checks that the board answers, sends it the preset's ADC gain and data rate, and configures the LMP91000 with the preset's settings. Call it once before reading. Each exchange with the board retries for up to 500 ms.

ReturnsTrue when the board answered and both configuration steps succeeded, False otherwise.

sensor.getPPM()returns float

Takes one reading and converts it to ppm: it subtracts the internal zero voltage (the 2.5 V reference times the preset's internal zero percentage), adds the zero calibration, divides by the amplifier gain and by the preset's sensitivity in nA per ppm. A result below zero is returned as 0.0.

ReturnsThe gas concentration in ppm.

sensor.getPPB()returns float

Same reading as getPPM(), times 1000. The example shows it in a comment as the alternative.

ReturnsThe gas concentration in ppb.

This example also uses I2C and Pin from MicroPython's machine module and time.sleep_ms(), which are not part of this library and come with MicroPython itself.

Putting it together​

begin() does all the setup, so the loop only calls getPPM() and prints the result. To read in ppb, swap in the getPPB() line from the comment.