class GoPro(threading.Thread): def __init__(self, parent, goproinfo, network): threading.Thread.__init__(self) self.info = goproinfo self.camera = GoProHero(password=self.info.getPassword(), log_level=logging.CRITICAL) self.storage = Storage() self.status = goprostatus.GoProStatus() self.files = goprofiles.GoProFiles() self.recordings = goprorecordings.GoProRecordings() self.gui = GoProGUI(parent, self.info.getSSID(), lambda: self.addObjective('snap'), lambda: self.addObjective('transfer'), self.status.clearObjectives) self.network = network self.exitVar = False self.load() self.files.unmount(self.info.getUSBid(), self.info.getUSBserial(), self.info.getModel()) print self.info.getSSID() + ': Initialized' def addObjective(self, objective): self.status.addObjective(objective) def run(self): actions = { 'record': self.record, 'snap': self.snap, 'transfer': self.transfer } actionThread = threading.Thread() while not self.exitVar: self.save() self.files.mount(self.info.getUSBid(), self.info.getUSBserial(), self.info.getModel()) self.status.setName(self.gui.getName()) self.gui.setUnsaved(self.recordings.isEmpty()) self.gui.setMounted(self.files.isMounted()) self.gui.setRecording(self.status.isRecording()) self.gui.displayObjectives(self.status.getObjectives()) action, args = self.status.decodeObjective() if action in actions and not actionThread.isAlive(): actionThread = threading.Thread(target=actions[action], args=(args,)) actionThread.start() time.sleep(0.1) def record(self, args): if args[0] == 'on' and self.status.isRecording() == False and self.gui.shouldRecord(): if not self.command(['mode video', 'record on']): self.status.completeObjective() return self.status.isRecording(True) self.recordings.stage(' '.join(args[1:]), self.status.getName()) elif args[0] == 'off' and self.status.isRecording() == True: time.sleep(1) if not self.command(['record off']): self.status.completeObjective() return self.status.isRecording(False) self.recordings.commit() self.status.completeObjective() def transfer(self, args): if self.files.isMounted() and not self.recordings.isEmpty(): patterns = self.files.findMatchingFiles(self.recordings.getRecordings()) correctPattern = self.gui.confirmPattern(self.recordings.getRecordings(), patterns) self.files.trackAllExcept(correctPattern) self.save() successfulIndices = self.files.copy(self.recordings.getRecordings(), correctPattern) self.files.trackAll() self.save() for i in reversed(successfulIndices): self.recordings.delete(i) self.status.completeObjective() def snap(self, args): try: self.connect() _, image = self.camera.image().split(',') if not os.path.isdir('tmp'): os.mkdir('tmp') file = open('tmp/image.png', 'wb') file.write(image.decode('base64')) file.close() os.system('eog tmp/image.png &') except: pass finally: self.disconnect() self.status.completeObjective() def connect(self): self.network.connect(self.info.getSSID(), self.info.getPassword()) def disconnect(self): self.network.disconnect() def testConnection(self): self.connect() self.disconnect() def cameraStatus(self, param): status = self.camera.status() if param in status: return status[param] def command(self, commands): try: self.connect() for com in commands: decoded = com.split(' ') self.camera.command(decoded[0], decoded[1]) time.sleep(1) if self.cameraStatus(decoded[0]) != decoded[1]: raise NetworkError(self.info.getSSID()) return True except NetworkError: print self.info.getSSID() + ': There was an error when connecting to the camera' finally: self.disconnect() return False def exit(self): self.exitVar = True def save(self): result = 'PART::RECORDINGS\n' result += self.recordings.pack() + '\n' result += 'PART::STATUS\n' result += self.status.pack() + '\n' result += 'PART::FILES\n' result += self.files.pack() + '\n' result += 'PART::GUI\n' result += self.gui.pack() self.storage.save(self.info.getSSID(), result) def load(self): info = self.storage.load(self.info.getSSID()) result = {} currentPart = '' if not info: return for line in info.split('\n'): if 'PART' in line: currentPart = line[6:] result[currentPart] = '' continue result[currentPart] += line + '\n' self.recordings = goprorecordings.unpack(result['RECORDINGS'].strip('\n')) self.status = goprostatus.unpack(result['STATUS'].strip('\n')) self.files = goprofiles.unpack(result['FILES'].strip('\n')) self.gui.load(result['GUI'].strip('\n')) def grid(self, **kwargs): self.gui.grid(**kwargs)