{"id":24732576,"url":"https://github.com/gonzalo123/weather","last_synced_at":"2025-07-08T07:36:38.095Z","repository":{"id":31066728,"uuid":"125244356","full_name":"gonzalo123/weather","owner":"gonzalo123","description":"Playing with Grafana and weather APIs","archived":false,"fork":false,"pushed_at":"2022-02-11T05:03:11.000Z","size":336,"stargazers_count":15,"open_issues_count":5,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-15T07:01:37.438Z","etag":null,"topics":["api","dashboards","grafana","influxdb","iot","node","python","weather"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gonzalo123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-03-14T16:47:50.000Z","updated_at":"2024-04-02T04:36:38.000Z","dependencies_parsed_at":"2022-08-07T16:00:39.833Z","dependency_job_id":null,"html_url":"https://github.com/gonzalo123/weather","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalo123%2Fweather","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalo123%2Fweather/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalo123%2Fweather/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalo123%2Fweather/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gonzalo123","download_url":"https://codeload.github.com/gonzalo123/weather/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235897263,"owners_count":19062685,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","dashboards","grafana","influxdb","iot","node","python","weather"],"created_at":"2025-01-27T17:52:50.222Z","updated_at":"2025-01-27T17:52:50.777Z","avatar_url":"https://github.com/gonzalo123.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Playing with Grafana and weather APIs\n\nToday I want to play with Grafana. Let me show you my idea:\nI've got a Beewi temperature sensor http://www.bee-wi.com/produits/capteurs/capteur-de-temperature/. I've been playing with it previously. Today I want to show the temperature within a grafana dashboard. \nI want to play also with openweathermap api https://openweathermap.org/\n\nFist 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.\nI only need to pass the sensor mac address and I obtain a JSON with the current temperature\n\n```js\n#!/usr/bin/env node\nnoble = require('noble');\n\nvar status = false;\nvar address = process.argv[2];\n\nif (!address) {\n    console.log('Usage \"./reader.py \u003csensor mac address\u003e\"');\n    process.exit();\n}\n\nfunction hexToInt(hex) {\n    var num, maxVal;\n    if (hex.length % 2 !== 0) {\n        hex = \"0\" + hex;\n    }\n    num = parseInt(hex, 16);\n    maxVal = Math.pow(2, hex.length / 2 * 8);\n    if (num \u003e maxVal / 2 - 1) {\n        num = num - maxVal;\n    }\n\n    return num;\n}\n\nnoble.on('stateChange', function(state) {\n    status = (state === 'poweredOn');\n});\n\nnoble.on('discover', function(peripheral) {\n    if (peripheral.address == address) {\n        var data = peripheral.advertisement.manufacturerData.toString('hex');\n        out = {\n            temperature: parseFloat(hexToInt(data.substr(10, 2)+data.substr(8, 2))/10).toFixed(1)\n        };\n        console.log(JSON.stringify(out))\n        noble.stopScanning();\n        process.exit();\n    }\n});\n\nnoble.on('scanStop', function() {\n    noble.stopScanning();\n});\n\nsetTimeout(function() {\n    noble.stopScanning();\n    noble.startScanning();\n}, 2000);\n\n\nsetTimeout(function() {\n    noble.stopScanning();\n    process.exit()\n}, 20000);\n```\n\nAnd 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.\n\n````python\nfrom sense_hat import SenseHat\nfrom influxdb import InfluxDBClient\nimport datetime\nimport logging\nimport requests\nimport json\nfrom subprocess import check_output\nimport os\nimport sys\nfrom dotenv import load_dotenv\n\nlogging.basicConfig(level=logging.INFO)\n\ncurrent_dir = os.path.dirname(os.path.abspath(__file__))\nload_dotenv(dotenv_path=\"{}/.env\".format(current_dir))\n\nsensor_mac_address = os.getenv(\"BEEWI_SENSOR\")\nopenweathermap_api_key = os.getenv(\"OPENWEATHERMAP_API_KEY\")\ninfluxdb_host = os.getenv(\"INFLUXDB_HOST\")\ninfluxdb_port = os.getenv(\"INFLUXDB_PORT\")\ninfluxdb_database = os.getenv(\"INFLUXDB_DATABASE\")\n\nreader = '{}/reader.js'.format(current_dir)\n\n\ndef get_rain_level_from_weather(weather):\n    rain = False\n    rain_level = 0\n    if len(weather) \u003e 0:\n        for w in weather:\n            if w['icon'] == '09d':\n                rain = True\n                rain_level = 1\n            elif w['icon'] == '10d':\n                rain = True\n                rain_level = 2\n            elif w['icon'] == '11d':\n                rain = True\n                rain_level = 3\n            elif w['icon'] == '13d':\n                rain = True\n                rain_level = 4\n\n    return rain, rain_level\n\n\ndef openweathermap():\n    data = {}\n    r = requests.get(\n        \"http://api.openweathermap.org/data/2.5/weather?id=3110044\u0026appid={}\u0026units=metric\".format(\n            openweathermap_api_key))\n\n    if r.status_code == 200:\n        current_data = r.json()\n        data['weather'] = current_data['main']\n        rain, rain_level = get_rain_level_from_weather(current_data['weather'])\n        data['weather']['rain'] = rain\n        data['weather']['rain_level'] = rain_level\n\n    r2 = requests.get(\n        \"http://api.openweathermap.org/data/2.5/uvi?lat=43.32\u0026lon=-1.93\u0026appid={}\".format(openweathermap_api_key))\n    if r2.status_code == 200:\n        data['uvi'] = r2.json()\n\n    r3 = requests.get(\n        \"http://api.openweathermap.org/data/2.5/forecast?id=3110044\u0026appid={}\u0026units=metric\".format(\n            openweathermap_api_key))\n\n    if r3.status_code == 200:\n        forecast = r3.json()['list']\n        data['forecast'] = []\n        for f in forecast:\n            rain, rain_level = get_rain_level_from_weather(f['weather'])\n            data['forecast'].append({\n                \"dt\": f['dt'],\n                \"fields\": {\n                    \"temp\": float(f['main']['temp']),\n                    \"humidity\": float(f['main']['humidity']),\n                    \"rain\": rain,\n                    \"rain_level\": int(rain_level),\n                    \"pressure\": float(float(f['main']['pressure']))\n                }\n            })\n\n        return data\n\n\ndef persists(measurement, fields, location, time):\n    logging.info(\"{} {} [{}] {}\".format(time, measurement, location, fields))\n    influx_client.write_points([{\n        \"measurement\": measurement,\n        \"tags\": {\"location\": location},\n        \"time\": time,\n        \"fields\": fields\n    }])\n\n\ndef in_sensors():\n    try:\n        sense = SenseHat()\n        pressure = sense.get_pressure()\n        reader_output = check_output([reader, sensor_mac_address]).strip()\n        sensor_info = json.loads(reader_output)\n        temperature = sensor_info['temperature']\n\n        persists(measurement='home_pressure', fields={\"value\": float(pressure)}, location=\"in\", time=current_time)\n        persists(measurement='home_temperature', fields={\"value\": float(temperature)}, location=\"in\",\n                 time=current_time)\n    except Exception as err:\n        logging.error(err)\n\n\ndef out_sensors():\n    try:\n        out_info = openweathermap()\n\n        persists(measurement='home_pressure',\n                 fields={\"value\": float(out_info['weather']['pressure'])},\n                 location=\"out\",\n                 time=current_time)\n        persists(measurement='home_humidity',\n                 fields={\"value\": float(out_info['weather']['humidity'])},\n                 location=\"out\",\n                 time=current_time)\n        persists(measurement='home_temperature',\n                 fields={\"value\": float(out_info['weather']['temp'])},\n                 location=\"out\",\n                 time=current_time)\n        persists(measurement='home_rain',\n                 fields={\"value\": out_info['weather']['rain'], \"level\": out_info['weather']['rain_level']},\n                 location=\"out\",\n                 time=current_time)\n        persists(measurement='home_uvi',\n                 fields={\"value\": float(out_info['uvi']['value'])},\n                 location=\"out\",\n                 time=current_time)\n        for f in out_info['forecast']:\n            persists(measurement='home_weather_forecast',\n                     fields=f['fields'],\n                     location=\"out\",\n                     time=datetime.datetime.utcfromtimestamp(f['dt']).isoformat())\n\n    except Exception as err:\n        logging.error(err)\n\n\ninflux_client = InfluxDBClient(host=influxdb_host, port=influxdb_port, database=influxdb_database)\ncurrent_time = datetime.datetime.utcnow().isoformat()\n\nin_sensors()\nout_sensors()\n````\n\nI'm running this python script from a Rasberry Pi3 with a Sense Hat. Sense Hat has a atmospheric pressure sensor, so I will also retrieve the pressure from the Sense Hat.\n\nFrom openweathermap I will obtain:\n* Current temperature/humidity and atmospheric pressure in the street\n* UV Index (the measure of the level of UV radiation)\n* Weather conditions (if it's raining or not)\n* Weather forecast\n\nI 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\n\nHere we can see the dashboard\n![Dashboard](img/dashboard.png \"Dashboard\")\n\n\n ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgonzalo123%2Fweather","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgonzalo123%2Fweather","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgonzalo123%2Fweather/lists"}