Skip to content

Commit

Permalink
Merge pull request #12 from mamercad/influx
Browse files Browse the repository at this point in the history
Getting InfluxDB working
  • Loading branch information
mamercad authored Feb 19, 2022
2 parents 72fcb59 + a828923 commit c3824cc
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 71 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ambientweather-exporter

Simple Python/Flask exporter for [AmbientWeather](https://ambientweather.net) that can be scraped by [Prometheus](https://prometheus.io). With that said, you'll need `flask` installed. I've also added support for pushing to [InfluxDB](https://www.influxdata.com/products/influxdb-overview/), but, I haven't tested it, let me know (you can set `$INFLUX_HOST` and `$INFLUX_PORT` to override the defaults, `influxdb` and `8086`, respectively). The endpoints `/influx` or `/influxdb` will trigger the sending.
Simple Python/Flask exporter for [AmbientWeather](https://ambientweather.net) that can be scraped by [Prometheus](https://prometheus.io). With that said, you'll need `flask` installed. I've also added support for pushing to [InfluxDB](https://www.influxdata.com/products/influxdb-overview/), but, I haven't tested it, let me know (you can set `$INFLUX_HOST`, `$INFLUX_PORT`, and `$INFLUX_DB` to override the defaults, `influxdb`, `8086`, `ambientweather`, respectively). The endpoints `/influx` or `/influxdb` will trigger the sending.

## Environment variables

Expand Down
173 changes: 105 additions & 68 deletions ambientweather-exporter.py
Original file line number Diff line number Diff line change
@@ -1,98 +1,135 @@
#!/usr/bin/env python3

import json.decoder
import logging
import os
import sys
import requests
import sys
import time

from flask import Flask

app = Flask(__name__)


applicationKey = os.getenv("AMBI_APP_KEY")
apiKey = os.getenv("AMBI_API_KEY")
influxHost = os.getenv("INFLUX_HOST", "influxdb")
influxPort = os.getenv("INFLUX_PORT", "8086")
exporterPort = os.getenv("EXPORTER_PORT", "10102")
listen_on = "0.0.0.0"
listen_port = os.getenv("EXPORTER_PORT", "10102")
ambi_app_key = os.getenv("AMBI_APP_KEY")
ambi_api_key = os.getenv("AMBI_API_KEY")
influx_host = os.getenv("INFLUX_HOST", "influxdb")
influx_port = os.getenv("INFLUX_PORT", "8086")
influx_db = os.getenv("INFLUX_DB", "ambientweather")

logging.basicConfig(
stream=sys.stdout,
level=logging.DEBUG,
)
logger = logging.getLogger("ambientweather-exporter")


@app.route("/")
@app.route("/metrics")
def prometheus():
return ambientweatherPrometheus()
metrics = ambientweather_prometheus()
logger.info(f"Prometheus scraped {len(metrics)} metrics from us")
return "\n".join(metrics) + "\n"


@app.route("/influx")
@app.route("/influxdb")
def influx():
data = ambientweatherInflux()
for row in data:
try:
r = requests.post(f"http://{influxHost}:{influxPort}/write", data=row)
except Exception as e:
print(e)
sys.exit(1)


def getData():
global applicationKey, apiKey
try:
r = requests.get(
f"https://api.ambientweather.net/v1/devices?applicationKey={applicationKey}&apiKey={apiKey}"
metrics = ambientweather_influx()
logger.info(f"Shipped {len(metrics)} metrics to InfluxDB")
for metric in metrics:
r = requests.post(
f"http://{influx_host}:{influx_port}/write?db={influx_db}", data=metric
)
return r.json()[0]
except Exception as e:
print("Couldn't fetch AmbientWeather data, bailing!")
sys.exit(1)
status_code = r.status_code
if status_code != requests.codes.ok:
raise Exception(
f"Got a {status_code} from InfluxDB at {influx_host}:{influx_port}"
)


def ambientweatherPrometheus():
retn = []
data = getData()
try:
labels = 'macAddress="{}",name="{}",lat="{}",lon="{}",address="{}",location="{}",tz="{}"'.format(
data["macAddress"],
data["info"]["name"],
data["info"]["coords"]["coords"]["lat"],
data["info"]["coords"]["coords"]["lon"],
data["info"]["coords"]["address"],
data["info"]["coords"]["location"],
data["lastData"]["tz"],
def get_ambientweather_data():
logger.info("Fetching data from AmbientWeather")
global ambi_app_key, ambi_api_key
r = requests.get(
f"https://api.ambientweather.net/v1/devices?applicationKey={ambi_app_key}&apiKey={ambi_api_key}"
)
status_code = r.status_code
if status_code != requests.codes.ok:
raise Exception(
f"Got a {status_code} from AmbientWeather; check your $AMBI_APP_KEY and $AMBI_API_KEY"
)
for k in data["lastData"].keys():
if k not in ["lastRain", "tz", "date"]:
retn.append(
"ambientweather_{}{{{}}} {}".format(k, labels, data["lastData"][k])
)
except Exception as e:
retn.append(e)
return "\n".join(retn)


def ambientweatherInflux():
retn = []
data = getData()
try:
tagset = (
"macAddress={},name={},lat={},lon={},address={},location={},tz={}".format(
data["macAddress"],
data["info"]["name"],
data["info"]["coords"]["coords"]["lat"],
data["info"]["coords"]["coords"]["lon"],
data["info"]["coords"]["address"],
data["info"]["coords"]["location"],
data["lastData"]["tz"],
weather_data = r.json()
if len(weather_data) == 1:
logger.info("Got a row of data from AmbientWeather")
return weather_data[0]
else:
logger.error("Not expecting more than one row of data")
except json.decoder.JSONDecodeError:
logger.error("Could not decode AmbientWeather into JSON")
raise


def ambientweather_prometheus():
logger.info("Collecting Prometheus metrics")
prom_data = []
data = get_ambientweather_data()
labels = 'macAddress="{}",name="{}",lat="{}",lon="{}",address="{}",location="{}",tz="{}"'.format(
data["macAddress"],
data["info"]["name"],
data["info"]["coords"]["coords"]["lat"],
data["info"]["coords"]["coords"]["lon"],
data["info"]["coords"]["address"],
data["info"]["coords"]["location"],
data["lastData"]["tz"],
)
for k in data["lastData"].keys():
if k not in ["lastRain", "tz", "date"]:
prom_data.append(
"ambientweather_{}{{{}}} {}".format(k, labels, data["lastData"][k])
)
logger.info(f"Returning {len(prom_data)} metrics for Prometheus")
return prom_data


def ambientweather_influx():
logger.info("Collecting Influx metrics")
influx_data = []
data = get_ambientweather_data()
tagset = 'macAddress="{}",name="{}",lat="{}",lon="{}",address="{}",location="{}",tz="{}"'.format(
data["macAddress"],
data["info"]["name"],
data["info"]["coords"]["coords"]["lat"],
data["info"]["coords"]["coords"]["lon"],
data["info"]["coords"]["address"],
data["info"]["coords"]["location"],
data["lastData"]["tz"],
)
for k in data["lastData"].keys():
if k not in ["lastRain", "tz", "date"]:
influx_data.append(
f"ambientweather_{k},{tagset} value={data['lastData'][k]} {time.time_ns()}"
)
)
for k in data["lastData"].keys():
if k not in ["lastRain", "tz", "date"]:
retn.append("ambientweather {}={}".format(k, data["lastData"][k]))
except Exception as e:
retn.append(e)
return "\n".join(retn)

logger.info(f"Returning {len(influx_data)} metrics for Influx")
return influx_data


if __name__ == "__main__":
if not applicationKey or not apiKey:
if not ambi_app_key or not ambi_api_key:
raise Exception("Ensure that both $AMBI_APP_KEY and $AMBI_API_KEY are set!")
app.run(debug=True, host="0.0.0.0", port=exporterPort)

logger.info(f"Listening on {listen_on}:{listen_port}")
logger.info(
f"Prometheus metrics at http://{listen_on}:{listen_port} or http://{listen_on}:{listen_port}/metrics"
)
logger.info(f"InfluxDB destination set as {influx_host}:{influx_port}/{influx_db}")
logger.info(
f"Trigger sending to InfluxDB with http://{listen_on}:{listen_port}/influx or http://{listen_on}:{listen_port}/influxdb"
)

app.run(debug=True, host=listen_on, port=int(listen_port))
4 changes: 2 additions & 2 deletions charts/ambientweather-exporter/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ apiVersion: v2
name: ambientweather-exporter
description: A Helm chart for the AmbientWeather Exporter
type: application
version: 0.3.0
appVersion: "0.3.0"
version: 0.4.0
appVersion: "0.4.0"
6 changes: 6 additions & 0 deletions charts/ambientweather-exporter/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,11 @@ spec:
secretKeyRef:
name: "{{ .Release.Name }}-creds"
key: AMBI_API_KEY
- name: INFLUX_HOST
value: "{{ .Values.influx.host }}"
- name: INFLUX_PORT
value: "{{ .Values.influx.port }}"
- name: INFLUX_DB
value: "{{ .Values.influx.db }}"
- name: EXPORTER_PORT
value: "{{ .Values.service.exporter_port }}"
5 changes: 5 additions & 0 deletions charts/ambientweather-exporter/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ service:
secret:
ambi_app_key: hunter2
ambi_api_key: hunter2

influx:
host: influxdb
port: 8086
db: ambientweather
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ services:
AMBI_API_KEY: ${AMBI_API_KEY}
INFLUX_HOST: ${INFLUX_HOST:-influxdb}
INFLUX_PORT: ${INFLUX_PORT:-8086}
INFLUX_DB: ${INFLUX_DB:-ambientweather}
EXPORTER_PORT: ${EXPORTER_PORT:-10102}

0 comments on commit c3824cc

Please sign in to comment.