Пример #1
0
    def testBug8(self):
        """
        Tests the resolution of bug #8
        """
        badDefaultName = "gremlin"
        registry = SkoobotRegistry(self.tempPath)
        with self.subTest("Setting bad default"):
            oldDefault = registry.getDefaultName()
            with self.assertRaises(ValueError):
                registry.setDefault(badDefaultName)
            self.assertEqual(oldDefault, registry.getDefaultName())

        with self.subTest("Loading bad default"):
            self.registryDict["default"] = badDefaultName
            with open(self.tempPath, "w") as registryFile:
                json.dump(self.registryDict, registryFile, indent=4)
            registry.load()
            self.assertEqual(None, registry.getDefaultName())

        with self.subTest("Loading good default"):
            self.registryDict["default"] = self.skooName
            with open(self.tempPath, "w") as registryFile:
                json.dump(self.registryDict, registryFile, indent=4)
            registry.load()
            self.assertEqual(self.skooName, registry.getDefaultName())
Пример #2
0
def scan():
    transport = TransportBluepy()
    registry = SkoobotRegistry()

    rawDevices = transport.findRawDevices()
    skoobots = []
    for device in rawDevices:
        scanList = device.getScanData()
        for scanItem in scanList:
            if scanItem[0] == 9 and scanItem[2] == "Skoobot":
                skoobots.append(device)

    for skoobot in skoobots:
        # print(transport.rawDeviceInfoStr(skoobot))
        addr = skoobot.addr
        registry.addSkoobot(addr)
        name = registry.getSkoobotsByAddress(addr)[0][1]
        if registry.getDefaultName() == None:
            registry.setDefault(name)
        defaultText = " (default)" if registry.getDefaultName() == name else ""
        msg = "Added Skoobot {0:s} to registry with name {1:s}{2:s}"
        print(msg.format(addr, name, defaultText))
    print("Saving to list of Skoobots to registry {0:s}".format(
        registry.registryPath))
    registry.save()
    shutil.chown(registry.registryPath, os.getlogin())
Пример #3
0
    def testSave(self):
        """
        Tests for the save() method

        Make sure that save() works, except when the registry is
        marked invalid.
        """
        registry = SkoobotRegistry(self.tempPath)
        altSkooAddr = "aa:aa:aa:aa:aa:aa"
        altSkooName = "Alt"
        extraSkooAddr = "ee:ee:ee:ee:ee:ee"
        extraSkooName = "Extra"

        with self.subTest("Undo alterations"):
            registry.addSkoobot(altSkooAddr, altSkooName)
            registry.setDefault(altSkooAddr)
            self.assertEqual(4, len(registry.registry))

            registry.load()

            self.assertEqual(3, len(registry.registry))
            self.assertEqual(self.skooName, registry.getDefaultName())

        with self.subTest("Alter and save"):
            registry.addSkoobot(altSkooAddr, altSkooName)
            registry.setDefault(altSkooAddr)
            self.assertEqual(4, len(registry.registry))

            # Save the state with the AltSkootbot entry
            registry.save()

            registry.addSkoobot(extraSkooAddr, extraSkooName)
            registry.setDefault(extraSkooAddr)
            self.assertEqual(5, len(registry.registry))
            self.assertEqual(extraSkooName, registry.getDefaultName())

            # Restore to the save() state
            registry.load()

            self.assertEqual(4, len(registry.registry))
            self.assertEqual(altSkooName, registry.getDefaultName())

        with self.subTest("Don't save invalid"):
            registry.addSkoobot(extraSkooAddr, altSkooName)
            registry.setDefault(extraSkooAddr)
            self.assertEqual(5, len(registry.registry))
            registry.valid = False

            # Fail to save the state with the Extra entry
            registry.save()

            # Restore to the previous save() state
            registry.load()

            self.assertEqual(4, len(registry.registry))
            self.assertEqual(altSkooName, registry.getDefaultName())
Пример #4
0
    def testGetDefaultName(self):
        """
        Test for method getDefaultName()

        Method gets the default name.
        """
        registry = SkoobotRegistry(self.tempPath)
        self.assertEqual(self.skooName, registry.getDefaultName())
Пример #5
0
    def testSetDefault(self):
        """
        Test for method setDefault()

        Method sets the default name. It takes one parameter, which is either
        the address or the name.
        """
        registry = SkoobotRegistry(self.tempPath)

        registry.setDefault(self.skooDupName)
        self.assertEqual(self.skooDupName, registry.getDefaultName())

        registry.setDefault(self.skooAddr)
        self.assertEqual(self.skooName, registry.getDefaultName())

        registry.setDefault(self.skooDupAddr1)
        self.assertEqual(self.skooDupName, registry.getDefaultName())
Пример #6
0
    def testConstruct(self):
        """
        Test construction with a non-existent file
        and the JSON file created during setup
        """
        with self.subTest("Empty registry"):
            emptyRegistry = SkoobotRegistry("~/nonexistent.json")
            self.assertEqual(dict(), emptyRegistry.registry)
            self.assertEqual(True, emptyRegistry.valid)
            self.assertEqual(None, emptyRegistry.getDefaultName())

            # Make sure that ~ in the filename was expanded
            self.assertNotIn("~", emptyRegistry.registryPath)

        with self.subTest("setUp() registry"):
            registry = SkoobotRegistry(self.tempPath)
            self.assertEqual(3, len(registry.registry))
            self.assertEqual(True, registry.valid)
            self.assertEqual(self.skooName, registry.getDefaultName())
