Skip to content

Instantly share code, notes, and snippets.

@acceptableEngineering
Last active January 3, 2026 00:12
Show Gist options
  • Select an option

  • Save acceptableEngineering/895892e1645e8e3e1ba6bfbc007d5dd8 to your computer and use it in GitHub Desktop.

Select an option

Save acceptableEngineering/895892e1645e8e3e1ba6bfbc007d5dd8 to your computer and use it in GitHub Desktop.
Ambient Weather, to Grafana via InfluxDB: Ingestion Script, and Grafana Dashboard JSON
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"id": 0,
"links": [],
"panels": [
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"max": 115,
"min": 28,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "blue",
"value": 0
},
{
"color": "green",
"value": 32
},
{
"color": "green",
"value": 60
},
{
"color": "orange",
"value": 80
},
{
"color": "red",
"value": 95
}
]
},
"unit": "fahrenheit"
},
"overrides": []
},
"gridPos": {
"h": 7,
"w": 6,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"minVizHeight": 75,
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showThresholdLabels": false,
"showThresholdMarkers": true,
"sizing": "auto"
},
"pluginVersion": "12.2.0",
"targets": [
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"query": "from(bucket: \"weather\")\n |> range(start: -5m)\n |> filter(fn: (r) => r._measurement == \"weather\")\n |> filter(fn: (r) => r._field == \"outdoor_temp\")\n |> filter(fn: (r) => r.station == \"ambient\")\n |> last()",
"refId": "A"
}
],
"title": "Current Outdoor Temperature",
"transparent": true,
"type": "gauge"
},
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"max": 100,
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "red",
"value": 0
},
{
"color": "orange",
"value": 20
},
{
"color": "yellow",
"value": 40
},
{
"color": "green",
"value": 50
}
]
},
"unit": "humidity"
},
"overrides": []
},
"gridPos": {
"h": 7,
"w": 6,
"x": 6,
"y": 0
},
"id": 2,
"options": {
"minVizHeight": 75,
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showThresholdLabels": false,
"showThresholdMarkers": true,
"sizing": "auto"
},
"pluginVersion": "12.2.0",
"targets": [
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"query": "from(bucket: \"weather\")\n |> range(start: -5m)\n |> filter(fn: (r) => r._measurement == \"weather\")\n |> filter(fn: (r) => r._field == \"outdoor_humidity\")\n |> filter(fn: (r) => r.station == \"ambient\")\n |> last()",
"refId": "A"
}
],
"title": "Current Humidity",
"transparent": true,
"type": "gauge"
},
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "fixed"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"fieldMinMax": false,
"mappings": []
},
"overrides": [
{
"matcher": {
"id": "byValue",
"options": {
"op": "gt",
"reducer": "lastNotNull",
"value": 999
}
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "red",
"mode": "fixed"
}
}
]
}
]
},
"gridPos": {
"h": 7,
"w": 6,
"x": 12,
"y": 0
},
"id": 3,
"options": {
"displayLabels": [
"name"
],
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": false
},
"pieType": "donut",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"sort": "none",
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.2.0",
"targets": [
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"query": "import \"array\"\n\nwindDir = from(bucket: \"weather\")\n |> range(start: -5m)\n |> filter(fn: (r) => r._measurement == \"weather\")\n |> filter(fn: (r) => r._field == \"wind_direction\")\n |> filter(fn: (r) => r.station == \"ambient\")\n |> last()\n |> findRecord(fn: (key) => true, idx: 0)\n\nactiveDir = if windDir._value >= 337.5 or windDir._value < 22.5 then \"N\"\n else if windDir._value >= 22.5 and windDir._value < 67.5 then \"NE\"\n else if windDir._value >= 67.5 and windDir._value < 112.5 then \"E\"\n else if windDir._value >= 112.5 and windDir._value < 157.5 then \"SE\"\n else if windDir._value >= 157.5 and windDir._value < 202.5 then \"S\"\n else if windDir._value >= 202.5 and windDir._value < 247.5 then \"SW\"\n else if windDir._value >= 247.5 and windDir._value < 292.5 then \"W\"\n else \"NW\"\n\n// Add small spacer to fine-tune rotation\nn = array.from(rows: [{_time: now(), _field: \"N\", _value: if activeDir == \"N\" then 1000 else 999, sort_order: 0}])\nne = array.from(rows: [{_time: now(), _field: \"NE\", _value: if activeDir == \"NE\" then 1000 else 999, sort_order: 1}])\nne1 = array.from(rows: [{_time: now(), _field: \"NE1\", _value: if activeDir == \"NE\" then 1000 else 999, sort_order: 2}])\ne = array.from(rows: [{_time: now(), _field: \"E\", _value: if activeDir == \"E\" then 1000 else 999, sort_order: 3}])\ne1 = array.from(rows: [{_time: now(), _field: \"E1\", _value: if activeDir == \"E\" then 1000 else 999, sort_order: 4}])\nse = array.from(rows: [{_time: now(), _field: \"SE\", _value: if activeDir == \"SE\" then 1000 else 999, sort_order: 5}])\nse1 = array.from(rows: [{_time: now(), _field: \"SE1\", _value: if activeDir == \"SE\" then 1000 else 999, sort_order: 6}])\ns = array.from(rows: [{_time: now(), _field: \"S\", _value: if activeDir == \"S\" then 1000 else 999, sort_order: 7}])\ns1 = array.from(rows: [{_time: now(), _field: \"S1\", _value: if activeDir == \"S\" then 1000 else 999, sort_order: 8}])\nsw = array.from(rows: [{_time: now(), _field: \"SW\", _value: if activeDir == \"SW\" then 1000 else 999, sort_order: 9}])\nsw1 = array.from(rows: [{_time: now(), _field: \"SW1\", _value: if activeDir == \"SW\" then 1000 else 999, sort_order: 10}])\nw = array.from(rows: [{_time: now(), _field: \"W\", _value: if activeDir == \"W\" then 1000 else 999, sort_order: 11}])\nw1 = array.from(rows: [{_time: now(), _field: \"W1\", _value: if activeDir == \"W\" then 1000 else 999, sort_order: 12}])\nnw = array.from(rows: [{_time: now(), _field: \"NW\", _value: if activeDir == \"NW\" then 1000 else 999, sort_order: 13}])\nnw1 = array.from(rows: [{_time: now(), _field: \"NW1\", _value: if activeDir == \"NW\" then 1000 else 999, sort_order: 14}])\nn1 = array.from(rows: [{_time: now(), _field: \"N1\", _value: if activeDir == \"N\" then 1000 else 999, sort_order: 15}])\n\nunion(tables: [n, ne, ne1, e, e1, se, se1, s, s1, sw, sw1, w, w1, nw, nw1, n1])\n |> sort(columns: [\"sort_order\"])",
"refId": "A"
}
],
"title": "Wind Direction (From)",
"transformations": [
{
"id": "partitionByValues",
"options": {
"fields": [
"_field"
],
"keepFields": false
}
},
{
"id": "prepareTimeSeries",
"options": {
"format": "multi"
}
},
{
"id": "renameByRegex",
"options": {
"regex": "_value ([A-Z]+)\\d*",
"renamePattern": "$1"
}
},
{
"id": "filterFieldsByName",
"options": {
"byVariable": false,
"include": {
"names": [
"_time",
"N",
"NE",
"E",
"SE",
"S",
"SW",
"W",
"NW"
]
}
}
}
],
"transparent": true,
"type": "piechart"
},
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
}
]
},
"unit": "pressurembar"
},
"overrides": []
},
"gridPos": {
"h": 7,
"w": 6,
"x": 18,
"y": 0
},
"id": 4,
"options": {
"minVizHeight": 75,
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showThresholdLabels": false,
"showThresholdMarkers": true,
"sizing": "auto"
},
"pluginVersion": "12.2.0",
"targets": [
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"query": "from(bucket: \"weather\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"weather\")\n |> filter(fn: (r) => r._field == \"pressure_relative\")\n |> filter(fn: (r) => r.station == \"ambient\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)",
"refId": "A"
}
],
"title": "Barometric Pressure",
"transparent": true,
"type": "gauge"
},
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 20,
"gradientMode": "opacity",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "smooth",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
}
]
},
"unit": "fahrenheit"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "outdoor_temp"
},
"properties": [
{
"id": "displayName",
"value": "Outdoor"
},
{
"id": "color",
"value": {
"fixedColor": "red",
"mode": "fixed"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "indoor_temp"
},
"properties": [
{
"id": "displayName",
"value": "Indoor"
},
{
"id": "color",
"value": {
"fixedColor": "blue",
"mode": "fixed"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "dewpoint"
},
"properties": [
{
"id": "displayName",
"value": "Dewpoint"
},
{
"id": "color",
"value": {
"fixedColor": "green",
"mode": "fixed"
}
}
]
}
]
},
"gridPos": {
"h": 13,
"w": 6,
"x": 0,
"y": 7
},
"id": 5,
"options": {
"legend": {
"calcs": [
"lastNotNull",
"min",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "none"
}
},
"pluginVersion": "12.2.0",
"targets": [
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"query": "from(bucket: \"weather\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"weather\")\n |> filter(fn: (r) => r._field == \"outdoor_temp\" or r._field == \"indoor_temp\" or r._field == \"dewpoint\")\n |> filter(fn: (r) => r.station == \"ambient\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)",
"refId": "A"
}
],
"title": "Temperature Overview",
"transparent": true,
"type": "timeseries"
},
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 20,
"gradientMode": "opacity",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "smooth",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
}
]
},
"unit": "humidity"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "outdoor_humidity"
},
"properties": [
{
"id": "displayName",
"value": "Outdoor"
},
{
"id": "color",
"value": {
"fixedColor": "blue",
"mode": "fixed"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "indoor_humidity"
},
"properties": [
{
"id": "displayName",
"value": "Indoor"
},
{
"id": "color",
"value": {
"fixedColor": "green",
"mode": "fixed"
}
}
]
}
]
},
"gridPos": {
"h": 13,
"w": 6,
"x": 6,
"y": 7
},
"id": 7,
"options": {
"legend": {
"calcs": [
"lastNotNull",
"min",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "none"
}
},
"pluginVersion": "12.2.0",
"targets": [
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"query": "from(bucket: \"weather\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"weather\")\n |> filter(fn: (r) => r._field == \"outdoor_humidity\" or r._field == \"indoor_humidity\")\n |> filter(fn: (r) => r.station == \"ambient\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)",
"refId": "A"
}
],
"title": "Humidity",
"transparent": true,
"type": "timeseries"
},
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 20,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "smooth",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"fieldMinMax": false,
"mappings": [],
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
}
]
},
"unit": "velocitymph"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "wind_speed"
},
"properties": [
{
"id": "displayName",
"value": "Wind Speed"
},
{
"id": "color",
"value": {
"fixedColor": "blue",
"mode": "fixed"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "wind_gust"
},
"properties": [
{
"id": "displayName",
"value": "Wind Gust"
},
{
"id": "color",
"value": {
"fixedColor": "red",
"mode": "fixed"
}
}
]
}
]
},
"gridPos": {
"h": 13,
"w": 6,
"x": 12,
"y": 7
},
"id": 6,
"options": {
"legend": {
"calcs": [
"lastNotNull",
"max",
"mean"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "none"
}
},
"pluginVersion": "12.2.0",
"targets": [
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"query": "from(bucket: \"weather\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"weather\")\n |> filter(fn: (r) => r._field == \"wind_speed\" or r._field == \"wind_gust\")\n |> filter(fn: (r) => r.station == \"ambient\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)",
"refId": "A"
}
],
"title": "Wind Speed & Gusts",
"transparent": true,
"type": "timeseries"
},
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 50,
"gradientMode": "opacity",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
}
]
},
"unit": "lengthin"
},
"overrides": []
},
"gridPos": {
"h": 13,
"w": 6,
"x": 18,
"y": 7
},
"id": 8,
"options": {
"legend": {
"calcs": [
"lastNotNull",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.2.0",
"targets": [
{
"datasource": {
"type": "influxdb",
"uid": "influxdb"
},
"query": "from(bucket: \"weather\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"weather\")\n |> filter(fn: (r) => r._field == \"rain_daily\" or r._field == \"rain_rate\")\n |> filter(fn: (r) => r.station == \"ambient\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> map(fn: (r) => ({\n r with\n _field: if r._field == \"rain_daily\" then \"Rain Daily\"\n else if r._field == \"rain_rate\" then \"Rain Rate\"\n else r._field\n }))",
"refId": "A"
}
],
"title": "Daily Rainfall",
"transparent": true,
"type": "timeseries"
}
],
"preload": false,
"refresh": "1m",
"schemaVersion": 42,
"tags": [
"weather",
"ambient"
],
"templating": {
"list": []
},
"time": {
"from": "now-24h",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Weather Station",
"uid": "weather-station",
"version": 32
}
#!/usr/bin/env python3
"""
Ambient Weather Station to InfluxDB ingestion script
Fetches live data from local weather station API and writes to InfluxDB
"""
import requests
import json
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
from datetime import datetime
import sys
import os
# Configuration
WEATHER_STATION_URL = "http://192.168.1.98/get_livedata_info"
INFLUXDB_URL = os.getenv("INFLUXDB_URL", "http://localhost:8086")
INFLUXDB_TOKEN = "root-token"
INFLUXDB_ORG = os.getenv("INFLUXDB_ORG", "meshorg")
INFLUXDB_BUCKET = os.getenv("INFLUXDB_BUCKET", "weather")
# Field ID mappings for Ambient Weather
FIELD_MAPPING = {
"0x02": "outdoor_temp", # Outdoor temperature
"0x07": "outdoor_humidity", # Outdoor humidity
"0x03": "dewpoint", # Dew point
"0x0B": "wind_speed", # Wind speed
"0x0C": "wind_gust", # Wind gust
"0x19": "max_daily_gust", # Max daily gust
"0x0A": "wind_direction", # Wind direction (degrees)
"0x15": "solar_radiation", # Solar radiation
"0x17": "uv_index", # UV index
"0x0D": "rain_event", # Event rain
"0x0E": "rain_rate", # Rain rate
"0x10": "rain_daily", # Daily rain
"0x11": "rain_weekly", # Weekly rain
"0x12": "rain_monthly", # Monthly rain
}
def parse_value(val_str):
"""Extract numeric value from string, removing units"""
if not val_str or val_str == "---.-":
return None
# Remove common units and convert to float
# Handle inHg BEFORE removing 'in' to avoid breaking it
val_str = val_str.replace("inHg", "").replace("F", "").replace("mph", "")
val_str = val_str.replace("in/Hr", "").replace("in", "").replace("%", "").strip()
try:
return float(val_str)
except ValueError:
return None
def fetch_weather_data():
"""Fetch live data from weather station"""
try:
response = requests.get(WEATHER_STATION_URL, timeout=10)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"Error fetching weather data: {e}", file=sys.stderr)
return None
def write_to_influxdb(data):
"""Write weather data to InfluxDB"""
if not INFLUXDB_TOKEN:
print("Error: INFLUXDB_TOKEN environment variable not set", file=sys.stderr)
sys.exit(1)
try:
client = InfluxDBClient(url=INFLUXDB_URL, token=INFLUXDB_TOKEN, org=INFLUXDB_ORG)
write_api = client.write_api(write_options=SYNCHRONOUS)
timestamp = datetime.utcnow()
points = []
# Process common_list fields
for item in data.get("common_list", []):
field_id = item.get("id")
if field_id in FIELD_MAPPING:
value = parse_value(item.get("val"))
if value is not None:
point = Point("weather") \
.tag("station", "ambient") \
.tag("location", "home") \
.field(FIELD_MAPPING[field_id], value) \
.time(timestamp)
points.append(point)
# Process rain data
for item in data.get("rain", []):
field_id = item.get("id")
if field_id in FIELD_MAPPING:
value = parse_value(item.get("val"))
if value is not None:
point = Point("weather") \
.tag("station", "ambient") \
.tag("location", "home") \
.field(FIELD_MAPPING[field_id], value) \
.time(timestamp)
points.append(point)
# Process indoor sensor (wh25)
for item in data.get("wh25", []):
if "intemp" in item:
value = parse_value(item["intemp"])
if value is not None:
points.append(Point("weather")
.tag("station", "ambient")
.tag("location", "indoor")
.field("indoor_temp", value)
.time(timestamp))
if "inhumi" in item:
value = parse_value(item["inhumi"])
if value is not None:
points.append(Point("weather")
.tag("station", "ambient")
.tag("location", "indoor")
.field("indoor_humidity", value)
.time(timestamp))
if "abs" in item:
value = parse_value(item["abs"])
if value is not None:
points.append(Point("weather")
.tag("station", "ambient")
.tag("location", "home")
.field("pressure_absolute", value)
.time(timestamp))
if "rel" in item:
value = parse_value(item["rel"])
if value is not None:
points.append(Point("weather")
.tag("station", "ambient")
.tag("location", "home")
.field("pressure_relative", value)
.time(timestamp))
# Write all points
write_api.write(bucket=INFLUXDB_BUCKET, record=points)
print(f"Successfully wrote {len(points)} data points to InfluxDB")
client.close()
return True
except Exception as e:
print(f"Error writing to InfluxDB: {e}", file=sys.stderr)
return False
def main():
"""Main execution"""
print(f"Fetching weather data from {WEATHER_STATION_URL}")
data = fetch_weather_data()
if not data:
sys.exit(1)
print(f"Writing data to InfluxDB at {INFLUXDB_URL}")
success = write_to_influxdb(data)
sys.exit(0 if success else 1)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment