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_indexes

Required list of integer PurpleAir sensor indexes.

sensor_names

Optional object mapping sensor indexes to display-name overrides. JSON object keys are strings and are converted to integers while loading.

read_keys

Optional object mapping private sensor indexes to sensor Read keys.

poll_interval_seconds

Poll delay. Values below 60 are clamped to 60.

http_host and http_port

HTTP bind address and port. Defaults are 127.0.0.1 and 9855.

matter_only

Describes 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 / or GET /health

Returns {"status": "ok", "sensor_count": N}.

GET /matter/sensors

Returns 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:
  1. Fetches raw sensor data from PurpleAir on a configurable interval.

  2. 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.

Requires purpleair_api >= 1.5.0a1 (includes purpleair_api.PurpleAirMatterConverter). 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.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)

Bases: PurpleAirDataLogger

Fetches PurpleAir sensors and exposes them as Matter device type JSON via an embedded HTTP server.

Inherits from PurpleAirDataLogger and 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_seconds config 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-only CLI flag):

When invoked via CLI with the --matter-only flag, 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-server or 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_id to fetch sensors).

  • paa_local_sensor_request_json_file (str) – Path to a local-only config file (uses ipv4_address filters).

  • 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.