1111
1212import logging
1313from math import tanh
14- from struct import Struct , error as struct_error
14+ from struct import Struct
1515
1616from bluetooth_data_tools import short_address
1717from bluetooth_sensor_state_data import BluetoothData
1818from sensor_state_data import SensorLibrary
1919
20- from habluetooth import BluetoothServiceInfoBleak
20+ from habluetooth import BluetoothServiceInfo , BluetoothServiceInfoBleak
2121
2222_LOGGER = logging .getLogger (__name__ )
2323
3030
3131UNPACK_TEMP_HUMID = Struct ("<hB" ).unpack
3232UNPACK_SPIKE_TEMP = Struct ("<BHHH" ).unpack
33+ UNPACK_SPIKE_PRO_TEMP = Struct ("<BHHfffHHH" ).unpack
3334
3435
3536# TP96x battery values appear to be a voltage reading, probably in millivolts.
@@ -47,7 +48,36 @@ def tp96_battery(voltage: int) -> float:
4748class ThermoProBluetoothDeviceData (BluetoothData ):
4849 """Date update for ThermoPro Bluetooth devices."""
4950
50- def _start_update (self , service_info : BluetoothServiceInfoBleak ) -> None :
51+ def _update_sensors (
52+ self ,
53+ probe_one_indexed : int ,
54+ internal_temp : int ,
55+ ambient_temp : int ,
56+ battery_percent : float ,
57+ ) -> None :
58+ self .update_predefined_sensor (
59+ SensorLibrary .TEMPERATURE__CELSIUS ,
60+ internal_temp ,
61+ key = f"internal_temperature_probe_{ probe_one_indexed } " ,
62+ name = f"Probe { probe_one_indexed } Internal Temperature" ,
63+ )
64+ self .update_predefined_sensor (
65+ SensorLibrary .TEMPERATURE__CELSIUS ,
66+ ambient_temp ,
67+ key = f"ambient_temperature_probe_{ probe_one_indexed } " ,
68+ name = f"Probe { probe_one_indexed } Ambient Temperature" ,
69+ )
70+ self .set_precision (0 )
71+ self .update_predefined_sensor (
72+ SensorLibrary .BATTERY__PERCENTAGE ,
73+ battery_percent ,
74+ key = f"battery_probe_{ probe_one_indexed } " ,
75+ name = f"Probe { probe_one_indexed } Battery" ,
76+ )
77+
78+ def _start_update (
79+ self , service_info : BluetoothServiceInfo | BluetoothServiceInfoBleak
80+ ) -> None :
5181 """Update from BLE advertisement data."""
5282 _LOGGER .debug ("Parsing thermopro BLE advertisement data: %s" , service_info )
5383 name = service_info .name
@@ -74,56 +104,63 @@ def _start_update(self, service_info: BluetoothServiceInfoBleak) -> None:
74104 + changed_manufacturer_data [last_id ]
75105 )
76106
77- if len (data ) < 6 :
107+ data_length = len (data )
108+
109+ if data_length == 23 and name .startswith ("TP97" ):
110+ # TP972 has a 23-byte format
111+ # It has an internal temp probe and an ambient temp probe
112+ (
113+ probe_zero_indexed ,
114+ ambient_temp ,
115+ battery_voltage ,
116+ _ , # looks to be part of some temp range (min)
117+ internal_temp ,
118+ _ , # looks to be part of some temp range (max)
119+ _ ,
120+ _ ,
121+ _ , # looks like a static id
122+ ) = UNPACK_SPIKE_PRO_TEMP (data )
123+
124+ probe_one_indexed = probe_zero_indexed + 1
125+ internal_temp = int (internal_temp ) - 54
126+ ambient_temp = int (ambient_temp ) - 54
127+ battery_percent = tp96_battery (battery_voltage )
128+ self ._update_sensors (
129+ probe_one_indexed , internal_temp , ambient_temp , battery_percent
130+ )
78131 return
79132
80- if name .startswith (("TP96" , "TP97" )):
81- # TP96 has a different format
133+ if data_length == 7 and name .startswith (("TP96" , "TP97" )):
134+ # TP96 has a different format that is shared with TP970
82135 # It has an internal temp probe and an ambient temp probe
83- try :
84- (
85- probe_zero_indexed ,
86- internal_temp ,
87- battery_voltage ,
88- ambient_temp ,
89- ) = UNPACK_SPIKE_TEMP (data )
90- except struct_error :
91- _LOGGER .error ("Error parsing data from probe: %s" , data )
92- return
136+ (
137+ probe_zero_indexed ,
138+ internal_temp ,
139+ battery_voltage ,
140+ ambient_temp ,
141+ ) = UNPACK_SPIKE_TEMP (data )
93142
94143 probe_one_indexed = probe_zero_indexed + 1
95144 internal_temp = internal_temp - 30
96145 ambient_temp = ambient_temp - 30
97146 battery_percent = tp96_battery (battery_voltage )
98- self .update_predefined_sensor (
99- SensorLibrary .TEMPERATURE__CELSIUS ,
100- internal_temp ,
101- key = f"internal_temperature_probe_{ probe_one_indexed } " ,
102- name = f"Probe { probe_one_indexed } Internal Temperature" ,
103- )
104- self .update_predefined_sensor (
105- SensorLibrary .TEMPERATURE__CELSIUS ,
106- ambient_temp ,
107- key = f"ambient_temperature_probe_{ probe_one_indexed } " ,
108- name = f"Probe { probe_one_indexed } Ambient Temperature" ,
109- )
110- self .set_precision (0 )
111- self .update_predefined_sensor (
112- SensorLibrary .BATTERY__PERCENTAGE ,
113- battery_percent ,
114- key = f"battery_probe_{ probe_one_indexed } " ,
115- name = f"Probe { probe_one_indexed } Battery" ,
147+ self ._update_sensors (
148+ probe_one_indexed , internal_temp , ambient_temp , battery_percent
116149 )
117150 return
118151
119152 # TP357S seems to be in 6, TP397 and TP393 in 4
120- battery_byte = data [6 ] if len (data ) == 7 else data [4 ]
121- if battery_byte in BATTERY_VALUE_TO_LEVEL :
122- self .update_predefined_sensor (
123- SensorLibrary .BATTERY__PERCENTAGE ,
124- BATTERY_VALUE_TO_LEVEL [battery_byte ],
125- )
153+ if data_length >= 6 and name .startswith ("TP3" ):
154+ battery_byte = data [6 ] if data_length == 7 else data [4 ]
155+ if battery_byte in BATTERY_VALUE_TO_LEVEL :
156+ self .update_predefined_sensor (
157+ SensorLibrary .BATTERY__PERCENTAGE ,
158+ BATTERY_VALUE_TO_LEVEL [battery_byte ],
159+ )
160+
161+ (temp , humi ) = UNPACK_TEMP_HUMID (data [1 :4 ])
162+ self .update_predefined_sensor (SensorLibrary .TEMPERATURE__CELSIUS , temp / 10 )
163+ self .update_predefined_sensor (SensorLibrary .HUMIDITY__PERCENTAGE , humi )
164+ return
126165
127- (temp , humi ) = UNPACK_TEMP_HUMID (data [1 :4 ])
128- self .update_predefined_sensor (SensorLibrary .TEMPERATURE__CELSIUS , temp / 10 )
129- self .update_predefined_sensor (SensorLibrary .HUMIDITY__PERCENTAGE , humi )
166+ _LOGGER .error ("Error parsing data from probe: %s" , data )
0 commit comments