Exemple #1
0
    def start():
        adapter = get_provider().get_adapter()

        q = Queue()

        observer = Observer(adapter)
        observer.on_advertising_data = q.put  # Put advertisement to queue

        observer.start()

        return (observer, q)
    def __init__(self, publishers, params):
        """Initializes the listener and kicks off the listening thread."""
        super().__init__(publishers, params)

        self.dest_root = params("Destination")

        self.log.info("Configuring Govee listener with destination %s",
                      self.dest_root)

        self.adapter = get_provider().get_adapter()
        self.observer = Observer(self.adapter)
        self.observer.on_advertising_data = self.on_advertisement
        self.observer.start()

        # Store readings so they can be reported on demand.
        self.devices = {}
def start_listen_ble():
    try:
        adapter = get_provider().get_adapter()
        global receiver_mac
        receiver_mac = adapter.get_device_info().address.address

        observer = Observer(adapter)
        observer.on_advertising_data = on_advertisement

        observer.start()
    except OSError:
        print(
            "Error listening for BLE advertisements, using fixed test data instead"
        )

        start_send_test_data()
Exemple #4
0
class Observer(object):
    '''
    '''
    def __init__(self, url="https://thu-band.org"):
        self.adapter = get_provider().get_adapter()

        self.observer = OB(self.adapter)
        self.observer.on_advertising_data = self.on_advertisement

    def print_eddystone_values(self, data):
        """
        :param data:
        :return:
        """
        expected_keys = {'name space': 'hex_format',
                         'instance': 'hex_format',
                         'url': 'string_format',
                         'mac address': 'string_format',
                         'tx_power': 'int_format',
                         'rssi': 'int_format'}
        endian = 'big'

        print('New Eddystone data:')
        for prop in data:
            if prop in expected_keys:
                if expected_keys[prop] == 'string_format':
                    print('\t{} = {}'.format(prop, data[prop]))
                if expected_keys[prop] == 'hex_format':
                    print('\t{} = 0x{:X}'.format(prop,
                                                 int.from_bytes(data[prop],
                                                                endian)))
                if expected_keys[prop] == 'int_format':
                    print('\t{} = {}'.format(prop, int(data[prop])))

    def on_advertisement(self, advertisement):
        if (check_prefix("https://thu-band.org")):
            print(advertisement)
            # self.print_eddystone_values(advertisement.mfg_data)

    def start(self):
        self.observer.start()
        # observer.scan_eddystone(on_data=self.print_eddystone_values)

    def stop(self):
        self.observer.stop()
Exemple #5
0
    def __init__(self, publisher, logger, params, sensors, actuators):
        """Initializes the listener and kicks off the listening"""

        self.logger = logger
        self.dest_root = params("Destination")
        self.publish = publisher

        self.logger.info(
            '----------Configuring Govee listener with destination {}'.format(
                self.dest_root))

        self.GOVEE_BT_MAC_PREFIX = "A4:C1:38"
        self.H5075_UPDATE_UUID16 = UUID16(0xEC88)

        self.adapter = get_provider().get_adapter()
        self.observer = Observer(self.adapter)
        self.observer.on_advertising_data = self.on_advertisement
        self.observer.start()
        self.poll = -1
        self.devices = {}
Exemple #6
0
    def __init__(self, callback, bt_device=''):
        '''
        Arguments:
           callback: Function that receives the data from BLE
           device (string): BLE device (default 0)
        '''
        super().__init__(callback, bt_device)

        self.observer = None

        if not bt_device:
            bt_device = 0
        else:
            # Old communication used hci0 etc.
            bt_device = bt_device.replace('hci', '')

        log.info('Observing broadcasts (device %s)', bt_device)

        adapter = get_provider().get_adapter(int(bt_device))
        self.observer = Observer(adapter)
        self.observer.on_advertising_data = self.handle_callback
