Example Air Quality Sensor - NRCHKB/node-red-contrib-homekit-bridged GitHub Wiki

Properties

Available Properties

To have a real Air Quality Sensor appear in the Home.app showing a Particulate Levels for 2.5 and 10 microns as well as an Air Quality Index based on the US EPA Scale, you can setup a Node-red flow to provide air characteristics value in HomeKit. The following characteristic properties are available for that:

Characteristic Optional/Required Characteristic Properties (to enable property)
AirQuality Required {"AirQuality": 1}
PM2_5Density Optional {"PM2_5Density": 24.5}
PM10Density Optional {"PM10Density": 16.2}
StatusActive Optional {"StatusActive":true}

Details

Characteristic Format Accepted Values Notes
AirQuality uint8 0, 1, 2, 3, 4, 5 Describes the subject assessment of the air quality by an accessory. Valid values are: 0 (unknown), 1 (Excellent), 2 (good), 3 (Fair), 4 (Inferior), 5 (Poor)
PM2_5Density float 0 - 1000 Indicates the current PM2.5 micrometer particulate density in micrograms/m^3
PM10Density float 0 - 1000 Indicates the current PM10 micrometer particulate density in micrograms/m^3
StatusActive bool true/false {"StatusActive":true} / {"StatusActive":false}

Example

These simple examples are meant to be copied into your Node-RED system and adapted to your setup.

Please note: Different from other HomeKit services (e. g. temperature sensor) the Home.app is not showing the Air Quality Measures on the device icon. To view the current values you have to open the preferences of the device in the Home.app. This works as designed by Apple and can't be changed with characteristics properties.

Simple Air Quality Sensor

This example is a simple air quality sensor passing the characteristics value for testing purposes.

Note: A value for {"AirQuality" : 4} and {"AirQuality" : 5} will trigger a notification on the device running the Home.app.

[{"id":"ffa9ddb4.26a9e8","type":"homekit-service","z":"7138f7e3.add4a8","isParent":true,"bridge":"60729d35.03880c","accessoryCategory":"OTHER","parentService":"","name":"AirQuality","serviceName":"AirQualitySensor","topic":"","filter":false,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","cameraConfigVideoProcessor":"ffmpeg","cameraConfigSource":"","cameraConfigStillImageSource":"","cameraConfigMaxStreams":2,"cameraConfigMaxWidth":1280,"cameraConfigMaxHeight":720,"cameraConfigMaxFPS":10,"cameraConfigMaxBitrate":300,"cameraConfigVideoCodec":"libx264","cameraConfigAudioCodec":"libfdk_aac","cameraConfigAudio":false,"cameraConfigPacketSize":1316,"cameraConfigVerticalFlip":false,"cameraConfigHorizontalFlip":false,"cameraConfigMapVideo":"0:0","cameraConfigMapAudio":"0:1","cameraConfigVideoFilter":"scale=1280:720","cameraConfigAdditionalCommandLine":"-tune zerolatency","cameraConfigDebug":false,"cameraConfigSnapshotOutput":"disabled","characteristicProperties":"{\n   \"AirQuality\" : 0,\n   \"PM2_5Density\" : 1.0,\n   \"PM10Density\" : 2.0,\n   \"StatusActive\" : 1\n}","x":1120,"y":1340,"wires":[],[](/NRCHKB/node-red-contrib-homekit-bridged/wiki/],[)},{"id":"56a1e83b.c2441","type":"inject","z":"7138f7e3.add4a8","name":"","topic":"","payload":"{\"foo\":\"bar\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":1200,"wires":["ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"ffa9ddb4.26a9e8")},{"id":"f9907030.d93868","type":"inject","z":"7138f7e3.add4a8","name":"","topic":"","payload":"{\"AirQuality\":3}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240,"y":1360,"wires":["ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"ffa9ddb4.26a9e8")},{"id":"17c07925.fe45a7","type":"inject","z":"7138f7e3.add4a8","name":"","topic":"","payload":"{\"PM2_5Density\":1}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1480,"wires":["ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"ffa9ddb4.26a9e8")},{"id":"e2706164.e33e5","type":"inject","z":"7138f7e3.add4a8","name":"","topic":"","payload":"{\"PM10Density\":1}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1520,"wires":["ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"ffa9ddb4.26a9e8")},{"id":"35ca8872.7b877","type":"inject","z":"7138f7e3.add4a8","name":"","topic":"","payload":"{\"AirQuality\":1}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240,"y":1280,"wires":["ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"ffa9ddb4.26a9e8")},{"id":"3e5ee1ad.6fd466","type":"inject","z":"7138f7e3.add4a8","name":"","topic":"","payload":"{\"AirQuality\":5}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240,"y":1440,"wires":["ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"ffa9ddb4.26a9e8")},{"id":"829b371b.08c6d","type":"inject","z":"7138f7e3.add4a8","name":"","topic":"","payload":"{\"AirQuality\":2}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240,"y":1320,"wires":["ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"ffa9ddb4.26a9e8")},{"id":"6b87d568.54d98c","type":"inject","z":"7138f7e3.add4a8","name":"","topic":"","payload":"{\"AirQuality\":0}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240,"y":1240,"wires":["ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"ffa9ddb4.26a9e8")},{"id":"e539751f.24eeb","type":"inject","z":"7138f7e3.add4a8","name":"","topic":"","payload":"{\"AirQuality\":4}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240,"y":1400,"wires":["ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"ffa9ddb4.26a9e8")},{"id":"60729d35.03880c","type":"homekit-bridge","z":"","bridgeName":"RedMatic-HAP-02","pinCode":"002-01-001","port":"","allowInsecureRequest":false,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true,"allowMessagePassthrough":true}]

