pickle test 2 from intern

This commit is contained in:
matt committed 2026-10-13 03:54:51 -07:00
1 parent d809a109e4
commit 0e58f6b73a
4 files changed
+58 -11

No files matched your search

+1 -5
View File
@@ -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
+6 -2
View File
@@ -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
View File
@@ -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
View File
@@ -71,7 +71,7 @@ class Sensor:
return is_valid
# ----------------------------------------------------------------------- #
# Life‑cycle hooks
# Life-cycle hooks
# ----------------------------------------------------------------------- #
def __post_init__(self) -> None: