# See if any existing connections are providing UARTService.
if ble.connected:
    for connection in ble.connections:
        if UARTService in connection:
            uart_connection = connection
        break

while True:
    if not uart_connection:
        for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=5):
            if UARTService in adv.services:
                uart_connection = ble.connect(adv)
                break
        # Stop scanning whether or not we are connected.
        ble.stop_scan()

    while uart_connection and uart_connection.connected:
        r = scale(a4.value)
        g = scale(a5.value)
        b = scale(a6.value)

        color = (r, g, b)
        print(color)
        color_packet = ColorPacket(color)
        try:
            uart_connection[UARTService].write(color_packet.to_bytes())
        except OSError:
            pass
        time.sleep(0.3)
        break

while True:
    blue_led.value = False
    #  BLE connection
    if not uart_connection or not uart_connection.connected:  # If not connected...
        print("Scanning...")
        for adv in ble.start_scan(ProvideServicesAdvertisement,
                                  timeout=5):  # Scan...
            if UARTService in adv.services:  # If UARTService found...
                print("Found a UARTService advertisement.")
                blue_led.value = True  #  LED turns on when connected
                uart_connection = ble.connect(
                    adv)  # Create a UART connection...
                break
        ble.stop_scan()  # And stop scanning.
    #  while connected..
    while uart_connection and uart_connection.connected:
        #  iterate through buttons and colors
        for switch_pin in switch_array:
            i = switch_array.index(switch_pin)
            switches_pressed_state = switches_pressed[i]
            colors = color[i]
            #  if the button is released
            #  worked best if placed before the button press portion
            if switch_pin.value and switches_pressed_state:
                print("button off")
                #  send button packet to stop tone & color (happens on CPB)
                if not send_packet(
                        uart_connection,
                        ButtonPacket(ButtonPacket.RIGHT, pressed=True)):
Beispiel #3
0
class Radio:
    """
    Represents a connection through which one can send or receive strings
    and bytes. The radio can be tuned to a specific channel upon initialisation
    or via the `configure` method.
    """

    def __init__(self, **args):
        """
        Takes the same configuration arguments as the `configure` method.
        """
        # For BLE related operations.
        self.ble = BLERadio()
        # The uid for outgoing message. Incremented by one on each send, up to
        # 255 when it's reset to 0.
        self.uid = 0
        # Contains timestamped message metadata to mitigate report of
        # receiving of duplicate messages within AD_DURATION time frame.
        self.msg_pool = set()
        # Handle user related configuration.
        self.configure(**args)

    def configure(self, channel=42):
        """
        Set configuration values for the radio.

        :param int channel: The channel (0-255) the radio is listening /
            broadcasting on.
        """
        if -1 < channel < 256:
            self._channel = channel
        else:
            raise ValueError("Channel must be in range 0-255")

    def send(self, message):
        """
        Send a message string on the channel to which the radio is
        broadcasting.

        :param str message: The message string to broadcast.
        """
        return self.send_bytes(message.encode("utf-8"))

    def send_bytes(self, message):
        """
        Send bytes on the channel to which the radio is broadcasting.

        :param bytes message: The bytes to broadcast.
        """
        # Ensure length of message.
        if len(message) > MAX_LENGTH:
            raise ValueError("Message too long (max length = {})".format(MAX_LENGTH))
        advertisement = _RadioAdvertisement()
        # Concatenate the bytes that make up the advertised message.
        advertisement.msg = struct.pack("<BB", self._channel, self.uid) + message

        self.uid = (self.uid + 1) % 255
        # Advertise (block) for AD_DURATION period of time.
        self.ble.start_advertising(advertisement)
        time.sleep(AD_DURATION)
        self.ble.stop_advertising()

    def receive(self):
        """
        Returns a message received on the channel on which the radio is
        listening.

        :return: A string representation of the received message, or else None.
        """
        msg = self.receive_full()
        if msg:
            return msg[0].decode("utf-8").replace("\x00", "")
        return None

    def receive_full(self):
        """
        Returns a tuple containing three values representing a message received
        on the channel on which the radio is listening. If no message was
        received then `None` is returned.

        The three values in the tuple represent:

        * the bytes received.
        * the RSSI (signal strength: 0 = max, -255 = min).
        * a microsecond timestamp: the value returned by time.monotonic() when
          the message was received.

        :return: A tuple representation of the received message, or else None.
        """
        try:
            for entry in self.ble.start_scan(
                _RadioAdvertisement, minimum_rssi=-255, timeout=1, extended=True
            ):
                # Extract channel and unique message ID bytes.
                chan, uid = struct.unpack("<BB", entry.msg[:2])
                if chan == self._channel:
                    now = time.monotonic()
                    addr = entry.address.address_bytes
                    # Ensure this message isn't a duplicate. Message metadata
                    # is a tuple of (now, chan, uid, addr), to (mostly)
                    # uniquely identify a specific message in a certain time
                    # window.
                    expired_metadata = set()
                    duplicate = False
                    for msg_metadata in self.msg_pool:
                        if msg_metadata[0] < now - AD_DURATION:
                            # Ignore expired entries and mark for removal.
                            expired_metadata.add(msg_metadata)
                        elif (chan, uid, addr) == msg_metadata[1:]:
                            # Ignore matched messages to avoid duplication.
                            duplicate = True
                    # Remove expired entries.
                    self.msg_pool = self.msg_pool - expired_metadata
                    if not duplicate:
                        # Add new message's metadata to the msg_pool and
                        # return it as a result.
                        self.msg_pool.add((now, chan, uid, addr))
                        msg = entry.msg[2:]
                        return (msg, entry.rssi, now)
        finally:
            self.ble.stop_scan()
        return None
