Exemplo n.º 1
0
def main():
    pi.wiringPiSetupGpio()
    pi.pinMode(BUZZER_GPIOPIN, pi.OUTPUT)
    service = BeaconService()
    service.start_advertising()
    oldbeacon = {}
    al_notification = {}
    # hoge = []

    devices = service.scan(2)
    for i, (address, data) in enumerate(list(devices.items())):
        b = Beacon(data, address)
        oldbeacon[b.get_uuid()] = b

    while True:
        devices = service.scan(1)
        for i, (address, data) in enumerate(list(devices.items())):
            b = Beacon(data, address, oldbeacon[data[0]].get_low_rssi(),
                       oldbeacon[data[0]].get_distance())

            # hoge.append(b.get_rssi())
            print(b)
            # print(len(hoge))
            # if len(hoge) == 100:
            #     print(oldbeacon)
            #     print(sum(hoge)/len(hoge))
            #     exit(0)
            is_address, userlist = check_uuid(b.get_uuid())

            # send_alert_mails(userlist, b)

            #出ているのか
            if is_out_distance(b.get_distance(),
                               oldbeacon[b.get_uuid()].get_distance(),
                               oldbeacon[b.get_uuid()].get_distance(
                                   set="old")) and is_address:

                # 以前通知したかどうか
                if check_notifincation(b.get_uuid(), al_notification):
                    al_notification[b.get_uuid()] = True
                    nonfication_mails(
                        userlist, "{0}さんが外出しました".format(userlist[0].name),
                        str(datetime.now().strftime("%Y/%m/%d %H:%M:%S")) +
                        "に外出されました")
            # 入っているのか
            elif is_in_distance(
                    b.get_distance(), oldbeacon[b.get_uuid()].get_distance(),
                    oldbeacon[b.get_uuid()].get_distance(set="old")):
                al_notification[b.get_uuid()] = False
                print("戻った")

            # 最後に今回のビーコン情報の更新
            oldbeacon[b.get_uuid()] = b

    print("Done.")
Exemplo n.º 2
0
def scan_beacon(leave_user):
    service = BeaconService()
    devices = service.scan(2)
    for address, data in list(devices.items()):
        b = Beacon(data, address)
        print(b)
        for i in leave_user:
            sql_str = "SELECT uuid FROM Employee WHERE Name = "+i+";"
            cur.execute(sql_str)
            tmp=cur.fetchall[0][0]
          if b._uuid==tmp:
            sql_str = "INSERT INTO time_card(Name,Time,State) VALUES("+i+","+datatime.datatime.now()+","+"enter);"
            cur.execute(sql_str)
    print("Done.")
Exemplo n.º 3
0
 def handle(self, *args, **options):
     iottalk = dan.Iottalk(
         dm_name="Dummy_Device",
         df_list=["Dummy_Sensor", "Dummy_Control"],
         d_name="Rollcall-Sensor-1",
         mac=uuid.uuid4().hex,
     )
     iottalk.device_registration_with_retry(os.getenv("IOTTALK_ENDPOINT"))
     service = BeaconService()
     try:
         while True:
             devices = service.scan(2)
             for address, data in devices.items():
                 student = Beacon(data, address)
                 if student._rssi > -40:
                     print("Get UUID: ", student._uuid)
                     iottalk.push("Dummy_Sensor", str(student._uuid))
             time.sleep(0.5)
     finally:
         iottalk.deregister()
Exemplo n.º 4
0
    def address(self):
        return self._address

    def __str__(self):
        ret = "Beacon:\n" \
              "\taddress: {ADDR}\n" \
              "\tuuid: {UUID}\n" \
              "\tmajor: {MAJOR} minor: {MINOR} txpower: {POWER}\n" \
              "\trssi: {RSSI}\n" \
              .format(ADDR=self._address, UUID=self._uuid, MAJOR=self._major,
                    MINOR=self._minor, POWER=self._power, RSSI=self._rssi)
        return ret

counter = 0
serviceB = BeaconService()

while True:
    beacons = serviceB.scan(2)    
    i = 0
    os.system('clear')
    print(counter)
    print("-"*20)
    for address, data in list(beacons.items()):
        b = Beacon(data, address, beacons, i)
        i += 1
        print(b.rssi)
        print(b.address)
        print("-"*20)

    # time.sleep(1)
    counter += 1
#!/usr/bin/python3

from bluetooth.ble import BeaconService

service = BeaconService()
devices = service.scan(10)

for addr, data in devices.items():
    print("%s (UUID %s Major %d Minor %d Power %d RSSI %d)" %
          (addr, data[0], data[1], data[2], data[3], data[4]))
Exemplo n.º 6
0
    """
    TODO
    """
    def __init__(self, address, data):
        """
        TODO
        """
        self._address = address
        self._uuid = data[0]
        self._major = data[1]
        self._minor = data[2]
        self._power = data[3]
        self._rssi = data[4]

    def __str__(self):
        """
        TODO
        """
        return 'Beacon: address:{ADDR} uuid:{UUID} major:{MAJOR} minor:{MINOR} txpower:{POWER} rssi:{RSSI}'\
            .format(ADDR=self._address, UUID=self._uuid, MAJOR=self._major, MINOR=self._minor, POWER=self._power, RSSI=self._rssi)


