Skip to content

Commit

Permalink
Merge pull request #14 from djjudas21/13_aqi
Browse files Browse the repository at this point in the history
Add AQI
  • Loading branch information
djjudas21 authored Oct 20, 2023
2 parents ce71b55 + 6a1dcfd commit 75e722d
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ for whom this will be a difficult time.
| `RAIN_UNIT` | `mm` | `mm`, `in` | Rainfall in millimetres or inches |
| `IRRADIANCE_UNIT` | `wm2` | `wm2`, `lx`, `fc` | Solar irradiance in Watts/m^2 |
| `DISTANCE_UNIT` | `km` | `km`, `mi` | Distance from the last lightning in kilometers |
| `AQI_STANDARD` | `uk` | `uk`, `epa`, `mep`, `nepm` | Air Quality Index standard in UK DAQI, US EPA, China MEP, Australia NEPM |
| `INFLUXDB_TOKEN` | | | InfluxDB token |
| `INFLUXDB_URL` | `http://localhost:8086/` | | InfluxDB endpoint |
| `INFLUXDB_ORG` | `influxdata` | | InfluxDB organisation |
Expand Down Expand Up @@ -94,7 +95,7 @@ Real data captured from the Ecowitt weather station with [http-webhook](https://
"content-length": "493"
},
"method": "POST",
"body": "PASSKEY=573AF40DB42C66057D20631F706CD585&stationtype=EasyWeatherPro_V5.1.1&runtime=1&dateutc=2023-06-20+14:56:02&tempinf=73.4&humidityin=49&baromrelin=29.917&baromabsin=29.536&tempf=72.5&humidity=58&winddir=251&windspeedmph=1.12&windgustmph=2.24&maxdailygust=9.17&solarradiation=293.99&uv=2&rainratein=0.000&eventrainin=0.638&hourlyrainin=0.000&dailyrainin=0.638&weeklyrainin=0.650&monthlyrainin=0.650&yearlyrainin=0.650&totalrainin=0.650&wh65batt=0&freq=868M&model=WS2900_V2.01.18&interval=60",
"body": "PASSKEY=573AF40DB42C66057D20631F706CD585&stationtype=EasyWeatherPro_V5.1.1&runtime=0&dateutc=2023-10-20+11:24:35&tempinf=73.4&humidityin=57&baromrelin=28.984&baromabsin=28.603&tempf=59.2&humidity=90&winddir=256&windspeedmph=2.91&windgustmph=4.47&maxdailygust=9.17&solarradiation=96.86&uv=0&rainratein=0.000&eventrainin=1.472&hourlyrainin=0.000&dailyrainin=0.154&weeklyrainin=1.480&monthlyrainin=3.720&yearlyrainin=15.642&totalrainin=15.642&temp1f=59.5&humidity1=79&pm25_ch1=3.0&pm25_avg_24h_ch1=6.8&wh65batt=0&batt1=0&pm25batt1=5&freq=868M&model=WS2900_V2.01.18&interval=60&lightning_num=22&lightning=20&lightning_time=1691007186",
"fresh": false,
"hostname": "192.168.0.65",
"ip": "::ffff:10.1.199.64",
Expand All @@ -113,7 +114,7 @@ Real data captured from the Ecowitt weather station with [http-webhook](https://
This POST request can be simulated with curl:

```
curl -d "PASSKEY=573AF40DB42C66057D20631F706CD585&stationtype=EasyWeatherPro_V5.1.1&runtime=1&dateutc=2023-06-20+14:56:02&tempinf=73.4&humidityin=49&baromrelin=29.917&baromabsin=29.536&tempf=72.5&humidity=58&winddir=251&windspeedmph=1.12&windgustmph=2.24&maxdailygust=9.17&solarradiation=293.99&uv=2&rainratein=0.000&eventrainin=0.638&hourlyrainin=0.000&dailyrainin=0.638&weeklyrainin=0.650&monthlyrainin=0.650&yearlyrainin=0.650&totalrainin=0.650&wh65batt=0&freq=868M&model=WS2900_V2.01.18&interval=60&lightning_num=22&lightning=20&lightning_time=1691007186" -X POST http://192.168.0.65:8080/report
curl -d "PASSKEY=573AF40DB42C66057D20631F706CD585&stationtype=EasyWeatherPro_V5.1.1&runtime=0&dateutc=2023-10-20+11:24:35&tempinf=73.4&humidityin=57&baromrelin=28.984&baromabsin=28.603&tempf=59.2&humidity=90&winddir=256&windspeedmph=2.91&windgustmph=4.47&maxdailygust=9.17&solarradiation=96.86&uv=0&rainratein=0.000&eventrainin=1.472&hourlyrainin=0.000&dailyrainin=0.154&weeklyrainin=1.480&monthlyrainin=3.720&yearlyrainin=15.642&totalrainin=15.642&temp1f=59.5&humidity1=79&pm25_ch1=3.0&pm25_avg_24h_ch1=6.8&wh65batt=0&batt1=0&pm25batt1=5&freq=868M&model=WS2900_V2.01.18&interval=60&lightning_num=22&lightning=20&lightning_time=1691007186" -X POST http://192.168.0.65:8080/report
```

We can then view the corresponding Prometheus metrics with a simple GET request (output has been truncated because it is very long):
Expand Down
65 changes: 65 additions & 0 deletions ecowitt_exporter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import logging
import aqi
from flask import Flask, request
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from prometheus_client import make_wsgi_app, Gauge
Expand All @@ -15,6 +16,7 @@
rain_unit = os.environ.get('RAIN_UNIT', 'mm')
distance_unit = os.environ.get('DISTANCE_UNIT', 'km')
irradiance_unit = os.environ.get('IRRADIANCE_UNIT', 'wm2')
aqi_standard = os.environ.get('AQI_STANDARD', 'uk')
influxdb_token = os.environ.get('INFLUXDB_TOKEN', None)
influxdb_url = os.environ.get('INFLUXDB_URL', 'http://localhost:8086/')
influxdb_org = os.environ.get('INFLUXDB_ORG', 'influxdata')
Expand All @@ -33,6 +35,7 @@
print (' RAIN_UNIT: ' + rain_unit)
print (' DISTANCE_UNIT: ' + distance_unit)
print (' IRRADIANCE_UNIT: ' + irradiance_unit)
print (' AQI STANDARD: ' + aqi_standard)
print (' INFLUXDB_TOKEN: ' + str(influxdb_token))
print (' INFLUXDB_URL: ' + influxdb_url)
print (' INFLUXDB_ORG: ' + str(influxdb_org))
Expand Down Expand Up @@ -91,6 +94,56 @@ def numify(value):
return float(value)
else:
return value

def aqi_uk(concentration):
'''
Calculate the AQI using the UK DAQI standard
https://en.wikipedia.org/wiki/Air_quality_index#United_Kingdom
'''
concentration = float(concentration)
if concentration < 12:
index = 1
elif 12 <= concentration <= 23:
index = 2
elif 24 <= concentration <= 35:
index = 3
elif 36 <= concentration <= 41:
index = 4
elif 42 <= concentration <= 47:
index = 5
elif 48 <= concentration <= 53:
index = 6
elif 54 <= concentration <= 58:
index = 7
elif 59 <= concentration <= 64:
index = 8
elif 65 <= concentration <= 70:
index = 9
elif concentration > 70:
index = 10
return index

def aqi_nepm(concentration):
'''
Calculate the AQI using the Austration NEPM standard
'''
concentration = float(concentration)
index = int(round(100 * concentration / 25))
return index

def aqi_epa(concentration):
'''
Calculate the AQI using the US EPA standard
'''
index = aqi.to_iaqi(aqi.POLLUTANT_PM25, concentration, algo=aqi.ALGO_EPA)
return index

def aqi_mep(concentration):
'''
Calculate the AQI using the China MEP standard
'''
index = aqi.to_iaqi(aqi.POLLUTANT_PM25, concentration, algo=aqi.ALGO_MEP)
return index


@app.route('/report', methods=['POST'])
Expand Down Expand Up @@ -195,6 +248,17 @@ def logecowitt():
value = "{:.2f}".format(distancemi)
results[key] = value

# Add Air Quality Index (AQI)
if data['pm25_avg_24h_ch1']:
if aqi_standard == 'uk':
results['aqi'] = aqi_uk(data['pm25_avg_24h_ch1'])
elif aqi_standard == 'epa':
results['aqi'] = aqi_epa(data['pm25_avg_24h_ch1'])
elif aqi_standard == 'mep':
results['aqi'] = aqi_mep(data['pm25_avg_24h_ch1'])
elif aqi_standard == 'nepm':
results['aqi'] = aqi_nepm(data['pm25_avg_24h_ch1'])

# Now loop on our processed results and do things with them
points = []
for key, value in results.items():
Expand Down Expand Up @@ -244,6 +308,7 @@ def logecowitt():
metrics['pm25_ch1'] = Gauge(name='pm25', documentation='PM2.5')
metrics['pm25_avg_24h_ch1'] = Gauge(name='pm25_avg_24h', documentation='PM2.5 24-hour average')
metrics['pm25batt1'] = Gauge(name='pm25batt', documentation='PM2.5 sensor battery')
metrics['aqi'] = Gauge(name='aqi', documentation='Air quality index')
metrics['wh65batt'] = Gauge(name='wh65batt', documentation='Weather station battery status')
metrics['solarradiation'] = Gauge(name='solarradiation', documentation='Solar irradiance', unit='wm2')
metrics['baromrel'] = Gauge(name='baromrel', documentation='Relative barometer', unit=pressure_unit)
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ flask==2.3.2
werkzeug==2.3.6
prometheus_client==0.17.0
influxdb-client==1.36.1
python-aqi==0.6.1

0 comments on commit 75e722d

Please sign in to comment.