getData.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import asyncio
  2. from bleak import BleakClient, BleakScanner
  3. from bleak.backends.characteristic import BleakGATTCharacteristic
  4. import struct
  5. import sqlite3
  6. from dotenv import load_dotenv
  7. import os
  8. import signal
  9. import logging
  10. import smbus2
  11. import bme280
  12. # Initialise the BME280
  13. port = 1
  14. address = 0x76
  15. bus = smbus2.SMBus(port)
  16. calibration_params = bme280.load_calibration_params(bus, address)
  17. load_dotenv()
  18. outdoorName = os.getenv("BLE_PERIPHERAL_NAME")
  19. outdoorConnected = 0
  20. TEMP_UUID = "2A6E"
  21. PRESSURE_UUID = "2A6D"
  22. HUMIDITY_UUID = "2A6F"
  23. indoorValues = {
  24. "Temperature": 0,
  25. "Pressure": 0,
  26. "Humidity": 0,
  27. }
  28. outdoorValues = {
  29. "Temperature": 0,
  30. "Pressure": 0,
  31. "Humidity": 0,
  32. }
  33. def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray):
  34. global outdoorValues
  35. outdoorValues[characteristic.description] = struct.unpack("<i", data)[0]
  36. async def ble_task():
  37. global outdoorConnected
  38. while True:
  39. device = await BleakScanner.find_device_by_name(outdoorName)
  40. if device is None:
  41. outdoorConnected = 0
  42. print("no device found, wait then scan again")
  43. await asyncio.sleep(10)
  44. continue
  45. await asyncio.sleep(2)
  46. try:
  47. async with BleakClient(device) as client:
  48. outdoorConnected = 1
  49. print(f"connected to {outdoorName}")
  50. await client.start_notify(TEMP_UUID, notification_handler)
  51. await asyncio.sleep(0.5)
  52. await client.start_notify(PRESSURE_UUID, notification_handler)
  53. await asyncio.sleep(0.5)
  54. await client.start_notify(HUMIDITY_UUID, notification_handler)
  55. while (client.is_connected):
  56. await asyncio.sleep(5)
  57. except Exception as e:
  58. outdoorConnected = 0
  59. logging.exception("Exception while connecting or getting data")
  60. await asyncio.sleep(5)
  61. async def sensor_task():
  62. global indoorValues
  63. while True:
  64. data = bme280.sample(bus, address, calibration_params)
  65. indoorValues["Temperature"] = round(data.temperature * 100)
  66. indoorValues["Pressure"] = round(data.pressure * 100)
  67. indoorValues["Humidity"] = round(data.humidity * 100)
  68. await asyncio.sleep(1)
  69. conn = sqlite3.connect('./data/meteostanica.sqlite')
  70. cursor = conn.cursor()
  71. cursor.execute(
  72. """CREATE TABLE IF NOT EXISTS data (
  73. timestamp datetime default current_timestamp primary key,
  74. indoorTemp text not null,
  75. indoorPressure text not null,
  76. indoorHumidity text not null,
  77. outdoorConnected integer not null,
  78. outdoorTemp text not null,
  79. outdoorPressure text not null,
  80. outdoorHumidity text not null
  81. );"""
  82. )
  83. conn.commit()
  84. async def write_task():
  85. while True:
  86. cursor.execute(f"""INSERT INTO data (
  87. 'indoorTemp', 'indoorPressure', 'indoorHumidity', 'outdoorConnected', 'outdoorTemp', 'outdoorPressure', 'outdoorHumidity'
  88. ) VALUES (
  89. ?, ?, ?, ?, ?, ?, ?
  90. )""",
  91. (
  92. indoorValues["Temperature"],
  93. indoorValues["Pressure"],
  94. indoorValues["Humidity"],
  95. outdoorConnected,
  96. outdoorValues["Temperature"],
  97. outdoorValues["Pressure"],
  98. outdoorValues["Humidity"]
  99. ))
  100. conn.commit()
  101. print(f"indoor: {indoorValues["Temperature"] / 100}°C, outdoor: {outdoorConnected} - {outdoorValues["Temperature"] / 100}°C")
  102. await asyncio.sleep(10)
  103. async def main():
  104. t1 = asyncio.create_task(ble_task())
  105. t2 = asyncio.create_task(sensor_task())
  106. t3 = asyncio.create_task(write_task())
  107. tasks = [t1, t2, t3]
  108. def handle_stop_signal():
  109. print("Received stop signal, cancelling tasks...")
  110. for t in tasks:
  111. t.cancel()
  112. loop = asyncio.get_running_loop()
  113. for sig in (signal.SIGINT, signal.SIGTERM):
  114. loop.add_signal_handler(sig, handle_stop_signal)
  115. try:
  116. await asyncio.gather(*tasks)
  117. except asyncio.CancelledError:
  118. print("Tasks were cancelled gracefully.")
  119. finally:
  120. print("Shutdown complete.")
  121. if __name__ == "__main__":
  122. asyncio.run(main())