Exemple #1
0
    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
Exemple #2
0
class BLEService(Thread):
    def __init__(self, q):
        Thread.__init__(self)
        self.scanner = Scanner()
        self.queue = q
        self.devicesScanned = []

    def run(self):
        print("Starting BLE service...")
        self.scanner.start()
        while True:
            self.devicesScanned.clear()
            self.scanner.clear()
            self.scanner.process(5.0)
            devices = self.scanner.getDevices()
            self.fillQueue(devices)
            #if len(self.queue) > 0:
            #test = self.getFromQueue()
            #for dev in test:
            #    print("DEV: {}".format(dev.getJson()))
            #    print("_________________________")
            print(
                "_____________________Save ble setup, queue size = {}".format(
                    len(self.queue)))
            delay(3)

    def fillQueue(self, devices):
        for d in devices:
            devDto = BLEDeviceDto(d.addr, d.addrType, d.rssi, d.getScanData())
            self.devicesScanned.append(devDto)
        self.queue.append(self.devicesScanned)

    def getFromQueue(self):
        if len(self.queue) is not 0:
            msg = self.queue.popleft()
            return msg
        else:
            return None
Exemple #3
0
import sys
from bluepy.btle import Peripheral, Scanner, DefaultDelegate, UUID, ADDR_TYPE_PUBLIC

# class ScanDelegate(DefaultDelegate):
#     def __init__(self):
#         DefaultDelegate.__init__(self)

#     def handleDiscovery(self, dev, isNewDev, isNewData):
#         if isNewDev:
#             print ("Discovered device", dev.addr)
#         elif isNewData:
#             print ("Received new data from", dev.addr)

scanner = Scanner()#.withDelegate(ScanDelegate())
scanner.scan(10.0)
devices = scanner.getDevices()

for i, device in enumerate(devices):
    print(f"\n~~~~~~ Device {i} ~~~~~~")
    print(f"Device Address: {device.addr}, RSSI: {device.rssi}, Connectable: {device.connectable}")
    for (adtype, desc, value) in device.getScanData():
        print (f"AD Type {adtype}, Type Name: {desc}, Value: {value}")

print("\n>>>>>>>>>> Connect to Arduino Nano 33 BLE and read characteristics <<<<<<<<<<\n")

arduino = Peripheral(addrType=ADDR_TYPE_PUBLIC, iface=None)

for device in devices:
    if device.addr == "e9:be:2d:f0:66:70":
        arduino.connect(device)
        for characteristic in arduino.getCharacteristics():
