PurpleAirMatterDataLogger module¶
Overview¶
PurpleAirMatterDataLogger converts PurpleAir sensor readings to JSON shaped
like a Matter 1.5.1 Air Quality Sensor device type (0x002D). The conversion
is provided by purpleair_api.PurpleAirMatterConverter. This logger does not
implement Matter transport, discovery, commissioning, fabrics, or certification.
To publish this JSON as commissionable Matter devices for Google Home or Home Assistant, use the proposed companion bridge described in JSON to Matter bridge.
Continuous HTTP service¶
The command-line interface polls configured sensors, retains the latest
successful reading for each sensor, and serves the converted devices over HTTP.
The default bind address is 127.0.0.1:9855.
Cloud sensors require a PurpleAir Read API key and a configuration containing
sensor_indexes:
python3 -m purpleair_data_logger.PurpleAirMatterDataLogger \
-paa_read_key YOUR_READ_KEY \
-paa_multiple_sensor_request_json_file \
./sample_json_config_files/sample_matter_request_json_file.json \
--matter-only
Local-network sensors use a configuration containing sensor_ip_list and do
not require a cloud API key:
python3 -m purpleair_data_logger.PurpleAirMatterDataLogger \
-paa_local_sensor_request_json_file \
./sample_json_config_files/sample_local_sensor_request_json_file.json \
--matter-only
Only one JSON configuration file may be supplied. The logger clamps polling intervals below 60 seconds to 60 seconds. An individual cloud polling failure is isolated so other configured sensors continue updating, and the HTTP API retains the failed sensor’s last-known-good value.
One-shot conversion¶
Call PurpleAirMatterDataLogger.run_once() to convert cloud sensor readings
without starting the HTTP server or polling loop:
from purpleair_data_logger.PurpleAirMatterDataLogger import (
PurpleAirMatterDataLogger,
)
matter_logger = PurpleAirMatterDataLogger(
PurpleAirApiReadKey="YOUR_READ_KEY",
)
devices = matter_logger.run_once([123456])
Configuration¶
Continuous cloud mode recognizes these fields:
sensor_indexesRequired list of integer PurpleAir sensor indexes.
sensor_namesOptional object mapping sensor indexes to display-name overrides. JSON object keys are strings and are converted to integers while loading.
read_keysOptional object mapping private sensor indexes to sensor Read keys.
poll_interval_secondsPoll delay. Values below 60 are clamped to 60.
http_hostandhttp_portHTTP bind address and port. Defaults are
127.0.0.1and9855.matter_onlyDescribes the Matter-only service mode. The current class has no raw-data persistence sink, so this option does not change persistence behavior.
Continuous local mode requires sensor_ip_list and accepts the same polling
and HTTP fields. Group configuration is not supported because group_id is
not resolved into sensor indexes. The standard single-sensor sample uses
sensor_index rather than the required sensor_indexes list and therefore
cannot be used unchanged.
HTTP API¶
GET /orGET /healthReturns
{"status": "ok", "sensor_count": N}.GET /matter/sensorsReturns all current devices and their sensor indexes, plus a
count.GET /matter/sensor/<sensor_index>Returns one device. A non-integer index returns 400 and an unavailable index returns 404. Query parameters do not affect route matching.
Security¶
The HTTP service does not provide authentication or TLS. Keep the default
loopback bind unless another trusted network layer protects access. Binding to
0.0.0.0 exposes the service to reachable networks.
Python API¶
Copyright 2025 carlkidcrypto, All rights reserved.
Matter Data Logger — exposes PurpleAir sensors as Matter device type structures via a lightweight HTTP API.
- Performs two roles:
Fetches raw sensor data from PurpleAir on a configurable interval.
Converts readings to Matter device type JSON and exposes them via HTTP.
Designed to run as a long-lived daemon (forever loop) or as a
one-shot converter when poll_interval_seconds is omitted.
When calling validate_parameters_and_run() without a JSON config file,
pass sensor_indexes via the constructor.
Usage:
from purpleair_data_logger.PurpleAirMatterDataLogger import (
PurpleAirMatterDataLogger,
)
logger = PurpleAirMatterDataLogger(
PurpleAirApiReadKey="YOUR_READ_KEY",
PurpleAirApiIpv4Address=["192.168.1.100"],
sensor_indexes=[123456],
poll_interval_seconds=65,
http_port=9855,
)
logger.validate_parameters_and_run()
- References:
Matter 1.5.1 Core Specification (CSA, 2024) <https://csa-iot.org/developer-resource/specifications/>
Air Quality Sensor Device Type (Device Type 0x002D)
Air Quality Measurement Cluster (Cluster 0x005D)
Temperature Measurement Cluster (Cluster 0x0402)
Relative Humidity Measurement Cluster (Cluster 0x0405)
Barometric Pressure Measurement Cluster (Cluster 0x0403)
- class PurpleAirMatterDataLogger.CachedSensor(data: dict[str, Any], last_seen: float, is_stale: bool = False)¶
Bases:
objectCached sensor reading and timestamp for offline and stale state handling.
- data: dict[str, Any]¶
- is_stale: bool = False¶
- last_seen: float¶
- class PurpleAirMatterDataLogger.PurpleAirMatterDataLogger(PurpleAirApiReadKey: str | None = None, PurpleAirApiWriteKey: str | None = None, PurpleAirApiIpv4Address: list[str] | None = None, poll_interval_seconds: int = 65, http_port: int = 9855, http_host: str = '127.0.0.1', sensor_indexes: list[int] | None = None, sensor_names: dict[int, str] | None = None, read_keys: dict[int, str] | None = None, matter_only: bool = False, offline_grace_seconds: int = 600, max_retries: int = 3, retry_backoff_factor: float = 0.05)¶
Bases:
PurpleAirDataLoggerFetches PurpleAir sensors and exposes them as Matter device type JSON via an embedded HTTP server.
Inherits from
PurpleAirDataLoggerand reuses its polling loop infrastructure. The run methods are overridden to perform PurpleAir → Matter conversion instead of database insertion.- Matter mode (default):
Runs a forever loop: fetch → convert → expose via HTTP. The
poll_interval_secondsconfig field controls the loop delay.- One-shot mode:
Call
run_once()directly to convert current readings without starting the HTTP server or the polling loop.- Matter-only mode (
--matter-onlyCLI flag): When invoked via CLI with the
--matter-onlyflag, the HTTP server is started without an associated database/CSV sink — only the Matter conversion runs, suitable for feeding a Matter bridge (e.g.python-matter-serveror Home Assistant Matter integration).
- Parameters:
PurpleAirApiReadKey (str) – PurpleAir Read API key.
PurpleAirApiWriteKey (str) – PurpleAir Write API key (optional).
PurpleAirApiIpv4Address (list) – List of IPv4 addresses for local sensor access (optional).
poll_interval_seconds (int) – How often to poll PurpleAir (default 65). Must be >= 60. Ignored in one-shot mode.
http_port (int) – HTTP server port (default 9855).
http_host (str) – HTTP server bind host (default 127.0.0.1).
sensor_indexes (list[int]) – Optional constructor defaults for sensors to poll when no config file is provided.
sensor_names (dict[int, str]) – Optional constructor defaults for sensor display names when no config file is provided.
read_keys (dict[int, str]) – Optional constructor defaults for per-sensor read keys when no config file is provided.
matter_only (bool) – If True, the forever loop runs without any database or file sink (Matter conversion only).
- run_once(sensor_indexes: list[int], sensor_names: dict[int, str] | None = None, primary_keys: dict[int, str] | None = None) dict[int, dict[str, Any]]¶
Fetch and convert sensors once (no HTTP server, no forever loop).
Returns the current Matter device map without starting any background service. Suitable for scripting or one-off exports.
- Parameters:
sensor_indexes – List of PurpleAir sensor indexes to poll.
sensor_names – Optional dict mapping sensor_index → display name.
primary_keys – Optional dict mapping sensor_index → Read key.
- Returns:
Dict mapping sensor_index → Matter device dict.
- validate_parameters_and_run(paa_multiple_sensor_request_json_file: str | None = None, paa_single_sensor_request_json_file: str | None = None, paa_group_sensor_request_json_file: str | None = None, paa_local_sensor_request_json_file: str | None = None, matter_only: bool | None = None) None¶
Main entry point for
PurpleAirMatterDataLogger.Accepts the same JSON config file arguments as the base class, but all four are mutually exclusive (only one config file per run). If no config file is provided, the logger runs with defaults from the constructor.
- Parameters:
paa_multiple_sensor_request_json_file (str) – Path to a multi-sensor config file. Required fields:
sensor_indexes(list of ints),poll_interval_seconds(int, >= 60),http_port(int, optional),http_host(str, optional),sensor_names(dict, optional),read_keys(dict, optional).paa_single_sensor_request_json_file (str) – Path to a single-sensor config file. Same fields as the multi-sensor file.
paa_group_sensor_request_json_file (str) – Path to a group config file (uses
group_idto fetch sensors).paa_local_sensor_request_json_file (str) – Path to a local-only config file (uses
ipv4_addressfilters).matter_only (bool) – If True, disables any non-Matter side effects (e.g. raw data persistence). Overrides the constructor value.
- PurpleAirMatterDataLogger.main(argv: list[str] | None = None) None¶
Run the Matter data logger from the command line.