Skip to content

Use as a library

PyPMS/pms is meant as a command line application. This section contain some help for those brave enough to use its internals as a library.

Basic examples

"""
Read PMSx003 sensor on /dev/ttyUSB0.

Read 4 samples, one sample every 20 seconds,
and print the observations on different formats.
"""

from pms.core import SensorReader

reader = SensorReader("PMSx003", "/dev/ttyUSB0", interval=20, samples=4)

print("\nPMSx003 4 samples on default format")
with reader:
    for obs in reader():
        print(obs)

print("\nPMSx003 4 samples on CSV format")
with reader:
    for obs in reader():
        print(f"{obs:csv}")

print("\nPMSx003 4 samples on CSV format with header")
with reader:
    print_header = True
    for obs in reader():
        if print_header:
            print(f"{obs:header}")
            print_header = False
        print(f"{obs:csv}")
PMSx003 4 samples on default format
2021-07-29 15:57:01: PM1 1.0, PM2.5 11.0, PM10 12.0 μg/m3
2021-07-29 15:57:21: PM1 0.0, PM2.5 6.0, PM10 6.0 μg/m3
2021-07-29 15:57:41: PM1 0.0, PM2.5 1.0, PM10 2.0 μg/m3
2021-07-29 15:58:01: PM1 0.0, PM2.5 1.0, PM10 2.0 μg/m3

PMSx003 4 samples on CSV format
1627567094, 2, 10, 12, 2.0, 10.0, 12.0, 4.35, 1.42, 0.52, 0.30, 0.00, 0.00
1627567114, 1, 7, 7, 1.0, 7.0, 7.0, 4.53, 1.44, 0.30, 0.09, 0.00, 0.00
1627567134, 1, 1, 2, 1.0, 1.0, 2.0, 3.27, 1.09, 0.09, 0.03, 0.03, 0.00
1627567154, 1, 1, 2, 1.0, 1.0, 2.0, 4.65, 1.44, 0.03, 0.00, 0.00, 0.00

PMSx003 4 samples on CSV format with header
time, raw01, raw25, raw10, pm01, pm25, pm10, n0_3, n0_5, n1_0, n2_5, n5_0, n10_0
1627567167, 2, 12, 15, 2.0, 12.0, 15.0, 5.70, 1.86, 0.68, 0.34, 0.00, 0.00
1627567187, 2, 8, 8, 2.0, 8.0, 8.0, 3.39, 1.13, 0.23, 0.09, 0.00, 0.00
1627567207, 1, 1, 1, 1.0, 1.0, 1.0, 4.26, 1.39, 0.12, 0.00, 0.00, 0.00
1627567227, 2, 2, 2, 2.0, 2.0, 2.0, 3.63, 1.21, 0.03, 0.00, 0.00, 0.00
"""
Read PMSx003 sensor on /dev/ttyUSB0
and MCU680 sensor on /dev/ttyUSB1

Read 4 samples from each sensor, one sample every 20 seconds,
and print the observations on different formats.
"""

from pms.core import SensorReader

pms = SensorReader("PMSx003", "/dev/ttyUSB0", interval=20, samples=4)
bme = SensorReader("MCU680", "/dev/ttyUSB1", interval=20, samples=4)


print("\nPMSx003 and MCU680, 4 samples each on default formats")
with pms, bme:
    for pm, bm in zip(pms(), bme()):
        print(pm)
        print(bm)

print("\nPMSx003 and MCU680, 4 samples each on CSV format")
with pms, bme:
    for pm, bm in zip(pms(), bme()):
        print(f"PMSx003, {pm:csv}, MCU680, {bm:csv}")

print("\nPMSx003 and MCU680, 4 samples each on CSV format with header")
with pms, bme:
    print_header = True
    for pm, bm in zip(pms(), bme()):
        if print_header:
            print(f"PMSx003, {pm:header}, MCU680, {bm:header}")
            print_header = False
        print(f"PMSx003, {pm:csv}, MCU680, {bm:csv}")
PMSx003 and MCU680, 4 samples each on default formats
2021-07-29 16:01:34: PM1 1.0, PM2.5 12.0, PM10 13.0 μg/m3
2021-07-29 16:01:36: Temp. 25.1 °C, Rel.Hum. 48.3 %, Press 988.94 hPa, 463.6 kΩ
2021-07-29 16:01:54: PM1 1.0, PM2.5 5.0, PM10 5.0 μg/m3
2021-07-29 16:01:58: Temp. 25.1 °C, Rel.Hum. 48.3 %, Press 989.00 hPa, 464.9 kΩ
2021-07-29 16:02:14: PM1 0.0, PM2.5 0.0, PM10 1.0 μg/m3
2021-07-29 16:02:20: Temp. 25.1 °C, Rel.Hum. 48.2 %, Press 988.98 hPa, 467.2 kΩ
2021-07-29 16:02:34: PM1 0.0, PM2.5 0.0, PM10 1.0 μg/m3
2021-07-29 16:02:42: Temp. 25.1 °C, Rel.Hum. 48.3 %, Press 988.98 hPa, 467.5 kΩ

PMSx003 and MCU680, 4 samples each on CSV format
PMSx003, 1627567375, 1, 10, 12, 1.0, 10.0, 12.0, 4.53, 1.44, 0.56, 0.30, 0.00, 0.00, MCU680, 1627567378, 25.1, 48.2, 988.94, 257, 28, 469.8, 204
PMSx003, 1627567395, 1, 6, 7, 1.0, 6.0, 7.0, 4.86, 1.52, 0.16, 0.09, 0.00, 0.00, MCU680, 1627567400, 25.0, 48.5, 988.98, 257, 27, 470.8, 204
PMSx003, 1627567415, 2, 3, 3, 2.0, 3.0, 3.0, 2.37, 0.75, 0.03, 0.00, 0.00, 0.00, MCU680, 1627567421, 25.1, 48.2, 988.94, 257, 17, 475.8, 204
PMSx003, 1627567435, 0, 0, 0, 0.0, 0.0, 0.0, 2.97, 0.92, 0.03, 0.03, 0.00, 0.00, MCU680, 1627567443, 25.0, 48.2, 989.00, 257, 27, 474.1, 203

PMSx003 and MCU680, 4 samples each on CSV format with header
PMSx003, time, raw01, raw25, raw10, pm01, pm25, pm10, n0_3, n0_5, n1_0, n2_5, n5_0, n10_0, MCU680, time, temp, rhum, pres, IAQ_acc, IAQ, gas, alt
PMSx003, 1627567457, 1, 10, 12, 1.0, 10.0, 12.0, 4.50, 1.46, 0.60, 0.30, 0.00, 0.00, MCU680, 1627567459, 25.1, 48.2, 989.00, 257, 30, 472.8, 203
PMSx003, 1627567477, 2, 7, 7, 2.0, 7.0, 7.0, 3.87, 1.29, 0.24, 0.09, 0.00, 0.00, MCU680, 1627567481, 25.1, 48.2, 988.94, 257, 30, 474.5, 204
PMSx003, 1627567497, 1, 2, 2, 1.0, 2.0, 2.0, 3.06, 1.02, 0.10, 0.00, 0.00, 0.00, MCU680, 1627567503, 25.1, 48.1, 989.00, 258, 34, 473.1, 203
PMSx003, 1627567517, 0, 0, 0, 0.0, 0.0, 0.0, 2.16, 0.72, 0.00, 0.00, 0.00, 0.00, MCU680, 1627567525, 25.1, 47.9, 988.96, 259, 50, 467.8, 204

Observation data fields

Each sensor provides different data fields. The pms -m SENSOR_MODEL info command will provide information about data fields and their units. The following table shows all possible data fields and the type provided by each sensor:

--sensor-model pm01 pm25 pms04 pm10 pm100 raw01 raw25 raw10
PMS3003 int int int int int int
PMSx003 int int int int int int
PMS5003S int int int int int int
PMS5003ST int int int int int int
PMS5003T int int int int int int
SDS01x float float
SDS198 int
HPMA115S0 int int
HPMA115C0 int int int int
SPS30 float float float float
ZH0xx int int int
MHZ19B
MCU680
--sensor-model n0_3 n0_5 n1_0 n2_5 n4_0 n5_0 n10_0
PMS3003 float float float float float float
PMSx003 float float float float float float
PMS5003S float float float float float float
PMS5003ST float float float float float float
PMS5003T float float float float
SDS01x
SDS198
HPMA115S0
HPMA115C0
SPS30 float float float float float
ZH0xx
MHZ19B
MCU680
--sensor-model time temp rhum pres HCHO CO2
PMS3003 int
PMSx003 int
PMS5003S int int
PMS5003ST int float float int
PMS5003T int float float
SDS01x int
SDS198 int
HPMA115S0 int
HPMA115C0 int
SPS30 int
ZH0xx int
MHZ19B int int
MCU680 int float float float
--sensor-model diam IAQ_acc IAQ gas alt
PMS3003
PMSx003
PMS5003S
PMS5003ST
PMS5003T
SDS01x
SDS198
HPMA115S0
HPMA115C0
SPS30 float
ZH0xx
MHZ19B
MCU680 int int int int

