4646
4747def broadcast (measurement , * , broadcast_time = 0.1 , extended = False ):
4848 """Broadcasts the given measurement for the given broadcast time. If extended is False and the
49- measurement would be too long, it will be split into multiple measurements for transmission.
50- """
49+ measurement would be too long, it will be split into multiple measurements for transmission.
50+ """
5151 global _sequence_number # pylint: disable=global-statement,invalid-name
5252 for submeasurement in measurement .split (252 if extended else 31 ):
5353 submeasurement .sequence_number = _sequence_number
@@ -61,14 +61,17 @@ def broadcast(measurement, *, broadcast_time=0.1, extended=False):
6161if not hasattr (os , "environ" ) or (
6262 "GITHUB_ACTION" not in os .environ and "READTHEDOCS" not in os .environ
6363):
64- device_address = "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}" .format ( # pylint: disable=invalid-name
65- * reversed (
66- list (
67- _ble ._adapter .address .address_bytes # pylint: disable=protected-access
64+ if _ble ._adapter .address : # pylint: disable=protected-access
65+ device_address = "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}" .format ( # pylint: disable=invalid-name
66+ * reversed (
67+ list (
68+ _ble ._adapter .address .address_bytes # pylint: disable=protected-access
69+ )
6870 )
6971 )
70- )
71- """Device address as a string."""
72+ else :
73+ device_address = "000000000000" # pylint: disable=invalid-name
74+ """Device address as a string."""
7275
7376_MANUFACTURING_DATA_ADT = const (0xFF )
7477_ADAFRUIT_COMPANY_ID = const (0x0822 )
@@ -79,7 +82,10 @@ class AdafruitSensorMeasurement(Advertisement):
7982
8083 # This prefix matches all
8184 match_prefixes = (
82- struct .pack ("<BBH" , 3 , _MANUFACTURING_DATA_ADT , _ADAFRUIT_COMPANY_ID ),
85+ # Matches the sequence number field header (length+ID)
86+ struct .pack (
87+ "<BHBH" , _MANUFACTURING_DATA_ADT , _ADAFRUIT_COMPANY_ID , 0x03 , 0x0003
88+ ),
8389 )
8490
8591 manufacturer_data = LazyObjectField (
@@ -175,9 +181,16 @@ def __str__(self):
175181 parts .append ("{}={}" .format (attr , str (value )))
176182 return "<{} {} >" .format (self .__class__ .__name__ , " " .join (parts ))
177183
184+ def __bytes__ (self ):
185+ """The raw packet bytes."""
186+ # Must reorder the ManufacturerData contents so the sequence number field is always first.
187+ # Necessary to ensure that match_prefixes works right to reconstruct on the receiver.
188+ self .data_dict [255 ].data .move_to_end (3 , last = False )
189+ return super ().__bytes__ ()
190+
178191 def split (self , max_packet_size = 31 ):
179192 """Split the measurement into multiple measurements with the given max_packet_size. Yields
180- each submeasurement."""
193+ each submeasurement."""
181194 current_size = 8 # baseline for mfg data and sequence number
182195 if current_size + len (self .manufacturer_data ) < max_packet_size :
183196 yield self
0 commit comments