class InkbirdUpdater(Entity):

    entity_id = "inkbird.updater"

    def __init__(self, hass, inkbird_devices):
        """Initialize the thermometer."""
        Entity.__init__(self)
        self._name = 'Inkbird Updater'
        self._state = None
        self._mac = None
        self.hass = hass
        self.scanner = Scanner()
        self.scanner.clear()
        self.scanner.start()
        self.no_results_counter = 0
        self.inkbird_devices = inkbird_devices

    @property
    def mac(self):
        """Return the mac of the sensor."""
        return self._mac

    @property
    def name(self):
        """Return the name of the sensor."""
        return self._name

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state

    @property
    def should_poll(self):
        """Return the name of the sensor."""
        _LOGGER.debug("Should_Poll called")
        return True

    def update(self):
        """Get the latest data and use it to update our sensor state."""
        _LOGGER.debug("UPDATE called")
        _LOGGER.debug(f"scanner here is {self.scanner}")

        # The btle on my raspberry pi 4 seems to go MIA
        if self.no_results_counter >= 5:
            _LOGGER.error("Btle went away .. restarting entire btle stack")
            self.scanner = Scanner()
            self.scanner.clear()
            self.scanner.start()
            self.no_results_counter = 0

        try:
            self.scanner.process(timeout=8.0)
        except:
            e = sys.exc_info()[0]
            _LOGGER.error(f" Exception occoured during scanning: {e}")
        results = self.scanner.getDevices()
        _LOGGER.debug(f"got results {results}")
        for dev in results:
            self.handleDiscovery(dev)

        # if we have no results at all, the scanner may have gone MIA.
        # it happens apparently. So, let's count upto 5 and then, if it
        # still happens, restart/refresh the btle stack.
        # any results though will reset the btle 'MIA counter' to 0
        if not any(results):
            self.no_results_counter += 1
        else:
            self.no_results_counter = 0
            self.scanner.clear()

        self._state = []
        return True

    def handleDiscovery(self, dev):
        _LOGGER.debug(f"Discovered device {dev.addr}")
        _LOGGER.debug("Device {} ({}), RSSI={} dB".format(
            dev.addr, dev.addrType, dev.rssi))
        for (adtype, desc, value) in dev.getScanData():
            _LOGGER.debug("[%s]  %s = %s" % (adtype, desc, value))
            if adtype == 255:
                humidity = "%2.2f" % (int(value[6:8] + value[4:6], 16) / 100)
                #temperature = "%2.2f" % (int(value[2:4]+value[:2], 16)/100)
                temperature = int(value[2:4] + value[:2], 16)
                temperature_bits = 16
                if temperature & (1 << (temperature_bits - 1)):
                    temperature -= 1 << temperature_bits
                temperature = "%2.2f" % (temperature / 100)
                battery = int(value[14:16], 16)
                _LOGGER.debug(self.inkbird_devices)
                for device in self.inkbird_devices:
                    _LOGGER.debug(
                        f" dev addr is {dev.addr} and mac is {device.mac}")
                    _LOGGER.debug(
                        f" --> {temperature} - {humidity} - {battery} ")
                    if dev.addr == device.mac:
                        _LOGGER.debug(
                            f" dev addr is {dev.addr} and mac is {device.mac} with parameter of {device.parameter}"
                        )
                        old_state = self.hass.states.get(
                            f"sensor.{device.entity_name}")
                        if old_state:
                            attrs = old_state.attributes
                        else:
                            attrs = None

                        if device.parameter == "temperature":
                            _LOGGER.debug(
                                f" >>>> updating device {device.mac} with {temperature}"
                            )
                            device.temperature = temperature
                            device._state = temperature
                            #self.hass.states.set(f"sensor.{device.entity_name}", temperature, attrs)
                        elif device.parameter == "humidity":
                            _LOGGER.debug(
                                f" >>>> updating device {device.mac} with {humidity}"
                            )
                            device.humidity = humidity
                            device._state = humidity
                            #self.hass.states.set(f"sensor.{device.entity_name}", humidity, attrs)
                        else:
                            _LOGGER.debug(
                                f" >>>> updating device {device.mac} with {battery}"
                            )
                            device.battery = battery
                            device._state = battery
Exemple #5
0
class InkbirdUpdater(Entity):

    entity_id = "inkbird.updater"

    def __init__(self, hass, inkbird_devices):
        """Initialize the thermometer."""
        Entity.__init__(self)
        self._name = 'Inkbird Updater'
        self._state = None
        self._mac = None
        self.hass = hass
        self.scanner = Scanner()
        self.scanner.clear()
        self.scanner.start()
        self.inkbird_devices = inkbird_devices

    @property
    def mac(self):
        """Return the mac of the sensor."""
        return self._mac

    @property
    def name(self):
        """Return the name of the sensor."""
        return self._name

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state

    @property
    def should_poll(self):
        """Return the name of the sensor."""
        _LOGGER.debug("Should_Poll called")
        return True

    def update(self):
        # added
        global pid
        ##
        """Get the latest data and use it to update our sensor state."""
        _LOGGER.debug("UPDATE called")
        _LOGGER.debug(f"scanner here is {self.scanner}")

        try:
            self.scanner.process(timeout=8.0)
        except:
            e = sys.exc_info()[0]
            _LOGGER.error(f" Exception occoured during scanning: {e}")
        results = self.scanner.getDevices()
        _LOGGER.debug(f"got results {results}")

        # The btle on my raspberry pi 4 seems to go MIA
        # if we have no results at all, the scanner may have gone MIA.
        # it happens apparently. So, let's count upto 5 and then, if it
        # still happens, restart/refresh the btle stack.
        # Seems to go MIA more frequently on RPi3B: removed counter and restart immediately if no results obtained
        # May generate 10 s update timeout errors
        if not any(results):
            _LOGGER.error("Btle went away .. restarting entire btle stack")
            ## Kill the bluepy-helper process
            # There is a memory leak: new instance of bluepy-helper is created with Scanner(), without terminating running instance
            # https://github.com/IanHarvey/bluepy/issues/267#issuecomment-657183840
            # adapted from: https://github.com/JsBergbau/MiTemperature2/blob/master/LYWSD03MMC.py
            del self.scanner  #probably not needed?
            bluepypid = 0
            pstree = os.popen("pstree -p " + str(pid)).read(
            )  #we want to kill only bluepy from our own process tree, because other python scripts have there own bluepy-helper process
            _LOGGER.debug("PSTree: " + pstree)
            try:
                bluepypid = re.findall(
                    r'bluepy-helper\((.*)\)',
                    pstree)[0]  #Store the bluepypid, to kill it later
            except IndexError:  #Should not happen since we're now connected
                _LOGGER.debug("Couldn't find pid of bluepy-helper")
            if bluepypid is not 0:
                os.system("kill " + bluepypid)
                _LOGGER.debug("Killed bluepy with pid: " + str(bluepypid))


