GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Test Failed
Push — master ( bd3d29...28348c )
by Virantha
01:19
created

bricknil.ble_queue.BLEventQ.connect()   A

Complexity

Conditions 2

Size

Total Lines 29
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 21
nop 2
dl 0
loc 29
rs 9.376
c 0
b 0
f 0
1
"""Singleton interface to the Adafruit Bluetooth library"""
2
import Adafruit_BluefruitLE
3
from curio import Queue, sleep, CancelledError
4
import sys, functools
5
6
from .sensor import Button # Hack! only to get the button sensor_id for the fake attach message
7
from .process import Process
8
from .messages import Message
9
from .const import USE_BLEAK
10
11
# Need a class to represent the bluetooth adapter provided
12
# by adafruit that receives messages
13
class BLEventQ(Process):
14
    """All bluetooth comms go through this object
15
16
       Provides interfaces to connect to a device/hub, send_messages to,
17
       and receive_messages from.  Also abstracts away the underlying bluetooth library
18
       that depends on the OS (Adafruit_Bluefruit for Mac, and Bleak for Linux/Win10)
19
20
       All requests to send messages to the BLE device must be inserted into
21
       the :class:`bricknil.BLEventQ.q` Queue object.
22
23
    """
24
25
    def __init__(self, ble):
26
        super().__init__('BLE Event Q')
27
        self.ble = ble
28
        self.q = Queue()
29
        if USE_BLEAK:
30
            self.message('using bleak')
31
            self.adapter = None
32
            # User needs to make sure adapter is powered up and on
33
            #    sudo hciconfig hci0 up
34
        else:
35
            self.message('Clearing BLE cache data')
36
            self.ble.clear_cached_data()
37
            self.adapter = self.ble.get_default_adapter()
38
            self.message(f'Found adapter {self.adapter.name}')
39
            self.message(f'Powering up adapter {self.adapter.name}')
40
            self.adapter.power_on()
41
        self.hubs = {}
42
43
    async def run(self):
44
        try:
45
            while True:
46
                msg = await self.q.get()
47
                msg_type, hub, msg_val = msg
48
                await self.q.task_done()
49
                self.message(f'Got msg: {msg_type} = {msg_val}')
50
                await self.send_message(hub.tx, msg_val)
51
        except CancelledError:
52
            self.message(f'Terminating and disconnecxting')
53
            if USE_BLEAK:
54
                await self.ble.in_queue.put( 'quit' )
55
            else:
56
                self.device.disconnect()
57
58
    async def send_message(self, characteristic, msg):
59
        """Prepends a byte with the length of the msg and writes it to
60
           the characteristic
61
62
           Arguments:
63
              characteristic : An object from bluefruit, or if using Bleak,
64
                  a tuple (device, uuid : str)
65
              msg (bytearray) : Message with header
66
        """
67
        # Message needs to have length prepended
68
        length = len(msg)+1
69
        values = bytearray([length]+msg)
70
        if USE_BLEAK:
71
            device, char_uuid = characteristic
72
            await self.ble.in_queue.put( ('tx', (device, char_uuid, values)) )
73
        else:
74
            characteristic.write_value(values)
75
76
    async def get_messages(self, hub):
77
        """Instance a Message object to parse incoming messages and setup
78
           the callback from the characteristic to call Message.parse on the
79
           incoming data bytes
80
        """
81
        # Message instance to parse and handle messages from this hub
82
        msg_parser = Message(hub)
83
84
        # Create a fake attach message on port 255, so that we can attach any instantiated Button listeners if present
85
        msg_parser.parse(bytearray([15, 0x00, 0x04,255, 1, Button._sensor_id, 0x00, 0,0,0,0, 0,0,0,0]))
86
87
        def bleak_received(sender, data):
88
            self.message_debug(f'Bleak Raw data received: {data}')
89
            msg = msg_parser.parse(data)
90
            self.message_debug('{0} Received: {1}'.format(hub.name, msg))
91
        def received(data):
92
            self.message_debug(f'Adafruit_Bluefruit Raw data received: {data}')
93
            msg = msg_parser.parse(data)
94
            self.message_debug('{0} Received: {1}'.format(hub.name, msg))
95
96
        if USE_BLEAK:
