11
11
import logging
12
12
from math import tanh
13
13
from struct import Struct
14
+ from typing import Union
14
15
15
16
from bluetooth_data_tools import short_address
16
17
from bluetooth_sensor_state_data import BluetoothData
29
30
UNPACK_TEMP_HUMID = Struct ("<hB" ).unpack
30
31
UNPACK_SPIKE_TEMP = Struct ("<BHHH" ).unpack
31
32
33
+ ABSOLUTE_MIN_HUMIDITY__PERCENTAGE = 0
34
+ ABSOLUTE_MAX_HUMIDITY__PERCENTAGE = 100
35
+ ABSOLUTE_MIN_TEMPERATURE__CELCIUS = - 273.15
32
36
33
37
# TP96x battery values appear to be a voltage reading, probably in millivolts.
34
38
# This means that calculating battery life from it is a non-linear function.
@@ -41,6 +45,15 @@ def tp96_battery(voltage: int) -> float:
41
45
clamped = max (0 , min (raw , 100 ))
42
46
return round (clamped , 2 )
43
47
48
+ def is_temp_hum_invalid (temperature : Union [int , float ], humidity : Union [int , float ]) -> bool :
49
+ """Returns true if the measured values are outside the physically possible range."""
50
+ # Note: This will not catch implausibly high temperature values, but a clear
51
+ # upper temperature cutoff is not easy to define
52
+ if temperature < ABSOLUTE_MIN_TEMPERATURE__CELCIUS :
53
+ return True
54
+ if not (ABSOLUTE_MIN_HUMIDITY__PERCENTAGE <= humidity <= ABSOLUTE_MAX_HUMIDITY__PERCENTAGE ):
55
+ return True
56
+ return False
44
57
45
58
class ThermoProBluetoothDeviceData (BluetoothData ):
46
59
"""Date update for ThermoPro Bluetooth devices."""
@@ -91,6 +104,11 @@ def _start_update(self, service_info: BluetoothServiceInfo) -> None:
91
104
internal_temp = internal_temp - 30
92
105
ambient_temp = ambient_temp - 30
93
106
battery_percent = tp96_battery (battery_voltage )
107
+
108
+ if is_temp_hum_invalid (internal_temp , 0 ) or is_temp_hum_invalid (ambient_temp , 0 ):
109
+ # Invalid packet, probably corrupted
110
+ return
111
+
94
112
self .update_predefined_sensor (
95
113
SensorLibrary .TEMPERATURE__CELSIUS ,
96
114
internal_temp ,
@@ -110,16 +128,21 @@ def _start_update(self, service_info: BluetoothServiceInfo) -> None:
110
128
key = f"battery_probe_{ probe_one_indexed } " ,
111
129
name = f"Probe { probe_one_indexed } Battery" ,
112
130
)
113
- return
114
-
115
- # TP357S seems to be in 6, TP397 and TP393 in 4
116
- battery_byte = data [6 ] if len (data ) == 7 else data [4 ]
117
- if battery_byte in BATTERY_VALUE_TO_LEVEL :
118
- self .update_predefined_sensor (
119
- SensorLibrary .BATTERY__PERCENTAGE ,
120
- BATTERY_VALUE_TO_LEVEL [battery_byte ],
121
- )
122
-
123
- (temp , humi ) = UNPACK_TEMP_HUMID (data [1 :4 ])
124
- self .update_predefined_sensor (SensorLibrary .TEMPERATURE__CELSIUS , temp / 10 )
125
- self .update_predefined_sensor (SensorLibrary .HUMIDITY__PERCENTAGE , humi )
131
+ else :
132
+ # TP357S seems to be in 6, TP397 and TP393 in 4
133
+ battery_byte = data [6 ] if len (data ) == 7 else data [4 ]
134
+ (temp_deci , humi ) = UNPACK_TEMP_HUMID (data [1 :4 ])
135
+ temp = temp_deci / 10
136
+
137
+ if is_temp_hum_invalid (temp , humi ):
138
+ # Invalid data, probably corrupted
139
+ return
140
+
141
+ if battery_byte in BATTERY_VALUE_TO_LEVEL :
142
+ self .update_predefined_sensor (
143
+ SensorLibrary .BATTERY__PERCENTAGE ,
144
+ BATTERY_VALUE_TO_LEVEL [battery_byte ],
145
+ )
146
+
147
+ self .update_predefined_sensor (SensorLibrary .TEMPERATURE__CELSIUS , temp )
148
+ self .update_predefined_sensor (SensorLibrary .HUMIDITY__PERCENTAGE , humi )
0 commit comments