Exemplo n.º 1
0
class GAmonitor(object):

    SERVICE_UUIDS = [
        UUID('c0be9c58-a717-4e18-828c-a41836f0c7e5'),  # Sensors
    ]

    CHARACTERISTIC_UUIDS = {'9a067338-1da7-4e0f-8b4a-1e445e1e2df9': 'ACC'}

    NOTIFICATION_CHARACTERISTIC_UUIDS = [
        'ACC',
    ]

    # Notification data
    NOTIFICATION_ON = struct.pack("BB", 0x01, 0x00)
    NOTIFICATION_OFF = struct.pack("BB", 0x00, 0x00)

    def __init__(self, mac_address):
        self.macAddress = mac_address
        self.delegate = ScanDelegate()

    def set_delegate(self, delegate):
        self.delegate = delegate

    def connect(self):
        print('getting peripheral', sys.stderr)
        self.peripheral = Peripheral(self.macAddress, addrType='public')
        # Retrieve all characteristics from desired services and map them from their UUID
        self.peripheral.getServices()
        svc = self.peripheral.getServiceByUUID(
            "c0be9c58-a717-4e18-828c-a41836f0c7e5")
        characteristics = {
            svcid: svc.getCharacteristics()[i]
            for svcid, i in zip(self.CHARACTERISTIC_UUIDS, range(2))
        }

        print(characteristics, sys.stderr)

        # Store each characteristic's value handle for each characteristic name
        self.characteristicValueHandles = dict(
            (name, characteristics[uuid].getHandle())
            for uuid, name in self.CHARACTERISTIC_UUIDS.items())

        # Subscribe for notifications
        for name in self.NOTIFICATION_CHARACTERISTIC_UUIDS:
            print('Enabling notification: ', sys.stderr)
            self.peripheral.writeCharacteristic(
                self.characteristicValueHandles[name] + 1,
                self.NOTIFICATION_ON, True)
            print(name, sys.stderr)
            print(self.characteristicValueHandles[name] + 1, sys.stderr)

        self.peripheral.setDelegate(self.delegate)

    def disconnect(self):
        self.peripheral.disconnect()

    def wait_for_notifications(self, timeout):
        print('calling wait for notifications')
        return self.peripheral.waitForNotifications(timeout)
Exemplo n.º 2
0
 def read_services_from_peripheral(self, peripheral: Peripheral, dev: ScanEntry) -> typing.List[Service]:
     ## Try getting servicex
     try: 
         services = peripheral.getServices()
         self.relay_discovered_services(peripheral, services)
         return services
     except Exception as e:
         DBG("Getting services from {} failed".format(dev.addr), logLevel=LogLevel.ERR) 
         logging.exception(e)
         services = list() 
         return services
Exemplo n.º 3
0
class BLEController:
    def __init__(self, delegate):
        # Variables
        self._delegate = delegate

    def connect(self, server_mac):
        self._server_mac = server_mac
        self._peripheral = Peripheral(self._server_mac)
        self._peripheral.setDelegate(self._delegate)
        self._listening = False

    def disconnect(self):
        self._peripheral.disconnect()

    def print_services(self, primary_service_uuid):
        svcs = self._peripheral.getServices()

        print("Services:")
        for s in svcs:
            print(s)

        print("Characteristics:")
        svc = self._peripheral.getServiceByUUID(primary_service_uuid)
        chs = svc.getCharacteristics()
        for c in chs:
            print(str(c) + " handle: " + str(c.getHandle()))

    def listen(self):
        if not self._listening:  # Are we listening already?
            self._listening = True
            while self._listening:
                if self._peripheral.waitForNotifications(
                        1.0):  # Calls the delegate if true
                    # Delegate was called
                    continue
                print('BLEController.listen() -> Listening...')

    def listen_async(self):
        #raise Exception("Not Implemented")
        self._listen_thread = _thread.start_new_thread(self.listen, ())

    def adjust_light_source(self, value):
        # value is a tuple of RGB i.e. (255, 255, 255)

        # BLE characteristic expects a byte array
        value_bytes = bytes(value)
        print("BLEController.adjust_light_source -> {}".format(value_bytes))

        handle = 49  # The handle value has to be found using e.g. print_services(), bluez, or similar
        self._peripheral.writeCharacteristic(handle, value_bytes)

    def stop_listening(self):
        self._listening = False
Exemplo n.º 4
0
class BleDevice:
    def __init__(self):
        self.scanner = Scanner().withDelegate(ScanDelegate())

    def Scan(self, time):
        self.devices = self.scanner.scan(time)

    def ListDevices(self, scan_data_flag):
        for dev in self.devices:
            print("Device {} ({}){}, RSSI={} dB".format(
                dev.addr, dev.addrType,
                ' [Connectable]' if dev.connectable else '', dev.rssi))

            if scan_data_flag:
                for (adtype, desc, value) in dev.getScanData():
                    print("  {} {} = {}".format(adtype, desc, value))

    def FindBoogie(self):

        boogie = None

        for dev in self.devices:
            for (adtype, desc, value) in dev.getScanData():
                if adtype == 9:
                    if value == "Boogie":
                        boogie = dev

        self.boogie = dev
        return boogie

    def ConnectToDevice(self, device):
        # Function returns Connected to device when device is not there

        try:
            self.peripheral = Peripheral(device)
            print("Connected to device")
        except BTLEException:
            print('Connection failed')

    def GetServices(self):

        services = self.peripheral.getServices()

        print('Services')

        for service in services:
            print('{}'.format(service))

            characteristics = service.getCharacteristics()

            for characteristic in characteristics:
                print('{}'.format(characteristic))
Exemplo n.º 5
0
 def from_device(address, addr_type):
     try:
         services = []
         device = Peripheral(address, addr_type)
         for s in device.getServices():
             services.append(
                 Service(uuid=str(s.uuid),
                         name=s.uuid.getCommonName(),
                         characteristics=Characteristic.from_service(s)))
         return services
     except BTLEException:
         print(address, "disconnected. could not read services")
         return []
class SmartLampController:

    LAMP_SERVICE_UUID = "00001101-0000-1000-8000-00805f9b34fb"
    DEVICE_RX_CHARACTERISTIC_UUID = "00001142-0000-1000-8000-00805f9b34fb"

    def __init__(self, device_name="SmartLamp", scan_time=10.):
        assert isinstance(device_name, str)
        self.name = device_name
        self.scanner = Scanner().withDelegate(ScanDelegate())
        print(self, "Start device scanning...")
        devices = self.scanner.scan(scan_time)
        print(self, "Scanning completed.")
        self.target_device = None
        for dev in devices:
            for adtype, desc, value in dev.getScanData():
                if desc == "Complete Local Name" and value == self.name:
                    self.target_device = dev
                    print(self, f"Found target device: {dev.addr}")
                    break
        assert self.target_device is not None
        self.peripheral = Peripheral(self.target_device.addr)
        print(self, f"Peripheral created.")
        services = self.peripheral.getServices()
        self.lamp_service = self.peripheral.getServiceByUUID(self.LAMP_SERVICE_UUID)
        print(self, f"Service is ready.")
        self.tx_characteristic = self.lamp_service.getCharacteristics(self.DEVICE_RX_CHARACTERISTIC_UUID)[0]
        print(self, f"Characteristic is ready.")

    def __del__(self):
        if self.peripheral is not None:
            self.peripheral.disconnect()

    def _write(self, msg):
        print(self, f"Send command: {msg}")
        self.tx_characteristic.write(bytes(msg, "utf-8"))

    def switch_lamp(self, state):
        r, g, b = 0, 0, 0
        if isinstance(state, bool):
            if state:
                r, g, b = 255, 255, 255
        elif isinstance(state, dict):
            r, g, b = state["r"], state["g"], state["b"]
        elif len(state) == 3:
            r, g, b = state
        self._write(f"rgb {r} {g} {b}")

    def __str__(self):
        return f"SmartLampController:{self.name}"