if __name__ == '__main__':
    # Create beacon service and scan for devices (2 seconds)
    service = BeaconService('hci0')
    devices = service.scan(2)
    # Connect to each beacon, print results of device scan
    for address, data in list(devices.items()):
        beacon = Beacon(address, data)
        print(beacon)
    print('*** Beacon scan complete! ***')
Exemplo n.º 7
0
class Scanner(object):
    """Instantiates a BLE beacon scanner.

    Attributes:
        control_file (pathlib.Path): BLE beacon scanner control file path.
        timeout (float, int): BLE beacon scanner timeout (s). Must be strictly
            positive and less than 600.
        revisit (int): BLE beacon scanner revisit interval (s). Must be
            strictly positive.
        filters (dict): Filters to apply to received beacons. Available
            filters/keys are {'address', 'uuid', 'major', 'minor'}.
    """
    def __init__(self, logger, **kwargs):
        """Instance initialization.

        Args:
            logger (logging.Logger): Configured logger.
            **kwargs: Keyword arguments corresponding to instance attributes.
                Any unassociated keyword arguments are ignored.
        """
        # Logger
        self.__logger = logger
        # Beacon settings
        for key, value in DEFAULT_CONFIG['scanner'].items():
            if key in kwargs and kwargs[key]:
                setattr(self, key, kwargs[key])
            else:
                self.__logger.debug("Using default beacon scanner "
                                    f"configuration {key}: {value}.")
                setattr(self, key, value)
        # Create beacon
        self.__service = BeaconService(BLE_DEVICE)
        self.__logger.info("Initialized beacon scanner.")

    def __del__(self):
        """Instance destruction."""
        if self.__control_file_handle is not None:
            self.__control_file_handle.close()
        self.__control_file.unlink()

    @property
    def control_file(self):
        """BLE beacon scanner control file path getter."""
        return self.__control_file

    @control_file.setter
    def control_file(self, value):
        """BLE beacon scanner control file path setter.

        Raises:
            TypeError: Beacon scanner control file must be a string.
        """
        if not isinstance(value, str):
            raise TypeError("Beacon scanner control file must be a string.")
        # Initialize control file
        self.__control_file = Path(value).resolve()
        self.__control_file.touch()
        self.__control_file.chmod(0o777)
        with self.__control_file.open(mode='w') as f:
            f.write("0")
        self.__control_file_handle = None

    @property
    def scan_prefix(self):
        """BLE beacon scanner scan file prefix getter."""
        return self.__scan_prefix

    @scan_prefix.setter
    def scan_prefix(self, value):
        """BLE beacon scanner scan file prefix setter.

        Raises:
            TypeError: Beacon scanner scan file prefix must be a string.
        """
        if not isinstance(value, str):
            raise TypeError(
                "Beacon scanner scan file prefix must be a string.")
        self.__scan_prefix = value

    @property
    def timeout(self):
        """BLE beacon scanner timeout getter."""
        return self.__timeout

    @timeout.setter
    def timeout(self, value):
        """BLE beacon scanner timeout setter.

        Raises:
            TypeError: Beacon scanner timeout must be a float, integer, or
                NoneType.
            ValueError: Beacon scanner timeout must be strictly positive.
            ValueError: Beacon scanner cannot exceed maximum allowable timeout.
        """
        if value is not None:
            if not isinstance(value, (float, int)):
                raise TypeError("Beacon scanner timeout must be a float, "
                                "integer, or NoneType.")
            elif value <= 0:
                raise ValueError("Beacon scanner timeout must be strictly "
                                 "positive.")
            elif value > MAX_TIMEOUT:
                raise ValueError("Beacon scanner timeout cannot exceed "
                                 "maximum allowable timeout.")
        self.__timeout = value

    @property
    def revisit(self):
        """BLE beacon scanner revisit interval getter."""
        return self.__revisit

    @revisit.setter
    def revisit(self, value):
        """BLE beacon scanner revisit interval setter.

        Raises:
            TypeError: Beacon scanner revisit interval must be an integer.
            ValueError: Beacon scanner revisit interval must be strictly
                positive.
         """
        if not isinstance(value, int):
            raise TypeError("Beacon scanner revisit interval must be an "
                            "integer.")
        elif value <= 0:
            raise ValueError("Beacon scanner revisit interval must strictly "
                             "positive.")
        self.__revisit = value

    @property
    def filters(self):
        """BLE beacon scanner filters getter."""
        return self.__filters

    @filters.setter
    def filters(self, value):
        """BLE beacon scanner filters setter.

        Raises:
            TypeError: Beacon scanner filters must be a dictionary.
            KeyError: Beacon scanner filters must be one of allowable filters.
        """
        if not isinstance(value, dict):
            raise TypeError("Beacon scanner filters must be a dictionary.")
        elif not all([key in ALLOWABLE_FILTERS for key in value.keys()]):
            raise KeyError("Beacon scanner filters must be one of allowable "
                           f"filters {ALLOWABLE_FILTERS}.")
        self.__filters = value

    def filter_advertisements(self, advertisements):
        """Filter received beacon advertisements based on filters.

        Args:
            advertisements (pandas.DataFrame): Parsed advertisements.

        Returns:
            Advertisements with all entries that were not compliant with the
            filters removed.
        """
        for key, value in self.filters.items():
            # Filter based on fixed identifiers
            if key in ID_FILTERS:
                advertisements = advertisements[advertisements[key].isin(
                    [value])]
            # Filter based on measurements
            else:
                query_str = f"{value[0]} <= {key} and {key} <= {value[1]}"
                advertisements = advertisements.query(query_str)
        advertisements.reset_index(inplace=True, drop=True)
        return advertisements

    def process_scans(self, scans, timestamps):
        """Process collection of received beacon advertisement scans.

        Organize collection of received beacon advertisement scans according
        to address, payload, and measurements.

        Args:
            scans (list): Received beacon advertisement scans. Each element
                contains all advertisements received from one scan. Elements
                are in temporal order.
            timestamps (list): Timestamps associated with each scan.

        Returns:
            Advertisements organized in a pandas.DataFrame by address first,
            timestamp second, and then remainder of advertisement payload,
            e.g., UUID, major, minor, etc.
        """
        # Collect all advertisements
        advertisements = []
        for (scan, timestamp) in zip_longest(scans, timestamps):
            for address, payload in scan.items():
                advertisement = {'ADDRESS': address, 'TIMESTAMP': timestamp}
                advertisement['UUID'] = payload[0]
                advertisement['MAJOR'] = payload[1]
                advertisement['MINOR'] = payload[2]
                advertisement['TX POWER'] = payload[3]
                advertisement['RSSI'] = payload[4]
                advertisements.append(advertisement)
        # Format into DataFrame
        return pd.DataFrame(advertisements,
                            columns=[
                                'ADDRESS', 'TIMESTAMP', 'UUID', 'MAJOR',
                                'MINOR', 'TX POWER', 'RSSI'
                            ])

    def nameScanLogs(self):
        latestNum = self.curr_file_id
        for file in os.listdir("~/reference_code"):
            if file.endswith(".csv"):
                print(os.path.join("", file))
        return None

    def scan(self, scan_prefix='', timeout=0, revisit=1, curr_file_id=0):
        """Execute BLE beacon scan.

        Args:
            scan_prefix (str): Scan output file prefix. Final output file name
                will be appended with first scan start timestamp. Defaults to
                configuration value.
            timeout (int, float): Time (s) for which to advertise beacon. If
                specified as None then advertises till user commanded stop via
                control file. Defaults to configuration value.
            revisit (int): Time interval (s) between consecutive scans.
                Defaults to 1.

        Returns:
            Filtered advertisements organized in a pandas.DataFrame by address
            first, timestamp second, and then remainder of advertisement
            payload, e.g., UUID, major, minor, etc.
        """
        # Parse inputs
        if scan_prefix == '':
            scan_prefix = self.scan_prefix
        if timeout == 0:
            timeout = self.timeout
        # Update control file and scan output file
        with open(self.__control_file, 'w') as f:
            f.write("0")

        latestNum = self.curr_file_id
        for file in os.listdir("pact_scans"):
            if file.endswith(".csv"):
                currNum = int(
                    re.findall('\d+', str(os.path.join("", file)))[0])
                if (currNum >= latestNum):
                    latestNum = currNum + 1

        scan_file = Path(f"pact_scans/scan_{latestNum}.csv")

        # scan_file = Path(f"{scan_prefix}_{datetime.now():%Y%m%dT%H%M%S}.csv")
        # Start advertising
        self.__logger.info(f"Starting beacon scanner with timeout {timeout}.")
        self.__control_file_handle = self.__control_file.open(mode='r+')
        run = True
        timestamps = []
        scans = []
        scan_count = 0
        start_time = time.monotonic()
        while run:
            scan_count += 1
            self.__logger.debug(f"Performing scan #{scan_count} at revisit "
                                f"{self.revisit}.")
            timestamps.append(datetime.now())
            scans.append(self.__service.scan(self.revisit))
            # Stop advertising based on either timeout or control file
            if timeout is not None:
                if (time.monotonic() - start_time) > timeout:
                    self.__logger.debug("Beacon scanner timed out.")
                    run = False
            self.__control_file_handle.seek(0)
            control_flag = self.__control_file_handle.read()
            if control_flag != "0":
                self.__logger.debug("Beacon scanner control flag set to stop.")
                run = False
        self.__logger.info("Stopping beacon scanner.")
        # Cleanup
        self.__control_file_handle.close()
        with self.__control_file.open('w') as f:
            f.write("0")
        # Process, filter, and output received scans
        advertisements = self.process_scans(scans, timestamps)
        advertisements = self.filter_advertisements(advertisements)
        advertisements.to_csv(scan_file, index_label='SCAN')
        return advertisements
