Today I want to play with Grafana. Let me show you my idea:
I’ve got a Beewi temperature sensor. I’ve been playing with it previously. Today I want to show the temperature within a Grafana dashboard.
I want to play also with openweathermap API.
Fist I want to retrieve the temperature from Beewi device. I’ve got a node script that connects via Bluetooth to the device using noble library.
I only need to pass the sensor mac address and I obtain a JSON with the current temperature
#!/usr/bin/env node noble = require('noble'); var status = false; var address = process.argv[2]; if (!address) { console.log('Usage "./reader.py <sensor mac address>"'); process.exit(); } function hexToInt(hex) { var num, maxVal; if (hex.length % 2 !== 0) { hex = "0" + hex; } num = parseInt(hex, 16); maxVal = Math.pow(2, hex.length / 2 * 8); if (num > maxVal / 2 - 1) { num = num - maxVal; } return num; } noble.on('stateChange', function(state) { status = (state === 'poweredOn'); }); noble.on('discover', function(peripheral) { if (peripheral.address == address) { var data = peripheral.advertisement.manufacturerData.toString('hex'); out = { temperature: parseFloat(hexToInt(data.substr(10, 2)+data.substr(8, 2))/10).toFixed(1) }; console.log(JSON.stringify(out)) noble.stopScanning(); process.exit(); } }); noble.on('scanStop', function() { noble.stopScanning(); }); setTimeout(function() { noble.stopScanning(); noble.startScanning(); }, 2000); setTimeout(function() { noble.stopScanning(); process.exit() }, 20000);
And finally another script (this time a Python script) to collect data from openweathermap API, collect data from node script and storing the information in a influxdb database.
from sense_hat import SenseHat from influxdb import InfluxDBClient import datetime import logging import requests import json from subprocess import check_output import os import sys from dotenv import load_dotenv logging.basicConfig(level=logging.INFO) current_dir = os.path.dirname(os.path.abspath(__file__)) load_dotenv(dotenv_path="{}/.env".format(current_dir)) sensor_mac_address = os.getenv("BEEWI_SENSOR") openweathermap_api_key = os.getenv("OPENWEATHERMAP_API_KEY") influxdb_host = os.getenv("INFLUXDB_HOST") influxdb_port = os.getenv("INFLUXDB_PORT") influxdb_database = os.getenv("INFLUXDB_DATABASE") reader = '{}/reader.js'.format(current_dir) def get_rain_level_from_weather(weather): rain = False rain_level = 0 if len(weather) > 0: for w in weather: if w['icon'] == '09d': rain = True rain_level = 1 elif w['icon'] == '10d': rain = True rain_level = 2 elif w['icon'] == '11d': rain = True rain_level = 3 elif w['icon'] == '13d': rain = True rain_level = 4 return rain, rain_level def openweathermap(): data = {} r = requests.get( "http://api.openweathermap.org/data/2.5/weather?id=3110044&appid={}&units=metric".format( openweathermap_api_key)) if r.status_code == 200: current_data = r.json() data['weather'] = current_data['main'] rain, rain_level = get_rain_level_from_weather(current_data['weather']) data['weather']['rain'] = rain data['weather']['rain_level'] = rain_level r2 = requests.get( "http://api.openweathermap.org/data/2.5/uvi?lat=43.32&lon=-1.93&appid={}".format(openweathermap_api_key)) if r2.status_code == 200: data['uvi'] = r2.json() r3 = requests.get( "http://api.openweathermap.org/data/2.5/forecast?id=3110044&appid={}&units=metric".format( openweathermap_api_key)) if r3.status_code == 200: forecast = r3.json()['list'] data['forecast'] = [] for f in forecast: rain, rain_level = get_rain_level_from_weather(f['weather']) data['forecast'].append({ "dt": f['dt'], "fields": { "temp": float(f['main']['temp']), "humidity": float(f['main']['humidity']), "rain": rain, "rain_level": int(rain_level), "pressure": float(float(f['main']['pressure'])) } }) return data def persists(measurement, fields, location, time): logging.info("{} {} [{}] {}".format(time, measurement, location, fields)) influx_client.write_points([{ "measurement": measurement, "tags": {"location": location}, "time": time, "fields": fields }]) def in_sensors(): try: sense = SenseHat() pressure = sense.get_pressure() reader_output = check_output([reader, sensor_mac_address]).strip() sensor_info = json.loads(reader_output) temperature = sensor_info['temperature'] persists(measurement='home_pressure', fields={"value": float(pressure)}, location="in", time=current_time) persists(measurement='home_temperature', fields={"value": float(temperature)}, location="in", time=current_time) except Exception as err: logging.error(err) def out_sensors(): try: out_info = openweathermap() persists(measurement='home_pressure', fields={"value": float(out_info['weather']['pressure'])}, location="out", time=current_time) persists(measurement='home_humidity', fields={"value": float(out_info['weather']['humidity'])}, location="out", time=current_time) persists(measurement='home_temperature', fields={"value": float(out_info['weather']['temp'])}, location="out", time=current_time) persists(measurement='home_rain', fields={"value": out_info['weather']['rain'], "level": out_info['weather']['rain_level']}, location="out", time=current_time) persists(measurement='home_uvi', fields={"value": float(out_info['uvi']['value'])}, location="out", time=current_time) for f in out_info['forecast']: persists(measurement='home_weather_forecast', fields=f['fields'], location="out", time=datetime.datetime.utcfromtimestamp(f['dt']).isoformat()) except Exception as err: logging.error(err) influx_client = InfluxDBClient(host=influxdb_host, port=influxdb_port, database=influxdb_database) current_time = datetime.datetime.utcnow().isoformat() in_sensors() out_sensors()
I’m running this python script from a Raspberry Pi3 with a Sense Hat. Sense Hat has a atmospheric pressure sensor, so I will also retrieve the pressure from the Sense Hat.
From openweathermap I will obtain:
- Current temperature/humidity and atmospheric pressure in the street
- UV Index (the measure of the level of UV radiation)
- Weather conditions (if it’s raining or not)
- Weather forecast
I run this script with the Rasberry Pi crontab each 5 minutes. That means that I’ve got a fancy time series ready to be shown with grafana.
Here we can see the dashboard
Source code available in my github account.