first commit

This commit is contained in:
Schemen
2021-02-17 17:58:11 +01:00
commit 5cb64e377a
5 changed files with 380 additions and 0 deletions

142
.gitignore vendored Normal file
View File

@@ -0,0 +1,142 @@
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# Custom
config.ini

9
README.md Normal file
View File

@@ -0,0 +1,9 @@
# airthings-influxdb
```x-sh
git clone ssh://git@git.ponz.io:10022/elia/airthings-influxdb.git && cd airthings-influxdb
virtualenv venv -p python3
source venv/bin/activate
pip install -r requirements.txt
deactivate
```

219
airthings-influxdb.py Executable file
View File

@@ -0,0 +1,219 @@
#!/usr/bin/env python3
import datetime
from os import environ as env
from time import sleep
import json
import click
import configparser
from airthings import fetch_measurements, discover_devices
from influxdb import InfluxDBClient
from influxdb.exceptions import InfluxDBClientError
def read_config(file):
config = configparser.ConfigParser()
config.read(file)
return config
@click.group()
@click.option('--debug/--no-debug')
@click.option('-c', '--config', default="config.ini", help='give config file')
@click.pass_context
def cli(ctx, debug, config):
click.echo('Debug mode is %s' % ('on' if debug else 'off'))
ctx.ensure_object(dict)
ctx.obj['DEBUG'] = debug
ctx.obj['CONFIG'] = config
@cli.command()
@click.pass_context
def verify(ctx):
"""verify your configuration"""
config = read_config(ctx.obj['CONFIG'])
influx_host = env.get("InfluxdbHost", config['DEFAULT']['InfluxdbHost'])
influx_port = env.get("InfluxdbPort", config['DEFAULT']['InfluxdbPort'])
influx_user = env.get("InfluxdbUser", config['DEFAULT']['InfluxdbUser'])
influx_pass = env.get("InfluxdbPassword", config['DEFAULT']['InfluxdbPassword'])
influx_db = env.get("InfluxdbDatabase", config['DEFAULT']['InfluxdbDatabase'])
client = InfluxDBClient(influx_host, influx_port, influx_user, influx_pass, influx_db)
@cli.command()
def identify():
"""Lists available sensors nearby"""
airthings_devices = fetch_measurements()
print("Found %s Airthings device(s):" % len(airthings_devices))
for device in airthings_devices:
print("=" * 36)
print("\tMAC address:", device.mac_address)
print("\tIdentifier:", device.identifier)
print("\tModel:", device.label)
print("\tModel number:", device.model_number)
print("\tHas measurements:", device.has_measurements)
print("\tSensor capabilities:")
for sensor, supported in device.sensor_capabilities.items():
print("\t", sensor, "=", "YES" if supported else "NO")
print("+" * 11, "Measurements", "+" * 11)
print("\t", device.humidity)
print("\t", device.radon_short_term_avg)
print("\t", device.radon_long_term_avg)
print("\t", device.temperature)
print("\t", device.atmospheric_pressure)
print("\t", device.co2)
print("\t", device.voc)
@cli.command()
@click.pass_context
def start(ctx):
"""
"""
click.echo("Starting the Airthings to Influxdb Bridge")
click.echo("Reading the config...")
config = read_config(ctx.obj['CONFIG'])
influx_host = env.get("InfluxdbHost", config['DEFAULT']['InfluxdbHost'])
influx_port = env.get("InfluxdbPort", config['DEFAULT']['InfluxdbPort'])
influx_user = env.get("InfluxdbUser", config['DEFAULT']['InfluxdbUser'])
influx_pass = env.get("InfluxdbPassword", config['DEFAULT']['InfluxdbPassword'])
influx_db = env.get("InfluxdbDatabase", config['DEFAULT']['InfluxdbDatabase'])
interval = env.get("Interval", config['DEFAULT']['Interval'])
click.echo("Starting the Influxdb Client...")
client = InfluxDBClient(influx_host, influx_port, influx_user, influx_pass, influx_db)
data = []
click.echo("Starting sensor probing")
while True:
click.echo("Searching devices...")
airthings_devices = fetch_measurements()
print("Found %s Airthings devices:" % len(airthings_devices))
for device in airthings_devices:
print("=" * 36)
print("\tMAC address:", device.mac_address)
print("\tIdentifier:", device.identifier)
print("\tModel:", device.label)
print("\tModel number:", device.model_number)
print("\tHas measurements:", device.has_measurements)
click.echo("Collecting sensor data...")
now = datetime.datetime.now()
if device.humidity:
json_body = {
"measurement": "humidity",
"tags": {
"mac address": device.mac_address,
"identifier": device.identifier,
"model": device.label,
"model number": device.model_number
},
"time": now,
"fields": {
"value": device.humidity.value
}
}
data.append(json_body)
if device.radon_short_term_avg:
json_body = {
"measurement": "radon_short_term_avg",
"tags": {
"mac address": device.mac_address,
"identifier": device.identifier,
"model": device.label,
"model number": device.model_number
},
"time": now,
"fields": {
"value": device.radon_short_term_avg.value
}
}
data.append(json_body)
if device.radon_long_term_avg:
json_body = {
"measurement": "radon_long_term_avg",
"tags": {
"mac address": device.mac_address,
"identifier": device.identifier,
"model": device.label,
"model number": device.model_number
},
"time": now,
"fields": {
"value": device.radon_long_term_avg.value
}
}
data.append(json_body)
if device.temperature:
json_body = {
"measurement": "temperature",
"tags": {
"mac address": device.mac_address,
"identifier": device.identifier,
"model": device.label,
"model number": device.model_number
},
"time": now,
"fields": {
"value": device.temperature.value
}
}
data.append(json_body)
if device.co2:
json_body = {
"measurement": "co2",
"tags": {
"mac address": device.mac_address,
"identifier": device.identifier,
"model": device.label,
"model number": device.model_number
},
"time": now,
"fields": {
"value": device.co2.value
}
}
data.append(json_body)
if device.voc:
json_body = {
"measurement": "voc",
"tags": {
"mac address": device.mac_address,
"identifier": device.identifier,
"model": device.label,
"model number": device.model_number
},
"time": now,
"fields": {
"value": device.voc.value
}
}
data.append(json_body)
#write data
click.echo("Trying to send datapoints...")
try:
client.write_points(data)
click.echo("Sent!")
except InfluxDBClientError as e:
click.echo("An error occured: %s" % e)
click.echo("Storing data for now, waiting for the next interval." % e)
click.echo("Sleeping for %s seconds" % interval)
sleep(int(interval))
if __name__ == '__main__':
cli()

7
config.ini.example Normal file
View File

@@ -0,0 +1,7 @@
[DEFAULT]
InfluxdbHost = influx.example.com
InfluxdbPort = 8086
InfluxdbUser = airthings
InfluxdbPassword = airthings
InfluxdbDatabase = airthings
Interval = 60

3
requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
airthings==3.2.0
influxdb==5.3.1
click==7.1.2