97
            device, char_uuid = hub.tx
98
            await self.ble.in_queue.put( ('notify', (device, char_uuid, bleak_received) ))
99
        else:
100
            # Adafruit library does not callback with the sender, only the data
101
            hub.tx.start_notify(received)
102
103
104
    def _check_devices_for(self, devices, name, address):
105
        """Check if any of the devices match what we're looking for
106
           
107
           First, check to make sure device.name is the name we're looking for.
108
           Then, if address is supplied, only return a device with a matching name
109
           if it's BLE MAC address also agrees
110
111
           Returns:
112
              device : Matching device (None if no matches)
113
        """
114
        for device in devices:
115
            self.message(f'checking device named {device.name} for {name}')
116
            if device.name == name:
117
                if not address:
118
                    return device
119
                else:
120
                    if USE_BLEAK: 
121
                        ble_address = device.address
122
                    else:
123
                        ble_address = device.id
124
                    if address == ble_address:
125
                        return device
126
                    else:
127
                        self.message(f'Address {ble_address} is not a match')
128
        return None
129
130
    async def _ble_connect(self, uart_uuid, ble_name, ble_id=None, timeout=60):
131
        """Connect to the underlying BLE device with the needed UART UUID
132
        """
133
        # Set hub.ble_id to a specific hub id if you want it to connect to a
134
        # particular hardware hub instance
135
        if ble_id:
136
            self.message_info(f'Looking for specific hub id {ble_id}')
137
        else:
138
            self.message_info(f'Looking for first matching hub')
139
140
        # Start discovery
141
        if not USE_BLEAK:
142
            self.adapter.start_scan()
143
144
        try:
145
            found = False
146
            while not found and timeout > 0:
147
                if USE_BLEAK:
148
                    await self.ble.in_queue.put('discover')  # Tell bleak to start discovery
149
                    devices = await self.ble.out_queue.get() # Wait for discovered devices
150
                    await self.ble.out_queue.task_done()
151
                    # Filter out no-matching uuid
152
                    devices = [d for d in devices if str(uart_uuid) in d.uuids]
153
                else:
154
                    devices = self.ble.find_devices(service_uuids=[uart_uuid])
155
156
                device = self._check_devices_for(devices, ble_name, ble_id)
157
                if device:
158
                    self.device = device
159
                    found = True
160
                else:
161
                    self.message(f'Rescanning for {uart_uuid} ({timeout} tries left)')
162
                    timeout -= 1
163
                    self.device = None
164
                    await sleep(1)
165
            if self.device is None:
166
                raise RuntimeError('Failed to find UART device!')
167
            assert self.device.name == ble_name
168
        except:
169
            raise
170
        finally:
171
            if not USE_BLEAK:
172
                self.adapter.stop_scan()
173
174
175
    async def connect(self, hub):
176
        # Connect the messaging queue for communication between self and the hub
177
        hub.message_queue = self.q
178
        self.message(f'Starting scan for UART {hub.uart_uuid}')
179
        await self._ble_connect(hub.uart_uuid, hub.ble_name, hub.ble_id)
180
181
        self.message(f"found device {self.device.name}")
182
183
        if USE_BLEAK:
184
            await self.ble.in_queue.put( ('connect', self.device.address) )
185
            device = await self.ble.out_queue.get()
186
            await self.ble.out_queue.task_done()
187
            hub.ble_id = self.device.address
188
            self.message(f'Device advertised: {device.characteristics}')
189
            hub.tx = (device, hub.char_uuid)   # Need to store device because the char is not an object in Bleak, unlike Bluefruit library
190
        else:
191
            self.device.connect()
192
            hub.ble_id = self.device.id
193
            # discover services
194
            self.device.discover([hub.uart_uuid], [hub.char_uuid])
195
            uart = self.device.find_service(hub.uart_uuid)
196
            hub.tx = uart.find_characteristic(hub.char_uuid) # same for rx
197
            self.message_info(f'Device advertised {self.device.advertised}')
198
199
200
        self.message_info(f"Connected to device {self.device.name}:{hub.ble_id}")
201
        self.hubs[hub.ble_id] = hub
202
203
        await self.get_messages(hub)
204
205
206
207