def checkUSB(self): if self.app.test is not None: if self.app.test.testing: return validUpdate = False scriptUpdate = False updatePath = os.path.join(d.USB_DATA_PATH, d.UPDATE_DIR) print('checking if update path exists') if os.path.exists(updatePath): updateDataPath = os.path.join(updatePath, d.UPDATE_DATA_FILE) print('update path exists') if os.path.isfile(updateDataPath): updateData = d.readSettingFromFile(updateDataPath) newVersion = updateData['version'] validUpdate = True print('update data exists') updateScriptFile = os.path.join(updatePath, d.UPDATE_SCRIPT_FILE) if os.path.isfile(updateScriptFile): print('update script exists') scriptUpdate = True if validUpdate: self.pushMsg( msg.Message( self.app, self, self.disp, 'Valid update found.', ('Update contains custom script. ' if scriptUpdate else '') + 'Current version: ' + self.app.getSetting(d.VERSION) + ' New version: ' + newVersion, btnDefs=({ 'label': 'UPDATE', 'id': 'yesBtn', 'funct': (self.popMsg, self.startUpdate) }, {}, {}, { 'label': 'CANCEL', 'id': 'yesBtn', 'funct': self.popMsg }))) else: #either no USB stick or incorrect folder structure self.pushMsg( msg.Message(self.app, self, self.disp, 'No valid update.', 'Insert USB stick with valid update', btnDefs=({ 'label': 'RETRY', 'id': 'yesBtn', 'funct': (self.popMsg, self.checkUSB) }, {}, {}, { 'label': 'CANCEL', 'id': 'yesBtn', 'funct': self.popMsg })))
def startExport(self): if not (os.path.isdir(d.RASPI_DATA_PATH) and os.path.isdir(os.path.join(d.RASPI_DATA_PATH, d.TESTS_DIR)) and os.path.isdir(d.USB_DATA_PATH) and os.path.ismount(d.USB_DATA_PATH)): #final check self.pushMsg( msg.Message( self.app, self, self.disp, 'Export failed.', 'Export failed. Check the existence of SD and USB folders and USB connection.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {}, {}))) return self.pushMsg( msg.Message(self.app, self, self.disp, 'EXPORTING...', 'Please wait while files are being exported.', btnDefs=({}, {}, {}, {}))) exportThread = thr.Thread(target=self.exportFiles) exportThread.setName('EXPORT THREAD') exportThread.daemon = True exportThread.start()
def addPoint2(self): realVal = self.getBtnValById(REAL) if type(realVal) != type(0.0): self.pushMsg(msg.Message(self.app, self, self.disp, 'Invalid real value.', 'Add a valid real value', btnDefs = ( {'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg}, {}, {}, {} ) ) ) return adcVal = np.mean(self.dataVector) self.resetVectors() self.nls[0].appendNote(str(realVal)) self.nls[1].appendNote(str(adcVal)) self.adcVals = np.append(self.adcVals, float(adcVal)) self.realVals = np.append(self.realVals, float(realVal)) print('finished adding to notelists') if len(self.realVals) >= 2: try: self.computeBestFit() #update with best fit line self.graph.updatePlot( x = self.realVals, y1 = self.adcVals, xlabel = 'REAL ' + self.sensorType + ' [' + self.sensorData['unit'] + ']', ylabel = self.sensorType + ' ADC', a = float(self.getBtnValById(A)), b = float(self.getBtnValById(B)) ) except Exception as e: self.pushMsg(msg.Message(self.app, self, self.disp, 'Best fit calculation error', 'Error: ' + str(e), btnDefs = ( {'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg}, {}, {}, {} ) ) ) else: self.graph.updatePlot( x = self.realVals, y1 = self.adcVals, xlabel = 'REAL ' + self.sensorType + ' [' + self.sensorData['unit'] + ']', ylabel = self.sensorType + ' ADC' )
def bringExportMsg(self): if not (os.path.isdir(d.RASPI_DATA_PATH) and os.path.isdir( os.path.join(d.RASPI_DATA_PATH, d.TESTS_DIR))): self.pushMsg(msg.Message(self.app, self, self.disp, 'No test folders.', 'Nothing to export. Perform tests or check that test files are correctly saved to device under'\ ' ' + os.path.join(d.RASPI_DATA_PATH,d.TESTS_DIR) + '.', btnDefs = ( {'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg}, {}, {}, {} ) ) ) return if not os.path.ismount(d.USB_DATA_PATH): self.pushMsg( msg.Message( self.app, self, self.disp, 'NO USB', 'Cannot detect USB. Check that USB stick is correctly plugged in and retry.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, { 'label': 'RETRY', 'id': 'yesBtn', 'funct': (self.popMsg, self.bringExportMsg) }, {}, {}))) return self.pushMsg( msg.Message( self.app, self, self.disp, 'Exporting to USB.', 'You are about to export all test files stored on device to USB stick. All duplicate data will be overwritten.', btnDefs=({ 'label': 'PROCEED', 'id': 'yesBtn', 'funct': (self.popMsg, self.startExport) }, { 'label': 'CANCEL', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {})))
def save(self): self.app.hd.getAll() if not len(self.times): self.pushMsg( msg.Message( self.app, self, self.disp, 'Unable to save.', 'No data or corrupted data. Check Serial Connection and retry.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {}, {}))) return startWait = t.time() i = 0 while not self.envDataReady(): if t.time() - startWait >= d.SAVE_TIMEOUT: self.resetEnvData() self.pushMsg( msg.Message( self.app, self, self.disp, 'Unable to save.', 'No environmental data available (time, location, humidity, temperature). Retry, save anyways, or abort.', btnDefs=({ 'label': 'SAVE\nANYWAY', 'id': 'yesBtn', 'funct': (self.resetEnvData, self.popMsg, self.saveTest, self.drop) }, { 'label': 'RETRY', 'id': 'yesBtn', 'funct': (self.popMsg, self.save) }, { 'label': 'ABORT', 'id': 'yesBtn', 'funct': (self.resetEnvData, self.popMsg) }, {}))) return i += 1 self.resetEnvData() self.saveTest() self.drop()
def loop(self): while self.running: try: self.btnInput.checkInput() self.checkBtns() for event in pg.event.get(): if event.type == pg.KEYDOWN: if event.key == pg.K_1: self.btn1Press() if event.key == pg.K_q: self.btn2Press() if event.key == pg.K_a: self.btn3Press() if event.key == pg.K_z: self.btn4Press() if event.key == pg.K_UP: self.upArrowPress() if event.key == pg.K_LEFT: self.leftArrowPress() if event.key == pg.K_RIGHT: self.rightArrowPress() if event.key == pg.K_DOWN: self.downArrowPress() if event.key == pg.K_p: self.takeScreenshot() if event.key == pg.K_t: self.toggleTest() if event.type == pg.QUIT: self.exit() if self.blitScreen: # print('display.update() start') self.disp.fill(self.bcg_col) self.view.display() pg.display.update() self.blitScreen = False # print('display.update() end') self.clock.tick(60) ########################## TO BE UNCOMMENTED except Exception as e: if self.view is not None: from items import message as ms self.view.pushMsg( ms.Message(self, self.view, self.disp, 'Software encountered an issue.', 'Error: ' + str(e) + '. Error written to log file.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.view.popMsg }, {}, {}, {}))) # else: # print('Software encountered an issue. Error: ' + str(e)) cropDevErrorLogFile.write('\n###\n' + str(e) + '\n###')
def exitBtn(self): if self.app.test is not None: if self.app.test.testing: return from items import message as ms self.pushMsg( ms.Message( self.app, self, self.disp, 'EXITING', 'Choose exit mode.', # You are about to exit. Just saying. So you will be exiting after you click yes so think about it very hard cause that might bring some unwanted consequences I think. One final word... this is very long.', btnDefs=( { 'label': 'CANCEL', 'id': 'cancelBtn', 'funct': self.popMsg }, { 'label': 'EXIT', 'id': 'exitBtn', 'funct': self.bringExitMsg }, { 'label': 'RESTART', 'id': 'restartBtn', 'funct': self.bringRestartMsg }, { 'label': 'SHUT\nDOWN', 'id': 'shutdownBtn', 'funct': self.bringShutdownMsg }, )))
def save(self): a = self.getBtnValById(A) b = self.getBtnValById(B) if type(a) != type(0.0) or type(b) != type(0.0):#invalid a or b parameters (not floats) self.pushMsg(msg.Message(self.app, self, self.disp, 'Cannot save.', 'Incomplete calibration. Add at least two points.', btnDefs = ( {'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg}, {}, {}, {} ) ) ) return self.stopQuerying() self.sensorData[d.SENSOR_A] = a self.sensorData[d.SENSOR_B] = b self.sensorData[d.SENSOR_LAST] = dp.DateParse(self.app.getEnvData(d.TIME)).getDateTime() #make it more efficient - access only needed data fields allSensors = self.app.getSetting(d.SENSOR_BANK) allSensors[self.sensorType][self.sensorName] = self.sensorData self.app.saveSetting(d.SENSOR_BANK, allSensors) self.goBack()
def keyboardReturn(self, key, value, status=1): if key == d.SENSOR_A or key == d.SENSOR_B: try: value = float(value) # self.sensorData[key] = value # self.initLists() except: self.pushMsg( msg.Message(self.app, self, self.disp, 'Invalid data', 'Input must be a valid numerical value. Retry', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, { 'label': 'RETRY', 'id': 'yesBtn', 'funct': (self.popMsg, self.editField) }, {}, {}))) return elif key == d.SENSOR_UNIT: pass self.sensorData[key] = value self.initLists()
def keyboardReturn(self, key, value, status=1): if key == 'testFolder': self.app.saveSetting(d.TEST_FOLDER, value) self.initPreTestInfoLayout() elif key == 'breakHeight': try: self.breakHeight = float(value) except: self.pushMsg( msg.Message(self.app, self, self.disp, 'Invalid height format.', 'Please enter a valid height.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, { 'label': 'RETRY', 'id': 'yesBtn', 'funct': (self.popMsg, self.setBreakHeight) }, {}, {}))) elif key == 'operator': self.app.saveSetting(d.OPERATOR, value) self.initPreTestInfoLayout()
def editField(self): fieldType = self.nls[0].getItem() input = self.nls[1].getItem() if fieldType == d.SENSOR_LAST: self.pushMsg(msg.Message(self.app, self, self.disp, 'Non-editable field.', 'This field is automatically updated when you introduce and save any changes to the sensor. The '\ 'current time, ' + dp.DateParse(self.app.getEnvData(d.TIME)).getDateTime() + ' will populate this field if you save this sensor.', btnDefs = ( {'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg}, {}, {}, {} ) ) ) return if fieldType == d.SENSOR_A or fieldType == d.SENSOR_B: kbType = d.NUM else: kbType = d.WORD self.app.setView( kbv.KeyboardView(self.app, self, kbType, fieldType, fieldType, input))
def startRemoveAll(self): delPath = self.testsPath # if not os.path.isdir(delPath): # delPath = os.path.dirname(delpath) if not os.path.isdir(delPath): self.pushMsg( msg.Message( self.app, self, self.disp, 'Cannot proceed', 'Either there are no test files to delete or the directory structure is invalid.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {}, {}))) return if self.mode == 'USB' and not os.path.ismount(d.USB_DATA_PATH): self.pushMsg( msg.Message(self.app, self, self.disp, 'Cannot proceed', 'USB is not mounted. Check USB connection first.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {}, {}))) return self.pushMsg( msg.Message(self.app, self, self.disp, 'REMOVING...', 'Please wait while files are being removed.', btnDefs=({}, {}, {}, {}))) delThread = thr.Thread(target=self.removeAll) delThread.setName('REMOVE THREAD') delThread.daemon = True delThread.start()
def defaultUpdate(self): updatePath = os.path.join(d.USB_DATA_PATH, d.UPDATE_DIR) updateDataPath = os.path.join(updatePath, d.UPDATE_DATA_FILE) updateData = d.readSettingFromFile(updateDataPath) newVersion = updateData['version'] overrideAppData = updateData['overrideAppData'] updSoftwarePath = os.path.join(updatePath, d.STALK_PUSHER_DIR) #copy if overrideAppData: m.osCommand('rm -r ' + d.APP_PATH) m.osCommand('cp -r ' + updSoftwarePath + ' ' + d.DESKTOP_PATH) else: oldAppData = d.readSettings() oldAppData[d.VERSION] = newVersion m.osCommand('rm -r ' + d.APP_PATH) m.osCommand('cp -r ' + updSoftwarePath + ' ' + d.DESKTOP_PATH) d.saveSettingsObject(oldAppData) #set permissions to all for path, subdirs, files in os.walk(d.APP_PATH): m.osCommand('chmod 777 ' + path) for name in files: filePath = os.path.join(path, name) m.osCommand('chmod 777 ' + filePath) updateScriptFile = os.path.join(updatePath, d.UPDATE_SCRIPT_FILE) if os.path.isfile(updateScriptFile): m.osCommand('python3 ' + updateScriptFile) try: restartRequired = updateData['restartRequired'] except: restartRequired = True self.popMsg() self.pushMsg( msg.Message( self.app, self, self.disp, 'Update succesful.', 'Restart is required.' if restartRequired else 'Restart is recommended. Changes will not apply until restart.', btnDefs=({ 'label': 'RESTART', 'id': 'yesBtn', 'funct': (self.popMsg, self.app.restartPi) }, {}, {}, {} if restartRequired else { 'label': 'LATER', 'id': 'yesBtn', 'funct': self.popMsg })))
def startUpdate(self): self.pushMsg( msg.Message(self.app, self, self.disp, 'UPDATING...', 'Please wait while software is updating.', btnDefs=({}, {}, {}, {}))) updateThread = thr.Thread(target=self.defaultUpdate) updateThread.setName('UPDATE THREAD') updateThread.daemon = True updateThread.start()
def bringRemoveMsg(self): self.pushMsg(msg.Message(self.app, self, self.disp, 'REMOVING ALL ' + self.mode +' FILES', 'You are about to permanently remove all files on ' + self.mode + \ '. Ensure that all files are safely stored as copies. Data removed cannot be retrieved.', btnDefs = ( {'label': 'PROCEED', 'id': 'yesBtn', 'funct': (self.popMsg, self.bringRemoveMsg2)}, {'label': 'CANCEL', 'id': 'yesBtn', 'funct': self.popMsg}, {}, {} ) ) )
def bringRemoveMsg2(self): self.pushMsg(msg.Message(self.app, self, self.disp, 'ARE YOU SURE?', 'All files on ' + self.mode + \ ' will be permanently deleted.', btnDefs = ( {'label': 'CANCEL', 'id': 'yesBtn', 'funct': self.popAllMsg}, {}, {'label': 'REMOVE\nALL', 'id': 'yesBtn', 'funct': (self.popAllMsg, self.startRemoveAll)}, {} ) ) )
def save(self): if len(self.input) > 0: self.goBack() self.prevView.keyboardReturn(self.retKey, self.input) else: self.pushMsg( msg.Message(self.app, self, self.disp, 'Cannot accept empty input', 'Please enter input or cancel', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {}, {})))
def keyboardReturn(self, key, value, status = 1): if key ==REAL: try: self.setLabelById(REAL, self.sensorType, float(value)) except Exception as e: self.pushMsg(msg.Message(self.app, self, self.disp, 'Invalid input', 'Error: ' + str(e), btnDefs = ( {'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg}, {'label': 'RETRY', 'id': 'noBtn', 'funct': self.retryInput}, {}, {} ) ) )
def bringRestartMsg(self): from items import message as ms self.pushMsg( ms.Message(self.app, self, self.disp, 'RESTARTING DEVICE...', 'ARE YOU SURE?', btnDefs=({ 'label': 'YES', 'id': 'yesBtn', 'funct': self.app.restartPi }, { 'label': 'NO', 'id': 'noBtn', 'funct': self.popMsg }, {}, {})))
def bringShutdownMsg(self): from items import message as ms self.pushMsg( ms.Message(self.app, self, self.disp, 'SHUTTING DOWN DEVICE...', 'ARE YOU SURE?', btnDefs=({ 'label': 'NO', 'id': 'noBtn', 'funct': self.popMsg }, {}, {}, { 'label': 'YES', 'id': 'yesBtn', 'funct': self.app.shutdownPi })))
def bringExitMsg(self): from items import message as ms self.pushMsg( ms.Message(self.app, self, self.disp, 'EXITING SOFTWARE', 'ARE YOU SURE?', btnDefs=({ 'label': 'YES', 'id': 'yesBtn', 'funct': self.app.exit }, { 'label': 'NO', 'id': 'noBtn', 'funct': self.popMsg }, {}, {})))
def addChar(self): if len(self.input) < self.maxlen: self.input += self.keyBoard.getChar() self.inputRect.setText(self.input + ' ' + self.suffix) else: self.pushMsg( msg.Message(self.app, self, self.disp, 'Input too long', 'Reached maximum length for this input: ' + str(self.maxlen), btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {}, {})))
def removeAll(self): delPath = self.testsPath if not os.path.isdir(delPath): delPath = os.path.dirname(delpath) m.osCommand('rm -rf ' + delPath) self.popAllMsg() self.makeLists() self.initButArea() self.pushMsg( msg.Message(self.app, self, self.disp, 'REMOVE COMPLETE', 'Please verify validity of remove operation.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {}, {})))
def serialConnFail(self): from items import message as ms self.pushMsg( ms.Message(self.app, self, self.disp, 'Serial connection failed', 'Please verify wiring and restart software.', btnDefs=({ 'label': 'OK', 'id': 'exitBtn', 'funct': self.popMsg }, { 'label': 'RETRY', 'id': 'restartBtn', 'funct': self.retrySerialConn }, { 'label': 'RESTART\nDEVICE', 'id': 'restartBtn', 'funct': self.bringRestartMsg }, {})))
def exportFiles(self): # m.osCommand('sudo chmod ' + d.RW_PERM_A + ' ' + d.USB_DATA_PATH) m.osCommand('rsync -a -u ' + os.path.join(d.RASPI_DATA_PATH, d.TESTS_DIR) + ' ' + d.USB_DATA_PATH) self.popMsg() self.makeLists() self.initButArea() self.pushMsg( msg.Message( self.app, self, self.disp, 'EXPORT COMPLETE', 'You can remove USB stick and verify the export outcome.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {}, {})))
def startSampling(self): realVal = self.getBtnValById(REAL) if type(realVal) != type(0.0): self.pushMsg(msg.Message(self.app, self, self.disp, 'Invalid real value.', 'Add a valid real value', btnDefs = ( {'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg}, {}, {}, {} ) ) ) return self.resetVectors() self.focusNum = inTest self.app.updateScreen() notifThread = thr.Thread(target = self.notifyAfterDelay) notifThread.setName('DATA GATHER NOTIF THREAD') notifThread.daemon = True notifThread.start()
def selectFile(self): if self.folderList[1].isEmpty(): self.pushMsg( msg.Message(self.app, self, self.disp, 'Test folder empty.', 'No test files in selected test folder.', btnDefs=({ 'label': 'OK', 'id': 'yesBtn', 'funct': self.popMsg }, {}, {}, {}))) return testFolderName = self.folderList[0].getItem() testFile = self.folderList[1].getItem() + d.TEST_FILE_FORMAT path = self.testsPath + '/' + testFolderName + '/' + testFile from views import testFileView as tfv self.app.setView(tfv.TestFileView(self.app, path, self.graph, self))
def makeConfirmMsgs(self): self.popAllMsg() #test folder self.pushMsg( msg.Message(self.app, self, self.disp, 'Confirm/edit test folder.', 'Current test folder: ' + self.app.getSetting(d.TEST_FOLDER), btnDefs=({ 'label': 'CONFIRM', 'id': 'yesBtn', 'funct': self.popMsg }, { 'label': 'EDIT', 'id': 'yesBtn', 'funct': (self.popMsg, self.toTestFolderSetting) }, {}, {}), bdData={'font': self.app.confMsgBdFont})) #plot number self.pushMsg( msg.Message(self.app, self, self.disp, 'Confirm/edit plot number.', 'Current plot number: ' + str(self.app.getSetting(d.TEST_PLOT)), btnDefs=({ 'label': 'CONFIRM', 'id': 'yesBtn', 'funct': self.popMsg }, { 'label': 'EDIT', 'id': 'yesBtn', 'funct': (self.popMsg, self.toPlotSetting) }, {}, {}), bdData={'font': self.app.confMsgBdFont})) #test height self.pushMsg( msg.Message(self.app, self, self.disp, 'Confirm/edit test height.', 'Current test height: ' + str(self.app.getSetting(d.TEST_HEIGHT)) + 'cm', btnDefs=({ 'label': 'CONFIRM', 'id': 'yesBtn', 'funct': self.popMsg }, { 'label': 'EDIT', 'id': 'yesBtn', 'funct': (self.popMsg, self.toHeightSetting) }, {}, {}), bdData={'font': self.app.confMsgBdFont})) #plot preTestNotes preTestNotes = self.app.getSetting(d.PRE_TEST_NOTES) self.pushMsg( msg.Message(self.app, self, self.disp, 'Confirm/edit pre-test notes.', 'Current pre-test notes: ' + ', '.join(preTestNotes), btnDefs=({ 'label': 'CONFIRM', 'id': 'yesBtn', 'funct': self.popMsg }, { 'label': 'EDIT', 'id': 'yesBtn', 'funct': (self.popMsg, self.toNoteSetting) }, {}, {}), bdData={'font': self.app.confMsgBdFont})) self.pushMsg( msg.Message(self.app, self, self.disp, 'Confirm test operator.', 'Current operator is: ' + self.app.getSetting(d.OPERATOR), btnDefs=({ 'label': 'CONFIRM', 'id': 'yesBtn', 'funct': self.popMsg }, { 'label': 'EDIT', 'id': 'yesBtn', 'funct': (self.popMsg, self.setOperator) }, {}, {}), bdData={'font': self.app.confMsgBdFont}))