Exemple #7
0
    def start(bt_device=''):
        '''
        Attributes:
           device (string): BLE device (default 0)
        '''

        if not bt_device:
            bt_device = 0
        else:
            # Old communication used hci0 etc.
            bt_device = bt_device.replace('hci', '')

        log.info('Start receiving broadcasts (device %s)', bt_device)

        q = Queue()

        adapter = get_provider().get_adapter(int(bt_device))
        observer = Observer(adapter)
        observer.on_advertising_data = q.put
        observer.start()

        return (observer, q)
Exemple #8
0
def sensor_data(json):

    print('sensor message:', json)
    if(json['sensorStatus'] == 'True'):
        adapter = get_provider().get_adapter()

        observer = Observer(adapter)
        observer.on_advertising_data = on_advertisement
        observer.start()
        time.sleep(5)
        observer.stop()
        emit('tempHumSensorUpdate', govee_devices)
    else:
        emit('tempHumSensorUpdate', {'data': 'data disabled'})
Exemple #9
0
class BlesonClient(BluetoothAdaptor):
    '''Bluetooth LE communication with Bleson'''
    def handle_callback(self, advertisement):

        if not advertisement.mfg_data:
            return

        processed_data = {
            # WARNING, Apple sucks, so it does not provide mac address
            # in the advertisement! Go tell them that they suck!
            # https://forums.developer.apple.com/thread/8442
            "address":
            advertisement.address.address
            if advertisement.address != None else None,
            # Linux returns bytearray for mfg_data, but mac os returns _NSInlineData
            # which casts to byte array. We need to explicitly cast it to use hex
            "raw_data":
            bytearray(advertisement.mfg_data).hex(),
            "tx_power":
            advertisement.tx_pwr_lvl,
            "rssi":
            advertisement.rssi,
            "name":
            advertisement.name,
        }

        if processed_data["raw_data"][0:2] != 'FF':
            processed_data["raw_data"] = 'FF' + processed_data["raw_data"]

        self.callback(processed_data)

    def __init__(self, callback, bt_device=''):
        '''
        Arguments:
           callback: Function that receives the data from BLE
           device (string): BLE device (default 0)
        '''
        super().__init__(callback, bt_device)

        self.observer = None

        if not bt_device:
            bt_device = 0
        else:
            # Old communication used hci0 etc.
            bt_device = bt_device.replace('hci', '')

        log.info('Observing broadcasts (device %s)', bt_device)

        adapter = get_provider().get_adapter(int(bt_device))
        self.observer = Observer(adapter)
        self.observer.on_advertising_data = self.handle_callback

    def start(self):
        if not self.observer:
            log.info('Cannot start a client that has not been setup')
            return
        self.observer.start()

    def stop(self):
        self.observer.stop()
#!/usr/bin/env python3

import sys
from time import sleep
from bleson import get_provider, Observer

# Get the wait time from the first script argument or default it to 10 seconds
WAIT_TIME = int(sys.argv[1]) if len(sys.argv) > 1 else 10


def on_advertisement(advertisement):
    print(advertisement)


adapter = get_provider().get_adapter()

observer = Observer(adapter)
observer.on_advertising_data = on_advertisement

observer.start()
sleep(WAIT_TIME)
observer.stop()
Exemple #11
0
def run_observer():
    with Observer(get_provider().get_adapter(), lambda advertisement_report: print(advertisement_report)):
        sleep(5)
Exemple #12
0
#!/usr/bin/env python3

import sys
from time import sleep
from bleson import get_provider, Observer
from bleson.logger import log, set_level, DEBUG

#set_level(DEBUG)

# Get the wait time from the first script argument or default it to 10 seconds
WAIT_TIME = int(sys.argv[1]) if len(sys.argv) > 1 else 10

with Observer(get_provider().get_adapter(), lambda device: log.info(device)):
    sleep(WAIT_TIME)
