summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--known-devices.yaml14
-rw-r--r--requirements.txt3
-rwxr-xr-xweather-db-from-old-log81
-rwxr-xr-xweather-logger-receiver112
4 files changed, 210 insertions, 0 deletions
diff --git a/known-devices.yaml b/known-devices.yaml
new file mode 100644
index 0000000..0986e39
--- /dev/null
+++ b/known-devices.yaml
@@ -0,0 +1,14 @@
+Berlin:
+ "f4:01":
+ handle: "inside"
+ type: "THGR810, THGN800"
+ "1f:01":
+ handle: "outside"
+ type: "BTHR918"
+Heidenheim:
+ "07:01":
+ handle: "inside"
+ type: "THC238/268,THN132,THWR288,THRN122,THN122,AW129/131"
+ "58:02":
+ handle: "outside"
+ type: "THGR810, THGN800"
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..752aa56
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+pyRFXtrx==0.26.1
+pyserial==3.5
+PyYAML==5.4.1
diff --git a/weather-db-from-old-log b/weather-db-from-old-log
new file mode 100755
index 0000000..3efa4b1
--- /dev/null
+++ b/weather-db-from-old-log
@@ -0,0 +1,81 @@
+#!/usr/bin/env ruby
+
+require 'sqlite3'
+
+# Berlin
+#$device_id_to_handle = {
+# "b7:01" => "outside",
+# "ca:01" => "outside",
+# "d5:01" => "outside",
+# "f4:01" => "outside",
+# "1d:01" => "inside",
+# "1f:01" => "inside",
+# "37:01" => "inside",
+# "38:01" => "inside",
+# "9c:01" => "inside",
+# "cb:01" => "inside"
+#}
+
+# Heidenheim
+$device_id_to_handle = {
+ "58:02" => "outside",
+ "62:02" => "outside",
+ "07:01" => "inside"
+}
+
+def db_execute s, d
+ begin
+ $db.execute(s, d)
+ rescue SQLite3::BusyException
+ sleep 3
+ begin
+ $db.execute(s, d)
+ rescue SQLite3::BusyException
+ STDERR.write "DB busy, skipping data point '#{d.to_s}'\n"
+ end
+ end
+end
+
+def db_insert timestamp, handle, temperature, humidity
+ db_execute("INSERT INTO weather(timestamp, handle, temperature, humidity) VALUES(?,?,?,?)",
+ [timestamp, handle, temperature, humidity])
+end
+
+
+$db = SQLite3::Database.new("weather.db")
+
+$db.execute <<-SQL
+ create table weather(
+ id INTEGER PRIMARY KEY,
+ timestamp DATETIME,
+ handle TEXT,
+ temperature FLOAT,
+ humidity FLOAT
+ );
+ SQL
+
+while line = STDIN.gets
+ parts = line.split "\t"
+ log_entry_type = parts.first.split("::")[1]
+ if log_entry_type == "temp"
+ data = {}
+ parts.each { |i|
+ key, value = i.split "::"
+ data[key] = value
+ }
+ data["timestamp"] = data["timestamp"].to_i
+ data["temperature"] = data["temperature"].to_f
+ data["humidity"] = data["humidity"].to_f
+
+ handle = $device_id_to_handle[data["device_id"]]
+ if handle
+ db_insert \
+ data["timestamp"], \
+ handle, \
+ data["temperature"], \
+ data["humidity"]
+ end
+ end
+end
+
+$db.close
diff --git a/weather-logger-receiver b/weather-logger-receiver
new file mode 100755
index 0000000..389a9de
--- /dev/null
+++ b/weather-logger-receiver
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+
+import logging
+import os
+import signal
+import sqlite3
+import sys
+import time
+import yaml
+
+from RFXtrx import PySerialTransport
+
+
+def setup_database(path="weather.db"):
+ db_connection = sqlite3.connect(path)
+ db_cursor = db_connection.cursor()
+ try:
+ db_cursor.execute("CREATE TABLE weather( \
+ id INTEGER PRIMARY KEY, \
+ timestamp DATETIME, \
+ handle TEXT, \
+ temperature FLOAT, \
+ humidity FLOAT);")
+ except sqlite3.OperationalError:
+ pass
+
+ return db_connection
+
+
+def setup_serial(device="/dev/ttyUSB0"):
+ serial_connection = PySerialTransport(device)
+ serial_connection.reset()
+
+ return serial_connection
+
+
+def load_known_devices(location, path="known-devices.yaml"):
+ known_devices = None
+ with open(path, "r") as f:
+ known_devices = yaml.safe_load(f.read())
+
+ return known_devices[location]
+
+
+def add_data_to_db(data, handle, db_connection):
+ db_cursor = db_connection.cursor()
+ db_cursor.execute(f"INSERT INTO weather \
+ (timestamp, handle, temperature, humidity) \
+ VALUES ( {int(time.time())}, \
+ \"{handle}\", \
+ {data.values['Temperature']}, \
+ {data.values['Humidity']})")
+ db_connection.commit()
+
+
+def loop(serial_connection, db_connection, logger):
+ while True:
+ logger.info("(Re-)Starting receiver loop")
+
+ data = serial_connection.receive_blocking()
+
+ if data is None:
+ logger.info("Received no data")
+ continue
+
+ logger.info(data)
+
+ try:
+ if data.device.id_string not in known_devices:
+ logger.info(f"Unknown device with id {device_id} and type {device_type}, ignoring")
+ continue
+ except:
+ logger.info("Device ID not found, likely no SensorEvent, ignoring")
+ continue
+
+ handle = known_devices[data.device.id_string]["handle"]
+
+ add_data_to_db(data, handle, db_connection)
+
+
+if __name__ == "__main__":
+ logger = logging.getLogger("weather-logger-receiver")
+ logging.basicConfig(format='%(asctime)-2s %(levelname)-8s %(message)s',
+ datefmt='%Y-%m-%dT%H:%M:%S',
+ level=logging.INFO)
+
+ assert len(sys.argv) == 2
+ location = sys.argv[1]
+ known_devices = load_known_devices(location=location)
+ logger.info(f"Loaded known devices for location {location}")
+
+ db_connection = setup_database()
+ logger.info("Set up database")
+
+ serial_connection = setup_serial()
+ logger.info("Set up serial connection")
+
+ def shutdown(*args):
+ logger.info("Shutting down")
+ serial_connection.close()
+ db_connection.close()
+ sys.exit(0)
+
+ signal.signal(signal.SIGINT, shutdown)
+ signal.signal(signal.SIGTERM, shutdown)
+
+ try:
+ loop(serial_connection, db_connection, logger)
+ except Exception as e:
+ logger.error(f"Exception: {e}")
+ finally:
+ shutdown(serial_connection, db_connection, logger)