Understanding PurpleAir Serial Output

When using the PurpleAir Utility or a Classic-SD sensor modified to record SD data every second data is not in CSV format. Instead, it is in a custom format described below, which may require additional processing to use.

Data From WiFi Capable Sensors

1-second Reports

Every second, one of the laser counters will report. Five reports will be recorded from channel A, then five reports from channel B. This process repeats until the next 2-minute report. This 2-minute report is the averaged data that is uploaded to our API as “Real-time” data. This is the same “Real-time” data you will see for sensors on our map. Intermittent reports from gas sensor (if gas sensor applicable) are recorded about every three seconds, and will appear interspersed with the 1-second reports from the laser counters. Example reports are found below.

Channel A report
.0h10:54.538 2022/12/30T22:10:10z: DATA A(34),82,14,29,859.35,0.03,17872,-57,654,222,508,955,147,338,636,505,388,38928,11925,4614,1296,592,368,25.00

Channel A report
.0h10:55.456 2022/12/30T22:10:11z: DATA A(35),82,14,29,859.35,0.03,17872,-57,655,223,508,967,148,338,644,505,388,38850,11927,4602,1318,610,372,25.00

Gas Sensor Report
.0h10:56.598 2022/12/30T22:10:12z: p:85936.06 gasR:12917166.00 iaq:25.00 iaqA:0 T:28.12(28.18) H:14.92(14.87) sIaq:25.00 co2Eq:500.00 breathVocEq:0.50

Channel B report
.0h10:57.350 2022/12/30T22:10:13z: DATA B(34),82,14,29,859.36,0.03,17872,-56,657,205,485,1018,136,323,678,490,373,35928,11126,4122,1506,756,376,25.00

Channel B report
.0h10:58.267 2022/12/30T22:10:14z: DATA B(35),82,14,29,859.36,0.02,17872,-56,658,203,490,1044,135,326,695,493,376,35853,11090,4177,1570,790,390,25.00

1-second Report Breakdown

Channel A Report

.0h11:24.761 2022/12/30T22:10:40z: DATA A(48),82,14,29,859.38,0.03,17872,-59,684,221,496,874,146,330,581,497,380,38442,11710,4418,1206,506,284,25.00

Name Value
Uptime (written out; includes milliseconds) .0h11:24.761
UTCDateTime 2022/12/30T22:10:40z
Channel (number of samples from channel since last upload) DATA A(48)
current_temp_f 82
current_humidity 14
current_dewpoint_f 29
pressure 859.38
adc 0.03
mem 17872
rssi -59
uptime 684
pm1_0_cf_1 221
pm2_5_cf_1 496
pm10_0_cf_1 874
pm1_0_atm 146
pm2_5_atm 330
pm10_0_atm 581
pm2.5_aqi_cf_1 497
pm2.5_aqi_atm 380
p_0_3_um 38442
p_0_5_um 11710
p_1_0_um 4418
p_2_5_um 1206
p_5_0_um 506
p_10_0_um 284
gas 25.00

2-minute Report

This data is what is considered “Real-time” on the Map and API

Every two minutes, the sensor attempts to upload data to PurpleAir, even if it isn’t connected to WiFi. If uploading data fails, an Error: -1 message will be output.

Below is an example of the three sections of a 2-minute report. Section 1 is the raw 2-minute data. This data is used to create the 2-minute report that is uploaded to the API (Section 3). Sections 2 and 3 will be broken down below the example.

1.