Exemple #13
0
    def __init__(self, url="https://thu-band.org"):
        self.adapter = get_provider().get_adapter()

        self.observer = OB(self.adapter)
        self.observer.on_advertising_data = self.on_advertisement
Exemple #14
0
        org=_influx_config["org"],
        enable_gzip=True,
        verify_ssl=True,
    )
    _write_client = _influx_client.write_api(write_options=WriteOptions(
        flush_interval=15_000, max_retries=1, max_retry_delay=10_000))

    _mac_list = [bytes.fromhex(x.replace(":", "")) for x in _config["macs"]]

    _measurements = Subject()
    thread_pool_scheduler = ThreadPoolScheduler(2)
    _measurements_subj = _measurements.pipe(
        ops.observe_on(thread_pool_scheduler))
    # _measurements_subj.subscribe(on_next=lambda x: print(x, flush=True))
    _write_client.write(
        bucket="sensors",
        record=_measurements_subj.pipe(ops.map(_ruuvi_data_to_influx)),
    )

    def on_advertisement(advertisement):
        msg = RuuviTagData.from_mfg_data(advertisement.mfg_data, _mac_list)
        if msg is not None:
            _measurements.on_next(msg)

    observer = Observer(get_provider().get_adapter())
    observer.on_advertising_data = on_advertisement
    observer.start()

    while True:
        sleep(10)
Exemple #15
0
class goveeSensor:
    """Listens for Govee temp/humi sensor BT broadcasts and publishes them."""
    def __init__(self, publisher, logger, params, sensors, actuators):
        """Initializes the listener and kicks off the listening"""

        self.logger = logger
        self.dest_root = params("Destination")
        self.publish = publisher

        self.logger.info(
            '----------Configuring Govee listener with destination {}'.format(
                self.dest_root))

        self.GOVEE_BT_MAC_PREFIX = "A4:C1:38"
        self.H5075_UPDATE_UUID16 = UUID16(0xEC88)

        self.adapter = get_provider().get_adapter()
        self.observer = Observer(self.adapter)
        self.observer.on_advertising_data = self.on_advertisement
        self.observer.start()
        self.poll = -1
        self.devices = {}

    def on_advertisement(self, advertisement):
        self.logger.debug("Received advertisement from {}".format(
            advertisement.address.address))

        if advertisement.address.address.startswith(self.GOVEE_BT_MAC_PREFIX):
            self.logger.debug("Received Govee advertisement")

            mac = advertisement.address.address

            if self.H5075_UPDATE_UUID16 in advertisement.uuid16s:
                split = advertisement.name.split("'")
                name = split[0] if len(split) == 1 else split[1]
                if mac not in self.devices:
                    self.devices[mac] = name
                encoded_data = int(advertisement.mfg_data.hex()[6:12], 16)
                battery = int(advertisement.mfg_data.hex()[12:14], 16)
                temp_c = format((encoded_data / 10000), ".2f")
                temp_f = format((((encoded_data / 10000) * 1.8) + 32), ".2f")
                humi = format(((encoded_data % 1000) / 10), ".2f")

                self.logger.debug(
                    "Govee data to publish: name = {}, "
                    "battery = {}, temp_c = {}, temp_f = {}, and "
                    "humi = {}".format(name, battery, temp_c, temp_f, humi))
                for conn in self.publish:
                    conn.publish(str(battery),
                                 "{}/{}/battery".format(self.dest_root, name))
                    conn.publish(str(temp_c),
                                 "{}/{}/temp_C".format(self.dest_root, name))
                    conn.publish(str(temp_f),
                                 "{}/{}/temp_F".format(self.dest_root, name))
                    conn.publish(str(humi),
                                 "{}/{}/humi".format(self.dest_root, name))

            if advertisement.rssi is not None and advertisement.rssi != 0:
                if mac in self.devices:
                    for conn in self.publish:
                        conn.publish(
                            str(advertisement.rssi),
                            "{}/{}/rssi".format(self.dest_root,
                                                self.devices[mac]))

    def checkState(self):
        """Does nothing"""

    def publishState(self):
        """Does nothing"""

    def cleanup(self):
        """Stop the observer"""

        self.logger.info("Stopping Govee observer")
        self.oberver.stop()