Beispiel #4
0
class PestCamera:
    def __init__(self):
        self.connection = sqlite3.connect('pest_alert.db')
        self.cursor = self.connection.cursor()

        # Define radio for finding deivice
        self.ble = BLERadio()
        # set global variable uart_connection, will be replaced with the service once connected
        self.uart_connection = None

        # creating the database, this needs to happen before the while loop
        command1 = """CREATE TABLE IF NOT EXISTS
        info(picture_path TEXT, humidity FLOAT, temperature FLOAT)"""

        self.cursor.execute(command1)
        # on launch, connect to the device and ask for input
        noCon = True
        while noCon:
            # imageName = 'IMAGE00.JPG'
            # If there is no uart connection yet, connect to an available device with a UART service,
            # TODO: Make it connect specifically to our project, and not any UART Device, not important
            if not self.uart_connection:
                print("Trying to connect...")
                for adv in self.ble.start_scan(ProvideServicesAdvertisement):
                    if UARTService in adv.services:
                        self.uart_connection = self.ble.connect(adv)
                        print("Connected")
                        break
                self.ble.stop_scan()
            # if there is a Uart device connected, ask the user for an input, then call the function corresponding to the input
            # TODO: Make this refresh automaticaly and with a button press, needed for CDR
            if self.uart_connection and self.uart_connection.connected:
                self.uart_service = self.uart_connection[UARTService]
                noCon = False

    # add image, temp, and humidity to database once all are recived
    # commented out for testing, will need to be working for actual project
    def addToDB(self, textString):
        vals = textString.split(", ")
        print(vals)
        self.cursor.execute("INSERT INTO info VALUES (?, ?, ?)",
                            (vals[0], vals[1], vals[2]))
        self.connection.commit()
        self.cursor.execute("SELECT * FROM info")
        results = self.cursor.fetchall()
        # render_template('template.html', value=results)
        print(results)

    # Testing function to get text from the device, can be removed once we know everything works
    def getText(self):
        self.uart_service.write("w".encode("utf-8"))
        textString = self.uart_service.readline().decode("utf-8")
        print(textString)
        self.addToDB(textString)

    def runAll(self):
        BUFFSIZE = 4
        # bytes received, used to tell if we are getting all of the data
        byteNum = 0
        # send the user input that was passed thru as s, this tells the arduino what we want to do
        # happens in each run function to ensure command isnt sent before we are ready to get the data
        self.uart_service.write("r".encode("utf-8"))
        # wait until the arduino sends an c back, to tell the rpi we are about to get data
        while (True):
            val = self.uart_service.read(nbytes=1)
            if (val == None):
                continue
            if (val.decode("utf-8") == 'c'):
                break
        # debug statement to know we are getting the name first
        print("readyForImgName")
        # read the image name, used to be readLine, but for some reason that broke
        # When possible use read(nbytes) instead of readline to fix errors if size of data is known

        # arduino will send a line with the image name, temperature, and humidity seperated by a comma
        # TODO: textString is sending an unknown number of bytes, should be 19, but for somereason its not
        imageName = self.uart_service.read(nbytes=12).decode("utf-8")
        fileName = Path("static/" + imageName)
        fileName.touch(exist_ok=True)
        # print the name to make sure its the right one
        print(imageName)
        # textString = uart_service.readline().decode("utf-8")
        # a file with the name of the image that we will save data to
        f = open(fileName, 'wb+')
        # get the first 4 bytes, then delay, print statemtns are for debugging
        val = self.uart_service.read(nbytes=BUFFSIZE)
        print("delay")
        time.sleep(.01)
        print("dd")
        # Get the data from the uart service, then write them to teh file, 4 bytes at a time for now, seems to be reliable
        while (val != None):
            # print(val)
            f.write(val)
            val = self.uart_service.read(nbytes=BUFFSIZE)
            byteNum = byteNum + BUFFSIZE
            # we need this delay to allow the arduino to send data, if we dont we might read the same data in
            # time.sleep(.005)
        # print the number of bytes recived,

        # close the file
        f.close()
