Skip to main content
Version: V2-Next

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 API (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​

Air-quality 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​

ElementURN
GeoPointurn:core:platform:civitas:element:common:GeoPoint:3ak90vqrog:1.0.0
Measurementurn:core:platform:civitas:element:luftqualitaet:Measurement:k9ta3hkxjf:1.0.0
AirQualityRawReadingurn:core:platform:civitas:element:luftqualitaet:AirQualityRawReading:42iv9tjv0c:1.0.0
StationCalibrationurn:core:platform:civitas:element:luftqualitaet:StationCalibration:aqokf4f3v2:1.0.0
StationMasterDataurn:core:platform:civitas:element:luftqualitaet:StationMasterData:ro0sfbbjfm:1.0.0
STALocationurn:core:platform:civitas:element:sta:STALocation:vktgfkub6y:1.0.0
STAThingurn:core:platform:civitas:element:sta:STAThing:1f0bfaterl:1.0.0
STAObservationurn:core:platform:civitas:element:sta:STAObservation:np3hnkoj04:1.0.0

Reference relationships (all via $ref, tracked in the dependency graph):

  • AirQualityRawReading -> Measurement -> GeoPoint
  • StationMasterData -> GeoPoint, StationCalibration
  • STAThing -> STALocation; STAObservation references its FROST Datastream by @iot.id

Mappings​

MappingURN
StationMasterData -> STAThingurn:core:platform:civitas:mapping:luftqualitaet:station-to-sta-thing:n34qmfpf7r:1.0.0
Air Quality NO2 -> STAObservationurn:core:platform:civitas:mapping:luftqualitaet:airquality-no2-to-observation:ca39n9nqqd:1.0.0
Air Quality PM2.5 -> STAObservationurn:core:platform:civitas:mapping:luftqualitaet:airquality-pm25-to-observation:wkk3xd31h0:1.0.0
Air Quality CO -> STAObservationurn: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

NodeKindConfiguration
ConsumeMQTTsourceTopic luftqualitaet/readings/+, Element AirQualityRawReading
RouteOnContentfilterForward when no2.quality, pm25.quality and co.quality are all != "bad"
LookupRecordenrichKey $.stationId -> PostgreSQL station database
Transform NO2 / PM2.5 / COmappingOne mapping node per pollutant
InvokeHTTPsinkFROST POST /Observations

FROST server endpoints​

EndpointDescription
GET /FROST-Server/v1.1/ThingsAll stations
GET /FROST-Server/v1.1/DatastreamsAll data streams
GET /FROST-Server/v1.1/ObservationsAll measurements
GET /FROST-Server/v1.1/ObservedPropertiesNO2, PM2.5, CO
GET /FROST-Server/v1.1/Things(1)/DatastreamsDatastreams of one station
GET /FROST-Server/v1.1/Datastreams(1)/Observations?$top=10&$orderby=phenomenonTime descLatest 10 measurements

Analogous scenarios ship in schemas/usecases/taf10-grid-sta/ and schemas/usecases/smartmeter-sta/.