Exemplo n.º 8
0
from bluetooth.ble import BeaconService

class Beacon(object):
    
    def __init__(self, data, address):
        self._uuid = data[0]
        self._major = data[1]
        self._minor = data[2]
        self._power = data[3]
        self._rssi = data[4]
        self._address = address
        
    def __str__(self):
        ret = "Beacon: address:{ADDR} uuid:{UUID} major:{MAJOR}"\
                " minor:{MINOR} txpower:{POWER} rssi:{RSSI}"\
                .format(ADDR=self._address, UUID=self._uuid, MAJOR=self._major,
                        MINOR=self._minor, POWER=self._power, RSSI=self._rssi)
        return ret

service = BeaconService()
devices = service.scan(2)

for address, data in list(devices.items()):
    b = Beacon(data, address)
    print(b)

print("Done.")
Exemplo n.º 9
0
service = BeaconService()  # Start the service object as beacon service


def getMaxRssi():
    rssiM = -100
    beacon = Beacon.Beacon([0, 0, 0, 0, -100], "")
    for beaconRead in beaconsRead:
        if int(beaconRead._rssi) > rssiM:
            rssiM = beaconRead._rssi
            beacon = beaconRead
    return beacon


while True:
    beaconsRead = []
    devices = service.scan(DISCOVER_TIME)
    # Scan the devices inside the beacon service
    for address, data in list(
            devices.items()):  # Run for loop for the scanned beacons
        b = Beacon.Beacon(data,
                          address)  # Create the object b from class Beacon
        beaconsRead.append(b)

    for beacon in beaconsList:
        if addressM != getMaxRssi()._address and int(getMaxRssi(
        )._rssi) >= -90 and beacon["BeaconMAC"] == getMaxRssi()._address:
            addressM = getMaxRssi()._address
            dataI = {}
            dataI["name"] = beacon["Station"]
            dataI["date"] = time.time()
            print(getMaxRssi()._address)