# Kill bluepy-helper systemwide anyways...not good if there are other scripts using bluepy
#            else:
#                os.system('pkill bluepy-helper')
#                _LOGGER.debug("Killed bluepy-helper")
##
            self.scanner = Scanner()
            self.scanner.clear()
            self.scanner.start()
            try:
                self.scanner.process(timeout=8.0)
            except:
                e = sys.exc_info()[0]
                _LOGGER.error(f" Exception occoured during scanning: {e}")
            results = self.scanner.getDevices()
            _LOGGER.debug(f"Got new results {results}")

        for dev in results:
            if dev.addr in devicemacs:
                self.handleDiscovery(dev)

        self.scanner.clear()
        self._state = []
        return True

    def handleDiscovery(self, dev):
        #        _LOGGER.debug(f"Discovered device {dev.addr}")
        _LOGGER.debug("Discovered device {} ({}), RSSI={} dB".format(
            dev.addr, dev.addrType, dev.rssi))
        for (adtype, desc, value) in dev.getScanData():
            _LOGGER.debug("[%s]  %s = %s" % (adtype, desc, value))
            if adtype == 255:
                _LOGGER.debug(
                    f"{dev.addr} is in devicemacs list and now gets parameters!"
                )
                humidity = "%2.2f" % (int(value[6:8] + value[4:6], 16) / 100)
                #temperature = "%2.2f" % (int(value[2:4]+value[:2], 16)/100)
                temperature = int(value[2:4] + value[:2], 16)
                temperature_bits = 16
                if temperature & (1 << (temperature_bits - 1)):
                    temperature -= 1 << temperature_bits
                temperature = "%2.2f" % (temperature / 100)
                battery = int(value[14:16], 16)
                _LOGGER.debug(self.inkbird_devices)
                for device in self.inkbird_devices:
                    _LOGGER.debug(
                        f" dev addr is {dev.addr} and mac is {device.mac}")
                    #                    _LOGGER.debug(f" --> {temperature} - {humidity} - {battery} ")
                    if dev.addr == device.mac:
                        _LOGGER.debug(
                            f" dev addr is {dev.addr} and mac is {device.mac} with parameter of {device.parameter}"
                        )
                        # What does this do? Removed
                        #                        old_state = self.hass.states.get(f"sensor.{device.entity_name}")
                        #                        if old_state:
                        #                            attrs = old_state.attributes
                        #                        else:
                        #                            attrs = None
                        if device.parameter == "temperature":
                            _LOGGER.debug(
                                f" >>>> updating device {device.mac} with {temperature}"
                            )
                            device.temperature = temperature
                            device._state = temperature
                            #self.hass.states.set(f"sensor.{device.entity_name}", temperature, attrs)
                        elif device.parameter == "humidity":
                            _LOGGER.debug(
                                f" >>>> updating device {device.mac} with {humidity}"
                            )
                            device.humidity = humidity
                            device._state = humidity
                            #self.hass.states.set(f"sensor.{device.entity_name}", humidity, attrs)
                        else:
                            _LOGGER.debug(
                                f" >>>> updating device {device.mac} with {battery}"
                            )
                            device.battery = battery
                            device._state = battery
                            #self.hass.states.set(f"sensor.{device.entity_name}", battery, attrs)
        _LOGGER.debug(f" Done with handleDiscovery")