###### Define graceful exit
atexit.register(exit_handler)

###### Define output
if args.logfile=="" or args.logfile=="stdout":
   _useStdOut = True
else:
   _useStdOut = False      

level=set_level(args.loglevel)


###### ibeacon adapter and observers
adapter = get_provider().get_adapter(args.hci)

observer = Observer(adapter)
observer.on_advertising_data = on_advertisement

observer.start(True)  # filter duplicates

###### Sleep this thread while the observer thread does its magic
listentime = args.listentime
if listentime == -1:
   ###### TODO: Service Healthcheck and sleep???
   while True:
      sleep (10)

      #TODO clean up files. 
      #TODO what other useful things could this thread do 

else:
class GoveeSensor(Sensor):
    """Listens for Govee temp/humi sensor BTLE broadcases and publishes them."""
    def __init__(self, publishers, params):
        """Initializes the listener and kicks off the listening thread."""
        super().__init__(publishers, params)

        self.dest_root = params("Destination")

        self.log.info("Configuring Govee listener with destination %s",
                      self.dest_root)

        self.adapter = get_provider().get_adapter()
        self.observer = Observer(self.adapter)
        self.observer.on_advertising_data = self.on_advertisement
        self.observer.start()

        # Store readings so they can be reported on demand.
        self.devices = {}

    def on_advertisement(self, advertisement):
        """Called when a BTLE advertisement is received. If it goes with one
        of the Govee H5075 sensors, the reading is parsed and published."""
        self.log.debug("Received advertisement from %s",
                       advertisement.address.address)

        if advertisement.address.address.startswith(GOVEE_BT_MAC_PREFIX):
            self.log.debug("Received Govee advertisement")

            mac = advertisement.address.address

            # Process a sensor reading.
            if H5075_UPDATE_UUID16 in advertisement.uuid16s:
                split = advertisement.name.split("'")

                name = split[0] if len(split) == 1 else split[1]
                if mac not in self.devices:
                    self.devices[mac] = {}
                    self.devices[mac]["name"] = name

                encoded_data = int(advertisement.mfg_data.hex()[6:12], 16)
                self.devices[mac]["battery"] = int(
                    advertisement.mfg_data.hex()[12:14], 16)
                self.devices[mac]["temp_c"] = format((encoded_data / 10000),
                                                     ".2f")
                self.devices[mac]["temp_f"] = format(
                    (((encoded_data / 10000) * 1.8) + 32), ".2f")
                self.devices[mac]["humi"] = format(
                    ((encoded_data % 1000) / 10), ".2f")

                self.log.debug("Govee data to publish: %s", self.devices)
                self.publish_state()

            # Process an rssi reading. Don't bother to publish now, wait for the
            # next sensor reading.
            if advertisement.rssi is not None and advertisement.rssi != 0:
                # Ignore rssi from devices that haven't reported a sensor
                # reading yet.
                if mac in self.devices:
                    self.devices[mac]["rssi"] = advertisement.rssi

    def publish_state(self):
        """Publishes the most recent of all the readings."""

        for conn in self.publishers:
            for mac in self.devices:
                if "name" in self.devices[mac]:
                    name = self.devices[mac]["name"]
                    dest = "{}/{}".format(self.dest_root, name)
                    for dev in [
                            dev for dev in self.devices[mac] if dev != "name"
                    ]:
                        conn.publish(str(self.devices[mac][dev]),
                                     "{}/{}".format(dest, dev))

    def cleanup(self):
        """Stop the observer."""
        self.log.info("Stopping Govee observer")
        self.observer.stop()