Exemplo n.º 10
0
class Scanner(object):
    def __init__(self, **kwargs):
        """Instance initialization.

        Args:
            logger (logging.Logger): Configured logger.
            **kwargs: Keyword arguments corresponding to instance attributes. 
                Any unassociated keyword arguments are ignored.
        """
        # Beacon settings
        for key, value in DEFAULT_CONFIG['scanner'].items():
            if key in kwargs and kwargs[key]:
                setattr(self, key, kwargs[key])
        # Create beacon
        self.__service = BeaconService(BLE_DEVICE)
        self.__timeout = None

    @property
    def timeout(self):
        """BLE beacon scanner timeout getter."""
        return self.__timeout

    @timeout.setter
    def timeout(self, value):
        """BLE beacon scanner timeout setter.

        Raises:
            TypeError: Beacon scanner timeout must be a float, integer, or 
                NoneType.
            ValueError: Beacon scanner timeout must be strictly positive.
            ValueError: Beacon scanner cannot exceed maximum allowable timeout.
        """
        if value is not None:
            if not isinstance(value, (float, int)):
                raise TypeError("Beacon scanner timeout must be a float, "
                                "integer, or NoneType.")
            elif value <= 0:
                raise ValueError("Beacon scanner timeout must be strictly "
                                 "positive.")
            elif value > MAX_TIMEOUT:
                raise ValueError("Beacon scanner timeout cannot exceed "
                                 "maximum allowable timeout.")
        self.__timeout = value

    @property
    def revisit(self):
        """BLE beacon scanner revisit interval getter."""
        return self.__revisit

    @revisit.setter
    def revisit(self, value):
        """BLE beacon scanner revisit interval setter.

        Raises:
            TypeError: Beacon scanner revisit interval must be an integer.
            ValueError: Beacon scanner revisit interval must be strictly 
                positive.
         """
        if not isinstance(value, int):
            raise TypeError("Beacon scanner revisit interval must be an "
                            "integer.")
        elif value <= 0:
            raise ValueError("Beacon scanner revisit interval must strictly "
                             "positive.")
        self.__revisit = value

    def scan(self, scan_prefix='', timeout=0, revisit=1):
        """Execute BLE beacon scan.

        Returns:
            Filtered advertisements by address 
            first, timestamp second, and then remainder of advertisement 
            payload, e.g., UUID, major, minor, etc.
        """
        # Parse inputs
        if timeout == 0:
            timeout = self.timeout
        # Start advertising
        run = True
        scan_count = 0
        start_time = time.monotonic()
        advertisements = []
        while run:
            scan_count += 1
            scans = []
            scans.append(self.__service.scan(self.revisit))
            print(scans[-1])
            if timeout is not None:
                if (time.monotonic() - start_time) > timeout:
                    run = False
Exemplo n.º 11
0
from bluetooth.ble import BeaconService
import dbFunctions
import Beacon
import time

DISCOVER_TIME = 3  # In seconds, scan interval duration.

service = BeaconService()   # Start the service object as beacon service
dbFunctions.createTable()   # If not exist, create the table sensors

while True:

    devices = service.scan(DISCOVER_TIME)   # Scan the devices inside the beacon service

    for address, data in list(devices.items()): # Run for loop for the scanned beacons
        b = Beacon.Beacon(data, address)    # Create the object b from class Beacon
        print(b)

        sensor = {}                      # Initialize the dictonary sensor
        sensor["date"] = time.time()     # Add current time
        sensor["address"] = b._address   # Add beacon address
        sensor["rssi"] = b._rssi         # Add beacon signal level rssi

        dbFunctions.insertSensorEvent(sensor)   # Insert sensor event to database