from blind import Blind
from bluepy.btle import Scanner, DefaultDelegate

# Where in the config to look for the name, and the name to search for
BLIND_AD_TYPE_NAME = 9
BLIND_NAME = "Blind"
SCAN_TIME = 10.0

if __name__ == "__main__":
    scanner = Scanner()
    print("Scanning for devices...")
    devices = scanner.scan(SCAN_TIME)
    blindaddrs = []
    print("\nDevices found:")
    for dev in scanner.getDevices():
        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))
        if dev.getValueText(BLIND_AD_TYPE_NAME) == BLIND_NAME:
            blindaddrs.append(dev.addr)

    if len(blindaddrs) > 0:
        print("\nBlinds found:")
        for i, addr in enumerate(blindaddrs):
            print(str(i) + ": " + addr)
        sel = -1
        while sel < 0 or sel >= len(blindaddrs):
            try:
                sel = int(
                    input(
Exemple #7
0
class CentralManager(DefaultDelegate):

    SCAN_COUNT = 5
    SCAN_INTERVAL = 2.0

    def __init__(self):
        DefaultDelegate.__init__(self)
        self._scanner = Scanner().withDelegate(self)
        self._lamps = []
        self._candidateFound = False
        self.isConnected = False

    def scan(self):
        self.isConnected = False

        # Clear existing connected lamps
        for lamp in self._lamps:
            lamp.disconnect()

        self._lamps = []

        # Scan for new lamps to connect to
        print("Scanning for devices...")

        self._candidateFound = False
        self._scanner.clear()
        self._scanner.start()

        for iter in range(0, CentralManager.SCAN_COUNT):
            self._scanner.process(CentralManager.SCAN_INTERVAL)
            if (self._candidateFound):
                print("Candidate found after {} scan(s). Ending early".format(
                    iter + 1))
                break

        self._scanner.stop()

        scanResult = self._scanner.getDevices()

        # Connect to any lamps found
        for device in scanResult:
            if (Lampi.isLampCandidate(device)):
                lamp = Lampi(device)
                lamp.validate()
                if (lamp.isValid):
                    print("Connected to a lamp with MAC address {}".format(
                        device.addr))
                    self._lamps.append(lamp)
                    self.isConnected = True
                else:
                    lamp.disconnect()

        print("Scan complete")

    def handleDiscovery(self, device, isNew, _):
        if isNew and device.connectable:
            if (Lampi.isLampCandidate(device)):
                self._candidateFound = True
                print(" • Candidate found with MAC address {}".format(
                    device.addr))

    # Discard any lamps that are no longer connected
    def pruneLamps(self):
        for i in range(0, len(self._lamps)):
            lamp = self._lamps[i]
            if (not lamp.isConnected()):
                print("Pruned {}".format(lamp.addr))
                self._lamps.pop(i)
                i -= 1

    def toggleOnOff(self):
        print("Toggling on/off")
        self.pruneLamps()
        for lamp in self._lamps:
            lamp.toggleOnOff()

    def brightnessUp(self):
        print("Sending brightness up")
        self.pruneLamps()
        for lamp in self._lamps:
            lamp.brightnessUp()

    def brightnessDown(self):
        print("Sending brightness down")
        self.pruneLamps()
        for lamp in self._lamps:
            lamp.brightnessDown()

    def preset(self, number):
        print("Starting Preset", str(number))
        self.pruneLamps()
        for lamp in self._lamps:
            lamp.setPreset(number)