def main(): if options.reset: print("Clearing all configuration values.") try: os.remove(os.path.expanduser('~/.config/spiro/spiro.conf')) except OSError as e: print("Could not remove file (~/.config/spiro/spiro.conf):", e.strerror) raise if options.install: print("Installing systemd service file.") installService() if options.resetpw: print("Resetting web UI password.") cfg.set('password', '') if options.toggle_debug: cfg.set('debug', not cfg.get('debug')) if cfg.get('debug'): print("Debug mode on.") else: print("Debug mode off") if any([ options.reset, options.resetpw, options.install, options.toggle_debug ]): sys.exit() # no options given, go ahead and start web ui global cam gpio.setmode(gpio.BCM) hw.GPIOInit() cam = initCam() log('Starting web UI.') webui.start(cam, hw)
def experiment(): if request.method == 'POST': if request.form['action'] == 'start': if experimenter.running: flash("Experiment is already running.") else: if request.form.get('duration'): experimenter.duration = int(request.form['duration']) else: experimenter.duration = 7 if request.form.get('delay'): experimenter.delay = int(request.form['delay']) else: experimenter.delay = 60 if request.form.get('directory'): experimenter.dir = os.path.expanduser(os.path.join('~', request.form['directory'].replace('/', '-'))) else: experimenter.dir = os.path.expanduser('~') setLive('off') log("Starting new experiment.") experimenter.next_status = 'run' experimenter.status_change.set() # give thread time to start before presenting template time.sleep(1) elif request.form['action'] == 'stop': experimenter.stop() time.sleep(1) if os.path.exists(experimenter.dir): df = shutil.disk_usage(experimenter.dir) else: df = shutil.disk_usage(os.path.expanduser('~')) diskspace = round(df.free / 1024 ** 3, 1) diskreq = round(experimenter.nshots * 4 * 10 / 1024, 1) return render_template('experiment.html', running=experimenter.running, directory=experimenter.dir, starttime=time.ctime(experimenter.starttime), delay=experimenter.delay, endtime=time.ctime(experimenter.endtime), diskspace=diskspace, duration=experimenter.duration, status=experimenter.status, nshots=experimenter.nshots + 1, diskreq=diskreq, name=cfg.get('name'))
def newpass(): if request.method == 'POST': currpass = request.form['currpass'] pwd1 = request.form['pwd1'] pwd2 = request.form['pwd2'] if cfg.get('password') != '': if not checkPass(currpass): flash("Current password incorrect.") return render_template('newpass.html', name=cfg.get('name')) if pwd1 == pwd2: hash = hashlib.sha1(pwd1.encode('utf-8')) cfg.set('password', hash.hexdigest()) session['password'] = pwd1 flash("Password was changed.") log("Password was changed.") return redirect(url_for('index')) else: flash("Passwords do not match.") return redirect(url_for('newpass')) else: return render_template('newpass.html', nopass=cfg.get('password') == '', name=cfg.get('name'))
def stop_ap(): log("Disabling services...") init() config_dhcpcd(enable=False) p = subprocess.run(['systemctl', 'restart', 'dhcpcd'], capture_output=True) disable_services() log("Access point disabled.")
def login(): if request.method == 'POST': pwd = request.form['password'] if checkPass(pwd): session['password'] = pwd log("Web user successfully logged in.") return redirect(url_for('index')) else: flash("Incorrect password.") log("Incorrect password in web login.") return redirect(url_for('login')) else: return render_template('login.html', name=cfg.get('name'))
def terminate(sig, frame): global shutdown if sig == signal.SIGALRM: # force shutdown debug("Shut down time-out, force-quitting.") debug("If the software locks up at this point, a reboot is needed.") debug("This is due to a bug in the underlying camera code.") cam.close() sys.exit() if not shutdown: # give the app 10 seconds to shut down, then force it shutdown = True signal.alarm(10) log("Signal " + str(sig) + " caught -- shutting down.") webui.stop() hw.motorOn(False) cam.close() hw.cleanup() sys.exit()
def findStart(self, calibration=None): """rotates the imaging stage until the positional switch is activated""" calibration = calibration or self.cfg.get('calibration') timeout = 60 starttime = time.time() # make sure that switch is not depressed when starting if gpio.input(self.pins['sensor']): while gpio.input( self.pins['sensor']) and time.time() < starttime + timeout: self.halfStep(1, 0.03) while not gpio.input( self.pins['sensor']) and time.time() < starttime + timeout: self.halfStep(1, 0.03) if time.time() < starttime + timeout: self.halfStep(calibration, 0.03) else: log("Timed out while finding start position! Images will be misaligned." )
def stop(self): self.status = "Stopping" self.next_status = '' self.stop_experiment = True log("Stopping running experiment...")
def runExperiment(self): if self.running: raise RuntimeError('An experiment is already running.') try: debug("Starting experiment.") self.running = True self.status = "Initiating" self.starttime = time.time() self.endtime = time.time() + 60 * 60 * 24 * self.duration self.last_captured = None self.delay = self.delay or 0.001 self.nshots = self.duration * 24 * 60 // self.delay self.cam.exposure_mode = "auto" self.cam.shutter_speed = 0 self.hw.LEDControl(False) for i in range(4): platedir = "plate" + str(i + 1) os.makedirs(os.path.join(self.dir, platedir), exist_ok=True) while time.time() < self.endtime and not self.stop_experiment: loopstart = time.time() nextloop = time.time() + 60 * self.delay if nextloop > self.endtime: nextloop = self.endtime for i in range(4): # rotate stage to starting position if i == 0: self.hw.motorOn(True) self.status = "Finding start position" debug("Finding initial position.") self.hw.findStart( calibration=self.cfg.get('calibration')) debug("Found initial position.") else: self.status = "Imaging" # rotate cube 90 degrees debug("Rotating stage.") self.hw.halfStep(100, 0.03) # wait for the cube to stabilize time.sleep(0.5) now = time.strftime("%Y%m%d-%H%M%S", time.localtime()) name = os.path.join("plate" + str(i + 1), "plate" + str(i + 1) + "-" + now) self.takePicture(name) self.nshots -= 1 self.hw.motorOn(False) self.status = "Waiting" if self.idlepos > 0: # alternate between resting positions during idle, stepping 45 degrees per image self.hw.motorOn(True) self.hw.halfStep(50 * self.idlepos, 0.03) self.hw.motorOn(False) self.idlepos += 1 if self.idlepos > 7: self.idlepos = 0 while time.time() < nextloop and not self.stop_experiment: # keep rotating while waiting, similar light conditions for each plate self.hw.motorOn(True) self.hw.halfStep(21, 0.03) self.hw.motorOn(False) time.sleep(60) finally: log("Experiment stopped.") self.cam.color_effects = None self.status = "Stopped" self.stop_experiment = False self.running = False self.cam.exposure_mode = "auto" self.cam.meter_mode = 'spot'
def runExperiment(self): if self.running: raise RuntimeError('An experiment is already running.') try: debug("Starting experiment.") self.running = True self.status = "Initiating" self.starttime = time.time() self.endtime = time.time() + 60 * 60 * 24 * self.duration self.last_captured = None self.delay = self.delay or 0.001 self.nshots = self.duration * 24 * 60 // self.delay self.cam.exposure_mode = "auto" self.cam.shutter_speed = 0 self.hw.LEDControl(False) for i in range(4): platedir = "plate" + str(i + 1) os.makedirs(os.path.join(self.dir, platedir), exist_ok=True) while time.time() < self.endtime and not self.stop_experiment: loopstart = time.time() nextloop = time.time() + 60 * self.delay if nextloop > self.endtime: nextloop = self.endtime for i in range(4): # rotate stage to starting position if i == 0: self.hw.motorOn(True) self.status = "Finding start position" debug("Finding initial position.") self.hw.findStart( calibration=self.cfg.get('calibration')) debug("Found initial position.") else: self.status = "Imaging" # rotate cube 90 degrees debug("Rotating stage.") self.hw.halfStep(100, 0.03) # wait for the cube to stabilize time.sleep(0.5) now = time.strftime("%Y%m%d-%H%M%S", time.localtime()) name = os.path.join("plate" + str(i + 1), "plate" + str(i + 1) + "-" + now) self.takePicture(name) self.nshots -= 1 self.hw.motorOn(False) # this part is "active waiting", rotating the cube slowly over the period of options.delay # this ensures consistent lighting for all plates. # account for the time spent capturing images. self.status = "Waiting" secs = 0 while time.time() < nextloop and not self.stop_experiment: time.sleep(1) secs += 1 if self.delay > 15 and secs == int(self.delay / 7.5): # don't bother if delay is very short (<= 15 min) secs = 0 self.hw.motorOn(True) self.hw.halfStep(50, 0.03) self.hw.motorOn(False) finally: log("Experiment stopped.") self.cam.color_effects = None self.status = "Stopped" self.stop_experiment = False self.running = False self.cam.exposure_mode = "auto" self.cam.meter_mode = 'spot'
def start_ap(): log("Setting up dependencies...") init() install_reqs() log("Configuring system...") config_dhcpcd(enable=True) config_dnsmasq() ssid, pwd = config_hostapd() log("Starting services...") enable_services() r = restart_services() if not r: log("Failed to restart services.") log("Setting up access point failed.") return (1) else: log("Access point configured and enabled. Below are the details for connecting to it:" ) log("\nSSID: " + ssid) log("Password: "******"\nConnect to the web interface using the address http://spiro.local" ) return (0)