ble.py - lots of comment maintenance
This commit is contained in:
1 parent
de616a5229
commit
6564d4941f
1 file changed
+161
-132
+161
-132
@@ -1,21 +1,34 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
####################################################
|
||||||
"""
|
"""
|
||||||
mi_ble_reader
|
|
||||||
==============
|
|
||||||
|
|
||||||
Async BLE reader for Xiaomi Mi temperature / humidity sensors.
|
BLE Temp Sensor Driver
|
||||||
|
First part of this file is the driver itself
|
||||||
|
Since it's intended to be used with a service that could run for months or more,
|
||||||
|
it also has a robust test system included
|
||||||
|
|
||||||
This module keeps the original helper names (`sensor_data_query`, `test`, etc.) so
|
The two primary functions for interacting with the driver are:
|
||||||
you can keep your existing code unchanged. In addition it exposes a minimal
|
def scan_macs() -> List[str]:
|
||||||
public API that other apps can import:
|
def sensor_data_query(mac_list: List[str]) -> List[dict]:
|
||||||
|
|
||||||
* `read_data` - async coroutine, returns SensorReading or None
|
A lot of this came from LLM assistance, including the next blurb
|
||||||
* `read_multiple` - async coroutine, reads a list of MACs concurrently
|
|
||||||
* `read_data_sync` - sync wrapper around `read_data` (creates its own loop)
|
Async BLE reader for Xiaomi Mi temperature / humidity sensors.
|
||||||
|
|
||||||
|
This module keeps the original helper names (`sensor_data_query`, `test`, etc.) so
|
||||||
|
you can keep your existing code unchanged. In addition it exposes a minimal
|
||||||
|
public API that other apps can import:
|
||||||
|
|
||||||
|
* `read_data` - async coroutine, returns SensorReading or None
|
||||||
|
* `read_multiple` - async coroutine, reads a list of MACs concurrently
|
||||||
|
* `read_data_sync` - sync wrapper around `read_data` (creates its own loop)
|
||||||
|
|
||||||
|
All heavy lifting is done in the async functions; the sync wrapper is only
|
||||||
|
provided for convenience.
|
||||||
|
|
||||||
All heavy lifting is done in the async functions; the sync wrapper is only
|
|
||||||
provided for convenience.
|
|
||||||
"""
|
"""
|
||||||
|
####################################################
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -28,9 +41,9 @@ from typing import List, Optional
|
|||||||
from config import *
|
from config import *
|
||||||
from bleak import BleakClient, BleakScanner
|
from bleak import BleakClient, BleakScanner
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
# Configuration
|
# Configuration
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
MI_SERVICE_UUID = "ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"
|
MI_SERVICE_UUID = "ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"
|
||||||
TEMP_CHAR_UUID = "ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6"
|
TEMP_CHAR_UUID = "ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6"
|
||||||
|
|
||||||
@@ -41,9 +54,9 @@ SERVICE_DISCOVERY_TIMEOUT = 10.0
|
|||||||
DISCOVER_TIMEOUT = SCAN_TIMEOUT + 5.0 # Timeout for discovering device
|
DISCOVER_TIMEOUT = SCAN_TIMEOUT + 5.0 # Timeout for discovering device
|
||||||
current_usb_id = None
|
current_usb_id = None
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
# Logging
|
# Logging
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
_logger.setLevel(logging.INFO)
|
_logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
@@ -60,9 +73,9 @@ _logger.addHandler(_stdout_handler)
|
|||||||
# finally create the log
|
# finally create the log
|
||||||
log = _logger
|
log = _logger
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
# Data model
|
# Data model
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
@dataclass
|
@dataclass
|
||||||
class SensorReading:
|
class SensorReading:
|
||||||
"""Single Mi sensor reading."""
|
"""Single Mi sensor reading."""
|
||||||
@@ -71,11 +84,13 @@ class SensorReading:
|
|||||||
humidity: int
|
humidity: int
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
# Helpers - kept identical to your original code
|
# BLE Helpers mined from the javascript
|
||||||
# --------------------------------------------------------------------------- #
|
# This magic is necessary and mysterious
|
||||||
|
####################################################
|
||||||
|
|
||||||
|
# Scan once for the given MAC and return its address if found
|
||||||
async def _discover_device(mac: str) -> Optional[str]:
|
async def _discover_device(mac: str) -> Optional[str]:
|
||||||
"""Scan once for the given MAC and return its address if found."""
|
|
||||||
try:
|
try:
|
||||||
devices = await asyncio.wait_for(
|
devices = await asyncio.wait_for(
|
||||||
BleakScanner.discover(timeout=SCAN_TIMEOUT),
|
BleakScanner.discover(timeout=SCAN_TIMEOUT),
|
||||||
@@ -93,8 +108,9 @@ async def _discover_device(mac: str) -> Optional[str]:
|
|||||||
reset_adapter()
|
reset_adapter()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Don't question the ancient magic
|
||||||
|
# This evidently will "Parse the 3-byte Mi packet into temperature & humidity."
|
||||||
def _parse_sensor_data(raw: bytes) -> (float, int):
|
def _parse_sensor_data(raw: bytes) -> (float, int):
|
||||||
"""Parse the 3-byte Mi packet into temperature & humidity."""
|
|
||||||
sign = raw[1] & (1 << 7)
|
sign = raw[1] & (1 << 7)
|
||||||
temp = ((raw[1] & 0x7F) << 8 | raw[0])
|
temp = ((raw[1] & 0x7F) << 8 | raw[0])
|
||||||
if sign:
|
if sign:
|
||||||
@@ -103,26 +119,42 @@ def _parse_sensor_data(raw: bytes) -> (float, int):
|
|||||||
hum = raw[2]
|
hum = raw[2]
|
||||||
return temp, hum
|
return temp, hum
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
# Optional device discovery helper
|
# BLE device discovery function and helpers
|
||||||
# --------------------------------------------------------------------------- #
|
# Returns a list of MACs of sensors detected
|
||||||
|
####################################################
|
||||||
|
|
||||||
|
# This is the primary function for interacting with the sensor data through the driver
|
||||||
|
# Provide it with a List of MACs and it will return a list of Sensor data
|
||||||
|
def sensor_data_query(mac_list: List[str]) -> List[dict]:
|
||||||
|
result = []
|
||||||
|
for mac in mac_list:
|
||||||
|
try:
|
||||||
|
# The main function used here is read_data
|
||||||
|
this_result = asyncio.run(read_data(mac))
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Error reading BLE data - {e}")
|
||||||
|
this_result = None
|
||||||
|
if "org.freedesktop.DBus.Error.AccessDenied" in e:
|
||||||
|
reset_adapter()
|
||||||
|
return result
|
||||||
|
if this_result:
|
||||||
|
result.append(
|
||||||
|
{"name": mac, "temp": this_result.temperature, "humidity": this_result.humidity}
|
||||||
|
)
|
||||||
|
log.info(f"Data query complete - returning result")
|
||||||
|
return result
|
||||||
|
|
||||||
|
# This non-async helper function scans for MACs
|
||||||
|
# Primary function to interact with this driver function
|
||||||
|
def scan_macs() -> List[str]:
|
||||||
|
log.info("Scanning for MACs:")
|
||||||
|
new_macs = asyncio.run(_scan_once())
|
||||||
|
log.info(f"Found {len(new_macs)} new MACs.")
|
||||||
|
return new_macs
|
||||||
|
|
||||||
|
# Scans nearby BT devices, return a list of detected MACs that pass the filter
|
||||||
async def _scan_once() -> List[str]:
|
async def _scan_once() -> List[str]:
|
||||||
"""
|
|
||||||
Scan once for nearby BLE devices and return the MAC addresses of those
|
|
||||||
that satisfy *filter_fn*.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
filter_fn : Callable[[address, name], bool] | None
|
|
||||||
If supplied, a predicate that receives the device address and name
|
|
||||||
and returns ``True`` when the device should be kept.
|
|
||||||
When ``None`` all discovered addresses are returned.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
List[str]
|
|
||||||
A list of MAC addresses (upper-case as returned by Bleak).
|
|
||||||
"""
|
|
||||||
log.info("Starting one-shot BLE scan (timeout = %.1fs)", SCAN_TIMEOUT)
|
log.info("Starting one-shot BLE scan (timeout = %.1fs)", SCAN_TIMEOUT)
|
||||||
try:
|
try:
|
||||||
devices = await BleakScanner.discover(timeout=SCAN_TIMEOUT)
|
devices = await BleakScanner.discover(timeout=SCAN_TIMEOUT)
|
||||||
@@ -131,26 +163,30 @@ async def _scan_once() -> List[str]:
|
|||||||
this_result = None
|
this_result = None
|
||||||
if "org.freedesktop.DBus.Error.AccessDenied" in e:
|
if "org.freedesktop.DBus.Error.AccessDenied" in e:
|
||||||
return []
|
return []
|
||||||
|
# only return MACs for devices that pass the _is_match
|
||||||
return [dev.address for dev in devices if _is_match(dev.address, dev.name)]
|
return [dev.address for dev in devices if _is_match(dev.address, dev.name)]
|
||||||
|
|
||||||
# this function filters MACs
|
# this function filters MACs for octets and model
|
||||||
def _is_match(mac: str, name: str) -> bool:
|
def _is_match(mac: str, name: str) -> bool:
|
||||||
"""Return True if the MAC starts with the configured prefix and is correct model."""
|
|
||||||
if name == "LYWSD03MMC":
|
if name == "LYWSD03MMC":
|
||||||
return mac.upper().startswith(MAC_PREFIX.upper())
|
return mac.upper().startswith(MAC_PREFIX.upper())
|
||||||
|
|
||||||
# this helper function scans for MACs
|
# This resets the BT adapter when things go caca
|
||||||
def scan_macs():
|
def reset_adapter():
|
||||||
log.info("Scanning for MACs:")
|
log.info("Restting BT Adapter...")
|
||||||
new_macs = asyncio.run(_scan_once())
|
if len(current_usb_id) > 0:
|
||||||
|
log.warning(f"Doing big reset - USB ID {current_usb_id}")
|
||||||
log.info(f"Found {len(new_macs)} new MACs.")
|
log.info(subprocess.run(["usbreset", current_usb_id], capture_output=True, text=True, check=True).stdout.strip())
|
||||||
return new_macs
|
time.sleep(2)
|
||||||
|
else:
|
||||||
|
log.warning("Hmm, this shouldn't happen, the current_usb_id is blank 0_o")
|
||||||
|
log.info("Reset complete. ")
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
# Core async read functions (unchanged from the refactored version)
|
# Core async read functions
|
||||||
# --------------------------------------------------------------------------- #
|
# Mined directly from the javascript
|
||||||
|
# This is the actual function that does the magic
|
||||||
|
####################################################
|
||||||
async def read_data(mac: str) -> Optional[SensorReading]:
|
async def read_data(mac: str) -> Optional[SensorReading]:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -165,13 +201,9 @@ async def read_data(mac: str) -> Optional[SensorReading]:
|
|||||||
if not address:
|
if not address:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
#address = await _discover_device(mac)
|
|
||||||
#if not address:
|
|
||||||
# return None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with BleakClient(address, timeout=CONNECT_TIMEOUT) as client:
|
async with BleakClient(address, timeout=CONNECT_TIMEOUT) as client:
|
||||||
# <--- NEW BLOCK ----------------------------------------------
|
# NEW BLOCK ----------------------------------------------
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(client.get_services(),
|
await asyncio.wait_for(client.get_services(),
|
||||||
timeout=SERVICE_DISCOVERY_TIMEOUT)
|
timeout=SERVICE_DISCOVERY_TIMEOUT)
|
||||||
@@ -181,9 +213,10 @@ async def read_data(mac: str) -> Optional[SensorReading]:
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Discovery failed - {e}")
|
log.error(f"Discovery failed - {e}")
|
||||||
# ---------------------------------------------------------------
|
|
||||||
|
|
||||||
|
####################################################
|
||||||
# If we get here, services are available.
|
# If we get here, services are available.
|
||||||
|
####################################################
|
||||||
if MI_SERVICE_UUID.lower() not in (
|
if MI_SERVICE_UUID.lower() not in (
|
||||||
s.uuid.lower() for s in client.services
|
s.uuid.lower() for s in client.services
|
||||||
):
|
):
|
||||||
@@ -205,11 +238,12 @@ async def read_data(mac: str) -> Optional[SensorReading]:
|
|||||||
log.exception("Error reading from %s: %s", mac, exc)
|
log.exception("Error reading from %s: %s", mac, exc)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
# Read all MACs concurrently. Skips any that fail.
|
||||||
|
# This was LLM written and is NOT TESTED!!!
|
||||||
|
# It will probably work as advertised though
|
||||||
|
####################################################
|
||||||
async def read_multiple(mac_list: List[str]) -> List[SensorReading]:
|
async def read_multiple(mac_list: List[str]) -> List[SensorReading]:
|
||||||
"""
|
|
||||||
Read all MACs concurrently. Skips any that fail.
|
|
||||||
"""
|
|
||||||
tasks = [asyncio.create_task(read_data(mac)) for mac in mac_list]
|
tasks = [asyncio.create_task(read_data(mac)) for mac in mac_list]
|
||||||
results = await asyncio.gather(*tasks, return_exceptions=False)
|
results = await asyncio.gather(*tasks, return_exceptions=False)
|
||||||
readings = [r for r in results if r is not None]
|
readings = [r for r in results if r is not None]
|
||||||
@@ -218,89 +252,71 @@ async def read_multiple(mac_list: List[str]) -> List[SensorReading]:
|
|||||||
log.warning("Failed to read: %s", ", ".join(failed))
|
log.warning("Failed to read: %s", ", ".join(failed))
|
||||||
return readings
|
return readings
|
||||||
|
|
||||||
|
####################################################
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Sync wrapper (kept for legacy code that cannot run an event loop)
|
# Sync wrapper (kept for legacy code that cannot run an event loop)
|
||||||
# --------------------------------------------------------------------------- #
|
# Also LLM Written and not used
|
||||||
|
####################################################
|
||||||
def read_data_sync(mac: str) -> Optional[SensorReading]:
|
def read_data_sync(mac: str) -> Optional[SensorReading]:
|
||||||
"""
|
|
||||||
Convenience wrapper that runs ``read_data`` in a fresh event-loop.
|
|
||||||
Use this from non-async code.
|
|
||||||
"""
|
|
||||||
return asyncio.run(read_data(mac))
|
return asyncio.run(read_data(mac))
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Other helper functions
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
def reset_adapter():
|
|
||||||
log.info("Restting BT Adapter...")
|
|
||||||
if len(current_usb_id) > 0:
|
|
||||||
log.warning(f"Doing big reset - USB ID {current_usb_id}")
|
|
||||||
log.info(subprocess.run(["usbreset", current_usb_id], capture_output=True, text=True, check=True).stdout.strip())
|
|
||||||
time.sleep(2)
|
|
||||||
else:
|
|
||||||
log.warning("Hmm, this shouldn't happen, the current_usb_id is blank 0_o")
|
|
||||||
#big_reset = False
|
|
||||||
#else:
|
|
||||||
# log.info(subprocess.run(["sudo", "rfkill", "block", "bluetooth"], capture_output=True, text=True, check=True).stdout.strip())
|
|
||||||
# time.sleep(2)
|
|
||||||
# log.info(subprocess.run(["sudo", "rfkill", "unblock", "bluetooth"], capture_output=True, text=True, check=True).stdout.strip())
|
|
||||||
# time.sleep(5)
|
|
||||||
log.info("Reset complete. ")
|
|
||||||
|
|
||||||
def sensor_data_query(mac_list: List[str]) -> List[dict]:
|
|
||||||
result = []
|
|
||||||
for mac in mac_list:
|
|
||||||
try:
|
|
||||||
this_result = asyncio.run(read_data(mac))
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f"Error reading BLE data - {e}")
|
|
||||||
this_result = None
|
|
||||||
if "org.freedesktop.DBus.Error.AccessDenied" in e:
|
|
||||||
reset_adapter()
|
|
||||||
return result
|
|
||||||
if this_result:
|
|
||||||
result.append(
|
|
||||||
{"name": mac, "temp": this_result.temperature, "humidity": this_result.humidity}
|
|
||||||
)
|
|
||||||
log.info(f"Data query complete - returning result")
|
|
||||||
return result
|
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
# Test Function
|
# Test Function Section
|
||||||
# This runs a single full test of the driver
|
# This runs a single full test of the driver
|
||||||
|
# This two-step process first runs a single scan
|
||||||
|
# Then, it scans the list until all devices have been scanned
|
||||||
####################################################
|
####################################################
|
||||||
def test(test_count = 0, bt_usb_id = None) -> None:
|
|
||||||
# first test scanner
|
def test_driver(test_count = 0, bt_usb_id = None):
|
||||||
|
|
||||||
|
# if this happens then this needs to fail
|
||||||
if bt_usb_id == None:
|
if bt_usb_id == None:
|
||||||
log.error(f"Error - no USB ID Passed, this is needed for the test")
|
log.error(f"Error - no USB ID Passed, this is needed for the test")
|
||||||
return -1
|
return -1
|
||||||
log.info(f"Ensuring BLE active...")
|
|
||||||
|
####################################################
|
||||||
|
# first test - scanner function
|
||||||
|
# the scanner function scans for compatible devices in range
|
||||||
|
# this is pretty simple
|
||||||
|
####################################################
|
||||||
|
|
||||||
test_loop_count = 0
|
test_loop_count = 0
|
||||||
found_macs = scan_macs()
|
found_macs = scan_macs()
|
||||||
log.info("Found these MACs on a scan:")
|
log.info("Found these MACs on a scan:")
|
||||||
log.info(found_macs)
|
log.info(found_macs)
|
||||||
test_result = False
|
|
||||||
|
####################################################
|
||||||
|
# second test - scan devices for data
|
||||||
|
# the primary function to perform this task is sensor_data_query
|
||||||
|
# that runs a single scan and returns a list of sensor data dicts
|
||||||
|
# this test runs that task as many times as it takes
|
||||||
|
# to get all the MACs in the mac_list
|
||||||
|
####################################################
|
||||||
|
|
||||||
|
test_complete = False
|
||||||
sensors = []
|
sensors = []
|
||||||
mac_list = []
|
mac_list = []
|
||||||
|
# this gets MACs from the comment dict in config
|
||||||
for mac in comment_lookup:
|
for mac in comment_lookup:
|
||||||
mac_list.append(mac['mac'])
|
mac_list.append(mac['mac'])
|
||||||
#[
|
|
||||||
# "A4:C1:38:96:53:30",
|
|
||||||
# "A4:C1:38:11:F4:2A",
|
|
||||||
# "A4:C1:38:24:15:B0",
|
|
||||||
# "A4:C1:38:D7:8D:26",
|
|
||||||
#]
|
|
||||||
log.info("Starting BLE test...")
|
log.info("Starting BLE test...")
|
||||||
log.info(f" Scanning MACs: {mac_list}")
|
log.info(f" Scanning MACs: {mac_list}")
|
||||||
|
# test_list shrinks with successful tests
|
||||||
test_list = mac_list
|
test_list = mac_list
|
||||||
|
# for the history logic
|
||||||
passed_list = []
|
passed_list = []
|
||||||
# History buffer - keep the last N snapshots (N=5)
|
|
||||||
mac_history = []
|
mac_history = []
|
||||||
prev_list_snapshot = None
|
prev_list_snapshot = None
|
||||||
while not test_result:
|
|
||||||
# Check if the failed list has been the same for 5 loops
|
####################################################
|
||||||
|
# here is the big main test loop
|
||||||
|
# only for second function
|
||||||
|
####################################################
|
||||||
|
|
||||||
|
while not test_complete:
|
||||||
|
|
||||||
|
# Check if the failed list has been the same for reset_retries loops
|
||||||
|
# If so, reset adapter and history
|
||||||
if prev_list_snapshot is not None and passed_list == prev_list_snapshot:
|
if prev_list_snapshot is not None and passed_list == prev_list_snapshot:
|
||||||
# List unchanged - add to mac_history
|
# List unchanged - add to mac_history
|
||||||
mac_history.append(passed_list)
|
mac_history.append(passed_list)
|
||||||
@@ -313,14 +329,22 @@ def test(test_count = 0, bt_usb_id = None) -> None:
|
|||||||
reset_adapter()
|
reset_adapter()
|
||||||
mac_history = []
|
mac_history = []
|
||||||
prev_list_snapshot = passed_list
|
prev_list_snapshot = passed_list
|
||||||
|
|
||||||
|
# Preparing this scan loop
|
||||||
log.info(f" Test run: {test_count} - loop {test_loop_count} start. Initializing run...")
|
log.info(f" Test run: {test_count} - loop {test_loop_count} start. Initializing run...")
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
# Here the primary sensor_data_query query is executed
|
||||||
|
####################################################
|
||||||
test_run_results = sensor_data_query(test_list)
|
test_run_results = sensor_data_query(test_list)
|
||||||
|
|
||||||
|
# This all governs the loop logic and test variable handling
|
||||||
test_loop_count = test_loop_count + 1
|
test_loop_count = test_loop_count + 1
|
||||||
for test_run_result in test_run_results:
|
for test_run_result in test_run_results:
|
||||||
sensors.append(test_run_result)
|
sensors.append(test_run_result)
|
||||||
passed_list = [device["name"] for device in sensors]
|
passed_list = [device["name"] for device in sensors]
|
||||||
log.info(f" Passed list - {passed_list}")
|
log.info(f" Passed list - {passed_list}")
|
||||||
|
# If all the MACs have been scanned, then this test is complete.
|
||||||
if len(mac_list) == len(passed_list):
|
if len(mac_list) == len(passed_list):
|
||||||
log.info(f" Test run {test_count} completed, yee-haw")
|
log.info(f" Test run {test_count} completed, yee-haw")
|
||||||
for sensor in sensors:
|
for sensor in sensors:
|
||||||
@@ -330,21 +354,26 @@ def test(test_count = 0, bt_usb_id = None) -> None:
|
|||||||
"found_macs": found_macs,
|
"found_macs": found_macs,
|
||||||
"sensor_results": sensors
|
"sensor_results": sensors
|
||||||
}
|
}
|
||||||
test_result = True
|
test_complete = True
|
||||||
return result
|
return result
|
||||||
|
# If not, then re-scan the failed sensors
|
||||||
else:
|
else:
|
||||||
log.warning(f" Test run incomplete/failed, attempt {len(mac_history)} of {reset_retries}, re-running, loop {test_loop_count}. Updating test list.")
|
log.warning(f" Test run incomplete/failed, attempt {len(mac_history)} of {reset_retries}, re-running, loop {test_loop_count}. Updating test list.")
|
||||||
for sensor in sensors:
|
for sensor in sensors:
|
||||||
|
# Sorry I can't feel celcius, I want my freedom degrees
|
||||||
temp_f = (sensor['temp'] * 1.80) + 32.0
|
temp_f = (sensor['temp'] * 1.80) + 32.0
|
||||||
log.info(f" {sensor['name']} - Temp: {round(temp_f,1)} | Humidity: {sensor['humidity']}")
|
log.info(f" {sensor['name']} - Temp: {round(temp_f,1)} | Humidity: {sensor['humidity']}")
|
||||||
mac_list_new = []
|
mac_list_new = []
|
||||||
for mac in mac_list:
|
for mac in mac_list:
|
||||||
if mac not in passed_list:
|
if mac not in passed_list:
|
||||||
mac_list_new.append(mac)
|
mac_list_new.append(mac)
|
||||||
|
# here is where test_list might shrink
|
||||||
test_list = mac_list_new
|
test_list = mac_list_new
|
||||||
log.warning(f" Re-do list - {test_list}")
|
log.warning(f" Re-do list - {test_list}")
|
||||||
|
|
||||||
# helper function to guess the USB ID. It isn't hard
|
# end of the big main test loop and test_driver function
|
||||||
|
|
||||||
|
# helper function to guess the USB ID. It isn't usually hard
|
||||||
def usb_id_guess():
|
def usb_id_guess():
|
||||||
log.warning("USB ID Not found, I'll try and guess...")
|
log.warning("USB ID Not found, I'll try and guess...")
|
||||||
result = ''
|
result = ''
|
||||||
@@ -364,12 +393,12 @@ def usb_id_guess():
|
|||||||
log.error(f"USB-ID guess failed: {exc}")
|
log.error(f"USB-ID guess failed: {exc}")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
# If run as a script, execute the legacy test
|
# If ble.py is run as a script, it will execute a test
|
||||||
# Since I intend to run this service for months at a time,
|
# Since I intend to run this driver for months at a time,
|
||||||
# I need to do some robust long term tests on the driver
|
# I need to do some robust long term tests on it
|
||||||
# This entire main subroutine is dedicated to testing the driver
|
# This entire main subroutine is dedicated to testing it
|
||||||
# --------------------------------------------------------------------------- #
|
####################################################
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
@@ -439,7 +468,7 @@ if __name__ == "__main__":
|
|||||||
# it's tricky, the test run is called here inside the json
|
# it's tricky, the test run is called here inside the json
|
||||||
this_test_result = {
|
this_test_result = {
|
||||||
"test_label": test_label,
|
"test_label": test_label,
|
||||||
"test_result": test(test_count = test_count, bt_usb_id = current_usb_id)
|
"test_result": test_driver(test_count = test_count, bt_usb_id = current_usb_id)
|
||||||
}
|
}
|
||||||
test_results.append(this_test_result)
|
test_results.append(this_test_result)
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user