| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import asyncio
- from bleak import BleakClient, BleakScanner
- from bleak.backends.characteristic import BleakGATTCharacteristic
- import struct
- import sqlite3
- from dotenv import load_dotenv
- import os
- import signal
- import logging
- import smbus2
- import bme280
- # Initialise the BME280
- port = 1
- address = 0x76
- bus = smbus2.SMBus(port)
- calibration_params = bme280.load_calibration_params(bus, address)
- load_dotenv()
- outdoorName = os.getenv("BLE_PERIPHERAL_NAME")
- outdoorConnected = 0
- TEMP_UUID = "2A6E"
- PRESSURE_UUID = "2A6D"
- HUMIDITY_UUID = "2A6F"
- indoorValues = {
- "Temperature": 0,
- "Pressure": 0,
- "Humidity": 0,
- }
- outdoorValues = {
- "Temperature": 0,
- "Pressure": 0,
- "Humidity": 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:
- 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(10)
- continue
- await asyncio.sleep(2)
- try:
- async with BleakClient(device) as client:
- outdoorConnected = 1
- print(f"connected to {outdoorName}")
- await client.start_notify(TEMP_UUID, notification_handler)
- await asyncio.sleep(0.5)
- await client.start_notify(PRESSURE_UUID, notification_handler)
- await asyncio.sleep(0.5)
- await client.start_notify(HUMIDITY_UUID, notification_handler)
- while (client.is_connected):
- await asyncio.sleep(5)
- except Exception as e:
- outdoorConnected = 0
- logging.exception("Exception while connecting or getting data")
- await asyncio.sleep(5)
- async def sensor_task():
- global indoorValues
-
- while True:
- data = bme280.sample(bus, address, calibration_params)
- indoorValues["Temperature"] = round(data.temperature * 100)
- indoorValues["Pressure"] = round(data.pressure * 100)
- indoorValues["Humidity"] = round(data.humidity * 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 text not null,
- indoorPressure text not null,
- indoorHumidity text not null,
- outdoorConnected integer not null,
- outdoorTemp text not null,
- outdoorPressure text not null,
- outdoorHumidity text not null
- );"""
- )
- conn.commit()
- async def write_task():
- while True:
- cursor.execute(f"""INSERT INTO data (
- 'indoorTemp', 'indoorPressure', 'indoorHumidity', 'outdoorConnected', 'outdoorTemp', 'outdoorPressure', 'outdoorHumidity'
- ) VALUES (
- ?, ?, ?, ?, ?, ?, ?
- )""",
- (
- indoorValues["Temperature"],
- indoorValues["Pressure"],
- indoorValues["Humidity"],
- outdoorConnected,
- outdoorValues["Temperature"],
- outdoorValues["Pressure"],
- outdoorValues["Humidity"]
- ))
- conn.commit()
- print(f"indoor: {indoorValues["Temperature"] / 100}°C, outdoor: {outdoorConnected} - {outdoorValues["Temperature"] / 100}°C")
- await asyncio.sleep(10)
- async def main():
- t1 = asyncio.create_task(ble_task())
- t2 = asyncio.create_task(sensor_task())
- t3 = asyncio.create_task(write_task())
- tasks = [t1, t2, t3]
- def handle_stop_signal():
- print("Received stop signal, cancelling tasks...")
- for t in tasks:
- t.cancel()
- loop = asyncio.get_running_loop()
- for sig in (signal.SIGINT, signal.SIGTERM):
- loop.add_signal_handler(sig, handle_stop_signal)
- try:
- await asyncio.gather(*tasks)
- except asyncio.CancelledError:
- print("Tasks were cancelled gracefully.")
- finally:
- print("Shutdown complete.")
- if __name__ == "__main__":
- asyncio.run(main())
|