Use Case: Urban Air Quality Monitoring -> OGC SensorThings API
Status: fully modelled - all artifacts ship with the repository as
reference artifacts under schemas/usecases/luftqualitaet-sta/. They can
be imported through the ModelForge facade of a host application.
Scenario
Urban air-quality monitoring stations continuously record:
- Pollutant concentrations (NO2, PM2.5, CO)
- Accompanying meteorological data (temperature, humidity)
- GPS position
The raw data arrives via MQTT. In parallel, station master data (name, operator, calibration factors) resides in a PostgreSQL database.
The goal is to expose the measurement data as an OGC SensorThings APISensorThings APIA standardized API based on the OGC SensorThings API specification for accessing time series and IoT data. It enables structured retrieval and management of observations and related entities. (FROST), so that STA-compatible clients can retrieve the data.
TAF10 is intentionally not part of this use case. TAF10 is modelled separately as low-voltage grid telemetry in Use Case: TAF10 Low-Voltage Grid Protection.
Data flow
Readings where any pollutant's quality is "bad" (the filter checks
no2.quality, pm25.quality and co.quality individually) are discarded;
"suspect" readings are flagged and forwarded. The enrich step joins station
master data from PostgreSQL by stationId and applies calibration factors. The
fan-out runs one mapping per pollutant, each posting to the FROST
/Observations endpoint.
In parallel (master-data sync, one-off / occasional): PostgreSQL master data is
mapped to STAThing and STADatastream documents and posted to
/FROST-Server/v1.1/Things and /Datastreams.
Data structures
| Element | URN |
|---|---|
| GeoPoint | urn:core:platform:civitas:element:common:GeoPoint:3ak90vqrog:1.0.0 |
| Measurement | urn:core:platform:civitas:element:luftqualitaet:Measurement:k9ta3hkxjf:1.0.0 |
| AirQualityRawReading | urn:core:platform:civitas:element:luftqualitaet:AirQualityRawReading:42iv9tjv0c:1.0.0 |
| StationCalibration | urn:core:platform:civitas:element:luftqualitaet:StationCalibration:aqokf4f3v2:1.0.0 |
| StationMasterData | urn:core:platform:civitas:element:luftqualitaet:StationMasterData:ro0sfbbjfm:1.0.0 |
| STALocation | urn:core:platform:civitas:element:sta:STALocation:vktgfkub6y:1.0.0 |
| STAThing | urn:core:platform:civitas:element:sta:STAThing:1f0bfaterl:1.0.0 |
| STAObservation | urn:core:platform:civitas:element:sta:STAObservation:np3hnkoj04:1.0.0 |
Reference relationships (all via $ref, tracked in the dependency graph):
AirQualityRawReading->Measurement->GeoPointStationMasterData->GeoPoint,StationCalibrationSTAThing->STALocation;STAObservationreferences its FROST Datastream by@iot.id
Mappings
| Mapping | URN |
|---|---|
| StationMasterData -> STAThing | urn:core:platform:civitas:mapping:luftqualitaet:station-to-sta-thing:n34qmfpf7r:1.0.0 |
| Air Quality NO2 -> STAObservation | urn:core:platform:civitas:mapping:luftqualitaet:airquality-no2-to-observation:ca39n9nqqd:1.0.0 |
| Air Quality PM2.5 -> STAObservation | urn:core:platform:civitas:mapping:luftqualitaet:airquality-pm25-to-observation:wkk3xd31h0:1.0.0 |
| Air Quality CO -> STAObservation | urn:core:platform:civitas:mapping:luftqualitaet:airquality-co-to-observation:mgth0uv301:1.0.0 |
The station mapping copies stationName, stationType and metadata into the
STAThing format. The per-pollutant mappings copy $.timestamp to
phenomenonTime/resultTime, the pollutant value to result, and the quality
flag to resultQuality.
Pipeline
urn:core:platform:civitas:pipeline:luftqualitaet:Luftqualitaet-Import:v7v1oagoqd:1.0.0
| Node | Kind | Configuration |
|---|---|---|
| ConsumeMQTT | source | Topic luftqualitaet/readings/+, Element AirQualityRawReading |
| RouteOnContent | filter | Forward when no2.quality, pm25.quality and co.quality are all != "bad" |
| LookupRecord | enrich | Key $.stationId -> PostgreSQL station database |
| Transform NO2 / PM2.5 / CO | mapping | One mapping node per pollutant |
| InvokeHTTP | sink | FROST POST /Observations |
FROST server endpoints
| Endpoint | Description |
|---|---|
GET /FROST-Server/v1.1/Things | All stations |
GET /FROST-Server/v1.1/Datastreams | All data streams |
GET /FROST-Server/v1.1/Observations | All measurements |
GET /FROST-Server/v1.1/ObservedProperties | NO2, PM2.5, CO |
GET /FROST-Server/v1.1/Things(1)/Datastreams | Datastreams of one station |
GET /FROST-Server/v1.1/Datastreams(1)/Observations?$top=10&$orderby=phenomenonTime desc | Latest 10 measurements |
Analogous scenarios ship in schemas/usecases/taf10-grid-sta/ and
schemas/usecases/smartmeter-sta/.