|
@@ -0,0 +1,143 @@
|
|
|
|
|
+import asyncio
|
|
|
|
|
+from bleak import BleakClient, BleakScanner
|
|
|
|
|
+from bleak.backends.characteristic import BleakGATTCharacteristic
|
|
|
|
|
+import struct
|
|
|
|
|
+import sqlite3
|
|
|
|
|
+from dotenv import load_dotenv
|
|
|
|
|
+import os
|
|
|
|
|
+
|
|
|
|
|
+from smbus2 import SMBus
|
|
|
|
|
+from bme280 import BME280
|
|
|
|
|
+
|
|
|
|
|
+# Initialise the BME280
|
|
|
|
|
+bus = SMBus(1)
|
|
|
|
|
+bme280 = BME280(i2c_dev=bus)
|
|
|
|
|
+
|
|
|
|
|
+load_dotenv()
|
|
|
|
|
+
|
|
|
|
|
+outdoorName = os.getenv("BLE_PERIPHERAL_NAME")
|
|
|
|
|
+outdoorConnected = 0
|
|
|
|
|
+
|
|
|
|
|
+TEMP_UUID = "2A6E"
|
|
|
|
|
+PRESSURE_UUID = "2A6D"
|
|
|
|
|
+HUMIDITY_UUID = "2A6F"
|
|
|
|
|
+ALTITUDE_UUID = "2AB3"
|
|
|
|
|
+
|
|
|
|
|
+indoorValues = {
|
|
|
|
|
+ "Temperature": 0,
|
|
|
|
|
+ "Pressure": 0,
|
|
|
|
|
+ "Humidity": 0,
|
|
|
|
|
+ "Altitude": 0,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+outdoorValues = {
|
|
|
|
|
+ "Temperature": 0,
|
|
|
|
|
+ "Pressure": 0,
|
|
|
|
|
+ "Humidity": 0,
|
|
|
|
|
+ "Altitude": 0,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray):
|
|
|
|
|
+ global outdoorValues
|
|
|
|
|
+ outdoorValues[characteristic.description] = struct.unpack("<i", data)[0]
|
|
|
|
|
+
|
|
|
|
|
+async def ble_task():
|
|
|
|
|
+ global outdoorConnected
|
|
|
|
|
+
|
|
|
|
|
+ while True:
|
|
|
|
|
+ disconnect_event = asyncio.Event()
|
|
|
|
|
+
|
|
|
|
|
+ device = await BleakScanner.find_device_by_name(outdoorName)
|
|
|
|
|
+
|
|
|
|
|
+ if device is None:
|
|
|
|
|
+ outdoorConnected = 0
|
|
|
|
|
+
|
|
|
|
|
+ print("no device found, wait then scan again")
|
|
|
|
|
+ await asyncio.sleep(30)
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ try:
|
|
|
|
|
+ async with BleakClient(device, disconnected_callback=lambda c: disconnect_event.set()) as client:
|
|
|
|
|
+ outdoorConnected = 1
|
|
|
|
|
+
|
|
|
|
|
+ await client.start_notify(TEMP_UUID, notification_handler)
|
|
|
|
|
+ await client.start_notify(PRESSURE_UUID, notification_handler)
|
|
|
|
|
+ await client.start_notify(HUMIDITY_UUID, notification_handler)
|
|
|
|
|
+ await client.start_notify(ALTITUDE_UUID, notification_handler)
|
|
|
|
|
+
|
|
|
|
|
+ await disconnect_event.wait()
|
|
|
|
|
+ except Exception:
|
|
|
|
|
+ outdoorConnected = 0
|
|
|
|
|
+ print("exception while connecting or getting data")
|
|
|
|
|
+
|
|
|
|
|
+async def sensor_task():
|
|
|
|
|
+ global indoorValues
|
|
|
|
|
+
|
|
|
|
|
+ while True:
|
|
|
|
|
+ temperature, pressure, humidity = bme280.read_compensated_data()
|
|
|
|
|
+ altitude = bme280.altitude
|
|
|
|
|
+
|
|
|
|
|
+ #print(_encode_value(pressure/100))
|
|
|
|
|
+
|
|
|
|
|
+ indoorValues["Temperature"] = temperature * 100
|
|
|
|
|
+ indoorValues["Pressure"] = pressure * 100
|
|
|
|
|
+ indoorValues["Humidity"] = humidity * 100
|
|
|
|
|
+ indoorValues["Altitude"] = altitude * 100
|
|
|
|
|
+
|
|
|
|
|
+ await asyncio.sleep(1)
|
|
|
|
|
+
|
|
|
|
|
+conn = sqlite3.connect('./data/meteostanica.sqlite')
|
|
|
|
|
+cursor = conn.cursor()
|
|
|
|
|
+
|
|
|
|
|
+cursor.execute(
|
|
|
|
|
+ """CREATE TABLE IF NOT EXISTS data (
|
|
|
|
|
+ timestamp datetime default current_timestamp primary key,
|
|
|
|
|
+
|
|
|
|
|
+ indoorTemp integer not null,
|
|
|
|
|
+ indoorPressure integer not null,
|
|
|
|
|
+ indoorHumidity integer not null,
|
|
|
|
|
+ indoorAltitude integer not null,
|
|
|
|
|
+
|
|
|
|
|
+ outdoorConnected integer not null,
|
|
|
|
|
+ outdoorTemp integer not null,
|
|
|
|
|
+ outdoorPressure integer not null,
|
|
|
|
|
+ outdoorHumidity integer not null,
|
|
|
|
|
+ outdoorAltitude integer not null
|
|
|
|
|
+ );"""
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+conn.commit()
|
|
|
|
|
+
|
|
|
|
|
+async def write_task():
|
|
|
|
|
+ while True:
|
|
|
|
|
+ cursor.execute(f"""INSERT INTO data (
|
|
|
|
|
+ 'indoorTemp', 'indoorPressure', 'indoorHumidity', 'indoorAltitude', 'outdoorConnected', 'outdoorTemp', 'outdoorPressure', 'outdoorHumidity', 'outdoorAltitude'
|
|
|
|
|
+ ) VALUES (
|
|
|
|
|
+ ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
|
|
|
+ )""",
|
|
|
|
|
+ (
|
|
|
|
|
+ indoorValues["Temperature"],
|
|
|
|
|
+ indoorValues["Pressure"],
|
|
|
|
|
+ indoorValues["Humidity"],
|
|
|
|
|
+ indoorValues["Altitude"],
|
|
|
|
|
+ outdoorConnected,
|
|
|
|
|
+ outdoorValues["Temperature"],
|
|
|
|
|
+ outdoorValues["Pressure"],
|
|
|
|
|
+ outdoorValues["Humidity"],
|
|
|
|
|
+ outdoorValues["Altitude"]
|
|
|
|
|
+ ))
|
|
|
|
|
+
|
|
|
|
|
+ conn.commit()
|
|
|
|
|
+
|
|
|
|
|
+ await asyncio.sleep(10)
|
|
|
|
|
+
|
|
|
|
|
+async def main():
|
|
|
|
|
+ try:
|
|
|
|
|
+ t1 = asyncio.create_task(ble_task())
|
|
|
|
|
+ t2 = asyncio.create_task(sensor_task())
|
|
|
|
|
+ t3 = asyncio.create_task(write_task())
|
|
|
|
|
+ await asyncio.gather(t1, t2, t3)
|
|
|
|
|
+ except asyncio.exceptions.CancelledError:
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+asyncio.run(main())
|