class Beacon(object):
    def __init__(self, data, address):
        self._uuid = data[0]
        self._major = data[1]
        self._minor = data[2]
        self._power = data[3]
        self._rssi = data[4]
        self._address = address

    def __str__(self):
        return '{0}, RSSI: {1}'.format(self._address, self._rssi)

datadir = '/home/pi/data'
beacon_service = BeaconService()

while True:

    devices = beacon_service.scan(30)
    
    if devices:
        with open('/home/pi/data/data.txt', 'a+') as f:
        
            for address, data in devices.items():
                b = Beacon(data, address)
                print(b)
                dt = datetime.now()
                f.write('{0},{1},{2},{3},{4},{5},{6},{7}\n'.format(b._address, b._rssi, dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second))

    else:
        print('no devices')
Exemplo n.º 13
0
class Scanner(object):
    """Instantiates a BLE beacon scanner.
    
    Attributes:
        timeout_s (float, int): BLE beacon scanner timeout (s). Must be strictly
            positive and less than 600.
        revisit (int): BLE beacon scanner revisit interval (s). Must be 
            strictly positive.
        filters (dict): Filters to apply to received beacons. Available
            filters/keys are {'address', 'uuid', 'major', 'minor'}.
    """
    def __init__(self, logger, **kwargs):
        """Instance initialization.

        Args:
            logger (logging.Logger): Configured logger.
            **kwargs: Keyword arguments corresponding to instance attributes. 
                Any unassociated keyword arguments are ignored.
        """
        # Logger
        self.__logger = logger
        # Beacon settings
        for key, value in DEFAULT_CONFIG['scanner'].items():
            if key in kwargs and kwargs[key]:
                setattr(self, key, kwargs[key])
            else:
                self.__logger.debug("Using default beacon scanner "
                                    f"configuration {key}: {value}.")
                setattr(self, key, value)
        # Create beacon
        self.__service = BeaconService(BLE_DEVICE)
#        GPIO.output(6,GPIO.HIGH);
#        self.__logger.info("Initialized beacon scanner.")

    def __del__(self):
        """Instance destruction."""
#        GPIO.output(6,GPIO.LOW);

    @property
    def scan_prefix(self):
        """BLE beacon scanner scan file prefix getter."""
        return self.__scan_prefix

    @scan_prefix.setter
    def scan_prefix(self, value):
        """BLE beacon scanner scan file prefix setter.
        
        Raises:
            TypeError: Beacon scanner scan file prefix must be a string.
        """
        if not isinstance(value, str):
            raise TypeError(
                "Beacon scanner scan file prefix must be a string.")
        self.__scan_prefix = value

    @property
    def timeout_s(self):
        """BLE beacon scanner timeout getter."""
        return self.__timeout_s

    @timeout_s.setter
    def timeout_s(self, value):
        """BLE beacon scanner timeout setter.

        Raises:
            TypeError: Beacon scanner timeout must be a float, integer, or 
                NoneType.
            ValueError: Beacon scanner timeout must be strictly positive.
            ValueError: Beacon scanner cannot exceed maximum allowable timeout.
        """
        if value is not None:
            if not isinstance(value, (float, int)):
                raise TypeError("Beacon scanner timeout must be a float, "
                                "integer, or NoneType.")
            elif value <= 0:
                raise ValueError("Beacon scanner timeout must be strictly "
                                 "positive.")
            elif value > MAX_TIMEOUT:
                raise ValueError("Beacon scanner timeout cannot exceed "
                                 "maximum allowable timeout.")
        self.__timeout_s = value

    @property
    def revisit(self):
        """BLE beacon scanner revisit interval getter."""
        return self.__revisit

    @revisit.setter
    def revisit(self, value):
        """BLE beacon scanner revisit interval setter.

        Raises:
            TypeError: Beacon scanner revisit interval must be an integer.
            ValueError: Beacon scanner revisit interval must be strictly 
                positive.
         """
        if not isinstance(value, int):
            raise TypeError("Beacon scanner revisit interval must be an "
                            "integer.")
        elif value <= 0:
            raise ValueError("Beacon scanner revisit interval must strictly "
                             "positive.")
        self.__revisit = value

    @property
    def filters(self):
        """BLE beacon scanner filters getter."""
        return self.__filters

    @filters.setter
    def filters(self, value):
        """BLE beacon scanner filters setter.

        Raises:
            TypeError: Beacon scanner filters must be a dictionary.
            KeyError: Beacon scanner filters must be one of allowable filters.
        """
        if not isinstance(value, dict):
            raise TypeError("Beacon scanner filters must be a dictionary.")
        elif not all([key in ALLOWABLE_FILTERS for key in value.keys()]):
            raise KeyError("Beacon scanner filters must be one of allowable "
                           f"filters {ALLOWABLE_FILTERS}.")
        self.__filters = value

    def filter_advertisements(self, advertisements):
        """Filter received beacon advertisements based on filters.
        
        Args:
            advertisements (pandas.DataFrame): Parsed advertisements.
            
        Returns:
            Advertisements with all entries that were not compliant with the 
            filters removed.
        """
        for key, value in self.filters.items():
            # Filter based on fixed identifiers
            if key in ID_FILTERS:
                advertisements = advertisements[advertisements[key].isin(
                    [value])]
            # Filter based on measurements
            else:
                query_str = f"{value[0]} <= {key} and {key} <= {value[1]}"
                advertisements = advertisements.query(query_str)
        advertisements.reset_index(inplace=True, drop=True)
        return advertisements

    def process_scans(self, scans, timestamps):
        """Process collection of received beacon advertisement scans.
        
        Organize collection of received beacon advertisement scans according 
        to address, payload, and measurements.

        Args:
            scans (list): Received beacon advertisement scans. Each element 
                contains all advertisements received from one scan. Elements 
                are in temporal order.
            timestamps (list): Timestamps associated with each scan.
            
        Returns:
            Advertisements organized in a pandas.DataFrame by address first, 
            timestamp second, and then remainder of advertisement payload, 
            e.g., UUID, major, minor, etc.
        """
        # Collect all advertisements
        advertisements = []
        for (scan, timestamp) in zip_longest(scans, timestamps):
            for address, payload in scan.items():
                advertisement = {
                    'ADDRESS': address,
                    'TIMESTAMP': timestamp.replace(microsecond=0)
                }
                advertisement['UUID'] = payload[0]
                advertisement['MAJOR'] = payload[1]
                advertisement['MINOR'] = payload[2]
                advertisement['TX_POWER'] = payload[3] if payload[3] < (
                    TX_POWER_LIMITS[1] + 1) else -(256 - payload[3]) * 2
                advertisement['RSSI'] = payload[4]
                if int(advertisement['RSSI']) < int(advertisement['TX_POWER']):
                    advertisement['SOS'] = 0
                else:
                    # close range detected !!!
                    GPIO.output(26, GPIO.HIGH)
                    advertisement['SOS'] = 1
                advertisements.append(advertisement)
        # Format into DataFrame
        return pd.DataFrame(advertisements,
                            columns=[
                                'TIMESTAMP', 'UUID', 'ADDRESS', 'MAJOR',
                                'MINOR', 'TX_POWER', 'RSSI', 'SOS'
                            ])

    def scan(self, scan_prefix='', timeout_s=5, revisit=0):
        """Execute BLE beacon scan.
        
        Args:
            scan_prefix (str): Scan output file prefix. Final output file name
                will be appended with first scan start timestamp. Defaults to
                configuration value.
            timeout_s (int, float): Time (s) for which to scan for beacons. 
                Defaults to configuration value.
            revisit (int): Time interval (s) between consecutive scans. 
                Defaults to 1.
            
        Returns:
            Filtered advertisements organized in a pandas.DataFrame by address 
            first, timestamp second, and then remainder of advertisement 
            payload, e.g., UUID, major, minor, etc.
        """
        # Parse inputs
        if scan_prefix == '':
            scan_prefix = self.scan_prefix
        if timeout_s == 0:
            timeout_s = self.timeout_s
