Zero calibration
What this example shows
The module's electrochemical-calibrateSensor.py example adds a fixed offset
voltage to every reading with setCustomZeroCalibration(). In air with none of
the target gas, adjust CUSTOM_CALIBRATION until the reading is just barely 0,
as the example's comment says.
The example creates the sensor with SENSOR_O3, the preset for the ozone cell.
The module calculates each reading 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
# FILE: electrochemical-calibrateSensor.py
# AUTHOR: Fran Fodor @ Soldered
# BRIEF: Sensor zero-point calibration example.
# LAST UPDATED: 2026-05-21
# Connecting diagram:
#
# Qwiic------------------------>Qwiic
# LMPEN------------------------>32 (GPIO pin, required for configuration)
from machine import I2C, Pin
import time
from ElectrochemicalGasSensor import ElectrochemicalGasSensor, SENSOR_O3
# This value is added to the voltage read from the ADC.
# In an environment with 0 of the target gas, the reading after calibration
# should be just barely 0 PPB — adjust this value until that is the case.
CUSTOM_CALIBRATION = 0
# Initialize I2C
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
# Custom ADC address (0x49 default) and GPIO pin for LMPEN
sensor = ElectrochemicalGasSensor(SENSOR_O3, i2c, adc_addr=0x49, config_pin=32)
# -------------------------------------------------------------------------
# Setup
# -------------------------------------------------------------------------
print("Electrochemical Gas Sensor - Calibration Example")
if not sensor.begin():
print("ERROR: Can't init the sensor! Check connections!")
while True:
time.sleep_ms(100)
# Apply the zero-point calibration offset
sensor.setCustomZeroCalibration(CUSTOM_CALIBRATION)
print("Sensor initialized successfully!")
# -------------------------------------------------------------------------
# Main loop
# -------------------------------------------------------------------------
while True:
reading = sensor.getPPB()
# O3 is typically measured in PPB
# Switch to getPPM() if PPM is more relevant for your use case
print("Sensor reading: {:.5f} PPB".format(reading))
time.sleep_ms(2500)
🔗Open the complete example
Examples/electrochemical-calibrateSensor.py at commit 623e1e6
The connecting diagram in the example wires LMPEN to GPIO 32. On this board a
10 kΩ resistor holds LMPEN low and it is wired to the ATtiny404, so you leave
it unconnected (see the pin table on
Hardware details).
Expected result:
Electrochemical Gas Sensor - Calibration Example
Sensor initialized successfully!
Then a line every 2.5 s: Sensor reading: , the concentration in ppb with five
decimals, and PPB. If begin() fails, the script prints
ERROR: Can't init the sensor! Check connections! and stops.
Functions used
ElectrochemicalGasSensor(sensor_type, i2c=None, adc_addr=0x49, config_pin=None)returns ElectrochemicalGasSensorCreates the sensor object. Nothing is sent over I2C until begin().
ReturnsThe sensor object.
Parameters
| Type | Name | Description |
|---|---|---|
SensorConfig | sensor_type | The cell preset. The example passes SENSOR_O3; this board's SGX-4CL2 cell has the preset SENSOR_CL2. |
I2C | i2c | A 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. |
int | adc_addr | The I2C address, 0x49 when left out; the example passes 0x49. For an address from 0x30 to 0x37, the range of this board's ADDRESS switch, begin() talks to the board's ATtiny404; for any other address it looks for an ADS1115 at that address and the LMP91000 at 0x48 on the bus you pass. |
int | config_pin | A GPIO for the LMP91000's MENB input: the module drives it low while it configures the LMP91000 directly, and high otherwise; the example passes 32. None when left out. Unused for addresses 0x30 to 0x37. |
sensor.begin()returns boolChecks that the board answers, sets the preset's ADC gain and data rate, and configures the LMP91000 with the preset's settings. Call it once before reading.
ReturnsTrue when the board answered and both configuration steps succeeded, False otherwise.
sensor.setCustomZeroCalibration(calibration)returns NoneSets the voltage that getPPM() and getPPB() add to every reading after subtracting the internal zero voltage. It replaces the preset's zero calibration, which is 0 in SENSOR_CL2.
ReturnsNothing.
Parameters
| Type | Name | Description |
|---|---|---|
float | calibration | The offset in volts. The example uses CUSTOM_CALIBRATION (0). |
sensor.getPPB()returns floatTakes one reading and converts it to ppb: getPPM() times 1000. getPPM() subtracts the internal zero voltage, adds the zero calibration, divides by the amplifier gain and the preset's sensitivity, and returns 0.0 for a result below zero.
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
Run the script in clean air and change CUSTOM_CALIBRATION until the reading
is just barely 0 ppb. Readings below zero are reported as 0, so a reading of
exactly 0 does not tell you how far below zero the offset leaves it. Use the
value you found with setCustomZeroCalibration() in your own script, after
begin().