Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add range check for temperature and humidity #32

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 44 additions & 13 deletions src/thermopro_ble/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
UNPACK_TEMP_HUMID = Struct("<hB").unpack
UNPACK_SPIKE_TEMP = Struct("<BHHH").unpack

ABSOLUTE_MIN_HUMIDITY__PERCENTAGE = 0
ABSOLUTE_MAX_HUMIDITY__PERCENTAGE = 100
ABSOLUTE_MIN_TEMPERATURE__CELCIUS = -273.15


# TP96x battery values appear to be a voltage reading, probably in millivolts.
# This means that calculating battery life from it is a non-linear function.
Expand All @@ -42,6 +46,21 @@ def tp96_battery(voltage: int) -> float:
return round(clamped, 2)


def is_temp_hum_invalid(temperature: int | float, humidity: int | float) -> bool:
"""Returns true if the measured values are outside the physically possible range."""
# Note: This will not catch implausibly high temperature values, but a clear
# upper temperature cutoff is not easy to define
if temperature < ABSOLUTE_MIN_TEMPERATURE__CELCIUS:
return True
if not (
ABSOLUTE_MIN_HUMIDITY__PERCENTAGE
<= humidity
<= ABSOLUTE_MAX_HUMIDITY__PERCENTAGE
):
return True
return False


class ThermoProBluetoothDeviceData(BluetoothData):
"""Date update for ThermoPro Bluetooth devices."""

Expand Down Expand Up @@ -91,6 +110,13 @@ def _start_update(self, service_info: BluetoothServiceInfo) -> None:
internal_temp = internal_temp - 30
ambient_temp = ambient_temp - 30
battery_percent = tp96_battery(battery_voltage)

if is_temp_hum_invalid(internal_temp, 0) or is_temp_hum_invalid(
ambient_temp, 0
):
# Invalid packet, probably corrupted
return

self.update_predefined_sensor(
SensorLibrary.TEMPERATURE__CELSIUS,
internal_temp,
Expand All @@ -110,16 +136,21 @@ def _start_update(self, service_info: BluetoothServiceInfo) -> None:
key=f"battery_probe_{probe_one_indexed}",
name=f"Probe {probe_one_indexed} Battery",
)
return

# TP357S seems to be in 6, TP397 and TP393 in 4
battery_byte = data[6] if len(data) == 7 else data[4]
if battery_byte in BATTERY_VALUE_TO_LEVEL:
self.update_predefined_sensor(
SensorLibrary.BATTERY__PERCENTAGE,
BATTERY_VALUE_TO_LEVEL[battery_byte],
)

(temp, humi) = UNPACK_TEMP_HUMID(data[1:4])
self.update_predefined_sensor(SensorLibrary.TEMPERATURE__CELSIUS, temp / 10)
self.update_predefined_sensor(SensorLibrary.HUMIDITY__PERCENTAGE, humi)
else:
# TP357S seems to be in 6, TP397 and TP393 in 4
battery_byte = data[6] if len(data) == 7 else data[4]
(temp_deci, humi) = UNPACK_TEMP_HUMID(data[1:4])
temp = temp_deci / 10

if is_temp_hum_invalid(temp, humi):
# Invalid data, probably corrupted
return

if battery_byte in BATTERY_VALUE_TO_LEVEL:
self.update_predefined_sensor(
SensorLibrary.BATTERY__PERCENTAGE,
BATTERY_VALUE_TO_LEVEL[battery_byte],
)

self.update_predefined_sensor(SensorLibrary.TEMPERATURE__CELSIUS, temp)
self.update_predefined_sensor(SensorLibrary.HUMIDITY__PERCENTAGE, humi)
Loading