#        scan_file = Path(f"{scan_prefix}_{datetime.now():%Y%m%dT%H%M%S}.csv")
        scan_file = Path(f"{scan_prefix}.csv")
        # Start scanning
        #        self.__logger.info(f"Starting beacon scanner with timeout {timeout_s}.")
        ##        GPIO.output(6,GPIO.HIGH);
        run = True
        timestamps = []
        scans = []
        scan_count = 0
        start_time = time.monotonic()
        while run:
            scan_count += 1
            #            self.__logger.debug(f"Performing scan #{scan_count} at revisit "
            #                    f"{self.revisit}.")
            timestamps.append(datetime.now())
            scans.append(self.__service.scan(self.revisit))
            # Stop scanning based on timeout
            if timeout_s is not None:
                if (time.monotonic() - start_time) > timeout_s:
                    #                    self.__logger.debug("Beacon scanner timed out.")
                    run = False


#        self.__logger.info("Stopping beacon scanner.")
##        GPIO.output(6,GPIO.LOW);
# Cleanup
# Process, filter, and output received scans
        advertisements = self.process_scans(scans, timestamps)
        advertisements = self.filter_advertisements(advertisements)

        # if file does not exist write header
        if not os.path.isfile(scan_file):
            advertisements.to_csv(scan_file, index=False, index_label=False)
        else:
            advertisements.to_csv(scan_file,
                                  mode='a',
                                  index=False,
                                  index_label=False,
                                  header=False)
        return advertisements