On the previous example, obs is a dataclasses.dataclass instance which an be inspected as follows

"""Inspect sensor data fields"""

from dataclasses import fields
from typing import Dict

from pms.core import Sensor
from pms.core.types import ObsData


def field_types(obs: ObsData) -> Dict[str, str]:
    """return a dictionary containing the type of each data field"""
    return {field.name: field.type.__name__ for field in fields(obs)}


for sensor in Sensor:
    print(sensor)
    print(field_types(sensor.Data))
HPMA115C0
{'time': 'int', 'pm01': 'int', 'pm25': 'int', 'pm04': 'int', 'pm10': 'int'}
HPMA115S0
{'time': 'int', 'pm25': 'int', 'pm10': 'int'}
MCU680
{'time': 'int', 'temp': 'float', 'rhum': 'float', 'pres': 'float', 'IAQ_acc': 'int', 'IAQ': 'int', 'gas': 'int', 'alt': 'int'}
MHZ19B
{'time': 'int', 'CO2': 'int'}
PMS3003
{'time': 'int', 'raw01': 'int', 'raw25': 'int', 'raw10': 'int', 'pm01': 'int', 'pm25': 'int', 'pm10': 'int'}
PMS5003S
{'time': 'int', 'raw01': 'int', 'raw25': 'int', 'raw10': 'int', 'pm01': 'int', 'pm25': 'int', 'pm10': 'int', 'n0_3': 'float', 'n0_5': 'float', 'n1_0': 'float', 'n2_5': 'float', 'n5_0': 'float', 'n10_0': 'float', 'HCHO': 'float'}
PMS5003ST
{'time': 'int', 'raw01': 'int', 'raw25': 'int', 'raw10': 'int', 'pm01': 'int', 'pm25': 'int', 'pm10': 'int', 'n0_3': 'float', 'n0_5': 'float', 'n1_0': 'float', 'n2_5': 'float', 'n5_0': 'float', 'n10_0': 'float', 'HCHO': 'float', 'temp': 'float', 'rhum': 'float'}
PMS5003T
{'time': 'int', 'raw01': 'int', 'raw25': 'int', 'raw10': 'int', 'pm01': 'int', 'pm25': 'int', 'pm10': 'int', 'n0_3': 'float', 'n0_5': 'float', 'n1_0': 'float', 'n2_5': 'float', 'temp': 'float', 'rhum': 'float'}
PMSx003
{'time': 'int', 'raw01': 'int', 'raw25': 'int', 'raw10': 'int', 'pm01': 'int', 'pm25': 'int', 'pm10': 'int', 'n0_3': 'float', 'n0_5': 'float', 'n1_0': 'float', 'n2_5': 'float', 'n5_0': 'float', 'n10_0': 'float'}
SDS01x
{'time': 'int', 'pm25': 'float', 'pm10': 'float'}
SDS198
{'time': 'int', 'pm100': 'int'}
SPS30
{'time': 'int', 'pm01': 'float', 'pm25': 'float', 'pm04': 'float', 'pm10': 'float', 'n0_5': 'float', 'n1_0': 'float', 'n2_5': 'float', 'n4_0': 'float', 'n10_0': 'float', 'diam': 'float'}
ZH0xx
{'time': 'int', 'pm25': 'int', 'pm10': 'int', 'pm01': 'int'}

Observation formats

As the example at the top of the page shows, the obs object has custom formats. Observations from different sensors support different formats. The following table shows all different formats

--sensor-model csv header pm num raw cf atm hcho co2 bme bsec
PMS3003
PMSx003
PMS5003T
PMS5003S
PMS5003ST
SDS01x
SDS198
HPMA115S0
HPMA115C0
SPS30
ZH0xx
MHZ19B
MCU680