class CameraController: def __init__(self): self.em = EventsManager() self.camera = Camera() self.ID = "Rpi-Fox-camera" self.info = {"info": "dummy"} self.commandQueue = [] self.run() self.em.subscribe("%s/command" % self.ID, self.sendCommand) self.em.subscribe("%s/info-request" % self.ID, self.getInfo) self.em.publish("component-added", {"componentID": self.ID}) def getInfo(self, message): self.em.publish("%s/info" % self.ID, {"info": self.info}) def getFrame(self): return self.camera.get_frame() def saveFrameToFile(self, file): my_file = open(file, 'wb') my_file.write(self.getFrame()) my_file.close() print("Image saved successfully to", file) def sendCommand(self, message): self.commandQueue.append(message) def _processCommandQueue(self): while True: if len(self.commandQueue) > 0: item = self.commandQueue.pop(0) command = item["command"] params = item["params"] if command == "take-photo": file = "/home/pi/IotBox/files/%s" % params['name'] self.saveFrameToFile(file) elif command == "timelapse": name = params['name'] number = params['number'] seconds_delay = params['seconds_delay'] #make folder 'output' to hold images folder = "/home/pi/IotBox/files/%s" % name print("Timelapse images stored in %s" % folder) if not os.path.exists(folder): os.makedirs(folder) for x in range(0, number): print("TODO: Taking photo number %d" % x) self.saveFrameToFile("{}/image_{}.jpg".format( folder, x)) sleep(seconds_delay) print("Timelapse complete!") else: print("Unknown command!") def run(self): t = threading.Thread(target=self._processCommandQueue) t.start()
class IoTInterfaceManager(): def __init__(self, mqttService): self.mqttService = mqttService self.em = EventsManager() self.interfaces = {} #get notified when components are added/removed self.em.subscribe("component-added", self.onComponentAdded) self.em.subscribe("component-removed", self.onComponentRemoved) def createInterface(self, componentID): self.interfaces[componentID] = IoTInterface(componentID, self.mqttService) def onComponentAdded(self, event): #create a new IoTInterface for each component, to subscribe to that component's topics componentID = event["componentID"] if not componentID in self.interfaces: self.createInterface(componentID) def onComponentRemoved(self, event): #destroy IoTInterfaces for each component componentID = event["componentID"] interface = self.interfaces.pop(componentID) interface.destroy()
class RhizoDeviceManager(): def __init__(self): self.em = EventsManager() self.connectedDevices = {} #dict of port:device self.em.subscribe("usb-connect", self.connectionEventHandler) self.em.subscribe("usb-disconnect", self.connectionEventHandler) def connectionEventHandler(self, event): type = event["topic"] port = event["port"] if (type == "usb-connect"): self.addDevice(port) elif (type == "usb-disconnect"): self.removeDevice(port) def addDevice(self, port): print("DeviceManager: Creating new device.") device = RhizoDevice(port) self.connectedDevices[port] = device self.em.publish("device-added", {"port": port}) def removeDevice(self, port): print("DeviceManager: Removing device.") device = self.connectedDevices.pop(port) device.destroy() self.em.publish("device-removed", {}) def getComponentIDsList(self): list = [] for port in self.connectedDevices: device = self.connectedDevices[port] for componentID in device.getComponentIDsList(): list.append(componentID) return list
class IoTInterface(): def __init__(self, componentID, mqttProvider): self.componentID = componentID self.mqtt = mqttProvider self.em = EventsManager() #subscribe to external/MQTT events to send in self.mqtt.subscribe("roll-call/who-there", self.announce) #receive commands addressed to this component topic = "%s/command" % self.componentID self.mqtt.subscribe(topic, self.processIncomingMessage) #subscribe to internal updates to send out topic = "%s/update" % self.componentID self.em.subscribe(topic, self.processOutgoingMessage) #subscribe to internal info to send out topic = "%s/info" % self.componentID self.em.subscribe(topic, self.processOutgoingMessage) #announce yourself msg = {"name": self.componentID} self.mqtt.publish("roll-call/hello", msg) #tell device to send its info self.em.publish("%s/info-request" % self.componentID, {}) def destroy(self): #unsubscribe before I get destroyed. self.em.unsubscribe(self.processOutgoingMessage) msg = {"name": self.componentID} self.mqtt.publish("roll-call/goodbye", msg) self.mqtt.unsubscribe(self.announce) self.mqtt.unsubscribe(self.processIncomingMessage) def announce(self, message): msg = {"name": self.componentID} self.mqtt.publish("roll-call/response", msg) self.em.publish("%s/info-request" % self.componentID, {}) def processOutgoingMessage(self, message): topic = message.pop( "topic") #Separate the message and topic to format for MQTT server self.mqtt.publish(topic, message) def processIncomingMessage(self, message): topic = message.pop("topic") self.em.publish(topic, message) #acknowledge topic = "%s/response" % message["topic"] msg = {"response": "ack"} self.mqtt.publish(topic, msg)
class Component(): def __init__(self, id): self.id = id self.info = {} self.em = EventsManager() self.em.subscribe("%s/info-request" % self.id, self.getInfo) def getInfo(self, message): self.em.publish("%s/info" % self.id, {"info": self.info}) def updateInfo(self, key, value): self.info[key] = value if key == "state": self.em.publish("%s/update" % self.id, {"value": value})
class RhizoDevice(): def __init__(self, port): print("Device: Initializing myself as a new device on port %s..." % port) self.port = port self.em = EventsManager() self.components = {} #Dict componentID:component self.abort = False self.deviceMessageQueue = [] self.serialConnection = SerialConnection(port, self.addToMessageQueue) self.processMessageQueue() self.sendCommand({ "command": "devices", "params": None }) #request info about what components are on the device self.sendCommand({ "command": "interval", "params": 2 }) #sets the data-sending rate to 1 second print("Device: Done Initializing.") def destroy(self): for componentID in self.components: self.em.unsubscribe(self.sendCommand) self.em.publish("component-removed", {"componentID": componentID}) self.serialConnection.closeConnection() self.serialConnection = False self.abort = True def addComponent(self, component_name): componentID = "%s/%s" % (self.port, component_name) if not componentID in self.components: self.components[componentID] = Component(componentID) self.em.publish("component-added", {"componentID": componentID}) self.em.subscribe("%s/command" % componentID, self.sendCommand) self.sendCommand({ "command": "%s: info" % component_name, "params": None }) #request info about this component def updateComponents(self, component_name, key, value): componentID = "%s/%s" % (self.port, component_name) if componentID in self.components: self.components[componentID].updateInfo(key, value) else: self.addComponent(component_name) #messaging related methods def sendCommand(self, message): command = message["command"] params = message["params"] try: if params is not None: msg = "%s %s" % (command, params) self.serialConnection.writeMessage(msg) else: msg = command self.serialConnection.writeMessage(msg) except: print("Device: Error sending command over serial connection.") # collect messages from the SerialConnection def addToMessageQueue(self, message): self.deviceMessageQueue.append(message) # process incoming serial message queue def _processMessageQueue(self): while True: if not self.abort: if len(self.deviceMessageQueue) > 0: msg = self.deviceMessageQueue.pop(0) msg_array = msg.decode('utf-8').split("|")[0].split( " " ) # Ugly, but this is just how the messages seem to be formatted: "c:v 492|69100" cmd = msg_array.pop(0).split(":") #Decide what kind of message it was-- either meta:devices [components], or componentId:info_type [value] if cmd[0] == "meta": if cmd[1] == "devices": for component in msg_array: self.addComponent(component) else: if cmd[0] == "nack": print("Device not acknowledging messages") pass if len(cmd) > 1: if cmd[1] == "nack" or cmd[1] == "ack": pass else: comp = cmd[0] key = cmd[1] value = msg_array if key == "v": key = "state" self.updateComponents(comp, key, value) else: pass else: break def processMessageQueue(self): t = threading.Thread(target=self._processMessageQueue) t.start()