{“SensorId”:“xx:xx:xx:xx:xx:xx”,“DateTime”:“2022/12/30T22:00:59z”,“Geo”:“PurpleAir-6e32”,“Mem”:12345,“memfrag”:3,“memfb”:35824,“memcs”:2464,“Id”:1,“lat”:0.000000,“lon”:0.000000,“Adc”:“nan”,“loggingrate”:15,“place”:“”,“version”:“7.02”,“uptime”:103,“rssi”:-62,“period”:103,“httpsuccess”:1,“httpsends”:1,“hardwareversion”:“3.0”,“hardwarediscovered”:“3.0+OPENLOG+NO-DISK+RV3028+BME680+PMSX003-A+PMSX003-B”,“current_temp_f”:82,“current_humidity”:15,“current_dewpoint_f”:30,“pressure”:859.56,“current_temp_f_680”:82,“current_humidity_680”:15,“current_dewpoint_f_680”:30,“pressure_680”:859.56,“gas_680”:“nan”,“p25aqic_b”:“rgb(0,228,0)”,“pm2.5_aqi_b”:0,“pm1_0_cf_1_b”:0.00,“p_0_3_um_b”:72.33,“pm2_5_cf_1_b”:0.00,“p_0_5_um_b”:22.96,“pm10_0_cf_1_b”:0.00,“p_1_0_um_b”:3.38,“pm1_0_atm_b”:0.00,“p_2_5_um_b”:0.22,“pm2_5_atm_b”:0.00,“p_5_0_um_b”:0.00,“pm10_0_atm_b”:0.00,“p_10_0_um_b”:0.00,“p25aqic”:“rgb(0,228,0)”,“pm2.5_aqi”:1,“pm1_0_cf_1”:0.00,“p_0_3_um”:128.02,“pm2_5_cf_1”:0.19,“p_0_5_um”:30.47,“pm10_0_cf_1”:0.33,“p_1_0_um”:7.02,“pm1_0_atm”:0.00,“p_2_5_um”:3.23,“pm2_5_atm”:0.19,“p_5_0_um”:0.56,“pm10_0_atm”:0.33,“p_10_0_um”:0.00,“wlstate”:“Connected”,“status_0”:2,“status_1”:2,“status_2”:2,“status_3”:0,“status_4”:0,“status_5”:0,“status_7”:0,“status_8”:0,“status_9”:0}

2.

UTCDateTime,mac_address,firmware_ver,hardware,current_temp_f,current_humidity,current_dewpoint_f,pressure,adc,mem,rssi,uptime,pm1_0_cf_1,pm2_5_cf_1,pm10_0_cf_1,pm1_0_atm,pm2_5_atm,pm10_0_atm,pm2.5_aqi_cf_1,pm2.5_aqi_atm,p_0_3_um,p_0_5_um,p_1_0_um,p_2_5_um,p_5_0_um,p_10_0_um,pm1_0_cf_1_b,pm2_5_cf_1_b,pm10_0_cf_1_b,pm1_0_atm_b,pm2_5_atm_b,pm10_0_atm_b,pm2.5_aqi_cf_1_b,pm2.5_aqi_atm_b,p_0_3_um_b,p_0_5_um_b,p_1_0_um_b,p_2_5_um_b,p_5_0_um_b,p_10_0_um_b,gas

3.

2022/12/30T22:01:01z,xx:xx:xx:xx:xx:xx,7.02,3.0+OPENLOG+NO-DISK+RV3028+BME680+PMSX003-A+PMSX003-B,82,15,30,859.56,nan,36848,-63,105,0.00,0.19,0.33,0.00,0.19,0.33,1,1,128.02,30.47,7.02,3.23,0.56,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,72.33,22.96,3.38,0.22,0.00,0.00,nan

2 and 3 Side-by-Side (from 2-min report)

Below is a table showing Section 2 (headers) next to Section 3 (values).