Beispiel #5
0
class Split(Module):
    '''Enables splitting keyboards wirelessly, or wired'''

    def __init__(
        self,
        split_flip=True,
        split_side=None,
        split_type=SplitType.UART,
        split_target_left=True,
        uart_interval=20,
        data_pin=None,
        data_pin2=None,
        target_left=True,
        uart_flip=True,
        debug_enabled=False,
    ):
        self._is_target = True
        self._uart_buffer = []
        self.split_flip = split_flip
        self.split_side = split_side
        self.split_type = split_type
        self.split_target_left = split_target_left
        self.split_offset = None
        self.data_pin = data_pin
        self.data_pin2 = data_pin2
        self.target_left = target_left
        self.uart_flip = uart_flip
        self._is_target = True
        self._uart = None
        self._uart_interval = uart_interval
        self._debug_enabled = debug_enabled
        if self.split_type == SplitType.BLE:
            try:
                from adafruit_ble import BLERadio
                from adafruit_ble.advertising.standard import (
                    ProvideServicesAdvertisement,
                )
                from adafruit_ble.services.nordic import UARTService

                self.ProvideServicesAdvertisement = ProvideServicesAdvertisement
                self.UARTService = UARTService
            except ImportError:
                print('BLE Import error')
                return  # BLE isn't supported on this platform
            self._ble = BLERadio()
            self._ble_last_scan = ticks_ms() - 5000
            self._connection_count = 0
            self._uart_connection = None
            self._advertisment = None
            self._advertising = False
            self._psave_enable = False

    def during_bootup(self, keyboard):
        # Set up name for target side detection and BLE advertisment
        name = str(getmount('/').label)
        if self.split_type == SplitType.BLE:
            self._ble.name = name
        else:
            # Try to guess data pins if not supplied
            if not self.data_pin:
                self.data_pin = keyboard.data_pin

        # Detect split side from name
        if self.split_side is None:
            if name.endswith('L'):
                # If name ends in 'L' assume left and strip from name
                self._is_target = bool(self.split_target_left)
                self.split_side = SplitSide.LEFT
            elif name.endswith('R'):
                # If name ends in 'R' assume right and strip from name
                self._is_target = not bool(self.split_target_left)
                self.split_side = SplitSide.RIGHT

        # if split side was given, find master from split_side.
        elif self.split_side == SplitSide.LEFT:
            self._is_target = bool(self.split_target_left)
        elif self.split_side == SplitSide.RIGHT:
            self._is_target = not bool(self.split_target_left)

        # Flips the col pins if PCB is the same but flipped on right
        if self.split_flip and self.split_side == SplitSide.RIGHT:
            keyboard.col_pins = list(reversed(keyboard.col_pins))

        self.split_offset = len(keyboard.col_pins)

        if self.split_type == SplitType.UART and self.data_pin is not None:
            if self._is_target:
                self._uart = busio.UART(
                    tx=self.data_pin2, rx=self.data_pin, timeout=self._uart_interval
                )
            else:
                self._uart = busio.UART(
                    tx=self.data_pin, rx=self.data_pin2, timeout=self._uart_interval
                )

        # Attempt to sanely guess a coord_mapping if one is not provided.
        if not keyboard.coord_mapping:
            keyboard.coord_mapping = []

            rows_to_calc = len(keyboard.row_pins) * 2
            cols_to_calc = len(keyboard.col_pins) * 2

            for ridx in range(rows_to_calc):
                for cidx in range(cols_to_calc):
                    keyboard.coord_mapping.append(intify_coordinate(ridx, cidx))

    def before_matrix_scan(self, keyboard):
        if self.split_type == SplitType.BLE:
            self._check_all_connections()
            self._receive_ble(keyboard)
        elif self.split_type == SplitType.UART:
            if self._is_target or self.data_pin2:
                self._receive_uart(keyboard)
        elif self.split_type == SplitType.ONEWIRE:
            pass  # Protocol needs written
        return

    def after_matrix_scan(self, keyboard):
        if keyboard.matrix_update:
            if self.split_type == SplitType.UART and self._is_target:
                pass  # explicit pass just for dev sanity...
            elif self.split_type == SplitType.UART and (
                self.data_pin2 or not self._is_target
            ):
                self._send_uart(keyboard.matrix_update)
            elif self.split_type == SplitType.BLE:
                self._send_ble(keyboard.matrix_update)
            elif self.split_type == SplitType.ONEWIRE:
                pass  # Protocol needs written
            else:
                print('Unexpected case in after_matrix_scan')

        return

    def before_hid_send(self, keyboard):
        if not self._is_target:
            keyboard.hid_pending = False

        return

    def after_hid_send(self, keyboard):
        return

    def on_powersave_enable(self, keyboard):
        if self.split_type == SplitType.BLE:
            if self._uart_connection and not self._psave_enable:
                self._uart_connection.connection_interval = self._uart_interval
                self._psave_enable = True

    def on_powersave_disable(self, keyboard):
        if self.split_type == SplitType.BLE:
            if self._uart_connection and self._psave_enable:
                self._uart_connection.connection_interval = 11.25
                self._psave_enable = False

    def _check_all_connections(self):
        '''Validates the correct number of BLE connections'''
        self._connection_count = len(self._ble.connections)
        if self._is_target and self._connection_count < 2:
            self._target_advertise()
        elif not self._is_target and self._connection_count < 1:
            self._initiator_scan()

    def _initiator_scan(self):
        '''Scans for target device'''
        self._uart = None
        self._uart_connection = None
        # See if any existing connections are providing UARTService.
        self._connection_count = len(self._ble.connections)
        if self._connection_count > 0 and not self._uart:
            for connection in self._ble.connections:
                if self.UARTService in connection:
                    self._uart_connection = connection
                    self._uart_connection.connection_interval = 11.25
                    self._uart = self._uart_connection[self.UARTService]
                    break

        if not self._uart:
            if self._debug_enabled:
                print('Scanning')
            self._ble.stop_scan()
            for adv in self._ble.start_scan(
                self.ProvideServicesAdvertisement, timeout=20
            ):
                if self._debug_enabled:
                    print('Scanning')
                if self.UARTService in adv.services and adv.rssi > -70:
                    self._uart_connection = self._ble.connect(adv)
                    self._uart_connection.connection_interval = 11.25
                    self._uart = self._uart_connection[self.UARTService]
                    self._ble.stop_scan()
                    if self._debug_enabled:
                        print('Scan complete')
                    break
        self._ble.stop_scan()

    def _target_advertise(self):
        '''Advertises the target for the initiator to find'''
        self._ble.stop_advertising()
        if self._debug_enabled:
            print('Advertising')
        # Uart must not change on this connection if reconnecting
        if not self._uart:
            self._uart = self.UARTService()
        advertisement = self.ProvideServicesAdvertisement(self._uart)

        self._ble.start_advertising(advertisement)

        self.ble_time_reset()
        while not self.ble_rescan_timer():
            self._connection_count = len(self._ble.connections)
            if self._connection_count > 1:
                self.ble_time_reset()
                if self._debug_enabled:
                    print('Advertising complete')
                break
        self._ble.stop_advertising()

    def ble_rescan_timer(self):
        '''If true, the rescan timer is up'''
        return bool(ticks_diff(ticks_ms(), self._ble_last_scan) > 5000)

    def ble_time_reset(self):
        '''Resets the rescan timer'''
        self._ble_last_scan = ticks_ms()

    def _send_ble(self, update):
        if self._uart:
            try:
                if not self._is_target:
                    update[1] += self.split_offset
                self._uart.write(update)
            except OSError:
                try:
                    self._uart.disconnect()
                except:  # noqa: E722
                    if self._debug_enabled:
                        print('UART disconnect failed')

                if self._debug_enabled:
                    print('Connection error')
                self._uart_connection = None
                self._uart = None

    def _receive_ble(self, keyboard):
        if self._uart is not None and self._uart.in_waiting > 0 or self._uart_buffer:
            while self._uart.in_waiting >= 3:
                self._uart_buffer.append(self._uart.read(3))
            if self._uart_buffer:
                keyboard.secondary_matrix_update = bytearray(self._uart_buffer.pop(0))
                return

    def _send_uart(self, update):
        # Change offsets depending on where the data is going to match the correct
        # matrix location of the receiever
        if self._is_target:
            if self.split_target_left:
                update[1] += self.split_offset
            else:
                update[1] -= self.split_offset
        else:
            if self.split_target_left:
                update[1] += self.split_offset
            else:
                update[1] -= self.split_offset

        if self._uart is not None:
            self._uart.write(update)

    def _receive_uart(self, keyboard):
        if self._uart is not None and self._uart.in_waiting > 0 or self._uart_buffer:
            if self._uart.in_waiting >= 60:
                # This is a dirty hack to prevent crashes in unrealistic cases
                import microcontroller

                microcontroller.reset()

            while self._uart.in_waiting >= 3:
                self._uart_buffer.append(self._uart.read(3))
            if self._uart_buffer:
                keyboard.secondary_matrix_update = bytearray(self._uart_buffer.pop(0))

                return