Пример #7
0
    def testLoad(self):
        """
        Test for loading the registry.

        Most of this is already tested by the constructor tests,
        however, we need to check that a reload works and that a
        failed load sets the valid flag to false
        """
        registry = SkoobotRegistry(self.tempPath)

        with self.subTest("Empty dict"):
            emptyDict = {}
            with open(self.tempPath, "w") as registryFile:
                json.dump(emptyDict, registryFile)
            self.assertEqual(3, len(registry.registry))
            registry.load()
            self.assertEqual(0, len(registry.registry))
            self.assertEqual(True, registry.valid)
            self.assertEqual(None, registry.getDefaultName())

        with self.subTest("Invalid dict"):
            with open(self.tempPath, "w") as registryFile:
                registryFile.write("rubbish")
            registry.addSkoobot(self.skooAddr)
            self.assertEqual(True, registry.valid)

            with self.assertRaises(json.JSONDecodeError):
                registry.load()

            self.assertEqual(0, len(registry.registry))
            self.assertEqual(False, registry.valid)
            self.assertEqual(None, registry.getDefaultName())

        with self.subTest("Reload good dict"):
            with open(self.tempPath, "w") as registryFile:
                json.dump(self.registryDict, registryFile)
            self.assertEqual(0, len(registry.registry))
            registry.load()
            self.assertEqual(3, len(registry.registry))
            self.assertEqual(True, registry.valid)
            self.assertEqual(self.skooName, registry.getDefaultName())
Пример #8
0
    def testBug11(self):
        """
        Tests the resolution of bug #11

        "Registry setDefault() does strange things if given a
        list of lists as a parameter"
        Check that it raises a TypeError when called with
        something other than String or None.
        It turns out that the error only triggers with tuples.
        """
        registry = SkoobotRegistry(self.tempPath)
        with self.subTest("Valid arguments"):
            registry.setDefault(None)
            self.assertEqual(None, registry.getDefaultName())

            registry.setDefault(self.skooName)
            self.assertEqual(self.skooName, registry.getDefaultName())

        with self.subTest("Invalid arguments"):
            with self.assertRaises(TypeError):
                registry.setDefault(("test", ))
Пример #9
0
class SkoobotController:
    """
    Control API for Skoobots
    """
    def __init__(self):
        self.transport = TransportBluepy()
        self.registry = SkoobotRegistry()

        # Table of characteristic name to uuid mappings.
        # The characteristic names used are the ones in the firmware.
        self.uuids = {
            "cmd": "00001525-1212-efde-1523-785feabcd123",
            "data": "00001524-1212-efde-1523-785feabcd123",
            "byte2": "00001526-1212-efde-1523-785feabcd123",
            "byte128": "00001527-1212-efde-1523-785feabcd123",
            "byte4": "00001528-1212-efde-1523-785feabcd123",
        }
        self.connectedSkoobot = None

    def connect(self, name=None, addr=None):
        """
        Connect to the given Skoobot.
        If no Skoobot is given, connects to the default.
        Returns the address of the connected Skoobot if successful;
        None otherwise.
        """
        addrList = []

        if addr != None:
            if isinstance(addr, str):
                addrList.append(addr)
            else:
                raise TypeError("addr should be a string")
        else:
            if name == None:
                name = self.registry.getDefaultName()
            elif not isinstance(name, str):
                raise TypeError("name should be a string")
            if name != None:
                skoobots = self.registry.getSkoobotsByName(name)
                addrList = [bot[0] for bot in skoobots]
            else:
                raise RuntimeError("No default skoobot defined")

            if len(addrList) == 0:
                raise ValueError(
                    "No Skoobot with name {0:s} found".format(name))

        if self.connectedSkoobot != None:
            self.disconnect()

        for botAddr in addrList:
            try:
                self.transport.connect(botAddr)
                self.connectedSkoobot = botAddr
                break
            except BTLEException:
                pass

        return self.connectedSkoobot

    def disconnect(self):
        self.transport.disconnect()
        self.connectedSkoobot = None

    def sendCommand(self, data, waitForResponse=False):
        if self.connectedSkoobot == None:
            raise RuntimeError("BLE not connected")
        data = int(data)
        cmdBytes = data.to_bytes(1, byteorder="little")
        characteristics = self.transport.getRawCharacteristicsByUUID(
            self.uuids["cmd"])
        if len(characteristics) == 0:
            raise RuntimeError("cmd characteristic not supported by firmware")
        cmd = characteristics[0]
        cmd.write(cmdBytes, waitForResponse)

    def readBytes(self, charName="data"):
        """
        Read an array of bytes from the named characteristic

        returns a bytearray of the data
        """
        if self.connectedSkoobot == None:
            raise RuntimeError("BLE not connected")
        characteristics = self.transport.getRawCharacteristicsByUUID(
            self.uuids[charName])
        if len(characteristics) == 0:
            raise RuntimeError(
                "{0:s} characteristic not supported by firmware".format(
                    charName))
        charac = characteristics[0]
        dataBytes = charac.read()
        return dataBytes

    def readData(self, charName="data"):
        dataBytes = self.readBytes(charName)
        value = int.from_bytes(dataBytes, byteorder="little")
        return value

    def cmdRight(self):
        self.sendCommand(CMD_RIGHT, True)

    def cmdLeft(self):
        self.sendCommand(CMD_LEFT, True)

    def cmdForward(self):
        self.sendCommand(CMD_FORWARD, True)

    def cmdBackward(self):
        self.sendCommand(CMD_BACKWARD, True)

    def cmdStop(self):
        self.sendCommand(CMD_STOP, True)

    def cmdSleep(self):
        self.sendCommand(CMD_SLEEP, True)

    def cmdRoverMode(self):
        self.sendCommand(CMD_ROVER_MODE, True)

    def requestDistance(self):
        self.sendCommand(CMD_GET_DISTANCE, True)
        return self.readData()

    def requestAmbientLight(self):
        self.sendCommand(CMD_GET_AMBIENT, True)
        return self.readData("byte2")