2. Name 3. Value
UTCDateTime 2022/12/30T22:01:01z
mac_address xx:xx:xx:xx:xx:xx
firmware_ver 7.02
hardware 3.0+OPENLOG+NO-DISK+RV3028+BME680+PMSX003-A+PMSX003-B
current_temp_f 82
current_humidity 15
current_dewpoint_f 30
pressure 859.56
adc NaN
mem 36848
rssi -63
uptime 105
pm1_0_cf_1 0.00
pm2_5_cf_1 0.19
pm10_0_cf_1 0.33
pm1_0_atm 0.00
pm2_5_atm 0.19
pm10_0_atm 0.33
pm2.5_aqi_cf_1 1
pm2.5_aqi_atm 1
p_0_3_um 128.02
p_0_5_um 30.47
p_1_0_um 7.02
p_2_5_um 3.23
p_5_0_um 0.56
p_10_0_um 0.00
pm1_0_cf_1_b 0.00
pm2_5_cf_1_b 0.00
pm10_0_cf_1_b 0.00
pm1_0_atm_b 0.00
pm2_5_atm_b 0.00
pm10_0_atm_b 0.00
pm2.5_aqi_cf_1_b 0
pm2.5_aqi_atm_b 0
p_0_3_um_b 72.33
p_0_5_um_b 22.96
p_1_0_um_b 3.38
p_2_5_um_b 0.22
p_5_0_um_b 0.00
p_10_0_um_b 0.00
gas NaN

Data From the PurpleAir Pixel

Data from the Pixel is also available via USB serial. The following is some example output starting from soon after the Pixel is first plugged in:

~git branch: main
~git commit: 39badc0e5beb434279403e1f0f40d24d1733ca70
~committed at: 2025-04-01T19:03:01-06:00
~generated at: 2025-04-01T19:03:20-06:00
~firmware version: 1.0.1

=====================================================================
=                          PurpleAir PIXEL                          =
=                    Board ID: 29C263A4261B19AE                     =
=                  https://www.purpleair.com/pixel                  =
=====================================================================

BOSCH BMV080 parameters:
  Volumetric Mass Density:  3.40 kg/m^3
  Integration Time:         2.0 s
  Power Mode:               2 (PM in the range of 0.02 - 3.0 m/s)
  Obstruction Detection:    false
  Vibration Filtering:      true
  Temperature Compensation: true
  Sensor ID:                BPC90206441C

uptime_millis,us_epa_aqi,pm2.5,pm2.5_raw,illuminance_percentage
3603,0,0.0,nan,86
4784,0,0.0,nan,79
5954,0,0.0,nan,80
7099,0,0.0,nan,79
7721,0,0.0,nan,80
8515,0,0.0,nan,80
9989,22,5.2,26.0,79
10801,59,15.8,53.0,79
11989,72,22.0,31.0,78
13177,72,22.0,nan,79
13821,72,22.0,nan,78
15059,74,22.6,3.0,79
16249,74,22.6,0.0,79
16893,74,22.6,nan,78
18066,74,22.6,nan,79

Meta Information

Information about the Pixel and its firmware is output shortly after booting up. In order to grab this information, you’ll need to connect to USB serial shortly after the device very first plugs in and powers on.

Items beginning with "~', such as “firmware version” and “generated at” pertain to the specific firmware version present on the device.

“BOSCH BMV080 parameters” refer to parameters which affect PM2.5 readings. Presently, these aren’t configurable but may be in a future firmware update.

CSV Data

After meta-information is output and the Pixel finishes booting up, it will output measured data in CSV format. The table below describes what each CSV field means:

CSV Field Meaning
uptime_millis How long the sensor has been running since it powered on, presented in milliseconds.
us_epa_aqi The US EPA PM2.5 AQI calculated using the pm2.5 field. A change in the us_epa_aqi may not be immediately reflected on the LEDs, as smoothing is applied to prevent abrupt color changes.
pm2.5 PM2.5 in µg/m³. This averages over the past few values, omitting data that is reported as being out of range.
pm2.5_raw A PM2.5 reading in µg/m³ taken directly from the Bosch BMV080. If this value is reported as being “out of range”, nan is output instead.
illuminance_percentage A percentage value between 0 and 100, indicating the illuminance measured by the Pixel’s light sensor. The illuminance percentage affects how bright the LEDs are.
1 Like