Exemplo n.º 7
0
def search_loop():
    while True:
        scanner = Scanner().withDelegate(ScanDelegate())
        devices = scanner.scan(5.0)

        for dev in devices:
            data = dev.getScanData()
            for (adtype, desc, value) in data:
                if "Short Local Name" in desc:
                    print("Cube found:")
                    print("  Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi))
                    for (adtype, desc, value) in data:
                        print("  %s = %s" % (desc, value))
                    p = Peripheral(deviceAddr=dev.addr, addrType=dev.addrType)
                    for serv in p.getServices():
                        print(serv.uuid.getCommonName())
                        for char in serv.getCharacteristics():
                            pprint(char.propertiesToString())
                    return
Exemplo n.º 8
0
def preparePeripheral(device):
    #print("  preparing peripheral:")
    print("     - address: \t{}".format(device.addr))
    print("     - addresstype: \t{}".format(device.addrType))
    print("     - interface: \t{}".format(device.iface))
    print("     - connectable: \t{}".format(device.connectable))
    peripheral = Peripheral(device)  #devices[0].addr, devices[0].addrType)
    #peripheral = Peripheral(device.addr,device.addrType,device.iface)
    print("  peripheral set")
    peripheral.setDelegate(MyDelegate(peripheral))
    print("  delegate set")
    Peripheral.availableHandles = {
    }  # Dictionary containing ['UUID' : cccHandle]
    Peripheral.availabeChararacteristics = []
    #peripheral.connect()
    time.sleep(3)
    print("  getting services")
    try:
        services = peripheral.getServices()
    except:
        print("Failed to get services")
        return 0
    print("  displaying services")
    for ser in services:
        if ser.uuid in recognizedServices.keys():
            print("  Found recognized service: {}".format(ser.uuid))
            serChar = ser.getCharacteristics()
            for char in serChar:
                #print("Found char: {}".format(char.uuid))
                if char.uuid in recognizedServices[str(ser.uuid)]:
                    #handle = char.getHandle()
                    print(
                        "   -with recognized charachteristic: {}\t({})".format(
                            char.uuid.getCommonName(), char.uuid))
                    #print("      -with handle: 0x{:02X}".format(handle))
                    #cccHandle = getCCCHandle(peripheral, handle)
                    #print ("      -CCC handle: 0x{:02X}".format(cccHandle))
                    #peripheral.availableHandles.append(cccHandle)
                    #peripheral.availableHandles[char.uuid]  = cccHandle
                    peripheral.availabeChararacteristics.append(char)

    return peripheral
Exemplo n.º 9
0
def newPetition(device):
    p = Peripheral(device)

    print(p.getServices())
    """
    c = p.getCharacteristics(uuid=STATUS_UUID)[0]
    user = p.getCharacteristics(uuid=USER_UUID)[0]
    status = p.getCharacteristics(uuid=STATUS_UUID)[0]
    """
    c = p.getCharacteristics(uuid=ANNOUNCE_UUID)[0]
    status = p.getCharacteristics(uuid=STATUS_UUID)[0]
    user_ble = p.getCharacteristics(uuid=USER_UUID)[0]
    user = user_ble.read()
    user_name = str(user, 'ascii')[1:]
    print(user_name)
    occupied_ble = p.getCharacteristics(uuid=OCCUPIED_UUID)[0]
    occupied = int(occupied_ble.read())
    if occupied == 1:
        print("This spot is occupied")
        release_spot = releaseSpot(user_name, 1)
        if release_spot:
            status.write(b'1')
            c.write(b'1')
        else:
            status.write(b'3')
            c.write(b'1')
    elif occupied == 0:
        print("This spot is free")
        use_spot = useSpot(user_name, 1)
        if use_spot:
            status.write(b'1')
            c.write(b'1')
        else:
            status.write(b'3')
            c.write(b'1')
    else:
        pass

    p.disconnect()
    sleep(10)
    """
Exemplo n.º 10
0
class PeripheralResource():
    def __init__(self, peripheral, id):
        self.visible = True
        self.device = Peripheral(peripheral, random)
        services = self.device.getServices()
        self.resources = []
        for service in services:
            try:
                for char in service.getCharacteristics():
                    btRes = BluetoothResource(char=char,
                                              type=char.propertiesToString())
                    self.resources.append(btRes)
                    if char.uuid != UUID(
                            0x2A00) and "WRITE" in char.propertiesToString():
                        self.led_indicator = char
            except BTLEException as btexc:
                if (btexc.code == 2):
                    continue
        self.device.setDelegate(NotifyDelegate(self.resources, id))
        notifyThread = NotifyThread(self)
        notifyThread.start()
Exemplo n.º 11
0
def preparePeripheral(device):
	#Create the peripheral object from bluetooth device
	peripheral = Peripheral(device)
	peripheral.setDelegate(MyDelegate(peripheral))
	Peripheral.availableChararacteristics = []
	time.sleep(2)
	
	
	#Read all device characteristics and add make a list of recognized characteristics
	services = peripheral.getServices()
	
	for ser in services:
		if ser.uuid == BLE_SERVICE_ENVIRONMENT:
			logging.debug("  Found recognized service: {}".format(ser.uuid.getCommonName()))
			serChar = ser.getCharacteristics()
			for char in serChar:
				if char.uuid in recognizedServices[str(ser.uuid)]:
					logging.debug("   Added characteristics: {}".format(char.uuid.getCommonName()))
					peripheral.availableChararacteristics.append(char)
				else:
					logging.debug("   (Unused characteristics: {})".format(char.uuid.getCommonName()))
					
	return peripheral
Exemplo n.º 12
0
class TaggerService:
    def __init__(self, device):
        self.device = device
        self.peripheral = None
        self.services = None
        self.chars = None
        self.telemetry = None
        self.tagger_type = TYPE_PISTOL

    def connect(self):
        if self.device is not None:
            print "Connecting to Tagger"
            self.peripheral = Peripheral(self.device)
            self.services = self.peripheral.getServices()
            self.chars = self.peripheral.getCharacteristics()
            self.telemetry = TelemetryService(self.peripheral)
            self.telemetry.enable()

    def set_type(self, type):
        self.tagger_type = type

    def dump_services(self):
        if self.services is not None:
            for service in self.services:
                print "Service: ", service.uuid
            for char in self.chars:
                print "Characteristic: ", char.uuid

    def poll_data(self, time):
        if self.peripheral is not None:
            try:
                self.peripheral.waitForNotifications(1.0)
                return True
            except BTLEException:
                return False
        else:
            return False
Exemplo n.º 13
0
class BtleDevice(DefaultDelegate):
    """Base class for a connection to a Bluetooth Low Energy device.

    Built on bluepy (which is built on bluez), and uses some bluepy classes,
    so this class is just a helper not really a full API.

    See https://ianharvey.github.io/bluepy-doc/index.html

    **** NOTE *****
    As of 2019-12-06, you have to fix a bug in the btle.py library:
    Comment out the _getResp in disconnect() or it can hang on readline
        when a 'stat disc' reply from the helper is overlooked (as in
        during a call to setMTU).
    **** NOTE *****
    """
    # Common Services:
    generic_access_service_uuid = UUID('1800')
    device_info_service_uuid = UUID('180a')

    # Common Descriptors:
    characteristic_description_uuid = UUID('2901')
    characteristic_configure_uuid = UUID('2902')

    # Common Characteristics:
    model_number_uuid = UUID('2a24')  # As string
    serial_number_uuid = UUID('2a25')  # As string
    firmware_revision_uuid = UUID('2a26')  # As string
    hardware_revision_uuid = UUID('2a27')  # As string
    manufacturer_name_uuid = UUID('2a29')  # As string

    def __init__(self, mac_addy, mtu=0xff, max_rate=10):
        """Connect to the device at the specified addy.

        Max_rate is the maximum rate in messages/second at which we will
            send messages to the device.  I imagine this could/should be
            automatically inferred from the Peripheral Preferred Connection
            Parameters, but that's above my pay grade.  All I know is,
            if you don't meter the outgoing messages, some peripherals
            will just start dropping requests, resulting in timeouts
            waiting for the acks.  For an Airthings Wave+, max_rate 10
            works with dumb throttling, or max_rate 5 with smart.  The
            whole issue seems fishy to me -- seems like the lower level
            protocols should handle this better.  But pragmatically, it
            regularly hangs without this.
        """
        DefaultDelegate.__init__(self)
        assert mac_addy

        self.mac_addy = mac_addy
        self.mtu = mtu
        self.min_delay = 1. / max_rate
        self.peripheral = None

        self.cache = None  # Will be dict mapping UUIDs to Characteristics; Created/cleared by connect()
        self.last_notification = None  # This is only used transiently by the default notification handler.  Ignore!

        if smart_throttle:
            self.last_xmt_time = 0  # Used to throttle outgoing messages.  Is the time() of last sent message (or 0)

    #=====
    # If you don't know the MAC address, you'll need to scan, but that requires root...
    #=====

    @staticmethod
    def scan(match=None, duration=5, just_one=False, match_scan_entry=False):
        """This looks through any advertising btle devices for matching ones.

        *** Note you must run this as root ***

        match(scan_data) should return True if scan_data is from the device you're looking for.

            If no match function is provided, it is treated as always returning True (you want
                to see all devices that respond within duration).

            scan_data is a dict mapping description to value, unless match_scan_entry is True
                in which case scan_data is a btle ScanEntry object.

        Duration is how many seconds to scan before returning.

        If just_one is False, scans for the full duration and then
            returns a list of matching ScanEntry objects. (https://ianharvey.github.io/bluepy-doc/scanentry.html)

        If just_one is True, this returns the first match immediately (no list)
            or None after full duration timeout.

        Note (match==None and just_one==True) results in just the first device
            to respond being immediately returned.
        """
        scanner = Scanner().withDelegate(DefaultDelegate())
        scanner.clear()
        scanner.start()
        if not just_one:
            found = []
        try:
            for i in range(max(int(duration * 10),
                               1)):  # Break duration into 10ths
                scanner.process(
                    0.1)  # Handle incoming messages for 1/10th of a second...
                devices = scanner.getDevices()
                for dev in devices:
                    if debug:
                        BtleDevice.dump_scan_entry(dev)
                    if match_scan_entry:
                        params = dev
                    else:
                        params = {
                            name: val
                            for tag, name, val in dev.getScanData()
                        }
                    if match is None or match(params):
                        if just_one:
                            return dev
                        else:
                            found.append(dev)
                scanner.clear()
        finally:
            scanner.stop()

        if just_one:
            return None
        return found

    def disconnect(self):
        """Do call this when you are done!
        (But no sooner.  This will automatically re-connect if you try to do anything after this...)
        """
        if self.peripheral is not None:
            if debug:
                print(
                    "Disconnecting."
                )  # TODO - need to wrap all these debugging messages in a better logger...
            self.throttle()
            self.peripheral.disconnect()
            self.peripheral = None
            self.cache = None
            return True
        return False

    def connect(self):
        """Optional: Connects to the device.

        Returns True if this causes the connection, or False if we were already connected.

        Most of the methods here will call this on-demand, so you only need to call this
            explicitly if you want to access self.peripheral directly straight away.
        """
        if self.peripheral is None:
            if debug:
                print("Connecting to %s." % (self.mac_addy, ))
            self.cache = {}
            self.peripheral = Peripheral(self.mac_addy).withDelegate(self)
            if self.mtu is not None:
                self.throttle()
                self.peripheral.setMTU(
                    self.mtu
                )  # Notification and Indications may not happen if we don't do this.
            return True
        return False

    #=====
    # Most of the good stuff is here -- ways to read and write values:
    #=====

    def __getitem__(self, char):
        """This reads and returns the current value of the given characteristic.
        Char can be a uuid string, UUID object, or Characteristic object.
        """
        self.throttle()
        return self.get_characteristic(char).read()

    def __setitem__(self, char, val):
        """This writes the byte array val to the specified characteristic.
        Char can be a uuid string, UUID object, or Characteristic object.
        """
        self.throttle()
        self.get_characteristic(char).write(val, True)

    def get_handle(self, char):
        """This returns the Handle (small integer) of the specified characteristic.
        Char can be a uuid string, UUID object, or Characteristic object.
        Mainly useful to compare to the handle returned by wait_for_notification().
        """
        return self.get_characteristic(char).getHandle()

    def get_characteristic(self, uuid):
        """If you're just doing basic sets, queries and commands with the high
            level interface you probably don't need to call this directly.

        This accepts strings or UUID objects and returns the associated
            Characteristic object.  (Or the first one if there are multiple
            with the same UUID.  So, this is mainly useful for high level
            variables, not for meta information attributes or such.)
        As a convenience, if you pass a Characteristic, this will return it.
            (Which is useful for functions that want to allow flexible
            identification of the Characteristic.)
        Results are cached for efficiency, so don't be shy about using it.
        Raises KeyError if uuid can't be found.
        """
        self.connect()
        if isinstance(uuid, Characteristic):
            return uuid
        if not isinstance(uuid, UUID):
            uuid = UUID(uuid)
        if uuid not in self.cache:
            self.throttle()
            c = self.peripheral.getCharacteristics(uuid=uuid)
            if c:
                self.cache[uuid] = c[0]
            else:
                self.cache[uuid] = None
        c = self.cache[uuid]
        if c is None:
            raise KeyError("Can't find characteristic %s" % (uuid, ))
        return c

    #=====
    # If you want Notifications or Indications, you need to enable each characteristic accordingly.
    #=====

    def can_notify(self, char):
        """Returns non-zero if this characteristic can generate Notifications or Indications.

        Char can be a uuid string, UUID object, or Characteristic object.

        Technically the return value can be further inspected to discern whether it
            supports Notifications, Indications, or (does this ever happen?) both.
        """
        char = self.get_characteristic(char)
        return char.properties & (char.props['INDICATE']
                                  | char.props['NOTIFY'])

    def enable(self, char):
        """Usually this is the easiest way to enable notifications from a characteristic.

        You have to call this (or one of the more specific ones below) before you will
            get any notifications from a given Characteristic.

        This enables characteristic char for either Indications or Notifications depending
            on which sort it claims to generate.

        Char can be a uuid string, UUID object, or Characteristic object.
        """
        char = self.get_characteristic(char)
        if char.properties & char.props['INDICATE']:
            self.configure_characteristic(char, 2)
        elif char.properties & char.props['NOTIFY']:
            self.configure_characteristic(char, 1)
        else:
            raise Exception(
                "Characteristic does not support any notifications: %s" %
                (char, ))

    def disable(self, char):
        self.configure_characteristic(char, 0)

    def wait_for_notification(self, timeout):
        """This waits for the next notification and then returns it
            as a (handle, data) tuple.

        This only works if you do not override handleNotifications.

        This only handles notifications that come in during this call.
            If you call this successively, you should catch all notifications
            as long as you don't make any other Btle calls in between (since
            those calls could let a notification slip into the gap).

        Returns None on timeout.
        """
        try:
            self.last_notification = False  # False means we're waiting; None means we're not!
            if self.peripheral.waitForNotifications(timeout):
                return self.last_notification  # Python should grab it before the finally clause resets it...
            else:
                return (None, None)
        finally:
            self.last_notification = None  # Make sure handleNotifications alerts us to notifications that come out of band.

    def handleNotification(self, handle, data):
        """Subclass can override this to do whatever it wants with notifications/indications.
        """
        if self.last_notification is None:
            # Don't put this under Debug flag.  This alerts you to Notifications you aren't handling yet...
            print("UNHANDLED NOTIFICATION: handle=%r data=%r" %
                  (handle, data.hex()))
        else:
            self.last_notification = (handle, data)

    #--- Unlikely you need to call any of these directly:

    def enable_notifications(self, char):
        """If you want to get Notifications from a characteristic, you need to call this first.
        Char can be a uuid string, UUID object, or Characteristic object.
        Note this also disables Indications for this characteristic.  Use configure_characteristic to enable both.
        """
        self.configure_characteristic(char, 1)

    def enable_indications(self, char):
        """If you want to get value Indications from a characteristic, you need to call this first.
        Char can be a uuid string, UUID object, or Characteristic object.
        Note this also disables Notifications for this characteristic.  Use configure_characteristic to enable both.
        """
        self.configure_characteristic(char, 2)

    def configure_characteristic(self, char, val):
        """This looks up the handle for the configuration descriptor for this characteristic,
            and then sends val to it.
        Char can be a uuid string, UUID object, or Characteristic object.
        Typically val here is 1 (enable Notifications) or 2 (enable Indications) or 0 (disable).
        """
        char = self.get_characteristic(char)
        if debug:
            print("Finding configuration descriptor for handle 0x%x" %
                  (char.getHandle(), ))
        self.throttle()
        d, = char.getDescriptors(forUUID=self.characteristic_configure_uuid)
        if debug:
            print("Found (handle 0x%x).  Setting to 0x%02x" % (d.handle, val))
        self.throttle()
        d.write(struct.pack('<H', val), True)

    def throttle(self):
        """This internal utility just waits until self.min_delay from the
            last time this method was called.
        """
        if smart_throttle:
            now = time()
            delay = self.last_xmt_time + self.min_delay - now
            if delay > 0:
                sleep(delay)
                now += delay
            self.last_xmt_time = now
        else:
            sleep(self.min_delay)

    #=====
    # Below here are just utilities for displaying the device's data layout,
    # Which also serve as examples of how to access the devices's attributes.
    #=====

    def dump_services(self, read=False, indent=''):
        """This calls dump_service on all services this device provides.
        If read is True, it reads and prints each characteristic's value.

        This is a good way to manually discover the layout of your device.
        """
        self.connect()
        for s in self.peripheral.getServices():
            self.dump_service(s, read, indent)

    def dump_service(self, service, read=False, indent=''):
        """This calls dump_characteristic on all the characteristics in the given service.
        If service is not a Service object, it's assumed to be a UUID and the service
            will be looked up by that.
        """
        self.connect()

        if not isinstance(service, Service):
            try:
                service = self.peripheral.getServiceByUUID(service)
            except BTLEEException:
                print("%sService %r: NOT FOUND" % (indent, service))
                return

        print("%sService %r (%s):" %
              (indent, service.uuid.getCommonName(), service.uuid))
        for c in service.getCharacteristics():
            self.dump_characteristic(c, read, indent + "    ")

    def dump_characteristic(self, c, read=False, indent=''):
        """Dumps whatever we can find out about a characteristic.
        If read is True, also reads and prints its value (when applicable)
        """
        print("%sCharacteristic %r (%s):" %
              (indent, c.uuid.getCommonName(), c.uuid))
        print("%s          Handle: %s (%x)" %
              (indent, c.getHandle(), c.getHandle()))
        print("%s        Readable: %s" % (
            indent,
            c.supportsRead(),
        ))
        print("%s      Properties: %s" % (
            indent,
            c.propertiesToString(),
        ))

        try:
            descriptors = c.getDescriptors()
        except BTLEGattError:
            pass
        else:
            for d in descriptors:
                print("%s      Descriptor: %s (handle 0x%x; uuid %s)" %
                      (indent, d, d.handle, d.uuid))
                if d.uuid == self.characteristic_description_uuid:
                    self.throttle()
                    print("%s          ------> %r" % (indent, d.read()))

        if c.supportsRead():
            try:
                self.throttle()
                val = c.read()
            except:
                print("%s    (Read) Value: [READ FAILED]" % (indent, ))
            else:
                print("%s    (Read) Value: %s (0x%s)" %
                      (indent, val, val.hex()))

    @staticmethod
    def dump_scan_entry(se):
        """Just prints the info that comes back from a Scan response.
        """
        print("Scanned Device:")
        print("              MAC: %s" % (se.addr, ))
        print("        Addr Type: %s" % (se.addrType, ))
        print("  Signal Strength: %s dB" % (se.rssi, ))
        print("      Connectable: %s" % (se.connectable, ))
        print("     Update Count: %s" % (se.updateCount, ))
        for t in se.getScanData():
            print("  %r" % (t, ))
Exemplo n.º 14
0
class Blueterm(cmd.Cmd):
    intro = cfg['intro']
    prompt = cfg['prompt']

    def __init__(self, device_index, scan_timeout):
        cmd.Cmd.__init__(self)
        self.device_index = device_index
        self.scan_timeout = scan_timeout
        self.ble_devs = set()
        self.ble_gatt = dict()

        # setup Bluetooth
        self.scanner = Scanner(device_index)
        self.periph = Peripheral(None, ADDR_TYPE_PUBLIC, device_index)
        self.periph.setDelegate(ShellEventHandler())

    # Pla
    def precmd(self, line):
        return line

    def do_scan(self, line):
        """Scan for available BLE RIOT shells.
Running this command will reset the cached list of available devices.
usage: scan <scan timeout in sec>
        """
        args = line.strip().split(' ')
        if len(args[0]) > 0:
            try:
                to = float(args[0])
            except:
                print("error: unable to parse timeout (must be a number)")
                return
        else:
            to = self.scan_timeout

        print("Scanning now (blocking for {} seconds)...".format(to))
        try:
            self.ble_devs = list(self.scanner.scan(to))
            print("Scan complete:")
            self.do_list("")
        except:
            print("error: failure while scanning")
            return

    def do_list(self, line):
        """List all available BLE devices offering a RIOT shell
        """
        if len(self.ble_devs) == 0:
            print("No BLE devices available")
            return

        for i, dev in enumerate(self.ble_devs):
            print("[{:2}] {}".format(i, dev.addr), end='')
            for (adtype, desc, value) in dev.getScanData():
                if adtype == 9:
                    print(" (Name: '{}'')".format(value), end='')
            print()

    def do_connect(self, line):
        args = line.strip().split(' ')
        if len(args[0]) == 0:
            print("usage: connect <device index>")
            return
        try:
            dev = self.ble_devs[int(args[0])]
        except:
            print("error: unable to find given device index")
            return

        try:
            self.periph.connect(dev.addr, dev.addrType)
            services = self.periph.getServices()
            for i, service in enumerate(services):
                print("Service {:2} UUID: {} ({})".format(
                    i, service.uuid, service.uuid.getCommonName()))
                chars = service.getCharacteristics()
                type(chars)
                for i, char in enumerate(chars):
                    print("   Char {:2} UUID: {} ({})".format(
                        i, char.uuid, char.uuid.getCommonName()))
                    # if char.supportsRead():
                    #     tmp = char.read()
                    #     print("Data: ", str(tmp))
        except:
            print("error: while conneting something was bad")
            return
Exemplo n.º 15
0
    def __get_services_and_chars(self):
        for device in self.__devices_around:
            try:
                if self.__devices_around.get(
                        device) is not None and self.__devices_around[
                            device].get('scanned_device') is not None:
                    log.debug('Connecting to device: %s', device)
                    if self.__devices_around[device].get('peripheral') is None:
                        address_type = self.__devices_around[device][
                            'device_config'].get('addrType', "public")
                        peripheral = Peripheral(
                            self.__devices_around[device]['scanned_device'],
                            address_type)
                        self.__devices_around[device][
                            'peripheral'] = peripheral
                    else:
                        peripheral = self.__devices_around[device][
                            'peripheral']
                    try:
                        log.info(peripheral.getState())
                    except BTLEInternalError:
                        peripheral.connect(
                            self.__devices_around[device]['scanned_device'])
                    try:
                        services = peripheral.getServices()
                    except BTLEDisconnectError:
                        self.__check_and_reconnect(device)
                        services = peripheral.getServices()
                    for service in services:
                        if self.__devices_around[device].get(
                                'services') is None:
                            log.debug(
                                'Building device %s map, it may take a time, please wait...',
                                device)
                            self.__devices_around[device]['services'] = {}
                        service_uuid = str(service.uuid).upper()
                        if self.__devices_around[device]['services'].get(
                                service_uuid) is None:
                            self.__devices_around[device]['services'][
                                service_uuid] = {}

                            try:
                                characteristics = service.getCharacteristics()
                            except BTLEDisconnectError:
                                self.__check_and_reconnect(device)
                                characteristics = service.getCharacteristics()

                            if self.__config.get('buildDevicesMap', False):
                                for characteristic in characteristics:
                                    descriptors = []
                                    self.__check_and_reconnect(device)
                                    try:
                                        descriptors = characteristic.getDescriptors(
                                        )
                                    except BTLEDisconnectError:
                                        self.__check_and_reconnect(device)
                                        descriptors = characteristic.getDescriptors(
                                        )
                                    except BTLEGattError as e:
                                        log.debug(e)
                                    except Exception as e:
                                        log.exception(e)
                                    characteristic_uuid = str(
                                        characteristic.uuid).upper()
                                    if self.__devices_around[device][
                                            'services'][service_uuid].get(
                                                characteristic_uuid) is None:
                                        self.__check_and_reconnect(device)
                                        self.__devices_around[device][
                                            'services'][service_uuid][
                                                characteristic_uuid] = {
                                                    'characteristic':
                                                    characteristic,
                                                    'handle':
                                                    characteristic.handle,
                                                    'descriptors': {}
                                                }
                                    for descriptor in descriptors:
                                        log.debug(descriptor.handle)
                                        log.debug(str(descriptor.uuid))
                                        log.debug(str(descriptor))
                                        self.__devices_around[device][
                                            'services'][service_uuid][
                                                characteristic_uuid][
                                                    'descriptors'][
                                                        descriptor.
                                                        handle] = descriptor
                            else:
                                for characteristic in characteristics:
                                    characteristic_uuid = str(
                                        characteristic.uuid).upper()
                                    self.__devices_around[device]['services'][
                                        service_uuid][characteristic_uuid] = {
                                            'characteristic': characteristic,
                                            'handle': characteristic.handle
                                        }

                    if self.__devices_around[device]['is_new_device']:
                        log.debug('New device %s - processing.', device)
                        self.__devices_around[device]['is_new_device'] = False
                        self.__new_device_processing(device)
                    for interest_char in self.__devices_around[device][
                            'interest_uuid']:
                        characteristics_configs_for_processing_by_methods = {}

                        for configuration_section in self.__devices_around[
                                device]['interest_uuid'][interest_char]:
                            characteristic_uuid_from_config = configuration_section[
                                'section_config'].get("characteristicUUID")
                            if characteristic_uuid_from_config is None:
                                log.error(
                                    'Characteristic not found in config: %s',
                                    pformat(configuration_section))
                                continue
                            method = configuration_section[
                                'section_config'].get('method')
                            if method is None:
                                log.error('Method not found in config: %s',
                                          pformat(configuration_section))
                                continue
                            characteristics_configs_for_processing_by_methods[
                                method.upper()] = {
                                    "method":
                                    method,
                                    "characteristicUUID":
                                    characteristic_uuid_from_config
                                }
                        for method in characteristics_configs_for_processing_by_methods:
                            data = self.__service_processing(
                                device,
                                characteristics_configs_for_processing_by_methods[
                                    method])
                            for section in self.__devices_around[device][
                                    'interest_uuid'][interest_char]:
                                converter = section['converter']
                                converted_data = converter.convert(
                                    section, data)
                                self.statistics[
                                    'MessagesReceived'] = self.statistics[
                                        'MessagesReceived'] + 1
                                log.debug(data)
                                log.debug(converted_data)
                                self.__gateway.send_to_storage(
                                    self.get_name(), converted_data)
                                self.statistics[
                                    'MessagesSent'] = self.statistics[
                                        'MessagesSent'] + 1
            except BTLEDisconnectError:
                log.debug('Connection lost. Device %s', device)
                continue
            except Exception as e:
                log.exception(e)
Exemplo n.º 16
0
class TransportBluepy():
    def __init__(self):
        self.devices = []
        self.peripheral = None

    def findRawDevices(self, timeout=1.0):
        rawDevices = []
        scanner = Scanner()
        rawDevices = scanner.scan(timeout)

        return rawDevices

    def rawDeviceInfoStr(self, rawDevice):
        """
        Convert the raw device into an info string.

        The format of the string is transport-specific.
        """
        info = "Address: {0:s}\n".format(rawDevice.addr)
        info += "Address type: {0:s}\n".format(
            "public" if rawDevice.addrType ==
            bluepy.btle.ADDR_TYPE_PUBLIC else "random")
        info += "Connections?: {0:s}\n".format(
            "yes" if rawDevice.connectable else "no")
        info += "Scan Data:\n"
        scanData = rawDevice.getScanData()
        for scanRow in scanData:
            info += "    {0:d}\t| {1:s}\t| {2:s}\n".format(
                scanRow[0], scanRow[1], scanRow[2])
        if rawDevice.connectable:
            self.connect(rawDevice.addr, rawDevice.addrType)
            info += "Services:\n"
            rawServices = self.getRawServices()
            for rawService in rawServices:
                info += "{0:s}".format(self.rawServiceInfoStr(rawService))
            self.disconnect()

        return info

    def rawServiceInfoStr(self, rawService):
        info = "    UUID: {0:s}\n".format(str(rawService.uuid))
        info += "    Characteristics:\n"
        rawCharacteristics = self.getRawCharacteristicsForService(rawService)
        for rawCharacteristic in rawCharacteristics:
            info += "{0:s}".format(
                self.rawCharacteristicInfoStr(rawCharacteristic))
        return info

    def rawCharacteristicInfoStr(self, rawCharacteristic):
        info = "    -   UUID: {0:s}\n".format(str(rawCharacteristic.uuid))
        info += "    -   Handle: {0:d} (0x{0:x})\n".format(
            rawCharacteristic.getHandle())
        info += "    -   Properties: {0:s}\n".format(
            rawCharacteristic.propertiesToString())
        return info

    def connect(self, addr, addrType=bluepy.btle.ADDR_TYPE_RANDOM):
        self.disconnect()
        self.peripheral = Peripheral(addr, addrType)

    def disconnect(self):
        if self.peripheral != None:
            self.peripheral.disconnect()
            self.peripheral = None

    def getRawServices(self):
        if self.peripheral == None:
            print("Not connected.\n")
            return {}
        rawServices = self.peripheral.getServices()
        print("Found {0:d} services\n".format(len(rawServices)))
        return rawServices

    def getRawCharacteristicsForService(self, service):
        return service.getCharacteristics()

    def getRawCharacteristicsByUUID(self, uuid):
        results = []
        if self.peripheral != None:
            results = self.peripheral.getCharacteristics(uuid=uuid)
        return results
Exemplo n.º 17
0
    def __get_services_and_chars(self):
        for device in self.__devices_around:
            try:
                if self.__devices_around.get(
                        device) is not None and self.__devices_around[
                            device].get('scanned_device') is not None:
                    log.debug(
                        'Connecting to device with address: %s',
                        self.__devices_around[device]
                        ['scanned_device'].addr.upper())
                    if self.__devices_around[device].get('peripheral') is None:
                        address_type = self.__devices_around[device][
                            'device_config'].get('addrType', "public")
                        peripheral = Peripheral(
                            self.__devices_around[device]['scanned_device'],
                            address_type)
                        self.__devices_around[device][
                            'peripheral'] = peripheral
                    else:
                        peripheral = self.__devices_around[device][
                            'peripheral']
                        try:
                            peripheral.connect(self.__devices_around[device]
                                               ['scanned_device'])
                        except Exception as e:
                            log.exception(e)
                    services = peripheral.getServices()
                    for service in services:
                        if self.__devices_around[device].get(
                                'services') is None:
                            log.debug(
                                'Building device %s map, it may take a time, please wait...',
                                device)
                            self.__devices_around[device]['services'] = {}
                        service_uuid = str(service.uuid).upper()
                        if self.__devices_around[device]['services'].get(
                                service_uuid) is None:
                            self.__devices_around[device]['services'][
                                service_uuid] = {}

                            try:
                                characteristics = service.getCharacteristics()
                            except BTLEDisconnectError:
                                self.__check_and_reconnect(device)
                                characteristics = service.getCharacteristics()

                            if self.__config.get('buildDevicesMap', False):
                                for characteristic in characteristics:
                                    descriptors = []
                                    try:
                                        self.__check_and_reconnect(device)
                                        try:
                                            descriptors = characteristic.getDescriptors(
                                            )
                                        except BTLEDisconnectError:
                                            self.__check_and_reconnect(device)
                                            descriptors = characteristic.getDescriptors(
                                            )
                                        except BTLEGattError as e:
                                            log.debug(e)
                                        except Exception as e:
                                            log.exception(e)
                                        characteristic_uuid = str(
                                            characteristic.uuid).upper()
                                        if self.__devices_around[device][
                                                'services'][service_uuid].get(
                                                    characteristic_uuid
                                                ) is None:
                                            self.__devices_around[device][
                                                'services'][service_uuid][
                                                    characteristic_uuid] = {
                                                        'characteristic':
                                                        characteristic,
                                                        'handle':
                                                        characteristic.handle,
                                                        'descriptors': {}
                                                    }
                                        for descriptor in descriptors:
                                            log.debug(descriptor.handle)
                                            log.debug(str(descriptor.uuid))
                                            log.debug(str(descriptor))
                                            self.__devices_around[device][
                                                'services'][service_uuid][
                                                    characteristic_uuid][
                                                        'descriptors'][
                                                            descriptor.
                                                            handle] = descriptor
                                    except BTLEDisconnectError:
                                        self.__check_and_reconnect(device)
                            else:
                                for characteristic in characteristics:
                                    characteristic_uuid = str(
                                        characteristic.uuid).upper()
                                    self.__devices_around[device]['services'][
                                        service_uuid][characteristic_uuid] = {
                                            'characteristic': characteristic,
                                            'handle': characteristic.handle
                                        }

                    if self.__devices_around[device]['is_new_device']:
                        log.debug('New device %s - processing.', device)
                        self.__devices_around[device]['is_new_device'] = False
                        self.__new_device_processing(device)
                    for interest_char in self.__devices_around[device][
                            'interest_uuid']:
                        for section in self.__devices_around[device][
                                'interest_uuid'][interest_char]:
                            data = self.__service_processing(
                                device, section['section_config'])
                            converter = section['converter']
                            converted_data = converter.convert(section, data)
                            self.statistics[
                                'MessagesReceived'] = self.statistics[
                                    'MessagesReceived'] + 1
                            log.debug(data)
                            log.debug(converted_data)
                            self.__gateway.send_to_storage(
                                self.get_name(), converted_data)
                            self.statistics['MessagesSent'] = self.statistics[
                                'MessagesSent'] + 1
            except BTLEDisconnectError:
                log.debug('Cannot connect to device %s', device)
                continue
            except Exception as e:
                log.exception(e)
Exemplo n.º 18
0
class BluetoothLE:
	def __init__(self, deviceAddress, deviceType, addrType, mqttConnection):
		self.deviceAddress = deviceAddress
		self.deviceType = deviceType
		self.mqtt = mqttConnection
		self.addrType = addrType
		self.bleConnection = None

		self.ConnectToBLEDevice(True)

	def ConnectToBLEDevice(self, createNew):
                print "Connecting to device ", self.deviceType
                if createNew:
                        self.bleConnection = Peripheral(self.deviceAddress, self.addrType)
                        self.mqtt.setDeviceStatus(self, True)
                else:
                        self.bleConnection.connect(self.deviceAddress, self.addrType)

		print "Connected to " + self.deviceType
		thread.start_new_thread(self.ReadLoop, ())

	text_characters = "".join(map(chr, range(32, 127)))
	_null_trans = string.maketrans("", "")

	def isText(self, s, text_characters=text_characters, threshold=0.30):
                # if s contains any null, it's not text:
                if "\x00" in s:
                        return False
                # an "empty" string is "text" (arbitrary but reasonable choice):
                if not s:
                        return True
                # Get the substring of s made up of non-text characters
                t = s.translate(self._null_trans, text_characters)
                # s is 'text' if less than 30% of its characters are non-text ones:
                return len(t)/len(s) <= threshold

        def formatValue(self, value):
                #We need to determine if we have hex data or a character string
                #The best we can do, without hard coding characteristic ID's is to
                #see if the valueis alphanumeric or contains only 1 or 2 characters.
                #If the value is not alphanumeric or is a length of 1 or 2, assume it is hex data
                theValue = value

                if not self.isText(theValue) or len(theValue) ==1 or len(theValue) == 2:
                        #Assume the data is hex. We now need to unpack it
                        if len(theValue) == 1:
                                #Assume signed char
                                theValue = struct.unpack('b', theValue)[0]
                        elif len(theValue) ==2:
                                #Assume short
                                theValue = struct.unpack('h', theValue)[0]
                        elif len(theValue) == 4:
                                #Assume long
                                theValue = struct.unpack('l', theValue)[0]
                        elif len(theValue) == 8:
                                #Assume long long
                                theValue = struct.unpack('q', theValue)[0]
                        else:
                                #Only other thing we can do
                                theValue = theValue.encode('string-escape')

                return theValue

	def ReadLoop(self):
                readData = {}
		characteristics = self.bleConnection.getCharacteristics()

		for char in characteristics:
                        if char.supportsRead():
                                try:
                                        value = self.formatValue(char.read())
                                        readData[str(char.uuid.getCommonName())] = value
                                except:
                                        print "Failed to read data for uuid ", str(char.uuid.getCommonName())
                                        print sys.exc_info()

                readData["services"] = []

		services = self.bleConnection.getServices()
		for service in services:
                        serviceData = {}
                        serviceData["name"] = str(service.uuid.getCommonName())

                        serviceChars = service.getCharacteristics()
                        for serviceChar in serviceChars:
                                if serviceChar.supportsRead():
                                        try:
                                                value = self.formatValue(serviceChar.read())
                                                serviceData[str(serviceChar.uuid.getCommonName())] = value
                                        except:
                                                print "Failed to read data for uuid ", str(serviceChar.uuid.getCommonName())
                                                print sys.exc_info()

                        if serviceData:
                                readData["services"].append(serviceData)

                print readData

		message = {}
		message["deviceAddress"] = self.deviceAddress
		message["deviceType"] = self.deviceType
		message["readData"] = str(readData)

		self.mqtt.PublishMessage(json.dumps(message), "BLEReadData", None)

		#Disconnect the peripheral once we are done reading data
		self.bleConnection.disconnect()

	def ReadValue(self, uuid):
                self.bleConnection.connect(self.deviceAddress, self.addrType)
		characteristics = self.bleConnection.getCharacteristics(uuid=uuid)[0]
		readValue = self.formatValue(characteristics.read())

		messageToPublish = {}
		messageToPublish["deviceType"] = self.deviceType
		messageToPublish["deviceAddress"] = self.deviceAddress
		messageToPublish["readData"] = readValue

		self.mqtt.PublishMessage(json.dumps(messageToPublish), "BLEReadData", None)
		self.bleConnection.disconnect()

		print "Successfully read data from device. Data value = ", readValue

	def WriteValue(self, data, uuid):
                self.bleConnection.connect(self.deviceAddress, self.addrType)
		uuidValue = UUID(uuid)
		characteristics = self.bleConnection.getCharacteristics(uuid=uuid)[0]
		characteristics.write(data, True)
		print "Successfully wrote data to device " + self.deviceAddress
		self.bleConnection.disconnect()
Exemplo n.º 19
0
        elif isNewData:
            print "Received new data from", dev.addr


scanner = Scanner().withDelegate(ScanDelegate())
devices = scanner.scan(0.1)

macAddress = "4b:4e:4f:00:00:01"

for dev in devices:
    print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)
    for (adtype, desc, value) in dev.getScanData():
        print "  %s = %s" % (desc, value)

periph = Peripheral(macAddress)
services = periph.getServices()
for service in services:
    print "Service UUID : %s" % (service.uuid.getCommonName())
    characteristics = service.getCharacteristics()
    for char in characteristics:
        print "UUID : %s, property : %s" % (char.uuid.getCommonName(),
                                            char.propertiesToString())
        if (char.uuid.getCommonName() == "626f6972-6564-656c-616c-636f6f6c0100"
            ):
            knocks = struct.unpack("<b", char.read())[0]
            print knocks
periph.disconnect()

url = "http://192.168.0.10/plugins/knocklet/core/api/knocklet.api.php"
headers = {'content-type': 'application/json'}
Exemplo n.º 20
0
        DefaultDelegate.__init__(self)

    def handleNotification(self, cHandle, data):
        print(data)


crtS = None
crtL = None

dev = Peripheral(mac)
dev.setMTU(1000)

dlg = delega()
dev.withDelegate(dlg)

srvz = dev.getServices()
for srv in srvz:
    crt = srv.getCharacteristics()
    for c in crt:
        cuuid = c.uuid.getCommonName()
        pts = c.propertiesToString()
        print(cuuid + ' : ' + pts)
        # if c.supportsRead():
        #     r = c.read()
        #     print(str(r))
        if str(c.uuid) == cuuid:
            if c.supportsRead():
                crtL = c  # c.getHandle()
            else:
                crtS = c  # c.getHandle()
Exemplo n.º 21
0
class SbrickAPI(object):
    # UUID of Remote Control Commands. The Remote Control Commands characteristic allows full control over SBrick.
    rcc_uuid = '02b8cbcc-0e25-4bda-8790-a15f53e6010f'
    stop_hex = '00'
    drive_hex = '01'

    class DriveThread(Thread):
        def __init__(self, logger, sbrick, channel, direction, power):
            Thread.__init__(self)
            self._sbrick = sbrick
            self._channel = channel
            self._direction = direction
            self._power = power
            self._logger = logger

            self._stop_event = Event()
            self._timer_thd = None

        def run(self):
            self.drive()

        def drive(self):
            self.drive_channel()
            self.break_channel()

        def stop(self):
            self._stop_event.set()
            self._timer_thd.cancel()

        def times_up(self):
            self._logger.debug('Drive action times_up {}{}{}{}'.format(
                SbrickAPI.drive_hex, self._channel, self._direction,
                self._power))
            self._stop_event.set()

        def reset_command(self, channel, direction, power):
            self._channel = channel
            self._direction = direction
            self._power = power

        def reset_timer(self, exec_time):
            if self._timer_thd:
                self._timer_thd.cancel()
            if self._stop_event:
                self._stop_event.clear()

            if MAGIC_FOREVER == exec_time:
                return
            self._timer_thd = Timer(exec_time, self.times_up)
            self._timer_thd.setName('timer_' + self._channel)
            self._timer_thd.start()

        def drive_channel(self):
            while (not self._stop_event.is_set()):
                drive_hex_string = SbrickAPI.drive_hex + self._channel + self._direction + self._power
                self.exec_command(drive_hex_string)
                # TODO: not need to sleep
                #time.sleep(0.1)
                time.sleep(1)

        def break_channel(self):
            stop_hex_string = SbrickAPI.stop_hex + self._channel
            self.exec_command(stop_hex_string)

        def exec_command(self, hex_string):
            self._logger.debug('Exec command {}'.format(hex_string))
            binary = bytes.fromhex(hex_string)
            self._sbrick.rcc_char_write_ex(binary, reconnect_do_again=False)
            #self._sbrick.rcc_char_read_ex(reconnect_do_again=False)

        @property
        def stop_event(self):
            return self._stop_event

        @property
        def timer_thd(self):
            return self._timer_thd

    def __init__(self, logger, dev_mac):
        self._dev_mac = dev_mac
        self._logger = logger
        self._lock = Lock()

        # bluepy is not thread-safe, must use lock to protect it
        self._blue = Peripheral()
        self._rcc_char = None

        self._channel_thread = {'00': None, '01': None, '02': None, '03': None}

    def __enter__(self):
        self.connect()
        return self

    def __exit__(self, type, value, traceback):
        self.disconnect()

    def _construct_new_bluetooth_object(self):
        self._lock.acquire()
        self._logger.info("Construct a new bluetooth object")
        del self._blue
        self._blue = Peripheral()
        self._lock.release()

    def connect(self):
        try:
            self._lock.acquire()
            self._logger.info('Try to connect to SBrick ({})'.format(
                self._dev_mac))
            # connect() is a blocking function
            self._blue.connect(self._dev_mac)
        except BTLEException as e:
            self._lock.release()
            self._logger.error('SBrick ({}): {}'.format(
                self._dev_mac, e.message))
            if isinstance(e, BTLEDisconnectError):
                return False
            else:
                self._construct_new_bluetooth_object()
                self._logger.error('exit -1')
                sys.exit(-1)
        except Exception as e:
            self._lock.release()
            self._logger.error(e)
            self._construct_new_bluetooth_object()
            self._logger.error('exit -1')
            sys.exit(-1)
        else:
            self._logger.info('Connect to SBrick ({}) successfully'.format(
                self._dev_mac))

        # Get remote control command characteristic
        try:
            self._logger.info('Get rcc characteristic')
            chars = self._blue.getCharacteristics(uuid=SbrickAPI.rcc_uuid)
        except Exception as e:
            self._lock.release()
            self._logger.error(
                "Failed to get SBrick characteristics ({}): {}".format(
                    SbrickAPI.rcc_uuid, e))
            self._construct_new_bluetooth_object()
            self._logger.error('exit -1')
            sys.exit(-1)
        else:
            for char in chars:
                if char.uuid == SbrickAPI.rcc_uuid:
                    self._rcc_char = char

        # Get services information
        try:
            services = self._blue.getServices()
        except Exception as e:
            self._lock.release()
            self._logger.error("Failed to get SBrick services ({}): {}".format(
                self._dev_mac, e))
            self._construct_new_bluetooth_object()
            self._logger.error('exit -1')
            sys.exit(-1)
        else:
            self._services = services
            self._lock.release()

        return True

    def disconnect_ex(self):
        # disconnect SBrick using bluetoothctl command
        bl_cmd = 'disconnect {}\nquit'.format(self._dev_mac)
        cmd = "echo -e '{}'".format(bl_cmd)
        p1 = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE)
        p2 = subprocess.Popen(shlex.split('bluetoothctl'),
                              stdin=p1.stdout,
                              stdout=subprocess.PIPE,
                              shell=True)
        p1.stdout.close()
        p2.communicate()
        # wait 3 seconds for real disconnection, because `bluetoothctl #disconnect` is an asynchronous command
        time.sleep(3)

    def disconnect(self):
        self._lock.acquire()
        self._blue.disconnect()
        self._logger.info('Disconnect from SBrick({}) successfully'.format(
            self._dev_mac))
        self._lock.release()

    def re_connect(self):
        self._logger.info('Re-connect to SBrick ({})'.format(self._dev_mac))
        self.disconnect()
        return self.connect()

    def drive(self, channel='00', direction='00', power='f0', exec_time=1):
        # reset thread status when the thread is dead
        if self._channel_thread[
                channel] and not self._channel_thread[channel].is_alive():
            self._channel_thread[channel].join()
            self._channel_thread[channel] = None

        if None == self._channel_thread[channel]:
            # Create a thread for executing drive
            thd = SbrickAPI.DriveThread(self._logger, self, channel, direction,
                                        power)
            thd.setName('channel_' + channel)
            thd.reset_timer(exec_time)
            self._channel_thread[channel] = thd
            thd.start()
        else:
            self._logger.debug('Overwrite drive action')
            running_thd = self._channel_thread[channel]
            running_thd.reset_command(channel, direction, power)
            running_thd.reset_timer(exec_time)

    def stop(self, channels=['00']):
        # TODO: validate parameters
        self._logger.debug('Stop action')
        for channel in channels:
            thd = self._channel_thread[channel]
            if thd:
                thd.stop()
                thd.join()
                self._channel_thread[channel] = None

    def rcc_char_write_ex(self, binary, reconnect_do_again=True):
        # make sure _rcc_char exist
        self._lock.acquire()
        self._logger.debug(
            'RCC characteristic writes binary: {}'.format(binary))
        if not self._rcc_char:
            self._lock.release()
            self._construct_new_bluetooth_object()
            if False == self.re_connect(): return False
        else:
            self._lock.release()

        # write binary
        try:
            self._lock.acquire()
            self._rcc_char.write(binary)
        except BrokenPipeError as e:
            self._lock.release()
            self._logger.error('BrokerPipeError with bluepy-helper')
            self._logger.error('exit -1')
            sys.exit(-1)
        except BTLEException as e:
            self._lock.release()
            self._logger.error('SBrick ({}): {}'.format(
                self._dev_mac, e.message))
            if isinstance(e, BTLEDisconnectError):
                self._construct_new_bluetooth_object()
                if False == self.re_connect(): return False
                if reconnect_do_again:
                    self.rcc_char_write_ex(binary, reconnect_do_again=False)
            elif isinstance(
                    e, BTLEInternalError
            ) and "Helper not started (did you call connect()?)" == e.message:
                self._construct_new_bluetooth_object()
                if False == self.re_connect(): return False
                if reconnect_do_again:
                    self.rcc_char_write_ex(binary, reconnect_do_again=False)
            elif isinstance(
                    e, BTLEException
            ) and "Error from bluepy-helper (badstate)" == e.message:
                if False == self.re_connect(): return False
                if reconnect_do_again:
                    self.rcc_char_write_ex(binary, reconnect_do_again=False)
            else:
                self._construct_new_bluetooth_object()
                self._logger.error('exit -1')
                sys.exit(-1)
        except Exception as e:
            self._lock.release()
            self._logger.error(e)
            self._construct_new_bluetooth_object()
            self._logger.error('exit -1')
            sys.exit(-1)
        else:
            self._lock.release()

        return True

    def rcc_char_read_ex(self, reconnect_do_again=True):
        try:
            self._lock.acquire()
            out = self._rcc_char.read()
        except BrokenPipeError as e:
            self._lock.release()
            self._logger.error('BrokerPipeError with bluepy-helper')
            self._logger.error('exit -1')
            sys.exit(-1)
        except BTLEException as e:
            self._lock.release()
            self._logger.error('SBrick ({}): {}'.format(
                self._dev_mac, e.message))
            if BTLEException.DISCONNECTED == e.code:
                if False == self.re_connect(): return False
                if reconnect_do_again:
                    self.rcc_char_read_ex(reconnect_do_again=False)
            else:
                self._construct_new_bluetooth_object()
                self._logger.error('exit -1')
                sys.exit(-1)
        except Exception as e:
            self._lock.release()
            self._logger.error(e)
            self._construct_new_bluetooth_object()
            self._logger.error('exit -1')
            sys.exit(-1)
        else:
            self._lock.release()

        return out

    def get_info_service(self):
        self._logger.debug("Service information:")
        for s in self._services:
            self._logger.debug("  {service}, {uuid}".format(service=s,
                                                            uuid=s.uuid))
            chars = s.getCharacteristics()
            for c in chars:
                self._logger.debug("    {char}, {uuid}, {proty}".format(
                    char=c, uuid=c.uuid, proty=c.propertiesToString()))

        ret = []
        for s in self._services:
            service = {}
            service['description'] = "{}".format(s)
            service['uuid'] = s.uuid.getCommonName()
            service['characteristics'] = []
            chars = s.getCharacteristics()
            for c in chars:
                characteristic = {}
                characteristic['description'] = "{}".format(c)
                characteristic['uuid'] = c.uuid.getCommonName()
                characteristic['property'] = c.propertiesToString()
                #characteristic['value'] = c.read() if c.supportsRead() else ''
                service['characteristics'].append(characteristic)
            ret.append(service)
        self.disconnect()
        return ret

    def get_info_adc(self):
        ret = {}
        # Get temperature
        code = bytes.fromhex('0F09')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<H", binary)[0]
        self._temperature = (value / 118.85795) - 160

        # Get voltage
        code = bytes.fromhex('0F08')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack('<H', binary)[0]
        self._voltage = (value * 0.83875) / 2047.0

        self._logger.debug("ADC information:")
        self._logger.debug("  Temperature = {}".format(self._temperature))
        self._logger.debug("  Voltage = {}".format(self._voltage))

        ret['temperature'] = self._temperature
        ret['voltage'] = self._voltage
        self.disconnect()
        return ret

    def get_info_general(self):
        ret = {}
        # Get is_authenticated
        code = bytes.fromhex('03')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<B", binary)[0]
        self._is_auth = value

        # Get authentication timeout
        code = bytes.fromhex('09')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<B", binary)[0]
        self._auth_timeout = value * 0.1  # second

        # Get brick ID
        code = bytes.fromhex('0A')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<6B", binary)
        l = list(map(lambda v: "%X" % (v), list(value)))
        self._brick_id = ' '.join(l)

        # Get watchdog timeout
        code = bytes.fromhex('0E')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<B", binary)[0]
        self._watchdog_timeout = value * 0.1  # second

        # Get thermal limit
        code = bytes.fromhex('15')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<H", binary)[0]
        self._thermal_limit = (value / 118.85795) - 160

        # Get PWM counter value
        code = bytes.fromhex('20')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<H", binary)[0]
        self._pwm_counter_value = value

        # Get channel status
        code = bytes.fromhex('22')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<7B", binary)
        self._channel_status = value

        # Get is guest password set
        code = bytes.fromhex('23')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<B", binary)[0]
        self._is_quest_pw_set = value

        # Get connection parameters
        code = bytes.fromhex('25')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<3H", binary)
        self._conn_param = value

        # Get release on reset
        code = bytes.fromhex('27')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<B", binary)[0]
        self._ror = value

        # Get power cycle counter
        code = bytes.fromhex('28')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<I", binary)[0]
        self._power_cycle_counter = value

        # Get uptime counter
        code = bytes.fromhex('29')
        if False == self.rcc_char_write_ex(code): return ret
        binary = self.rcc_char_read_ex()
        value = struct.unpack("<I", binary)[0]
        self._uptime_counter = value

        self._logger.debug("General information:")
        self._logger.debug("  Is authenticated: {}".format(self._is_auth))
        self._logger.debug("  Authentication timeout(second): {}".format(
            self._auth_timeout))
        self._logger.debug("  Brick ID: {}".format(self._brick_id))
        self._logger.debug("  Watchdog timeout(second): {}".format(
            self._watchdog_timeout))
        self._logger.debug("  Thermal limit: {}".format(self._thermal_limit))
        self._logger.debug("  PWM counter value: {}".format(
            self._pwm_counter_value))
        self._logger.debug("  Channel status: {}".format(self._channel_status))
        self._logger.debug("  Is guest password set: {}".format(
            self._is_quest_pw_set))
        self._logger.debug("  Connection parameters(ms): {}".format(
            self._conn_param))
        self._logger.debug("  Release on reset: {}".format(self._ror))
        self._logger.debug("  Power cycle counter: {}".format(
            self._power_cycle_counter))
        self._logger.debug("  Uptime counter: {}".format(self._uptime_counter))

        ret['is_auth'] = self._is_auth
        ret['auth_timeout'] = self._auth_timeout
        ret['brick_id'] = self._brick_id
        ret['watchdog_timeout'] = self._watchdog_timeout
        ret['thermal_limit'] = self._thermal_limit
        ret['is_quest_password_set'] = self._is_quest_pw_set
        ret['power_cycle_count'] = self._power_cycle_counter
        ret['uptime_count'] = self._uptime_counter
        self.disconnect()
        return ret

    def set_watchdog_timeout(self, timeout):
        """
        timeout: 0.1 seconds, 1 byte. Ragne: 0 ~ 255
        """

        self.connect()
        code = bytes.fromhex('0D') + struct.pack('<B', timeout)
        self.rcc_char_write_ex(code)
        self.disconnect()

    @property
    def blue(self):
        return self._blue
                                                                                                  # To solve the endianess problem reverse the
                                                                                                  # string to find exact value

devices = Scanner()                 # Scanner Object
temp=devices.scan(10)               # Start Scan
try:
    for dev in temp:
        if dev.getScanData()[3][2] == "mr. singh":      # Check for the target BLE device name
            if dev.connectable:
                p = Peripheral(dev.addr, "random")
                p.setDelegate(ScanDelegate())           # Create internal Object of scandelegate class to handle the notifications
except (RuntimeError, TypeError, NameError):
    print "Device not found"
    exit(1)
################### Check for the Services and its characteristics #################
print p.getServices()[0]
print p.getServices()[1]
print p.getServices()[2]
Heart_Rate_Measurement = p.getServiceByUUID(0x180D).getCharacteristics()[0]
Body_Sensor_Location = p.getServiceByUUID(0x180D).getCharacteristics()[1]
Heart_Rate_Control_Point = p.getServiceByUUID(0x180D).getCharacteristics()[2]
print Heart_Rate_Measurement , Heart_Rate_Measurement.uuid              # Print characteristic and its uuid
print Body_Sensor_Location , Body_Sensor_Location.uuid
print Heart_Rate_Control_Point , Heart_Rate_Control_Point.uuid

################## Print the Value ###########################

body_sensor=["not_selected","Chest","Wrist","Finger","Hand","Ear Lobe","Foot"]  # List for body sensor location

try:
    ch = p.getServiceByUUID(0x180D).getCharacteristics()[1]                     # body sensor location characteristics
Exemplo n.º 23
0
     print("  %04x: %s = %s" % (adtype, desc, value))
 print("Try to connect to %s..." % dev.addr)
 for i in range(0, 5):
     try:
         p = Peripheral(dev)
         break
     except BTLEException as e:
         print("Problems connecting to %s:" % dev.addr, e)
         continue
 if not p:
     print("Could not connect to device, giving up.")
     continue
 try:
     # p = Peripheral(dev)
     p.setDelegate(MyDelegate(None))
     for service in p.getServices():
         uuid = str(service.uuid)
         uuid = uuid[:4] + "'''" + uuid[4:8] + "'''"  # + uuid[8:] # '''
         desc = uuid_desc(str(service.uuid)[:8]) or "?"
         print("|  Service          || <code>%s</code> || || || %s || ||" %
               (uuid, desc))
         print("|-")
         for char in service.getCharacteristics():
             uuid = str(char.uuid)
             uuid = uuid[:4] + "'''" + uuid[4:8] + "'''"  # + uuid[8:] # '''
             desc = uuid_desc(str(char.uuid)[:8]) or "?"
             type = uuid_type(str(char.uuid)[:8]) or ""
             data = ""
             if char.supportsRead():
                 if str(service.uuid) in ignore_char:
                     data = '(ignored service)'
Exemplo n.º 24
0
class Switcher:
    switcher = None
    characteristics = None
    battery_handler = None
    hashed_share_code_handler = None
    authority_handler = None
    time_handler = None
    switch_handler = None
    uuids = None
    share_code = None

    def __init__(self, mac_address, share_code, debug=False):
        bluepy.btle.Debugging = debug
        self.mac_address = mac_address
        self.share_code = share_code

    def scan(self):
        scan_timeout = 10  # seconds
        scanner = Scanner()
        retry = True
        while (retry):
            try:
                print('Scanning...')
                devices = scanner.scan(scan_timeout)
                for device in devices:
                    name = None
                    for ad_type, description, value in device.getScanData():
                        if ad_type == 9:
                            name = value
                    if name is None or 'SWITCHER_M' not in name:
                        continue
                    print('A switcher is found: {}({} {})'.format(
                        name, device.addr, device.addrType))
                    if device.connectable:
                        print('Connectable switcher is found.')
                        self.mac_address = device.addr
                        retry = False
                        break
                    else:
                        print('The switcher is busy')
                if retry:
                    print('Connectable switcher is not found. Retry...')
                    sleep(2)
            except Exception as e:
                print('Error on scanning')
                traceback.print_exc()
        self.connect()

    def connect(self, callback=None):
        retry = True
        while retry:
            try:
                print('Try to connect to the switcher...')
                self.switcher = Peripheral(self.mac_address, 'random')
                retry = False
            except Exception as e:
                print('Error on connecting')
                traceback.print_exc()
        print('Switcher is connected')
        if callback:
            try:
                callback.on_connected(self)
            except BTLEException as e:
                traceback.print_exc()
                if e.code == BTLEException.DISCONNECTED:
                    print('Switcher disconnected')
                    self.switcher = None
                    # TODO: try re-connect
            except Exception as e:
                print('Error on using')
                traceback.print_exc()
            finally:
                if self.switcher:
                    print('Disconnect due to an error')
                    self.switcher.disconnect()

    def auto_reconnect(func):
        @functools.wraps(func)
        def wrap(self, *args, **kargs):
            if self.switcher is None:
                self.connect()
            while (True):
                try:
                    return func(self, *args, **kargs)
                except BTLEException as e:
                    if e.code == BTLEException.DISCONNECTED:
                        print('Switcher has gone')
                    else:
                        traceback.print_exc()
                    print('Try reconnect...')
                    self.connect()

        return wrap

    def disconnect(self):
        if self.switcher:
            self.switcher.disconnect()
            print('Switcher is disconnected')

    def to_bytes(self, digits):
        return bytearray(int(ch) for ch in str(digits))

    def show_informations(self):
        self.load_uuids()
        self.get_services(True)
        self.get_characteristics(True)

    def load_uuids(self):
        import json

        with open('uuid.json') as f:
            self.uuids = {v: k for k, v in json.load(f).items()}

    def get_uuid_description(self, uuid):
        try:
            return self.uuids[uuid]
        except:
            return 'Unknown'

    def get_services(self, print_services=False):
        print('get_services')
        services = self.switcher.getServices()
        if print_services:
            for service in services:
                uuid = str(service.uuid)
                print('UUID: {} ({})'.format(uuid,
                                             self.get_uuid_description(uuid)))

    def get_characteristics(self, print_characteristics=False):
        print('get_characteristics')
        if self.characteristics is None:
            self.characteristics = self.switcher.getCharacteristics()
        if print_characteristics:
            for ch in self.characteristics:
                uuid = str(ch.uuid)
                print('UUID: {} ({})'.format(uuid,
                                             self.get_uuid_description(uuid)))
                print('Properties: {} ({})'.format(ch.properties,
                                                   ch.propertiesToString()))
                print('Handler: 0x{:02x}'.format(ch.getHandle()))
                print('\n')
        return self.characteristics

    def get_descriptors(self):
        """
        Switcher sends no response for this method
        """
        descriptors = self.switcher.getDescriptors()
        print('descriptors')
        print(descriptors)

    def get_handler(self, number_of_handler):
        characteristics = self.get_characteristics()
        for ch in characteristics:
            if ch.getHandle() == number_of_handler:
                return ch
        print('There is no handler: {}'.format(number_of_handler))
        return None

    def get_hashed_share_code_handler(self):
        if not self.hashed_share_code_handler:
            self.hashed_share_code_handler = self.get_handler(0x1d)
        return self.hashed_share_code_handler

    @auto_reconnect
    def get_battery(self):
        battery = int.from_bytes(self.switcher.readCharacteristic(0xe),
                                 byteorder='big')
        return battery

    @auto_reconnect
    def compare_hashed_share_code(self):
        hashed_share_code = self.to_bytes('0' + self.share_code)
        print('Write: {}'.format(hashed_share_code))
        result = self.switcher.writeCharacteristic(0x1d, hashed_share_code,
                                                   True)
        print(result)

    @auto_reconnect
    def get_authority(self):
        return self.switcher.readCharacteristic(0x1f)[0]

    def get_day_name(self, day):
        days = [
            'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
            'Sunday'
        ]
        return days[day]

    @auto_reconnect
    def get_time(self):
        day, hours, minutes = self.switcher.readCharacteristic(0x2b)
        return '{} {:02d}:{:02d}'.format(self.get_day_name(day), hours,
                                         minutes)

    @auto_reconnect
    def manage_switch(self, switch, on=True):
        """
            switch: 1, 2
            on: True / False
            switch 1 on -> 0
            switch 1 off -> 1
            switch 2 on -> 2
            switch 2 off -> 3
        """
        if switch not in [1, 2]:
            print('Switch must be 1 or 2')
            return
        print('Switch {} {}'.format(switch, 'ON' if on else 'OFF'))
        param = (switch - 1) * 2 + (0 if on else 1)
        print(param)
        result = self.switcher.writeCharacteristic(0x11, bytes([param]), True)
        print(result)

    @auto_reconnect
    def test_switch(self, value):
        result = self.switcher.writeCharacteristic(0x11, bytes([value]), True)
        print(result)
Exemplo n.º 25
0
 #print'Connected: '+str(len(connection_threads))
 #print 'Scanning...'
 devices = scanner.scan(2)
 for d in devices:
     #print "[",d.addr,"]:",d.rssi
     s = ""
     found = 0
     for (adtype, desc, value) in d.getScanData():
         #print "    %s = %s"%(desc,value)
         s = s + str(desc) + " : " + str(value) + "\n"
         if desc == "Complete Local Name" and "HMSoft" in value:
             #print s
             try:
                 p = Peripheral(d)
                 p.setDelegate(NotificationDelegate(0))
                 services = p.getServices()
                 for srv in services:
                     #print "    UUID:", srv.uuid
                     try:
                         characteristics = srv.getCharacteristics()
                         for c in characteristics:
                             #print "        UUID:", c.uuid
                             if c.uuid == "0000ffe1-0000-1000-8000-00805f9b34fb":
                                 print "Alco char found!"
                                 #Connect
                                 c.write(
                                     binascii.unhexlify(
                                         sendDataPacket(
                                             "0x04", "0x04,0xff,0x01")))
                                 p.waitForNotifications(1.0)
                                 #Measure
Exemplo n.º 26
0
    def scan(self, bdaddr, addr_type, include_descriptor: bool):
        """
        bdaddr - Remote BD_ADDR
        """
        def run_mainloop():
            mainloop.run()

        mainloop_thread = threading.Thread(target=run_mainloop, args=[])
        mainloop_thread.start()

        try:
            try:
                target = Peripheral(bdaddr,
                                    iface=self.devid,
                                    addrType=addr_type)
            except BTLEDisconnectError as e:
                logger.error("BTLEDisconnectError")
                print(ERROR_INDENT, e, sep='')
                return

            services = target.getServices()
            print("Number of services: %s\n\n" % len(services))

            # Show service
            for service in services:
                logger.debug('Start handle: {}'.format(service.hndStart))
                logger.debug('End handle: {}'.format(service.hndEnd))

                try:
                    characteristics = []
                    characteristics = service.getCharacteristics()
                except BTLEException as e:
                    logger.warning("BTLEException")
                    print(WARNING_INDENT, e, sep='')
                    # continue

                print(
                    blue('Service'), '(0x%04x - 0x%04x, %s characteristics)' %
                    (service.hndStart, service.hndEnd, len(characteristics)))
                print(
                    indent + 'Handle: 0x%04x' % service.hndStart
                )  # ", "\"attr handle\" by using gatttool -b <BD_ADDR> --primary
                print(indent + 'Type: (May be primary service 0x2800)')
                print(indent + 'Value (Service UUID): ',
                      blue(str(service.uuid).replace(sig_uuid_suffix, '')),
                      end=' ')
                try:
                    print(
                        '(' +
                        services_spec['0x' +
                                      ("%s" %
                                       service.uuid)[4:8].upper()]['Name'] +
                        ')', '\x1B[0m')
                except KeyError:
                    print('(' + red('unknown') + ')', '\x1B[0m')
                print(
                    indent +
                    'Permission: Read Only, No Authentication, No Authorization\n'
                )

                # Show characteristic
                for characteristic in characteristics:
                    descriptors = []
                    # 对每个 characteristic 都获取 descriptor 会很耗时
                    # 有些设备会因此断开连接。于是这里提供了一个是否获取 descriptor 的选项
                    if include_descriptor:
                        descriptors = characteristic.getDescriptors()

                    try:
                        print(indent + yellow('Characteristic'),
                              '(%s descriptors)' % len(descriptors))
                        #print('-'*8)
                        print(indent * 2 + 'Handle: %#06x' %
                              (characteristic.getHandle() - 1))
                        print(indent * 2 + 'Type: 0x2803 (Characteristic)')
                        print(indent * 2 + 'Value:')
                        print(indent * 3 + 'Characteristic properties:',
                              green(characteristic.propertiesToString()))
                        print(indent * 3 +
                              'Characteristic value handle: %#06x' %
                              characteristic.getHandle())
                        print(
                            indent * 3 + 'Characteristic UUID: ',
                            green(
                                str(characteristic.uuid).replace(
                                    sig_uuid_suffix, '')),
                            end=' '
                        )  # This UUID is also the type field of characteristic value declaration attribute.
                        try:
                            print('(' + characteristics_spec['0x' + (
                                "%s" %
                                characteristic.uuid)[4:8].upper()]['Name'] +
                                  ')')
                        except KeyError:
                            print('(' + red('unknown') + ')')
                        print(
                            indent * 3 +
                            'Permission: Read Only, No Authentication, No Authorization'
                        )

                        if characteristic.supportsRead():
                            print(indent + yellow('Characteristic value'))
                            print(indent * 2 + 'Handle:',
                                  green('%#06x' % characteristic.getHandle()))
                            print(
                                indent * 2 + 'Type:',
                                str(characteristic.uuid).replace(
                                    sig_uuid_suffix, ''))
                            print(indent * 2 + 'Value:',
                                  green(str(characteristic.read())))
                            print(
                                indent * 2 +
                                'Permission: Higher layer profile or implementation-specific'
                            )
                    except BTLEException as e:
                        print('        ' + str(e))

                    # Show descriptor
                    for descriptor in descriptors:
                        try:
                            print(indent + yellow('Descriptor'))
                            print(indent * 2 + 'Handle:',
                                  green('%#06x' % descriptor.handle))
                            print(indent * 2 + 'Type:',
                                  str(descriptor.uuid).replace(
                                      sig_uuid_suffix, ''),
                                  end=' ')
                            try:
                                print('(' + descriptors_spec['0x' + (
                                    "%s" %
                                    descriptor.uuid)[4:8].upper()]['Name'] +
                                      ')')
                            except KeyError:
                                print('(Unknown descriptor)')
                            print(indent * 2 + 'Value:',
                                  green(str(descriptor.read())))
                            print(indent * 2 + 'Permissions:')
                        except BTLEException as e:
                            print(indent * 2 + str(e))
                    print()
                print()

            # Set remote device untursted
            output = subprocess.check_output(' '.join(
                ['bluetoothctl', 'untrust', bdaddr]),
                                             stderr=STDOUT,
                                             timeout=60,
                                             shell=True)
            logger.info(output.decode())

            # output = subprocess.check_output(
            #     ' '.join(['sudo', 'systemctl', 'stop', 'bluetooth.service']),
            #     stderr=STDOUT, timeout=60, shell=True)

            # output = subprocess.check_output(
            #     ' '.join(['sudo', 'rm', '-rf', '/var/lib/bluetooth/' + \
            #               self.hci_bdaddr + '/' + bdaddr.upper()]),
            #     stderr=STDOUT, timeout=60, shell=True)

            # output = subprocess.check_output(
            #     ' '.join(['sudo', 'systemctl', 'start', 'bluetooth.service']),
            #     stderr=STDOUT, timeout=60, shell=True)
        finally:
            if self.agent_registered:
                self.agent_mgr_1_iface.UnregisterAgent(
                    ObjectPath(self.bluescan_agent.path))
                logger.info('Unregistered Agent object')

                mainloop.quit()
Exemplo n.º 27
0
class BLEConnection:
    def __init__(self, address, mambo):
        """
             Initialize with its BLE address - if you don't know the address, call findMambo
             and that will discover it for you.

             :param address: unique address for this mambo
             :param mambo: the Mambo object for this mambo (needed for callbacks for sensors)
             """
        self.address = address
        self.drone_connection = Peripheral()
        self.mambo = mambo

        # the following UUID segments come from the Mambo and from the documenation at
        # http://forum.developer.parrot.com/t/minidrone-characteristics-uuid/4686/3
        # the 3rd and 4th bytes are used to identify the service
        self.service_uuids = {
            'fa00': 'ARCOMMAND_SENDING_SERVICE',
            'fb00': 'ARCOMMAND_RECEIVING_SERVICE',
            'fc00': 'PERFORMANCE_COUNTER_SERVICE',
            'fd21': 'NORMAL_BLE_FTP_SERVICE',
            'fd51': 'UPDATE_BLE_FTP',
            'fe00': 'UPDATE_RFCOMM_SERVICE',
            '1800': 'Device Info',
            '1801': 'unknown',
        }
        # the following characteristic UUID segments come from the documentation at
        # http://forum.developer.parrot.com/t/minidrone-characteristics-uuid/4686/3
        # the 4th bytes are used to identify the characteristic
        # the usage of the channels are also documented here
        # http://forum.developer.parrot.com/t/ble-characteristics-of-minidrones/5912/2
        self.characteristic_send_uuids = {
            '0a': 'SEND_NO_ACK',  # not-ack commandsandsensors (PCMD only)
            '0b': 'SEND_WITH_ACK',  # ack commandsandsensors (all piloting commandsandsensors)
            '0c': 'SEND_HIGH_PRIORITY',  # emergency commandsandsensors
            '1e': 'ACK_COMMAND'  # ack for data sent on 0e
        }

        # counters for each packet (required as part of the packet)
        self.characteristic_send_counter = {
            'SEND_NO_ACK': 0,
            'SEND_WITH_ACK': 0,
            'SEND_HIGH_PRIORITY': 0,
            'ACK_COMMAND': 0,
            'RECEIVE_WITH_ACK': 0
        }

        # the following characteristic UUID segments come from the documentation at
        # http://forum.developer.parrot.com/t/minidrone-characteristics-uuid/4686/3
        # the 4th bytes are used to identify the characteristic
        # the types of commandsandsensors and data coming back are also documented here
        # http://forum.developer.parrot.com/t/ble-characteristics-of-minidrones/5912/2
        self.characteristic_receive_uuids = {
            '0e': 'ACK_DRONE_DATA',  # drone data that needs an ack (needs to be ack on 1e)
            '0f': 'NO_ACK_DRONE_DATA',  # data from drone (including battery and others), no ack
            '1b': 'ACK_COMMAND_SENT',  # ack 0b channel, SEND_WITH_ACK
            '1c': 'ACK_HIGH_PRIORITY',  # ack 0c channel, SEND_HIGH_PRIORITY
        }

        # these are the FTP incoming and outcoming channels
        # the handling characteristic seems to be the one to send commandsandsensors to (per the SDK)
        # information gained from reading ARUTILS_BLEFtp.m in the SDK
        self.characteristic_ftp_uuids = {
            '22': 'NORMAL_FTP_TRANSFERRING',
            '23': 'NORMAL_FTP_GETTING',
            '24': 'NORMAL_FTP_HANDLING',
            '52': 'UPDATE_FTP_TRANSFERRING',
            '53': 'UPDATE_FTP_GETTING',
            '54': 'UPDATE_FTP_HANDLING',
        }

        # FTP commandsandsensors (obtained via ARUTILS_BLEFtp.m in the SDK)
        self.ftp_commands = {
            "list": "LIS",
            "get": "GET"
        }

        # need to save for communication (but they are initialized in connect)
        self.services = None
        self.send_characteristics = dict()
        self.receive_characteristics = dict()
        self.handshake_characteristics = dict()
        self.ftp_characteristics = dict()

        self.data_types = {
            'ACK': 1,
            'DATA_NO_ACK': 2,
            'LOW_LATENCY_DATA': 3,
            'DATA_WITH_ACK': 4
        }

        # store whether a command was acked
        self.command_received = {
            'SEND_WITH_ACK': False,
            'SEND_HIGH_PRIORITY': False,
            'ACK_COMMAND': False
        }

        # instead of parsing the XML file every time, cache the results
        self.command_tuple_cache = dict()
        self.sensor_tuple_cache = dict()

        # maximum number of times to try a packet before assuming it failed
        self.max_packet_retries = 3

    def connect(self, num_retries):
        """
        Connects to the drone and re-tries in case of failure the specified number of times

        :param: num_retries is the number of times to retry

        :return: True if it succeeds and False otherwise
        """

        # first try to connect to the wifi
        try_num = 1
        connected = False
        while (try_num < num_retries and not connected):
            try:
                self._connect()
                connected = True
            except BTLEException:
                color_print("retrying connections", "INFO")
                try_num += 1

        # fall through, return False as something failed
        return connected

    def _reconnect(self, num_retries):
        """
        Reconnect to the drone (assumed the BLE crashed)

        :param: num_retries is the number of times to retry

        :return: True if it succeeds and False otherwise
        """
        try_num = 1
        success = False
        while (try_num < num_retries and not success):
            try:
                color_print("trying to re-connect to the mambo at address %s" % self.address, "WARN")
                self.drone_connection.connect(self.address, "random")
                color_print("connected!  Asking for services and characteristics", "SUCCESS")
                success = True
            except BTLEException:
                color_print("retrying connections", "WARN")
                try_num += 1

        if (success):
            # do the magic handshake
            self._perform_handshake()

        return success

    def _connect(self):
        """
        Connect to the mambo to prepare for flying - includes getting the services and characteristics
        for communication

        :return: throws an error if the drone connection failed.  Returns void if nothing failed.
        """
        color_print("trying to connect to the mambo at address %s" % self.address, "INFO")
        self.drone_connection.connect(self.address, "random")
        color_print("connected!  Asking for services and characteristics", "SUCCESS")

        # re-try until all services have been found
        allServicesFound = False

        # used for notifications
        handle_map = dict()

        while not allServicesFound:
            # get the services
            self.services = self.drone_connection.getServices()

            # loop through the services
            for s in self.services:
                hex_str = self._get_byte_str_from_uuid(s.uuid, 3, 4)

                # store the characteristics for receive & send
                if (self.service_uuids[hex_str] == 'ARCOMMAND_RECEIVING_SERVICE'):
                    # only store the ones used to receive data
                    for c in s.getCharacteristics():
                        hex_str = self._get_byte_str_from_uuid(c.uuid, 4, 4)
                        if hex_str in self.characteristic_receive_uuids:
                            self.receive_characteristics[self.characteristic_receive_uuids[hex_str]] = c
                            handle_map[c.getHandle()] = hex_str


                elif (self.service_uuids[hex_str] == 'ARCOMMAND_SENDING_SERVICE'):
                    # only store the ones used to send data
                    for c in s.getCharacteristics():
                        hex_str = self._get_byte_str_from_uuid(c.uuid, 4, 4)
                        if hex_str in self.characteristic_send_uuids:
                            self.send_characteristics[self.characteristic_send_uuids[hex_str]] = c


                elif (self.service_uuids[hex_str] == 'UPDATE_BLE_FTP'):
                    # store the FTP info
                    for c in s.getCharacteristics():
                        hex_str = self._get_byte_str_from_uuid(c.uuid, 4, 4)
                        if hex_str in self.characteristic_ftp_uuids:
                            self.ftp_characteristics[self.characteristic_ftp_uuids[hex_str]] = c

                elif (self.service_uuids[hex_str] == 'NORMAL_BLE_FTP_SERVICE'):
                    # store the FTP info
                    for c in s.getCharacteristics():
                        hex_str = self._get_byte_str_from_uuid(c.uuid, 4, 4)
                        if hex_str in self.characteristic_ftp_uuids:
                            self.ftp_characteristics[self.characteristic_ftp_uuids[hex_str]] = c

                # need to register for notifications and write 0100 to the right handles
                # this is sort of magic (not in the docs!) but it shows up on the forum here
                # http://forum.developer.parrot.com/t/minimal-ble-commands-to-send-for-take-off/1686/2
                # Note this code snippet below more or less came from the python example posted to that forum (I adapted it to my interface)
                for c in s.getCharacteristics():
                    if self._get_byte_str_from_uuid(c.uuid, 3, 4) in \
                            ['fb0f', 'fb0e', 'fb1b', 'fb1c', 'fd22', 'fd23', 'fd24', 'fd52', 'fd53', 'fd54']:
                        self.handshake_characteristics[self._get_byte_str_from_uuid(c.uuid, 3, 4)] = c

            # check to see if all 8 characteristics were found
            allServicesFound = True
            for r_id in self.characteristic_receive_uuids.values():
                if r_id not in self.receive_characteristics:
                    color_print("setting to false in receive on %s" % r_id)
                    allServicesFound = False

            for s_id in self.characteristic_send_uuids.values():
                if s_id not in self.send_characteristics:
                    color_print("setting to false in send")
                    allServicesFound = False

            for f_id in self.characteristic_ftp_uuids.values():
                if f_id not in self.ftp_characteristics:
                    color_print("setting to false in ftp")
                    allServicesFound = False

            # and ensure all handshake characteristics were found
            if len(self.handshake_characteristics.keys()) != 10:
                color_print("setting to false in len")
                allServicesFound = False

        # do the magic handshake
        self._perform_handshake()

        # initialize the delegate to handle notifications
        self.drone_connection.setDelegate(MamboDelegate(handle_map, self.mambo, self))

    def _perform_handshake(self):
        """
        Magic handshake
        Need to register for notifications and write 0100 to the right handles
        This is sort of magic (not in the docs!) but it shows up on the forum here
        http://forum.developer.parrot.com/t/minimal-ble-commandsandsensors-to-send-for-take-off/1686/2

        :return: nothing
        """
        color_print("magic handshake to make the drone listen to our commandsandsensors")

        # Note this code snippet below more or less came from the python example posted to that forum (I adapted it to my interface)
        for c in self.handshake_characteristics.values():
            # for some reason bluepy characteristic handle is two lower than what I need...
            # Need to write 0x0100 to the characteristics value handle (which is 2 higher)
            self.drone_connection.writeCharacteristic(c.handle + 2, struct.pack("<BB", 1, 0))

    def disconnect(self):
        """
        Disconnect the BLE connection.  Always call this at the end of your programs to
        cleanly disconnect.

        :return: void
        """
        self.drone_connection.disconnect()

    def _get_byte_str_from_uuid(self, uuid, byte_start, byte_end):
        """
        Extract the specified byte string from the UUID btle object.  This is an ugly hack
        but it was necessary because of the way the UUID object is represented and the documentation
        on the byte strings from Parrot.  You give it the starting byte (counting from 1 since
        that is how their docs count) and the ending byte and it returns that as a string extracted
        from the UUID.  It is assumed it happens before the first - in the UUID.

        :param uuid: btle UUID object
        :param byte_start: starting byte (counting from 1)
        :param byte_end: ending byte (counting from 1)
        :return: string with the requested bytes (to be used as a key in the lookup tables for services)
        """
        uuid_str = format("%s" % uuid)
        idx_start = 2 * (byte_start - 1)
        idx_end = 2 * (byte_end)

        my_hex_str = uuid_str[idx_start:idx_end]
        return my_hex_str


    def send_turn_command(self, command_tuple, degrees):
        """
        Build the packet for turning and send it

        :param command_tuple: command tuple from the parser
        :param degrees: how many degrees to turn
        :return: True if the command was sent and False otherwise
        """
        self.characteristic_send_counter['SEND_WITH_ACK'] = (self.characteristic_send_counter['SEND_WITH_ACK'] + 1) % 256

        packet = struct.pack("<BBBBHh", self.data_types['DATA_WITH_ACK'],
                             self.characteristic_send_counter['SEND_WITH_ACK'],
                             command_tuple[0], command_tuple[1], command_tuple[2],
                             degrees)

        return self.send_command_packet_ack(packet)

    def send_auto_takeoff_command(self, command_tuple):
        """
        Build the packet for auto takeoff and send it

        :param command_tuple: command tuple from the parser
        :return: True if the command was sent and False otherwise
        """
        # print command_tuple
        self.characteristic_send_counter['SEND_WITH_ACK'] = (
                                                                self.characteristic_send_counter[
                                                                    'SEND_WITH_ACK'] + 1) % 256
        packet = struct.pack("<BBBBHB", self.data_types['DATA_WITH_ACK'],
                             self.characteristic_send_counter['SEND_WITH_ACK'],
                             command_tuple[0], command_tuple[1], command_tuple[2],
                             1)

        return self.send_command_packet_ack(packet)


    def send_command_packet_ack(self, packet):
        """
        Sends the actual packet on the ack channel.  Internal function only.

        :param packet: packet constructed according to the command rules (variable size, constructed elsewhere)
        :return: True if the command was sent and False otherwise
        """
        try_num = 0
        self._set_command_received('SEND_WITH_ACK', False)
        while (try_num < self.max_packet_retries and not self.command_received['SEND_WITH_ACK']):
            color_print("sending command packet on try %d" % try_num, 2)
            self._safe_ble_write(characteristic=self.send_characteristics['SEND_WITH_ACK'], packet=packet)
            #self.send_characteristics['SEND_WITH_ACK'].write(packet)
            try_num += 1
            color_print("sleeping for a notification", 2)
            #notify = self.drone.waitForNotifications(1.0)
            self.smart_sleep(0.5)
            #color_print("awake %s " % notify, 2)

        return self.command_received['SEND_WITH_ACK']

    def send_pcmd_command(self, command_tuple, roll, pitch, yaw, vertical_movement, duration):
        """
        Send the PCMD command with the specified roll, pitch, and yaw

        :param command_tuple: command tuple per the parser
        :param roll:
        :param pitch:
        :param yaw:
        :param vertical_movement:
        :param duration:
        """
        start_time = time.time()
        while (time.time() - start_time < duration):

            self.characteristic_send_counter['SEND_NO_ACK'] = (
                                                              self.characteristic_send_counter['SEND_NO_ACK'] + 1) % 256
            packet = struct.pack("<BBBBHBbbbbI", self.data_types['DATA_NO_ACK'],
                                 self.characteristic_send_counter['SEND_NO_ACK'],
                                 command_tuple[0], command_tuple[1], command_tuple[2],
                                 1, roll, pitch, yaw, vertical_movement, 0)

            self._safe_ble_write(characteristic=self.send_characteristics['SEND_NO_ACK'], packet=packet)
            # self.send_characteristics['SEND_NO_ACK'].write(packet)
            notify = self.drone_connection.waitForNotifications(0.1)

    def send_noparam_command_packet_ack(self, command_tuple):
        """
        Send a command on the ack channel - where all commandsandsensors except PCMD go, per
        http://forum.developer.parrot.com/t/ble-characteristics-of-minidrones/5912/2

        the id of the last command sent (for use in ack) is the send counter (which is incremented before sending)

        Ensures the packet was received or sends it again up to a maximum number of times.

        :param command_tuple: 3 tuple of the command bytes.  0 padded for 4th byte
        :return: True if the command was sent and False otherwise
        """
        self.characteristic_send_counter['SEND_WITH_ACK'] = (self.characteristic_send_counter['SEND_WITH_ACK'] + 1) % 256
        packet = struct.pack("<BBBBH", self.data_types['DATA_WITH_ACK'], self.characteristic_send_counter['SEND_WITH_ACK'],
                             command_tuple[0], command_tuple[1], command_tuple[2])
        return self.send_command_packet_ack(packet)



    def send_enum_command_packet_ack(self, command_tuple, enum_value, usb_id=None):
        """
        Send a command on the ack channel with enum parameters as well (most likely a flip).
        All commandsandsensors except PCMD go on the ack channel per
        http://forum.developer.parrot.com/t/ble-characteristics-of-minidrones/5912/2

        the id of the last command sent (for use in ack) is the send counter (which is incremented before sending)

        :param command_tuple: 3 tuple of the command bytes.  0 padded for 4th byte
        :param enum_value: the enum index
        :return: nothing
        """
        self.characteristic_send_counter['SEND_WITH_ACK'] = (self.characteristic_send_counter['SEND_WITH_ACK'] + 1) % 256
        if (usb_id is None):
            packet = struct.pack("<BBBBBBI", self.data_types['DATA_WITH_ACK'], self.characteristic_send_counter['SEND_WITH_ACK'],
                                 command_tuple[0], command_tuple[1], command_tuple[2], 0,
                                 enum_value)
        else:
            color_print((self.data_types['DATA_WITH_ACK'], self.characteristic_send_counter['SEND_WITH_ACK'],
                         command_tuple[0], command_tuple[1], command_tuple[2], 0, usb_id, enum_value), 1)
            packet = struct.pack("<BBBBHBI", self.data_types['DATA_WITH_ACK'], self.characteristic_send_counter['SEND_WITH_ACK'],
                                 command_tuple[0], command_tuple[1], command_tuple[2],
                                 usb_id, enum_value)
        return self.send_command_packet_ack(packet)

    def send_param_command_packet(self, command_tuple, param_tuple=None, param_type_tuple=0, ack=True):
        """
        Send a command packet with parameters. Ack channel is optional for future flexibility,
        but currently commands are always send over the Ack channel so it defaults to True.

        Contributed by awm102 on github.  Edited by Amy McGovern to work for BLE commands also.

        :param: command_tuple: the command tuple derived from command_parser.get_command_tuple()
        :param: param_tuple (optional): the parameter values to be sent (can be found in the XML files)
        :param: param_size_tuple (optional): a tuple of strings representing the data type of the parameters
        e.g. u8, float etc. (can be found in the XML files)
        :param: ack (optional): allows ack to be turned off if required
        :return:
        """
        # Create lists to store the number of bytes and pack chars needed for parameters
        # Default them to zero so that if no params are provided the packet size is correct
        param_size_list = [0] * len(param_tuple)
        pack_char_list = [0] * len(param_tuple)

        if param_tuple is not None:
            # Fetch the parameter sizes. By looping over the param_tuple we only get the data
            # for requested parameters so a mismatch in params and types does not matter
            for i, param in enumerate(param_tuple):
                pack_char_list[i], param_size_list[i] = get_data_format_and_size(param, param_type_tuple[i])

        if ack:
            ack_string = 'SEND_WITH_ACK'
            data_ack_string = 'DATA_WITH_ACK'
        else:
            ack_string = 'SEND_NO_ACK'
            data_ack_string = 'DATA_NO_ACK'

        # Construct the base packet
        self.characteristic_send_counter['SEND_WITH_ACK'] = (self.characteristic_send_counter['SEND_WITH_ACK'] + 1) % 256

        # TODO:  Amy changed this to match the BLE packet structure but needs to fully test it
        packet = struct.pack("<BBBBH", self.data_types[data_ack_string],
                             self.characteristic_send_counter[ack_string],
                             command_tuple[0], command_tuple[1], command_tuple[2])

        if param_tuple is not None:
            # Add in the parameter values based on their sizes
            for i, param in enumerate(param_tuple):
                packet += struct.pack(pack_char_list[i], param)

        # TODO: Fix this to not go with ack always
        return self.send_command_packet_ack(packet)

    def _set_command_received(self, channel, val):
        """
        Set the command received on the specified channel to the specified value (used for acks)

        :param channel: channel
        :param val: True or False
        :return:
        """
        self.command_received[channel] = val

    def _safe_ble_write(self, characteristic, packet):
        """
        Write to the specified BLE characteristic but first ensure the connection is valid

        :param characteristic:
        :param packet:
        :return:
        """

        success = False

        while (not success):
            try:
                characteristic.write(packet)
                success = True
            except BTLEException:
                color_print("reconnecting to send packet", "WARN")
                self._reconnect(3)

    def ack_packet(self, buffer_id, packet_id):
        """
        Ack the packet id specified by the argument on the ACK_COMMAND channel

        :param packet_id: the packet id to ack
        :return: nothing
        """
        #color_print("ack last packet on the ACK_COMMAND channel", "INFO")
        self.characteristic_send_counter['ACK_COMMAND'] = (self.characteristic_send_counter['ACK_COMMAND'] + 1) % 256
        packet = struct.pack("<BBB", self.data_types['ACK'], self.characteristic_send_counter['ACK_COMMAND'],
                             packet_id)
        #color_print("sending packet %d %d %d" % (self.data_types['ACK'], self.characteristic_send_counter['ACK_COMMAND'],
        #                                   packet_id), "INFO")

        self._safe_ble_write(characteristic=self.send_characteristics['ACK_COMMAND'], packet=packet)
        #self.send_characteristics['ACK_COMMAND'].write(packet)


    def smart_sleep(self, timeout):
        """
        Sleeps the requested number of seconds but wakes up for notifications

        Note: NEVER use regular time.sleep!  It is a blocking sleep and it will likely
        cause the BLE to disconnect due to dropped notifications.  Always use smart_sleep instead!

        :param timeout: number of seconds to sleep
        :return:
        """

        start_time = time.time()
        while (time.time() - start_time < timeout):
            try:
                notify = self.drone_connection.waitForNotifications(0.1)
            except:
                color_print("reconnecting to wait", "WARN")
                self._reconnect(3)
Exemplo n.º 28
0
 def scan_services(self, mac_address):
     p = Peripheral(mac_address)
     services = p.getServices()
     for service in services:
         print(service)
     self.savetofile(data=services)
Exemplo n.º 29
0
    sample_size = 128
    # p = Peripheral("D9:35:6A:75:9F:9D", "random") # Rfduino sur usb
    continuer = True
    while(continuer):
        try:
            p = Peripheral("D1:7F:06:ED:66:DC", "random")  # Rfduino sur pcb
            continuer = False
        except:
            print "Module bluetooth deja connecte, nouvel essai dans 3 sec..."
            time.sleep(3)
    p.withDelegate(MyDelegate())
    Analyser.set_p(p)
    print " device connected..."

    try:
        p.getServices()
        ch = p.getCharacteristics(uuid=rx_uuid)[0]
        print ("notify characteristic with uuid 0x" + rx_uuid.getCommonName())
        cccid = btle.AssignedNumbers.client_characteristic_configuration
        # Ox000F : handle of Client Characteristic Configuration descriptor Rx - (generic uuid 0x2902)
        p.writeCharacteristic(0x000F, struct.pack('<bb', 0x01, 0x00), False)

        if ch.supportsRead():
            while 1:
                p.waitForNotifications(604800)  # 1 semaine d'attente
                # handleNotification() was called
                continue

    finally:
        Analyser.ls.close()
        p.disconnect()
Exemplo n.º 30
0
        if len(data) >= 3:
            data1 = data[0]
            data2 = data[1]
            data3 = data[2]
            data4 = float(data2 * 256 + data1) / 100.0
            print("Get Temp:" + str(data4) + "C;   Humidity:" + str(data3) +
                  "%RH")


print("Start To Connect BLE")
p = Peripheral('a4:c1:38:0b:99:ed')
p.setDelegate(MyDelegate())
try:
    chList = p.getCharacteristics()

    seList = p.getServices()
    for se in seList:
        try:
            print(se.uuid)
        except:
            print("SE Error")

    print("---------------------------")
    print("Get Service1")

    try:
        se1 = p.getServiceByUUID('0000180f-0000-1000-8000-00805f9b34fb')
        ch1 = se1.getCharacteristics('00002a19-0000-1000-8000-00805f9b34fb')

        for _ch1 in ch1:
            print(_ch1.uuid)
Exemplo n.º 31
0
class Blueterm(cmd.Cmd):
    intro = cfg['intro']
    prompt = cfg['prompt']

    class State(Enum):
        IDLE = 1
        CONNECTED = 2

    def __init__(self, device_index, scan_timeout):
        cmd.Cmd.__init__(self)
        self.device_index = device_index
        self.scan_timeout = scan_timeout
        self.ble_devs = set()
        self.ble_gatt = dict()
        self.chars = dict()
        self.state = self.State.IDLE

        # setup Bluetooth
        self.scanner = Scanner(device_index)
        self.periph = Peripheral(None, ADDR_TYPE_PUBLIC, device_index)
        self.periph.setDelegate(ShellEventHandler())

    # Pla
    def precmd(self, line):
        return line

    def do_state(self, line):
        """Print current connection state
        """
        if self.state == self.State.CONNECTED:
            print("Connected to {}".format(self.periph.addr))
        else:
            print(self.state)

    def do_scan(self, line):
        """Scan for available BLE RIOT shells.
Running this command will reset the cached list of available devices.
usage: scan <scan timeout in sec>
        """
        args = line.strip().split(' ')
        if len(args[0]) > 0:
            try:
                to = float(args[0])
            except:
                print("error: unable to parse timeout (must be a number)")
                return
        else:
            to = self.scan_timeout

        print("Scanning now (blocking for {} seconds)...".format(to))
        try:
            self.ble_devs = list(self.scanner.scan(to))
            print("Scan complete:")
            self.do_list("")
        except:
            print("error: failure while scanning")
            return

    def do_list(self, line):
        """List all available BLE devices offering a RIOT shell
        """
        if len(self.ble_devs) == 0:
            print("No BLE devices available")
            return

        for i, dev in enumerate(self.ble_devs):
            print("[{:2}] {}".format(i, dev.addr), end='')
            for (adtype, desc, value) in dev.getScanData():
                if adtype == 9:
                    print(" (Name: '{}'')".format(value), end='')
            print()

    def do_connect(self, line):
        args = line.strip().split(' ')
        if len(args[0]) == 0:
            print("usage: connect <device index>")
            return
        try:
            dev = self.ble_devs[int(args[0])]
        except:
            print("error: unable to find given device index")
            return

        try:
            self.periph.connect(dev.addr, dev.addrType)
            services = self.periph.getServices()
            for i, service in enumerate(services):
                print("     Service {:2} UUID: {} ({})".format(
                    i, service.uuid, service.uuid.getCommonName()))
                chars = service.getCharacteristics()
                type(chars)
                for i, char in enumerate(chars):
                    self.chars[char.getHandle()] = char
                    print("{:5}   Char {:2} UUID: {} ({})".format(
                        char.getHandle(), i, char.uuid,
                        char.uuid.getCommonName()))
                    # if char.supportsRead():
                    #     tmp = char.read()
                    #     print("Data: ", str(tmp))
            self.state = self.State.CONNECTED
        except:
            print("error: while conneting something was bad")
            return

    def do_disconnect(self, line):
        """Close any open connection
        """
        self.periph.disconnect()
        self.chars = dict()
        self.state = self.State.IDLE
        print(self.periph.addr)

    def do_read(self, line):
        try:
            handle = int(line.strip())
            char = self.chars[handle]
            if not char.supportsRead():
                print("error: characteristic is not readable")
            else:
                buf = char.read()
                print("out: {}".format(buf.decode('utf-8')))
        except:
            print("usage: read <handle>")
            return

    def do_write(self, line):
        cmd = line.strip().partition(' ')
        if not cmd[2]:
            print("usage: write <handle> <data>")
            return

        try:
            handle = int(cmd[0])
            char = self.chars[handle]
            char.write(cmd[2].encode('utf-8'))
        except:
            print("error: unable to find characteristic")
Exemplo n.º 32
0
class BleDevice:
    def __init__(self):
        self.scanner = Scanner().withDelegate(ScanDelegate())

    def Scan(self, time):
        self.devices = self.scanner.scan(time)

    def ListDevices(self, scan_data_flag):
        for dev in self.devices:
            # print("Device {} ({}){}, RSSI={} dB".format(dev.addr, dev.addrType, ' [Connectable]' if dev.connectable else '', dev.rssi))

            if scan_data_flag:
                for (adtype, desc, value) in dev.getScanData():
                    print("  {} {} = {}".format(adtype, desc, value))

    def FindBoogie(self):

        boogie = None

        for dev in self.devices:
            for (adtype, desc, value) in dev.getScanData():
                if adtype == 9:
                    if value == "Boogie":
                        boogie = dev

        self.boogie = dev
        return boogie

    def ConnectToDevice(self, device):
        # Function returns Connected to device when device is not there
        # print('EXIT IS : {}'.format(device))
        if device is None:
            print("No device detected")
        else:
            try:
                self.peripheral = Peripheral(device)
                print("Connected to device")
            except BTLEException:
                print('Connection failed')

    def GetServices(self):

        services = self.peripheral.getServices()
        print('Services')

        for service in services:
            print('My Service : {}'.format(service))
            characteristics = service.getCharacteristics()

            for characteristic in characteristics:
                print('{}'.format(characteristic))

        self.services = services

    def ConnectToBoogie(self):
        # Function find & connect to boogie. Validate connection with a known service and characteristic
        # Service : 1a49d922-e3a9-4b00-9253-c4c72a1bcb5d      Characteristic : 7895cecb-a923-4ce4-bc58-27e8ce6e00ea   Expected value : (0x32) or if char = (2)

        UUID_ack = False
        CHARACT_ack = False
        UUIDval = "1a49d922-e3a9-4b00-9253-c4c72a1bcb5d"
        CHARACTval = "Characteristic <7895cecb-a923-4ce4-bc58-27e8ce6e00ea>"

        boogie = ble.FindBoogie()
        ble.ConnectToDevice(boogie)

        print('Trying to verify')
        try:
            serviceUUID = self.peripheral.getServiceByUUID(UUIDval)
            print('My UUID service : {}'.format(serviceUUID))
            UUID_ack = True
        except BTLEException:
            print('Service not found')
            UUID_ack = False

        if UUID_ack is True:
            Service_charact = serviceUUID.getCharacteristics()
            # print('Caracteristic list : {}'.format(Service_charact))

            for characteristic in Service_charact:
                print('My CHARACT : {}'.format(characteristic))
                print(characteristic)

            if characteristic == CHARACTval:
                CHARACT_ack = True
        print('UUIDack is : {}, CHARACTack is : {}'.format(
            UUID_ack, CHARACT_ack))