Skip to content

Commit

Permalink
Merge pull request #6 from sighmon/add/3-luftdaten-support
Browse files Browse the repository at this point in the history
#3 Add luftdaten support
  • Loading branch information
tijmenvandenbrink authored Jun 27, 2020
2 parents 4210eda + 83d9f39 commit 353f52c
Showing 1 changed file with 108 additions and 21 deletions.
129 changes: 108 additions & 21 deletions enviroplus_exporter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python
import os
import random
import requests
import time
import logging
import argparse
Expand Down Expand Up @@ -37,6 +38,8 @@
""")

DEBUG = os.getenv('DEBUG', 'false') == 'true'

bus = SMBus(1)
bme280 = BME280(i2c_dev=bus)
pms5003 = PMS5003()
Expand Down Expand Up @@ -68,6 +71,9 @@
influxdb_client = InfluxDBClient(url=INFLUXDB_URL, token=INFLUXDB_TOKEN, org=INFLUXDB_ORG_ID)
influxdb_api = influxdb_client.write_api(write_options=SYNCHRONOUS)

# Setup Luftdaten
LUFTDATEN_TIME_BETWEEN_POSTS = int(os.getenv('LUFTDATEN_TIME_BETWEEN_POSTS', '30'))

# Get the temperature of the CPU for compensation
def get_cpu_temperature():
with open("/sys/class/thermal/thermal_zone0/temp", "r") as f:
Expand Down Expand Up @@ -129,37 +135,104 @@ def get_particulates():
try:
pms_data = pms5003.read()
except pmsReadTimeoutError:
logging.warn("Failed to read PMS5003")
logging.warning("Failed to read PMS5003")
else:
PM1.set(pms_data.pm_ug_per_m3(1.0))
PM25.set(pms_data.pm_ug_per_m3(2.5))
PM10.set(pms_data.pm_ug_per_m3(10))

def collect_all_data():
"""Collects all the data currently set"""
sensor_data = {}
sensor_data['temperature'] = TEMPERATURE.collect()[0].samples[0].value
sensor_data['humidity'] = HUMIDITY.collect()[0].samples[0].value
sensor_data['pressure'] = PRESSURE.collect()[0].samples[0].value
sensor_data['oxidising'] = OXIDISING.collect()[0].samples[0].value
sensor_data['reducing'] = REDUCING.collect()[0].samples[0].value
sensor_data['nh3'] = NH3.collect()[0].samples[0].value
sensor_data['lux'] = LUX.collect()[0].samples[0].value
sensor_data['proximity'] = PROXIMITY.collect()[0].samples[0].value
sensor_data['pm1'] = PM1.collect()[0].samples[0].value
sensor_data['pm25'] = PM25.collect()[0].samples[0].value
sensor_data['pm10'] = PM10.collect()[0].samples[0].value
return sensor_data

def post_to_influxdb():
"""Post all sensor data to InfluxDB"""
name = 'enviroplus'
tag = ['location', 'adelaide']
while True:
time.sleep(INFLUXDB_TIME_BETWEEN_POSTS)
name = 'enviroplus'
tag = ['location', 'adelaide']
fields = {}
data_points = []
epoch_time_now = round(time.time())
fields['temperature'] = TEMPERATURE.collect()[0].samples[0].value
fields['humidity'] = HUMIDITY.collect()[0].samples[0].value
fields['pressure'] = PRESSURE.collect()[0].samples[0].value
fields['oxidising'] = OXIDISING.collect()[0].samples[0].value
fields['reducing'] = REDUCING.collect()[0].samples[0].value
fields['nh3'] = NH3.collect()[0].samples[0].value
fields['lux'] = LUX.collect()[0].samples[0].value
fields['proximity'] = PROXIMITY.collect()[0].samples[0].value
fields['pm1'] = PM1.collect()[0].samples[0].value
fields['pm25'] = PM25.collect()[0].samples[0].value
fields['pm10'] = PM10.collect()[0].samples[0].value
for field_name in fields:
data_points.append(Point('enviroplus').tag('location', INFLUXDB_SENSOR_LOCATION).field(field_name, fields[field_name]))
influxdb_api.write(bucket=INFLUXDB_BUCKET, record=data_points)

sensor_data = collect_all_data()
for field_name in sensor_data:
data_points.append(Point('enviroplus').tag('location', INFLUXDB_SENSOR_LOCATION).field(field_name, sensor_data[field_name]))
try:
influxdb_api.write(bucket=INFLUXDB_BUCKET, record=data_points)
if DEBUG:
logging.info('InfluxDB response: OK')
except Exception as exception:
logging.warning('Exception sending to InfluxDB: {}'.format(exception))

def post_to_luftdaten():
"""Post relevant sensor data to luftdaten.info"""
"""Code from: https://github.com/sepulworld/balena-environ-plus"""
LUFTDATEN_SENSOR_UID = 'raspi-' + get_serial_number()
while True:
time.sleep(LUFTDATEN_TIME_BETWEEN_POSTS)
sensor_data = collect_all_data()
values = {}
values["P2"] = sensor_data['pm25']
values["P1"] = sensor_data['pm10']
values["temperature"] = "{:.2f}".format(sensor_data['temperature'])
values["pressure"] = "{:.2f}".format(sensor_data['pressure'] * 100)
values["humidity"] = "{:.2f}".format(sensor_data['humidity'])
pm_values = dict(i for i in values.items() if i[0].startswith('P'))
temperature_values = dict(i for i in values.items() if not i[0].startswith('P'))
try:
response_pin_1 = requests.post('https://api.luftdaten.info/v1/push-sensor-data/',
json={
"software_version": "enviro-plus 0.0.1",
"sensordatavalues": [{"value_type": key, "value": val} for
key, val in pm_values.items()]
},
headers={
"X-PIN": "1",
"X-Sensor": LUFTDATEN_SENSOR_UID,
"Content-Type": "application/json",
"cache-control": "no-cache"
}
)

