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())
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())
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())
def testGetDefaultName(self): """ Test for method getDefaultName() Method gets the default name. """ registry = SkoobotRegistry(self.tempPath) self.assertEqual(self.skooName, registry.getDefaultName())
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())
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())
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())
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", ))
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")