def processBLEBeacon(data): # While I'm not a fan of globals, not sure how else we can store state here easily global opts global reload_objects_at global tilts global uuids ev = aiobs.HCI_Event() xx = ev.decode(data) # To make things easier, let's convert the byte string to a hex string first raw_data_hex = ev.raw_data.hex() if len(raw_data_hex) < 80: # Very quick filter to determine if this is a valid Tilt device return False if "1370f02d74de" not in raw_data_hex: # Another very quick filter (honestly, might not be faster than just looking at uuid below) return False # For testing/viewing raw announcements, uncomment the following # print("Raw data (hex) {}: {}".format(len(raw_data_hex), raw_data_hex)) # ev.show(0) try: # Let's use some of the functions of aioblesscan to tease out the mfg_specific_data payload payload = ev.retrieve("Payload for mfg_specific_data")[0].val.hex() # ...and then dissect said payload into a UUID, temp, gravity, and rssi (which isn't actually rssi) uuid = payload[8:40] temp = int.from_bytes(bytes.fromhex(payload[40:44]), byteorder='big') gravity = int.from_bytes(bytes.fromhex(payload[44:48]), byteorder='big') # tx_pwr = int.from_bytes(bytes.fromhex(payload[48:49]), byteorder='big') # rssi = int.from_bytes(bytes.fromhex(payload[49:50]), byteorder='big') rssi = 0 # TODO - Fix this except: return if verbose: print("Tilt Payload (hex): {}".format(payload)) color = TiltHydrometer.color_lookup(uuid) # Map the uuid back to our TiltHydrometer object tilts[color].process_decoded_values(gravity, temp, rssi) # Process the data sent from the Tilt # The Fermentrack specific stuff: reload = False if datetime.datetime.now() > reload_objects_at: # Doing this so that as time passes while we're polling objects, we still end up reloading everything reload = True reload_objects_at = datetime.datetime.now() + datetime.timedelta(seconds=15) for this_tilt in tilts: if tilts[this_tilt].should_save(): tilts[this_tilt].save_value_to_fermentrack(verbose=verbose) if reload: # Users editing/changing objects in Fermentrack doesn't signal this process so reload on a timer tilts[this_tilt].load_obj_from_fermentrack()
def callback(bt_addr, rssi, packet, additional_info): # Although beacontools provides a device filter option, we're not going to use it as it doesn't currently allow # specifying a list of UUIDs (I don't think, at least). Instead, we'll filter here. if additional_info['uuid'] in uuids: color = TiltHydrometer.color_lookup( additional_info['uuid'] ) # Map the uuid back to our TiltHydrometer object tilts[color].process_ibeacon_info( packet, rssi) # Process the data sent from the Tilt if verbose: # If we're in 'verbose' mode, also go ahead and print out the data we received tilts[color].print_data()
def processBLEBeacon(data): # While I'm not a fan of globals, not sure how else we can store state here easily global verbose global reload_objects_at global tilts ev = aiobs.HCI_Event() xx = ev.decode(data) # To make things easier, let's convert the byte string to a hex string first if ev.raw_data is None: if verbose: LOG.error("Event has no raw data") return False raw_data_hex = ev.raw_data.hex() if len( raw_data_hex ) < 80: # Very quick filter to determine if this is a valid Tilt device # if verbose: # LOG.info("Small raw_data_hex: {}".format(raw_data_hex)) return False if "1370f02d74de" not in raw_data_hex: # Another very quick filter (honestly, might not be faster than just looking at uuid below) # if verbose: # LOG.info("Missing key in raw_data_hex: {}".format(raw_data_hex)) return False # For testing/viewing raw announcements, uncomment the following # print("Raw data (hex) {}: {}".format(len(raw_data_hex), raw_data_hex)) # ev.show(0) # try: # mac_addr = ev.retrieve("peer")[0].val # except: # pass try: # Let's use some of the functions of aioblesscan to tease out the mfg_specific_data payload manufacturer_data = ev.retrieve("Manufacturer Specific Data") payload = manufacturer_data[0].payload payload = payload[1].val.hex() # ...and then dissect said payload into a UUID, temp, and gravity uuid = payload[4:36] temp = int.from_bytes(bytes.fromhex(payload[36:40]), byteorder='big') gravity = int.from_bytes(bytes.fromhex(payload[40:44]), byteorder='big') # On the latest tilts, TX power is used for battery tx_pwr = int.from_bytes(bytes.fromhex(payload[44:46]), byteorder='big', signed=False) rssi = ev.retrieve("rssi")[-1].val except Exception as e: LOG.error(e) capture_exception(e) exit(1) return False # This can't be called, but it's here to make Pycharm happy if verbose: LOG.info("Tilt Payload (hex): {}".format(raw_data_hex)) color = TiltHydrometer.color_lookup( uuid) # Map the uuid back to our TiltHydrometer object tilts[color].process_decoded_values( gravity, temp, rssi, tx_pwr) # Process the data sent from the Tilt if verbose: # print("Color {} - MAC {}".format(color, mac_addr)) print("Raw Data: `{}`".format(raw_data_hex)) print( f"{color} - Temp: {temp}, Gravity: {gravity}, RSSI: {rssi}, TX Pwr: {tx_pwr}" ) # The Fermentrack specific stuff: reload = False if datetime.datetime.now() > reload_objects_at: # Doing this so that as time passes while we're polling objects, we still end up reloading everything reload = True reload_objects_at = datetime.datetime.now() + datetime.timedelta( seconds=30) for this_tilt in tilts: if tilts[this_tilt].should_save(): if verbose: LOG.info("Saving {} to Fermentrack".format(this_tilt)) tilts[this_tilt].save_value_to_fermentrack(verbose=verbose) if reload: # Users editing/changing objects in Fermentrack doesn't signal this process so reload on a timer if verbose: LOG.info("Loading {} from Fermentrack".format(this_tilt)) tilts[this_tilt].load_obj_from_fermentrack()
def centralManager_didDiscoverPeripheral_advertisementData_RSSI_( self, manager, peripheral, advertisementData, rssi): #is it an iBeacon? # print(advertisementData) if advertisementData == None: return # advertisementData is an NSDictionary manufacturerData = advertisementData.objectForKey_( "kCBAdvDataManufacturerData") if manufacturerData == None: return # see if we have an iBeacon if manufacturerData.length() != 25: return data = manufacturerData.bytes() if data[0] != 0x4C or data[1] != 0x00: return # { return nil } // Apple identifier if data[2] != 0x02: return #{ return nil } // iBeacon subtype identifier if data[3] != 0x15: return # { return nil } // Subtype length (fixed) uuid_data = data[4:20] # how to better convert bytes to a string? uuid = "" for i in range(16): uuid = uuid + "{0:x}".format(uuid_data[i]) # is this a tilt? color = TiltHydrometer.color_lookup( uuid) # Map the uuid back to our TiltHydrometer object if color == None: return temp = int.from_bytes(data[20:22], byteorder='big') gravity = int.from_bytes(data[22:24], byteorder='big') transmitPower = int.from_bytes(data[24:2], byteorder='big') global tilts global reload_objects_at tilts[color].process_decoded_values( gravity, temp, transmitPower) # Process the data sent from the Tilt # This stuff below seems racy.. # The Fermentrack specific stuff: reload = False if datetime.datetime.now() > reload_objects_at: # Doing this so that as time passes while we're polling objects, we still end up reloading everything reload = True reload_objects_at = datetime.datetime.now() + datetime.timedelta( seconds=30) for this_tilt in tilts: if tilts[this_tilt].should_save(): tilts[this_tilt].save_value_to_fermentrack( verbose=tilt_monitor_utils.verbose) if reload: # Users editing/changing objects in Fermentrack doesn't signal this process so reload on a timer tilts[this_tilt].load_obj_from_fermentrack()