response_pin_11 = requests.post('https://api.luftdaten.info/v1/push-sensor-data/',
json={
"software_version": "enviro-plus 0.0.1",
"sensordatavalues": [{"value_type": key, "value": val} for
key, val in temperature_values.items()]
},
headers={
"X-PIN": "11",
"X-Sensor": LUFTDATEN_SENSOR_UID,
"Content-Type": "application/json",
"cache-control": "no-cache"
}
)

if response_pin_1.ok and response_pin_11.ok:
if DEBUG:
logging.info('Luftdaten response: OK')
else:
logging.warning('Luftdaten response: Failed')
except Exception as exception:
logging.warning('Exception sending to Luftdaten: {}'.format(exception))

def get_serial_number():
"""Get Raspberry Pi serial number to use as LUFTDATEN_SENSOR_UID"""
with open('/proc/cpuinfo', 'r') as f:
for line in f:
if line[0:6] == 'Serial':
return str(line.split(":")[1].strip())

def str_to_bool(value):
if value.lower() in {'false', 'f', '0', 'no', 'n'}:
Expand All @@ -174,22 +247,34 @@ def str_to_bool(value):
parser.add_argument("-b", "--bind", metavar='ADDRESS', default='0.0.0.0', help="Specify alternate bind address [default: 0.0.0.0]")
parser.add_argument("-p", "--port", metavar='PORT', default=8000, type=int, help="Specify alternate port [default: 8000]")
parser.add_argument("-f", "--factor", metavar='FACTOR', type=float, help="The compensation factor to get better temperature results when the Enviro+ pHAT is too close to the Raspberry Pi board")
parser.add_argument("-d", "--debug", metavar='DEBUG', type=str_to_bool, help="Turns on more vebose logging, showing sensor output and post responses [default: false]")
parser.add_argument("-i", "--influxdb", metavar='INFLUXDB', type=str_to_bool, default='false', help="Post sensor data to InfluxDB [default: false]")
parser.add_argument("-l", "--luftdaten", metavar='LUFTDATEN', type=str_to_bool, default='false', help="Post sensor data to Luftdaten [default: false]")
args = parser.parse_args()

# Start up the server to expose the metrics.
start_http_server(addr=args.bind, port=args.port)
# Generate some requests.


if args.debug:
DEBUG = True

if args.factor:
logging.info("Using compensating algorithm (factor={}) to account for heat leakage from Raspberry Pi board".format(args.factor))

if args.influxdb:
# Post to InfluxDB on another thread
# Post to InfluxDB in another thread
logging.info("Sensor data will be posted to InfluxDB every {} seconds".format(INFLUXDB_TIME_BETWEEN_POSTS))
influx_thread = Thread(target=post_to_influxdb)
influx_thread.start()

if args.luftdaten:
# Post to Luftdaten in another thread
LUFTDATEN_SENSOR_UID = 'raspi-' + get_serial_number()
logging.info("Sensor data will be posted to Luftdaten every {} seconds for the UID {}".format(LUFTDATEN_TIME_BETWEEN_POSTS, LUFTDATEN_SENSOR_UID))
luftdaten_thread = Thread(target=post_to_luftdaten)
luftdaten_thread.start()

logging.info("Listening on http://{}:{}".format(args.bind, args.port))

while True:
Expand All @@ -199,3 +284,5 @@ def str_to_bool(value):
get_gas()
get_light()
get_particulates()
if DEBUG:
logging.info('Sensor data: {}'.format(collect_all_data()))

0 comments on commit 353f52c

Please sign in to comment.