Full Featured Air Quality Sensor with real data

This is a example of an Air Quality Sensor captures real-time date from an simple web service using a http-request:

There are a couple of public available websites providing real-time data to monitor pollution in public available areas. The author of this Wiki has been chosen the service luftdaten.info for the setup above, a service provided by the OK Lab Stuttgart. The OK Lab Stuttgart is part of the program Code for Germany of the Open Knowledge Foundation Germany. The aim of the program is to promote developments in the areas of transparency, Open Data and Citizen Science.

As such the service is providing a web based accessible network of air quality sensors, distributed across Germany. A few sensors are also located outside of Germany across Europe.

This service is providing real-time values for PM 10 and PM 2.5 particulate density. A URL (e. g. http://api.luftdaten.info/v1/sensor/{{SENSOR_ID}}/) can be called by a http request node in Node-red to retrieve a parsed payload with sensor data, formed as an analyzed JSON-object.

The following Node-RED flow uses one particular sensor.:

[{"id":"cae95a6c.0010d8","type":"inject","z":"7138f7e3.add4a8","name":"Initiate Airquality Read","topic":"","payload":"true","payloadType":"bool","repeat":"1200","crontab":"","once":true,"onceDelay":"10","x":270,"y":1120,"wires":["8dee64b7.b1cd"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"8dee64b7.b1cd")},{"id":"9f84bead.b2093","type":"debug","z":"7138f7e3.add4a8","name":"HK Output","active":false,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":1130,"y":1120,"wires":[]},{"id":"8dee64b7.b1cd","type":"http request","z":"7138f7e3.add4a8","name":"Air Quality Kiedrich","method":"GET","ret":"obj","paytoqs":false,"url":"http://api.luftdaten.info/v1/sensor/23490/","tls":"","persist":false,"proxy":"","authType":"","x":530,"y":1120,"wires":["3d68d0ef.68703"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"3d68d0ef.68703"),"info":"Source: [Kiedrich](https://luftdaten.info)"},{"id":"3d68d0ef.68703","type":"function","z":"7138f7e3.add4a8","name":"Adjust payload for HomeKit","func":"var hkMsg = {};\n\nvar pm10 = Number(msg.payload[0].sensordatavalues[0].value);\nvar pm2 = Number(msg.payload[0].sensordatavalues[1].value);\nvar airQualityPM10, airQualityPM2, airQuality;\n\n// Banding AirQiality based on US AQI to provide HomeKit Levels\n//   Source: https://aqicn.org/calculator\n\nif (pm10 < 55) {\n    airQualityPM10 = 1;\n} else if (pm10 < 155) {\n    airQualityPM10 = 2\n} else if (pm10 < 255) {\n    airQualityPM10 = 3\n} else if (pm10 < 355) {\n    airQualityPM10 = 4\n} else if (pm10 >= 425) {\n    airQualityPM10 = 5;\n} else {\n  airQualityPM10 = 0;  \n}\n\nif (pm2 < 12) {\n    airQualityPM2 = 1;\n} else if (pm2 < 35.5) {\n    airQualityPM2 = 2\n} else if (pm2 < 55.5) {\n    airQualityPM2 = 3\n} else if (pm2 < 150.5) {\n    airQualityPM2 = 4\n} else if (pm2 >= 250.5) {\n    airQualityPM2 = 5;\n} else {\n  airQualityPM2 = 0;  \n}\n\n// Average airQuality derived from PM2 and PM10\n\nairQuality = (airQualityPM10 + airQualityPM2) / 2;\n\nhkMsg.payload = {\n    \"AirQuality\" : Number(airQuality.toFixed(0)),\n    \"PM10Density\" : pm10,\n    \"PM2_5Density\" : pm2,\n    \"StatusActive\" : 1\n    };\n\nreturn hkMsg;","outputs":1,"noerr":0,"x":800,"y":1120,"wires":["9f84bead.b2093","ffa9ddb4.26a9e8"](/NRCHKB/node-red-contrib-homekit-bridged/wiki/"9f84bead.b2093","ffa9ddb4.26a9e8")},{"id":"ffa9ddb4.26a9e8","type":"homekit-service","z":"7138f7e3.add4a8","isParent":true,"bridge":"60729d35.03880c","accessoryCategory":"OTHER","parentService":"","name":"AirQuality","serviceName":"AirQualitySensor","topic":"","filter":false,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","cameraConfigVideoProcessor":"ffmpeg","cameraConfigSource":"","cameraConfigStillImageSource":"","cameraConfigMaxStreams":2,"cameraConfigMaxWidth":1280,"cameraConfigMaxHeight":720,"cameraConfigMaxFPS":10,"cameraConfigMaxBitrate":300,"cameraConfigVideoCodec":"libx264","cameraConfigAudioCodec":"libfdk_aac","cameraConfigAudio":false,"cameraConfigPacketSize":1316,"cameraConfigVerticalFlip":false,"cameraConfigHorizontalFlip":false,"cameraConfigMapVideo":"0:0","cameraConfigMapAudio":"0:1","cameraConfigVideoFilter":"scale=1280:720","cameraConfigAdditionalCommandLine":"-tune zerolatency","cameraConfigDebug":false,"cameraConfigSnapshotOutput":"disabled","characteristicProperties":"{\n   \"AirQuality\" : 0,\n   \"PM2_5Density\" : 1.0,\n   \"PM10Density\" : 2.0,\n   \"StatusActive\" : 1\n}","x":1120,"y":1200,"wires":[],[](/NRCHKB/node-red-contrib-homekit-bridged/wiki/],[)},{"id":"60729d35.03880c","type":"homekit-bridge","z":"","bridgeName":"RedMatic-HAP-02","pinCode":"002-01-001","port":"","allowInsecureRequest":false,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true,"allowMessagePassthrough":true}]

The PM 10 and PM 2.5 value is directly mapped to the appropriate HomeKit-Characterstics value, using a function node.

var pm10 = Number(msg.payload[0].sensordatavalues[0].value);
var pm2 = Number(msg.payload[0].sensordatavalues[1].value);

...
hkMsg.payload = {
    "AirQuality" : Number(airQuality.toFixed(0)),
    "PM10Density" : pm10,
    "PM2_5Density" : pm2,
    "StatusActive" : 1
    };

A special calculation is applied for the AirQuality value itself. Since the HAP specification doesn't necessarily dictate how the value has to be calculated it is up to the accessory to determine the subject assessment of the air quality. For the example above the author decide to calculate an mean value derived from the different scale of the PM 10 and PM 2.5 particulate density US AQI scale. For reference please see here.

However, with such a setup you can decide for yourself, whether your windows open/closes automatically based on air quality outside. In addition to that, the project encourages you to become part of the network by building your own air quality sensor.