Beispiel #6
0
class PolymathTraining():
    """ Core class used for collecting data from the Polymath system."""

    def __init__(self, filename="out.csv"):
        self.filename = filename

        self.ble = BLERadio()
        self.uart_connection = None
        
        self.config = None
        self.sample_rate = 0 # In Hz
        self.samples_per_packet = 0
        self.columns = []

        self.sequence = 0
        self.data = []
        pass

    def connect(self):
        result = False 

        if not self.uart_connection:
            for adv in self.ble.start_scan(ProvideServicesAdvertisement):
                if UARTServiceCustom in adv.services:
                    print("Found a device to connect to: {0}".format(adv))
                    self.uart_connection = self.ble.connect(adv, timeout=30)
                    print("Connected Successfully")

                    result = True
                    break
            
            self.ble.stop_scan()

        return result

    def connected(self):
        return (self.uart_connection and self.uart_connection.connected)

    def disconnect(self):
        self.uart_connection.disconnect()

    def run(self):
        if self.connected():
            uart_service = self.uart_connection[UARTServiceCustom]
            if (uart_service.in_waiting > 0):
                line = uart_service.readline().decode()
                print(line)

                if ((line is not None) and (len(line) > 0)):
                    if not self.config:
                        # First try getting the configuration for the system.

                        try:
                            read_config = json.loads(line)
                            print(read_config)
                            print("Parsed JSON successfully")
                            
                            # for key in read_config:
                            #     print("Key: {0}, Value {1}".format(key, read_config[key]))

                            if (    ("sample_rate" in read_config) 
                                    and ("samples_per_packet" in read_config) 
                                    and ("column_location" in read_config)):

                                self.sample_rate = read_config["sample_rate"]
                                self.samples_per_packet = read_config["samples_per_packet"]

                                self.column_locations = []
                                for i in range(0, self.samples_per_packet):
                                    self.column_locations.append("")

                                for key in read_config["column_location"]:
                                    self.column_locations[read_config["column_location"][key]] = key

                                self.config = read_config
                                print("Read a valid config. Columns are {0}".format(self.column_locations))

                                # Initiate a connection
                                uart_service.write("connect".encode())

                                # Set up the output file
                                with open(self.filename, "w") as f:
                                    f.write("sequence,{0}\n".format(','.join(self.column_locations)))
                            else:
                                print("Not all of the expected keys were present.")
                                
                        except ValueError as e:
                            print("Failed to decode JSON due to: {0}".format(e))
                            pass

                    else:
                        # Collect data.

                        data = line.strip().split(',')
                        packet = []

                        add_packet = True #Assume
                        
                        if (len(data) == self.samples_per_packet):
                            for sample in data:
                                try:
                                    packet.append(int(sample))
                                except ValueError:
                                    add_packet = False
                                    break
                        else:
                            add_packet = False

                        if (add_packet):
                            self.data.append(data)
                        
                            with open(self.filename, "a") as f:
                                f.write("{0},{1}\n".format(self.sequence, ','.join(data)))
                                
                            print("Appended {0}".format(data))

                            self.sequence += 1

                        pass