def update(self, new_data): ro_props = [x for x in new_data.keys() if x in self.ro_props] unsupported_props = [ x for x in new_data.keys() if x not in self.rw_props ] if ro_props: raise BadRequestError( 'The following settings are read only and cannot be updated: {}' .format(', '.join(ro_props))) if unsupported_props: raise BadRequestError( 'The following settings are invalid: {}'.format( ', '.join(unsupported_props))) if 'server_name' in new_data: new_data[ 'autogenerated_access_points_ssid'] = self.__autogenerated_access_point_ssid( server_name=new_data['server_name']) on_update_args = [(x, getattr(self, x), new_data[x]) for x in new_data.keys()] self.json_map.update(new_data) if 'log_level' in new_data: self.update_log_level() redis_client.dict_set('settings', self.to_map()) for on_update_listener in self.on_update: for new_item in on_update_args: on_update_listener(*new_item)
def __start_slew_solver(self, options): if not 'cameraOptions' in options: raise BadRequestError( 'You need to capture from camera when using Slew mode') if not 'target' in options: raise BadRequestError('You need a target when using Slew mode') if not 'telescope' in options: raise BadRequestError('You need a telescope when using Slew mode') self.solver_thread = start_thread(self.__slew_solver_thread, options) return self.to_map()
def shoot(self, guider_id, exposure, initial_pause): if exposure < 30: raise BadRequestError('Exposure should be at least 30 seconds') guider = [ g for g in controller.indi_server.guiders() if g.id == guider_id ] if not guider: raise BadRequestError('Guider not found: {} (guiders: {})'.format( guider_id, ', '.join([g.id for g in controller.indi_server.guiders()]))) start_thread(self.__darv, guider[0], exposure, initial_pause) return {'started': 'ok'}
def start(self, binary_path='/usr/bin/phd2', display=None): if self.running: raise BadRequestError('PHD2 is already running') try: if not binary_path or not display: raise BadRequestError( 'Both PHD2 binary path and display must be specified') phd2_env = os.environ.copy() phd2_env['DISPLAY'] = display self.__process = subprocess.Popen(['phd2'], env=phd2_env) return {'started': self.running} except Exception as e: raise FailedMethodError(str(e))
def __execute(self, *args, **kwargs): try: return self.__service.execute(*args, **kwargs) except PHD2ConnectionError as e: raise BadRequestError(e.message) except PHD2MethodError as e: raise FailedMethodError(str(e))
def stop_stale(self): if self.status != 'stale': raise BadRequestError('Sequence not stale') self.status = 'stopped' for job in self.sequence_jobs: if job.status == 'running': job.status = 'stopped'
def update(self, data): if 'name' not in data and 'drivers' not in data: raise BadRequestError( 'Invalid json: either name or drivers must be specified') if 'name' in data: self.name = data['name'] if 'drivers' in data: self.drivers = data['drivers']
def run(self, sequence_id): if not self.controller.indi_server.is_connected(): raise BadRequestError('INDI server not connected.') sequence = self.controller.sequences.lookup(sequence_id) def cleanup_sequence(_): del self.running_sequences[sequence_id] running_sequence = RunningSequence(sequence, self.controller, self.logger, on_finished=cleanup_sequence) self.running_sequences[sequence_id] = running_sequence
def update(self, new_data): ro_props = [x for x in new_data.keys() if x in self.ro_props] unsupported_props = [x for x in new_data.keys() if x not in self.rw_props] if ro_props: raise BadRequestError('The following settings are read only and cannot be updated: {}'.format(', '.join(ro_props))) if unsupported_props: raise BadRequestError('The following settings are invalid: {}'.format(', '.join(unsupported_props))) on_update_args = [(x, getattr(self, x), new_data[x]) for x in new_data.keys()] self.json_map.update(new_data) if 'log_level' in new_data: self.update_log_level() redis_client.dict_set('settings', self.to_map()) if self.on_update: for new_item in on_update_args: self.on_update(*new_item)
def stop(self): if not self.running: raise BadRequestError('PHD2 is not running') self.__process.terminate() try: self.__process.wait(timeout=5) return {'stopped': not self.running} except Exception as e: raise FailedMethodError(str(e))
def download(self, arcminutes): if self.__download_thread: raise BadRequestError('Already downloading') self.downloaded = 0 fov_limit = arcminutes * 0.1 files = [f for f in astrometry_indexes if f['arcminutes'] >= fov_limit] self.__download_thread = threading.Thread( target=functools.partial(self.__download, files)) self.__download_thread.start() return {'files': files, 'path': settings.astrometry_path()}
def stop(self, on_update=None): if not self.is_running() or not self.running_sequence_job: raise BadRequestError('Sequence not running') self.stopped = True self.status = 'stopping' if on_update: on_update() self.running_sequence_job.stop() self.status = 'stopped' if on_update: on_update()
def solve_field(self, options): if not self.is_available(): raise BadRequestError( 'Astrometry.net solve-field not found in {}'.format( settings.astrometry_solve_field_path)) self.__set_status('solving') if not options['slewTelescope']: return self.__start_solver(options) else: return self.__start_slew_solver(options)
def abort(self): if self.status != 'solving': raise BadRequestError('Solver is not running') self.__set_status('abort') if self.solver_process and self.solver_process_cancel_file: with open(self.solver_process_cancel_file, 'w') as f: f.write('abort') self.solver_process.wait() self.solver_process = None if self.solver_thread: self.solver_thread.join() self.solver_thread = None return self.to_map()
def __validate(self, format_string): test_params = { 'exposure': 1, 'number': 2, 'timestamp': 1, 'datetime': 'date-string', 'filter': 'filter-name', 'filter_index': 1 } if not os.path.splitext(format_string.lower())[1] in ['.fit', '.fits']: raise BadRequestError('Unrecognized file extension') try: first_string = format_string.format(**test_params) test_params['number'] = 200 if first_string == format_string.format(**test_params): raise BadRequestError( '"number" parameter not present in format string: {}'. format(format_string)) except KeyError as e: raise BadRequestError( 'Bad filename template: {} parameter not valid'.format( e.args[0]))
def __data_to_fits(self, data, temp_path): temp_upload_prefix = os.path.join(temp_path, 'solve_field_input') fits_file_path = temp_upload_prefix + '.fits' with open(temp_upload_prefix, 'wb') as file: file.write(data) if self.__check_fits_file(temp_upload_prefix): shutil.move(temp_upload_prefix, fits_file_path) else: if not self.__img_to_fits( temp_upload_prefix, fits_file_path, remove=True): raise BadRequestError( 'File is not a FITS nor a recognizable image format') return fits_file_path
def guide(self, direction, duration): property_values = { 'north': ('NS', 'N'), 'south': ('NS', 'S'), 'west': ('WE', 'W'), 'east': ('WE', 'E'), } try: guide_axis, guide_direction = property_values[direction] except KeyError: raise BadRequestError('Bad guide direction: {}'.format(direction)) guide_property = self.device.get_property( 'TELESCOPE_TIMED_GUIDE_{}'.format(guide_axis)) guide_property.set_values( {'TIMED_GUIDE_{}'.format(guide_direction): int(1000 * duration)}) return self.guider_status()
def __start_solver(self, options): temp_path = os.path.join(StaticSettings.ASTROMETRY_TEMP_PATH, 'solve_field_{}'.format(time.time())) os.makedirs(temp_path, exist_ok=True) fits_file_path = None logger.debug('Solve field options: %s', self.__platesolving_options_log(options)) if 'fileBuffer' in options: data = base64.b64decode( options['fileBuffer'] [options['fileBuffer'].find(PlateSolving.DATAURL_SEPARATOR) + len(PlateSolving.DATAURL_SEPARATOR):]) fits_file_path = self.__data_to_fits(data, temp_path) elif 'filePath' in options and os.path.isfile(options['filePath']): fits_file_path = options['filePath'] elif 'cameraOptions' in options: from system import controller cameraOptions = options['cameraOptions'] camera = controller.indi_server.get_camera( cameraOptions['camera']['id']) logger.debug('Shooting on camera {} with options {}'.format( camera, cameraOptions)) result = camera.shoot_image(cameraOptions) logger.debug('Shoot successfull: {}'.format(result)) fits_file_path = result['filename'] else: raise BadRequestError( 'You must pass either a fileBuffer object (data-uri formatted) or a filePath argument' ) resolution = None with fits.open(fits_file_path) as fits_file: resolution = fits_file[0].data.shape if options.get('sync', False): return self.__wait_for_solution(options, resolution, fits_file_path, temp_path) else: self.solver_thread = start_thread(self.__async_wait_for_solution, options, resolution, fits_file_path, temp_path) return self.to_map()
def convert(self, args): key = '&'.join( ['{}={}'.format(key, value) for key, value in args.items()]) key = hashlib.md5(key.encode()).hexdigest() format_name = args.get('format', 'jpeg') if format_name == 'original': return self.__file_info(self.path, format_name) if key not in self.cached_conversions: if format_name not in Image.FORMATS: raise BadRequestError( 'Unrecognized format: {}'.format(format_name)) format = Image.FORMATS[format_name] filename = '{}_{}.{}'.format(self.id, key, format['extension']) filepath = os.path.join(self.directory, filename) self.__convert(args, filepath, format) self.cached_conversions[key] = self.__file_info( filepath, format_name, format['content_type']) return self.cached_conversions[key]
def set_content_type(): e = request.environ c.render_style = e['render_style'] c.response_content_type = e['content_type'] if e.has_key('extension'): c.extension = ext = e['extension'] if ext in ('embed', 'wired', 'widget'): def to_js(content): return utils.to_js(content, callback=request.params.get( "callback", "document.write")) c.response_wrappers.append(to_js) if ext in ("rss", "api", "json") and request.method.upper() == "GET": user = valid_feed(request.GET.get("user"), request.GET.get("feed"), request.path) if user and not g.read_only_mode: c.user = user c.user_is_loggedin = True if ext in ("mobile", "m") and not request.GET.get("keep_extension"): try: if request.cookies['reddit_mobility'] == "compact": c.extension = "compact" c.render_style = "compact" except (ValueError, KeyError): c.suggest_compact = True if ext in ("mobile", "m", "compact"): if request.GET.get("keep_extension"): c.cookies['reddit_mobility'] = Cookie(ext, expires=NEVER) # allow JSONP requests to generate callbacks, but do not allow # the user to be logged in for these callback = request.GET.get("jsonp") if is_api() and request.method.upper() == "GET" and callback: if not valid_jsonp_callback(callback): abort(BadRequestError(errors.BAD_JSONP_CALLBACK)) c.allowed_callback = callback c.user = UnloggedUser(get_browser_langs()) c.user_is_loggedin = False
def __init__(self, data): self.id = random_id(data.get('id')) self.type = data['type'] data.update({'id': self.id}) self.job = None if self.type == 'shots': self.job = ExposureSequenceJob(data) elif self.type == 'filter': self.job = FilterWheelSequenceJob(data) elif self.type == 'property': self.job = PropertySequenceJob(data) elif self.type == 'command': self.job = CommandSequenceJob(data) elif self.type == 'pause': self.job = PauseSequenceJob(data) else: raise BadRequestError('Invalid sequence job type: {}'.format( self.type)) self.status = data.get('status', 'idle') self.started_ts, self.finished_ts = None, None self.stopped = False
def get_drift(self): if len(polar_alignment_platesolving_capture.captures) != 2: raise BadRequestError('You need to execute two captures') dec_drift = polar_alignment_platesolving_capture.coordinates(0).dec - polar_alignment_platesolving_capture.coordinates(1).dec return { 'declination_drift': dec_drift.deg }
def disconnect(self): if not self.__thread: return BadRequestError('PHD2 Not connected') self.__connect = False self.__thread.join()
def f_wrapper(*args, **kwargs): if not controller.indi_server.is_connected(): raise BadRequestError('INDI server not connected') return f(*args, **kwargs)
def import_catalog(self, name): if name == 'ngc_ic': return self.import_ngc_ic() raise BadRequestError('Catalog {} not supported'.format(name))