Exemplo n.º 14
0
class Scanner(object):
    """Instantiates a BLE beacon scanner.

    Attributes:
        control_file (pathlib.Path): BLE beacon scanner control file path.
        timeout (float, int): BLE beacon scanner timeout (s). Must be strictly
            positive and less than 600.
        revisit (int): BLE beacon scanner revisit interval (s). Must be
            strictly positive.
        filters (dict): Filters to apply to received beacons. Available
            filters/keys are {'address', 'uuid', 'major', 'minor'}.
    """
    def __init__(self, logger, **kwargs):
        """Instance initialization.

        Args:
            logger (logging.Logger): Configured logger.
            **kwargs: Keyword arguments corresponding to instance attributes.
                Any unassociated keyword arguments are ignored.
        """
        # Logger
        self.__logger = logger
        # Beacon settings
        for key, value in DEFAULT_CONFIG['scanner'].items():
            if key in kwargs and kwargs[key]:
                setattr(self, key, kwargs[key])
            else:
                self.__logger.debug("Using default beacon scanner "
                                    f"configuration {key}: {value}.")
                setattr(self, key, value)
        # Create beacon
        self.__service = BeaconService(BLE_DEVICE)
        self.__logger.info("Initialized beacon scanner.")

    def __del__(self):
        """Instance destruction."""
        if self.__control_file_handle is not None:
            self.__control_file_handle.close()
        self.__control_file.unlink()

    @property
    def control_file(self):
        """BLE beacon scanner control file path getter."""
        return self.__control_file

    @control_file.setter
    def control_file(self, value):
        """BLE beacon scanner control file path setter.

        Raises:
            TypeError: Beacon scanner control file must be a string.
        """
        if not isinstance(value, str):
            raise TypeError("Beacon scanner control file must be a string.")
        # Initialize control file
        self.__control_file = Path(value).resolve()
        self.__control_file.touch()
        self.__control_file.chmod(0o777)
        with self.__control_file.open(mode='w') as f:
            f.write("0")
        self.__control_file_handle = None

    @property
    def scan_prefix(self):
        """BLE beacon scanner scan file prefix getter."""
        return self.__scan_prefix

    @scan_prefix.setter
    def scan_prefix(self, value):
        """BLE beacon scanner scan file prefix setter.

        Raises:
            TypeError: Beacon scanner scan file prefix must be a string.
        """
        if not isinstance(value, str):
            raise TypeError(
                "Beacon scanner scan file prefix must be a string.")
        self.__scan_prefix = value

    @property
    def timeout(self):
        """BLE beacon scanner timeout getter."""
        return self.__timeout

    @timeout.setter
    def timeout(self, value):
        """BLE beacon scanner timeout setter.

        Raises:
            TypeError: Beacon scanner timeout must be a float, integer, or
                NoneType.
            ValueError: Beacon scanner timeout must be strictly positive.
            ValueError: Beacon scanner cannot exceed maximum allowable timeout.
        """
        if value is not None:
            if not isinstance(value, (float, int)):
                raise TypeError("Beacon scanner timeout must be a float, "
                                "integer, or NoneType.")
            elif value <= 0:
                raise ValueError("Beacon scanner timeout must be strictly "
                                 "positive.")
            elif value > MAX_TIMEOUT:
                raise ValueError("Beacon scanner timeout cannot exceed "
                                 "maximum allowable timeout.")
        self.__timeout = value

    @property
    def revisit(self):
        """BLE beacon scanner revisit interval getter."""
        return self.__revisit

    @revisit.setter
    def revisit(self, value):
        """BLE beacon scanner revisit interval setter.

        Raises:
            TypeError: Beacon scanner revisit interval must be an integer.
            ValueError: Beacon scanner revisit interval must be strictly
                positive.
         """
        if not isinstance(value, (int)):
            raise TypeError("Beacon scanner revisit interval must be an "
                            "integer")
        elif value <= 0:
            raise ValueError("Beacon scanner revisit interval must strictly "
                             "positive.")
        self.__revisit = value

    @property
    def filters(self):
        """BLE beacon scanner filters getter."""
        return self.__filters

    @filters.setter
    def filters(self, value):
        """BLE beacon scanner filters setter.

        Raises:
            TypeError: Beacon scanner filters must be a dictionary.
            KeyError: Beacon scanner filters must be one of allowable filters.
        """
        if not isinstance(value, dict):
            raise TypeError("Beacon scanner filters must be a dictionary.")
        elif not all([key in ALLOWABLE_FILTERS for key in value.keys()]):
            raise KeyError("Beacon scanner filters must be one of allowable "
                           f"filters {ALLOWABLE_FILTERS}.")
        self.__filters = value

    def filter_advertisements(self, advertisements):
        """Filter received beacon advertisements based on filters.

        Args:
            advertisements (pandas.DataFrame): Parsed advertisements.

        Returns:
            Advertisements with all entries that were not compliant with the
            filters removed.
        """
        for key, value in self.filters.items():
            # Filter based on fixed identifiers
            if key in ID_FILTERS:
                advertisements = advertisements[advertisements[key].isin(
                    [value])]
            # Filter based on measurements
            else:
                query_str = f"{value[0]} <= {key} and {key} <= {value[1]}"
                advertisements = advertisements.query(query_str)
        advertisements.reset_index(inplace=True, drop=True)
        return advertisements

    def process_scans(self, scans, timestamps):
        """Process collection of received beacon advertisement scans.

        Organize collection of received beacon advertisement scans according
        to address, payload, and measurements.

        Args:
            scans (list): Received beacon advertisement scans. Each element
                contains all advertisements received from one scan. Elements
                are in temporal order.
            timestamps (list): Timestamps associated with each scan.

        Returns:
            Advertisements organized in a pandas.DataFrame by address first,
            timestamp second, and then remainder of advertisement payload,
            e.g., UUID, major, minor, etc.
        """
        # Collect all advertisements
        advertisements = []
        for bucket_id in scans.keys():
            cnt = 0
            for (scan, timestamp) in zip_longest(scans[bucket_id],
                                                 timestamps[bucket_id]):
                advertisement = pd.Series(np.zeros(10),
                                          index=[
                                              'RSSI', 'ax', 'ay', 'az', 'gx',
                                              'gy', 'gz', 'mx', 'my', 'mz'
                                          ])
                for address, payload in scan[0].items():
                    advertisement['RSSI'] += payload[4]
                    cnt += 1
                advertisement['ax'] += scan[1][0]
                advertisement['ay'] += scan[1][1]
                advertisement['az'] += scan[1][2]
                advertisement['gx'] += scan[2][0]
                advertisement['gy'] += scan[2][1]
                advertisement['gz'] += scan[2][2]
                advertisement['mx'] += scan[3][0]
                advertisement['my'] += scan[3][1]
                advertisement['mz'] += scan[3][2]
            advertisement / cnt
            advertisement['ADDRESS'] = address
            advertisement['TIMESTAMP'] = timestamp
            advertisement['UUID'] = payload[0]
            advertisement['MAJOR'] = payload[1]
            advertisement['MINOR'] = payload[2]
            advertisement['TX POWER'] = payload[3]
            advertisements.append(advertisement)
            print(advertisement)
        # Format into DataFrame
        return pd.DataFrame(advertisements,
                            columns=[
                                'ADDRESS', 'TIMESTAMP', 'UUID', 'MAJOR',
                                'MINOR', 'TX POWER', 'RSSI', 'ax', 'ay', 'az',
                                'gx', 'gy', 'gz', 'mx', 'my', 'mz'
                            ])

    def scan(self, scan_prefix='', timeout=0, revisit=1):
        """Execute BLE beacon scan.

        Args:
            scan_prefix (str): Scan output file prefix. Final output file name
                will be appended with first scan start timestamp. Defaults to
                configuration value.
            timeout (int, float): Time (s) for which to advertise beacon. If
                specified as None then advertises till user commanded stop via
                control file. Defaults to configuration value.
            revisit (int): Time interval (s) between consecutive scans.
                Defaults to 1.

        Returns:
            Filtered advertisements organized in a pandas.DataFrame by address
            first, timestamp second, and then remainder of advertisement
            payload, e.g., UUID, major, minor, etc.
        """
        #Printing Test
        bucket_start_time = datetime.now()
        print(bucket_start_time)
        # Parse inputs
        if scan_prefix == '':
            scan_prefix = self.scan_prefix
        if timeout == 0:
            timeout = self.timeout
        # Update control file and scan output file
        with open(self.__control_file, 'w') as f:
            f.write("0")
        scan_file = Path(f"{scan_prefix}_{datetime.now():%Y%m%dT%H%M%S}.csv")
        # Start advertising
        self.__logger.info(f"Starting beacon scanner with timeout {timeout}.")
        self.__control_file_handle = self.__control_file.open(mode='r+')
        run = True
        timestamps = defaultdict(list)
        scans = defaultdict(list)
        scan_count = 0

        current_bucket_id = 0
        #9250
        mpu = MPU9250(
            address_ak=AK8963_ADDRESS,
            address_mpu_master=MPU9050_ADDRESS_68,  # In 0x68 Address
            address_mpu_slave=None,
            bus=1,
            gfs=GFS_1000,
            afs=AFS_8G,
            mfs=AK8963_BIT_16,
            mode=AK8963_MODE_C100HZ)
        mpu.configure()
        mpu.calibrate()
        print("Done Calibration")
        mpu.configure()
        start_time = time.monotonic()
        while run:
            scan_count += 1
            self.__logger.debug(f"Performing scan #{scan_count} at revisit "
                                f"{self.revisit}.")
            ble_scan = self.__service.scan(self.revisit)
            diff = datetime.now() - bucket_start_time
            bucket_id = diff.seconds // TIME_INTERVAL
            if ble_scan:
                accel = mpu.readAccelerometerMaster()
                gyro = mpu.readMagnetometerMaster()
                mag = mpu.readGyroscopeMaster()
                if current_bucket_id != bucket_id:
                    print("New bucket created")
                    current_bucket_id = bucket_id
                scans[current_bucket_id].append([ble_scan, accel, gyro, mag])
                timestamps[current_bucket_id].append(datetime.now())
            # Stop advertising based on either timeout or control file
            if timeout is not None:
                if (time.monotonic() - start_time) > timeout:
                    self.__logger.debug("Beacon scanner timed out.")
                    run = False
            self.__control_file_handle.seek(0)
            control_flag = self.__control_file_handle.read()
            if control_flag != "0":
                self.__logger.debug("Beacon scanner control flag set to stop.")
                run = False
        self.__logger.info("Stopping beacon scanner.")
        # Cleanup
        self.__control_file_handle.close()
        with self.__control_file.open('w') as f:
            f.write("0")
        # Process, filter, and output received scans
        advertisements = self.process_scans(scans, timestamps)
        advertisements = self.filter_advertisements(advertisements)
        advertisements.to_csv(scan_file, index_label='SCAN')
        return advertisements
def beacon_scan():
    service = BeaconService()
    return service.scan(2)