pickle test 2 from intern
This commit is contained in:
1 parent
d809a109e4
commit
0e58f6b73a
4 files changed
+58
-11
No files matched your search
@@ -2,7 +2,7 @@
|
||||
|
||||
## Summary
|
||||
|
||||
This is an API for monitoring Temperature and Humidity data for Xiaomii LYWSD03MMC BLE sensors. The app will scan for any of these devices by looking for the Bluetooth MAC octet and then filtering by model. Once it has a list of MACs, it will then attempt to read the Temp/Humidity data for each MAC and record it. This data can be interacted with through an API.
|
||||
This is an API for monitoring Temperature and Humidity data for Xiaomii LYWSD03MMC BLE sensors. The app will scan for any of these devices by looking for the Bluetooth MAC octet and then filtering by model. Once it has a list of MACs, it will then attempt to read the Temp/Humidity data for each MAC and record it. This data can be interacted with through an API. The app has a Redis publishing function for use with websockets. The comment field for sensors can be configured using the appropriate variable in the `config.py` as well.
|
||||
|
||||
Some product info can be found here at my Knowledgebase:
|
||||
|
||||
@@ -12,10 +12,6 @@ https://kb.matt-cloud.com/books/07-saved-articles/page/xiaomii-temperaturehumidi
|
||||
|
||||
Aside from a REST API, there are a few more features which need to be added to this app.
|
||||
|
||||
* Friendly Names for Sensors
|
||||
* There will be a variable added to the `config.py` file to pre-configure friendly names for specific MAC addresses.
|
||||
* For example, *Living Room* or *Main Bedroom*
|
||||
* This data will also be integrated into the API to replace the **comment** field
|
||||
* Data persistence across app launches
|
||||
* I will do this with the **Pickle** package
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import redis
|
||||
import atexit
|
||||
from flask import Flask, jsonify
|
||||
from flask_apscheduler import APScheduler
|
||||
from datetime import datetime, timedelta
|
||||
from scanner import update_cache, get_cache_snapshot, get_sensor_summary, get_sensor_details, scan_macs
|
||||
from scanner import *
|
||||
from config import *
|
||||
from ble_redis import *
|
||||
import logging
|
||||
logging.getLogger('apscheduler').setLevel(logging.ERROR)
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
scheduler = APScheduler()
|
||||
scheduler.init_app(app)
|
||||
@@ -54,4 +56,6 @@ def hello():
|
||||
# --- Run --------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
# The scheduler runs in its own thread; the main thread serves Flask.
|
||||
app.run(host=bind_ip, port=api_port, debug=False)
|
||||
app.run(host=bind_ip, port=api_port, debug=False)
|
||||
# Register a graceful shutdown hook so the scanner state is persisted
|
||||
atexit.register(save_state)
|
||||
+50
-3
@@ -2,6 +2,8 @@ import asyncio
|
||||
import threading
|
||||
import time
|
||||
import redis
|
||||
import pickle
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
from zoneinfo import ZoneInfo # Python 3.9+
|
||||
from bleak import BleakScanner, BleakClient
|
||||
@@ -16,9 +18,53 @@ _mac_cache: Set[str] = set()
|
||||
_lock = threading.Lock()
|
||||
_sensors_cache = []
|
||||
|
||||
# other vars
|
||||
MI_SERVICE_UUID = "ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"
|
||||
TEMP_CHAR_UUID = "ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6"
|
||||
# ----------------------------------------------------------------------
|
||||
# Pickle persistence helpers
|
||||
# ----------------------------------------------------------------------
|
||||
STATE_FILE = "scanner_state.pkl"
|
||||
|
||||
def save_state() -> None:
|
||||
"""
|
||||
Persist the MAC cache and sensor objects to disk.
|
||||
Called automatically after each cache refresh and at program exit.
|
||||
"""
|
||||
with _lock:
|
||||
state = {
|
||||
"mac_cache": _mac_cache,
|
||||
"sensors": _sensors_cache,
|
||||
}
|
||||
try:
|
||||
with open(STATE_FILE, "wb") as f:
|
||||
pickle.dump(state, f, protocol=pickle.HIGHEST_PROTOCOL)
|
||||
if debug_output:
|
||||
print("[Scanner] State persisted to", STATE_FILE)
|
||||
except Exception as exc:
|
||||
# Don't crash the app – just log the error
|
||||
print("[Scanner] Warning: could not persist state:", exc)
|
||||
|
||||
def load_state() -> None:
|
||||
"""
|
||||
Load the MAC cache and sensor objects from disk if the file exists.
|
||||
Called automatically on import.
|
||||
"""
|
||||
if not os.path.exists(STATE_FILE):
|
||||
return
|
||||
try:
|
||||
with open(STATE_FILE, "rb") as f:
|
||||
state = pickle.load(f)
|
||||
with _lock:
|
||||
# NOTE: we replace the lists/sets to avoid mutating old references
|
||||
_mac_cache.clear()
|
||||
_mac_cache.update(state.get("mac_cache", []))
|
||||
global _sensors_cache
|
||||
_sensors_cache = state.get("sensors", [])
|
||||
if debug_output:
|
||||
print("[Scanner] Loaded state from", STATE_FILE)
|
||||
except Exception as exc:
|
||||
print("[Scanner] Warning: could not load state:", exc)
|
||||
|
||||
# Load any persisted state on module import
|
||||
load_state()
|
||||
|
||||
# Redis Functions
|
||||
r = redis.Redis(host=bind_ip, port=redis_port)
|
||||
@@ -72,6 +118,7 @@ def update_cache() -> None:
|
||||
# if redis is enabled, push full details to the redis server
|
||||
if enable_redis:
|
||||
update_redis(get_sensor_details())
|
||||
save_state()
|
||||
|
||||
# this helper function scans for MACs
|
||||
def scan_macs():
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ class Sensor:
|
||||
return is_valid
|
||||
|
||||
# ----------------------------------------------------------------------- #
|
||||
# Life‑cycle hooks
|
||||
# Life-cycle hooks
|
||||
# ----------------------------------------------------------------------- #
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
|
||||
Reference in new issue
Block a user