PurpleAirMatterConverter module
===============================
.. contents::
:local:
:depth: 2
Overview
--------
The ``purpleair_api.PurpleAirMatterConverter`` module maps PurpleAir sensor readings to
Matter-compatible device type structures per the **Matter 1.5.1 Core
Specification** (Connectivity Standards Alliance, 2024).
This enables PurpleAir sensors to be exposed through any Matter-compatible
bridge — including Apple Home, Google Home, Amazon Alexa, Samsung SmartThings,
and Home Assistant — by providing data in the canonical format those platforms
consume.
.. note::
This module generates *Matter device data structures*. It does **not**
implement the full Matter protocol stack. A Matter bridge (e.g.
``python-matter-server`` or the Home Assistant Matter integration) is
required to actually commission and serve these devices on a Matter network.
References
----------
- `Matter 1.5.1 Core Specification `_
— Connectivity Standards Alliance, 2024.
- `Matter Air Quality Sensor Device Type
`_
— Section 11.3, Matter Device Library.
- `Air Quality Measurement Cluster (0x005D) `_
— Matter.js implementation reference.
- `Temperature Measurement Cluster (0x0402)
`_
— Matter.js implementation reference.
- `Relative Humidity Measurement Cluster (0x0405)
`_
— Matter.js implementation reference.
- `Barometric Pressure Measurement Cluster (0x0403)
`_
— Matter.js implementation reference.
- `EPA AQI Technical Assistance Document (2012 revision)
`_
— AQI breakpoint table and formula.
- `python-matter-server
`_
— Reference Python Matter bridge server.
Installation
------------
``PurpleAirMatterConverter`` is included with the ``purpleair_api`` package.
No additional dependencies are required beyond ``requests``.
.. code-block:: bash
pip install purpleair_api
Quick Start
-----------
.. code-block:: python
from purpleair_api.PurpleAirReadAPI import PurpleAirReadAPI
from purpleair_api.PurpleAirMatterConverter import PurpleAirMatterConverter
# Fetch sensor data from PurpleAir
pa = PurpleAirReadAPI("YOUR_PURPLEAIR_READ_API_KEY")
raw = pa.request_sensor_data(282168)
# Convert to Matter Air Quality Sensor structure
matter_device = PurpleAirMatterConverter.to_air_quality_sensor(raw)
print(matter_device["device_type"]) # {'id': 45, 'label': 'Air Quality Sensor', ...}
print(matter_device["air_quality_summary"]) # {'epa_aqi': 68, 'epa_category': 'Moderate', ...}
Field Mapping
-------------
The following table shows how PurpleAir API fields map to Matter clusters
and attributes.
.. list-table::
:header-rows: 1
:widths: 30 30 20 20
* - PurpleAir Field
- Matter Cluster
- Matter Attribute
- Unit
* - ``pm2.5``
- Air Quality Measurement (0x005D)
- ``measuredValue`` (scaled ×100)
- µg/m³
* - ``pm1.0``
- Air Quality Measurement (0x005D)
- ``pm1Density`` (scaled ×100)
- µg/m³
* - ``pm10.0``
- Air Quality Measurement (0x005D)
- ``pm10Density`` (scaled ×100)
- µg/m³
* - ``voc``
- Air Quality Measurement (0x005D)
- ``vocDensity`` (scaled ×100)
- µg/m³
* - *(computed)*
- Air Quality Measurement (0x005D)
- ``airQuality`` enum
- category
* - *(computed)*
- Air Quality Measurement (0x005D)
- ``aqiRating`` enum
- rating
* - ``temperature`` (°F)
- Temperature Measurement (0x0402)
- ``measuredValue`` (scaled ×100)
- °C
* - ``humidity``
- Relative Humidity Measurement (0x0405)
- ``measuredValue`` (scaled ×100)
- %
* - ``pressure`` (PSI)
- Barometric Pressure Measurement (0x0403)
- ``measuredValue`` (scaled ×10)
- kPa
Matter Scaled-Integer Convention
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Matter clusters store numeric values as **scaled integers** to avoid
floating-point complexity in the protocol:
- Temperature: ``round(celsius × 100)`` — e.g., 23.45 °C → **2345**
- Humidity: ``round(percent × 100)`` — e.g., 45.6 % → **4560**
- Pressure: ``round(kPa × 10)`` — e.g., 101.3 kPa → **1013**
- PM densities: ``round(ug_m3 × 100)`` — e.g., 12.3 µg/m³ → **1230**
The ``_raw`` fields in the output dictionary retain the original floating-point
values for debugging and display purposes.
EPA AQI Computation
~~~~~~~~~~~~~~~~~~~
PurpleAir provides raw PM2.5 readings but not the EPA Air Quality Index.
:class:`EpaAqiCalculator` applies the EPA's piecewise-linear formula:
.. code-block:: text
AQI = ((I_high - I_low) / (C_high - C_low)) × (C - C_low) + I_low
Where:
- **C** = PM2.5 24-hour average concentration (µg/m³)
- **C_low, C_high** = concentration breakpoints from the EPA table
- **I_low, I_high** = AQI breakpoints corresponding to ``C_low, C_high``
Matter Air Quality Rating is then derived from the computed AQI:
.. list-table::
:header-rows: 1
* - AQI Range
- EPA Category
- Matter ``airQuality`` Value
* - 0–50
- Good
- 1 (Excellent)
* - 51–100
- Moderate
- 2 (Good)
* - 101–150
- Unhealthy for Sensitive Groups
- 3 (Fair)
* - 151–200
- Unhealthy
- 4 (Poor)
* - 201–300
- Very Unhealthy
- 5 (Very Poor)
* - 301–500
- Hazardous
- 6 (Extremely Poor)
* - < 0 / unknown
- —
- 0 (Unknown)
API Reference
-------------
.. automodule:: PurpleAirMatterConverter
:members:
:undoc-members:
:show-inheritance:
Example — All Device Types
--------------------------
.. code-block:: python
from purpleair_api.PurpleAirReadAPI import PurpleAirReadAPI
from purpleair_api.PurpleAirMatterConverter import PurpleAirMatterConverter
pa = PurpleAirReadAPI("YOUR_READ_API_KEY")
data = pa.request_sensor_data(282168)
# Air Quality Sensor (full)
aqs = PurpleAirMatterConverter.to_air_quality_sensor(data)
# Temperature-only sensor
tmp = PurpleAirMatterConverter.to_temperature_sensor(data)
# Environmental sensor (temp + humidity + pressure)
env = PurpleAirMatterConverter.to_environmental_sensor(data)
# EPA AQI directly
from purpleair_api.PurpleAirMatterConverter import EpaAqiCalculator
aqi = EpaAqiCalculator.pm25_to_aqi(data["sensor"]["pm2.5"])
print(f"AQI: {aqi} — {EpaAqiCalculator.aqi_to_epa_category(aqi)}")