@@ -27,9 +27,9 @@ class BTHome:
2727 _local_name = ""
2828
2929 # Naming convention is:
30- # <property> "_" <data-type> "_x" <inverse of factor> = <object-id >
31- # For example, 0x02 temperature sint16 0.01 becomes:
32- # TEMPERATURE _ SINT16 _x 100 = 0x02
30+ # <const_name> ::= < property> "_" <data-type> "_x" <inverse of factor>
31+ # For example, temperature sint16 0.01 becomes:
32+ # TEMPERATURE _ SINT16 _x 100
3333 # See "Sensor Data" table at https://bthome.io/format/
3434 BATTERY_UINT8_X1 = const (0x01 ) # %
3535 TEMPERATURE_SINT16_X100 = const (0x02 ) # °C
@@ -75,6 +75,17 @@ class BTHome:
7575 TEXT_BYTES = const (0x53 )
7676 RAW_BYTES = const (0x54 )
7777 VOLUME_STORAGE_UINT32_X1000 = const (0x55 ) # L
78+ CONDUCTIVITY_UINT16_X1 = const (0x56 ) # µS/cm
79+ TEMPERATURE_SINT8_X1 = const (0x57 ) # °C
80+ # Skipping 0x58 due to strange factor of 0.35
81+ COUNT_SINT8_X1 = const (0x59 )
82+ COUNT_SINT16_X1 = const (0x5A )
83+ COUNT_SINT32_X1 = const (0x5B )
84+ POWER_SINT16_X100 = const (0x5C ) # W
85+ CURRENT_SINT16_X1000 = const (0x5D ) # A
86+ DIRECTION_UINT16_X100 = const (0x5E ) # °
87+ PRECIPITATION_UINT16_X1 = const (0x5F ) # mm
88+ CHANNEL_UINT8_X1 = const (0x60 )
7889
7990 # There is more than one way to represent most sensor properties. This
8091 # dictionary maps the object id to the property name.
@@ -119,7 +130,17 @@ class BTHome:
119130 TIMESTAMP_UINT48_X1 : "timestamp" ,
120131 ACCELERATION_UINT16_X1000 : "acceleration" ,
121132 GYROSCOPE_UINT16_X1000 : "gyroscope" ,
122- VOLUME_STORAGE_UINT32_X1000 : "volume_storage"
133+ VOLUME_STORAGE_UINT32_X1000 : "volume_storage" ,
134+ CONDUCTIVITY_UINT16_X1 : "conductivity" ,
135+ TEMPERATURE_SINT8_X1 : "temperature" ,
136+ COUNT_SINT8_X1 : "count" ,
137+ COUNT_SINT16_X1 : "count" ,
138+ COUNT_SINT32_X1 : "count" ,
139+ POWER_SINT16_X100 : "power" ,
140+ CURRENT_SINT16_X1000 : "current" ,
141+ DIRECTION_UINT16_X100 : "direction" ,
142+ PRECIPITATION_UINT16_X1 : "precipitation" ,
143+ CHANNEL_UINT8_X1 : "channel"
123144 }
124145
125146 # Properties below are updated externally when sensor values are read.
@@ -170,15 +191,6 @@ def __init__(self, local_name="BTHome", debug=False):
170191 def local_name (self ):
171192 return self ._local_name
172193
173- def pack_local_name (self ):
174- name_type = bytes .fromhex ("09" ) # indicator for complete name
175- local_name_bytes = name_type + self ._local_name .encode ()
176- local_name_bytes = bytes ([len (local_name_bytes )]) + local_name_bytes
177- if self .debug :
178- print ("Local name:" , self ._local_name )
179- print ("Packed representation:" , local_name_bytes .hex ().upper ())
180- return local_name_bytes
181-
182194 # Technically, the functions below could be static methods, but @staticmethod
183195 # on a dictionary of functions only works with Python >3.10, and MicroPython
184196 # is based on 3.4. Also, __func__ and __get()__ workarounds throw errors in
@@ -192,13 +204,9 @@ def _pack_uint8_x1(self, object_id, value):
192204 def _pack_uint8_x10 (self , object_id , value ):
193205 return pack ("BB" , object_id , round (value * 10 ))
194206
195- # 16-bit signed integer with scalling of 10 (1 decimal place)
196- def _pack_sint16_x10 (self , object_id , value ):
197- return pack ("<Bh" , object_id , round (value * 10 ))
198-
199- # 16-bit signed integer with scalling of 100 (2 decimal places)
200- def _pack_sint16_x100 (self , object_id , value ):
201- return pack ("<Bh" , object_id , round (value * 100 ))
207+ # 8-bit signed integer with scalling of 1 (no decimal places)
208+ def _pack_sint8_x1 (self , object_id , value ):
209+ return pack ("BB" , object_id , round (value ))
202210
203211 # 16-bit unsigned integer with scalling of 1 (no decimal places)
204212 def _pack_uint16_x1 (self , object_id , value ):
@@ -216,6 +224,22 @@ def _pack_uint16_x100(self, object_id, value):
216224 def _pack_uint16_x1000 (self , object_id , value ):
217225 return pack ("<BH" , object_id , round (value * 1000 ))
218226
227+ # 16-bit signed integer with scalling of 1 (no decimal places)
228+ def _pack_sint16_x1 (self , object_id , value ):
229+ return pack ("<BH" , object_id , round (value ))
230+
231+ # 16-bit signed integer with scalling of 10 (1 decimal place)
232+ def _pack_sint16_x10 (self , object_id , value ):
233+ return pack ("<Bh" , object_id , round (value * 10 ))
234+
235+ # 16-bit signed integer with scalling of 100 (2 decimal places)
236+ def _pack_sint16_x100 (self , object_id , value ):
237+ return pack ("<Bh" , object_id , round (value * 100 ))
238+
239+ # 16-bit signed integer with scalling of 1000 (3 decimal places)
240+ def _pack_sint16_x1000 (self , object_id , value ):
241+ return pack ("<Bh" , object_id , round (value * 1000 ))
242+
219243 # 24-bit unsigned integer with scaling of 100 (2 decimal places)
220244 def _pack_uint24_x100 (self , object_id , value ):
221245 return pack ("<BL" , object_id , round (value * 100 ))[:- 1 ]
@@ -232,12 +256,16 @@ def _pack_uint32_x1(self, object_id, value):
232256 def _pack_uint32_x1000 (self , object_id , value ):
233257 return pack ("<BL" , object_id , round (value * 1000 ))
234258
259+ # 32-bit signed integer with scalling of 1 (no decimal places)
260+ def _pack_sint32_x1 (self , object_id , value ):
261+ return pack ("<BL" , object_id , round (value ))
262+
235263 # 48-bit unsigned integer with scaling of 1 (no decimal places)
236264 def _pack_uint48_x1 (self , object_id , value ):
237265 return pack ("<BQ" , object_id , value )[:- 2 ]
238266
239267 def _pack_raw_text (self , object_id , value ):
240- packed_value = bytes ( object_id ) + value .encode ()
268+ packed_value = pack ( "B" , object_id ) + value .encode ()
241269 packed_value = bytes ([len (packed_value )]) + packed_value
242270 return packed_value
243271
@@ -285,7 +313,17 @@ def _pack_raw_text(self, object_id, value):
285313 GYROSCOPE_UINT16_X1000 : _pack_uint16_x1000 ,
286314 TEXT_BYTES : _pack_raw_text ,
287315 RAW_BYTES : _pack_raw_text ,
288- VOLUME_STORAGE_UINT32_X1000 : _pack_uint32_x1000
316+ VOLUME_STORAGE_UINT32_X1000 : _pack_uint32_x1000 ,
317+ CONDUCTIVITY_UINT16_X1 : _pack_uint16_x1 ,
318+ TEMPERATURE_SINT8_X1 : _pack_sint8_x1 ,
319+ COUNT_SINT8_X1 : _pack_sint8_x1 ,
320+ COUNT_SINT16_X1 : _pack_sint16_x1 ,
321+ COUNT_SINT32_X1 : _pack_sint32_x1 ,
322+ POWER_SINT16_X100 : _pack_sint16_x100 ,
323+ CURRENT_SINT16_X1000 : _pack_sint16_x1000 ,
324+ DIRECTION_UINT16_X100 : _pack_uint16_x100 ,
325+ PRECIPITATION_UINT16_X1 : _pack_uint16_x1 ,
326+ CHANNEL_UINT8_X1 : _pack_uint8_x1
289327 }
290328
291329 # Concatenate an arbitrary number of sensor readings using parameters
@@ -312,7 +350,7 @@ def _pack_service_data(self, *args):
312350
313351 def pack_advertisement (self , * args ):
314352 advertisement_bytes = self ._ADVERT_FLAGS # All BTHome adverts start this way.
315- advertisement_bytes += self .pack_local_name ()
353+ advertisement_bytes += self ._pack_raw_text ( 0x09 , self . local_name ) # 0x09 indicates complete name
316354 advertisement_bytes += self ._pack_service_data (* args )
317355 if self .debug :
318356 print ("BLE Advertisement:" , advertisement_bytes .hex ().upper ())
0 commit comments