def decoding_depth(self): pm = Config.get() # return global default if "js8_decoding_depth" in pm: return pm["js8_decoding_depth"] # default when no setting is provided return 3
def start(): if not Config.get()["services_enabled"]: return for source in SdrService.getSources().values(): props = source.getProps() if "services" not in props or props["services"] is not False: Services.handlers.append(ServiceHandler(source))
def deleteProfile(self): if self.profile_id is None: return self.send_response("profile not found", code=404) config = Config.get() del self.device["profiles"][self.profile_id] config.store() return self.send_redirect("{}settings/sdr/{}".format(self.get_document_root(), quote(self.device_id)))
def getSunTimes(self, date): pm = Config.get() lat = pm["receiver_gps"]["lat"] lng = pm["receiver_gps"]["lon"] degtorad = math.pi / 180 radtodeg = 180 / math.pi #Number of days since 01/01 days = date.timetuple().tm_yday # Longitudinal correction longCorr = 4 * lng # calibrate for solstice b = 2 * math.pi * (days - 81) / 365 # Equation of Time Correction eoTCorr = 9.87 * math.sin(2 * b) - 7.53 * math.cos(b) - 1.5 * math.sin(b) # Solar correction solarCorr = longCorr + eoTCorr # Solar declination declination = math.asin(math.sin(23.45 * degtorad) * math.sin(b)) sunrise = 12 - math.acos(-math.tan(lat * degtorad) * math.tan(declination)) * radtodeg / 15 - solarCorr / 60 sunset = 12 + math.acos(-math.tan(lat * degtorad) * math.tan(declination)) * radtodeg / 15 - solarCorr / 60 midnight = datetime.combine(date, datetime.min.time()) sunrise = midnight + timedelta(hours=sunrise) sunset = midnight + timedelta(hours=sunset) logger.debug("for {date} sunrise: {sunrise} sunset {sunset}".format(date=date, sunrise=sunrise, sunset=sunset)) return sunrise, sunset
def uploadSpot(self, spot): config = Config.get() # function=wspr&date=210114&time=1732&sig=-15&dt=0.5&drift=0&tqrg=7.040019&tcall=DF2UU&tgrid=JN48&dbm=37&version=2.3.0-rc3&rcall=DD5JFK&rgrid=JN58SC&rqrg=7.040047&mode=2 # {'timestamp': 1610655960000, 'db': -23.0, 'dt': 0.3, 'freq': 7040048, 'drift': -1, 'msg': 'LA3JJ JO59 37', 'callsign': 'LA3JJ', 'locator': 'JO59', 'mode': 'WSPR'} date = datetime.fromtimestamp(spot["timestamp"] / 1000, tz=timezone.utc) data = parse.urlencode( { "function": "wspr", "date": date.strftime("%y%m%d"), "time": date.strftime("%H%M"), "sig": spot["db"], "dt": spot["dt"], # FST4W does not have drift "drift": spot["drift"] if "drift" in spot else 0, "tqrg": spot["freq"] / 1e6, "tcall": spot["callsign"], "tgrid": spot["locator"], "dbm": spot["dbm"], "version": openwebrx_version, "rcall": config["wsprnet_callsign"], "rgrid": Locator.fromCoordinates(config["receiver_gps"]), "mode": self._getMode(spot), } ).encode() request.urlopen("http://wsprnet.org/post/", data, timeout=60)
def handleSdrAvailable(self): # send initial config self.getDsp().setProperties(self.connectionProperties) stack = PropertyStack() stack.addLayer(0, self.sdr.getProps()) stack.addLayer(1, Config.get()) configProps = stack.filter(*OpenWebRxReceiverClient.config_keys) def sendConfig(key, value): config = configProps.__dict__() # TODO mathematical properties? hmmmm config["start_offset_freq"] = configProps["start_freq"] - configProps["center_freq"] # TODO this is a hack to support multiple sdrs config["sdr_id"] = self.sdr.getId() self.write_config(config) cf = configProps["center_freq"] srh = configProps["samp_rate"] / 2 frequencyRange = (cf - srh, cf + srh) self.write_dial_frequendies(Bandplan.getSharedInstance().collectDialFrequencies(frequencyRange)) bookmarks = [b.__dict__() for b in Bookmarks.getSharedInstance().getBookmarks(frequencyRange)] self.write_bookmarks(bookmarks) self.configSub = configProps.wire(sendConfig) sendConfig(None, None) self.__sendProfiles() self.sdr.addSpectrumClient(self)
def store(self): # need to overwrite the existing key in the config since the layering won't capture the changes otherwise config = Config.get() sdrs = config["sdrs"] sdrs[self.device_id] = self.device config["sdrs"] = sdrs super().store()
def __init__(self, id, props): self.id = id self.commandMapper = None self.props = PropertyStack() # layer 0 reserved for profile properties self.props.addLayer(1, props) self.props.addLayer(2, Config.get()) self.sdrProps = self.props.filter(*self.getEventNames()) self.profile_id = None self.activateProfile() self.wireEvents() if "port" in props and props["port"] is not None: self.port = props["port"] else: self.port = getAvailablePort() self.monitor = None self.clients = [] self.spectrumClients = [] self.spectrumThread = None self.process = None self.modificationLock = threading.Lock() self.failed = False self.state = SdrSource.STATE_STOPPED self.busyState = SdrSource.BUSYSTATE_IDLE if self.isAlwaysOn(): self.start()
def __init__(self, handler, request, options): pm = Config.get() path = pm["aprs_symbols_path"] if not path.endswith("/"): path += "/" self.path = path super().__init__(handler, request, options)
def start(): config = Config.get() config.wireProperty("services_enabled", Services._receiveEnabledEvent) activeSources = SdrService.getActiveSources() activeSources.wire(Services._receiveDeviceEvent) for key, source in activeSources.items(): Services.schedulers[key] = ServiceScheduler(source)
def getReceiverInformationHeader(self): pm = Config.get() with_antenna = "pskreporter_antenna_information" in pm and pm[ "pskreporter_antenna_information"] is not None num_fields = 4 if with_antenna else 3 length = 12 + num_fields * 8 return bytes( # id [0x00, 0x03] # length + list(length.to_bytes(2, "big")) + Uploader.receieverDelimiter # number of fields + list(num_fields.to_bytes(2, "big")) # padding + [0x00, 0x00] # receiverCallsign + [0x80, 0x02, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F] # receiverLocator + [0x80, 0x04, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F] # decodingSoftware + [0x80, 0x08, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F] # antennaInformation + ([0x80, 0x09, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F] if with_antenna else []) # padding + [0x00, 0x00])
def __init__(self, conn): super().__init__(conn) pm = Config.get() self.write_config(pm.filter("google_maps_api_key", "receiver_gps", "map_position_retention_time").__dict__()) Map.getSharedInstance().addClient(self)
def enrich(self, meta, callback): config_key = "digital_voice_{}_id_lookup".format(self.mode) if not Config.get()[config_key]: return meta if "source" not in meta: return meta id = int(meta["source"]) cache = RadioIDCache.getSharedInstance() if not cache.isValid(self.mode, id): if id not in self.threads: self.threads[id] = threading.Thread(target=self._fillCache, args=[id], daemon=True) self.threads[id].start() if id not in self.callbacks: self.callbacks[id] = [] def onFinish(data): if data is not None: meta["additional"] = data callback(meta) self.callbacks[id].append(onFinish) return meta data = cache.get(self.mode, id) if data is not None: meta["additional"] = data return meta
def setupService(self, mode, frequency, source): logger.debug("setting up service {0} on frequency {1}".format( mode, frequency)) # TODO selecting outputs will need some more intelligence here if mode == "packet": output = AprsServiceOutput(frequency) elif mode == "js8": output = Js8ServiceOutput(frequency) else: output = WsjtServiceOutput(frequency) d = dsp(output) d.nc_port = source.getPort() center_freq = source.getProps()["center_freq"] d.set_offset_freq(frequency - center_freq) d.set_center_freq(center_freq) if mode == "packet": d.set_demodulator("nfm") d.set_bpf(-4000, 4000) elif mode == "wspr": d.set_demodulator("usb") # WSPR only samples between 1400 and 1600 Hz d.set_bpf(1350, 1650) else: d.set_demodulator("usb") d.set_bpf(0, 3000) d.set_secondary_demodulator(mode) d.set_audio_compression("none") d.set_samp_rate(source.getProps()["samp_rate"]) d.set_temporary_directory(Config.get()['temporary_directory']) d.set_service() d.start() return d
def getSharedInstance(): with DecoderQueue.creationLock: if DecoderQueue.sharedInstance is None: pm = Config.get() DecoderQueue.sharedInstance = DecoderQueue( maxsize=pm["decoding_queue_length"], workers=pm["decoding_queue_workers"]) return DecoderQueue.sharedInstance
def _start(self): self.running = True self.source.addClient(self) props = self.source.getProps() self.activitySub = props.filter("center_freq", "samp_rate").wire(self.onFrequencyChange) self.decodersSub = Config.get().wireProperty("services_decoders", self.onFrequencyChange) if self.source.isAvailable(): self._scheduleServiceStartup()
def __init__(self): config = Config.get() if "waterfall_colors" in config and config["waterfall_colors"]: colors = config["waterfall_colors"] else: # fallback: black and white colors = [0x000000, 0xffffff] super().__init__(colors)
def getSharedInstance(): with PskReporter.creationLock: if PskReporter.sharedInstance is None: if Config.get()["pskreporter_enabled"]: PskReporter.sharedInstance = PskReporter() else: PskReporter.sharedInstance = PskReporterDummy() return PskReporter.sharedInstance
def template_variables(self): settingslink = "" pm = Config.get() if "webadmin_enabled" in pm and pm["webadmin_enabled"]: settingslink = """<a class="button" href="settings" target="openwebrx-settings"><img src="static/gfx/openwebrx-panel-settings.png" alt="Settings"/><br/>Settings</a>""" header = self.render_template("include/header.include.html", settingslink=settingslink) return {"header": header}
def removeOldPositions(self): pm = Config.get() retention = timedelta(seconds=pm["map_position_retention_time"]) cutoff = datetime.now() - retention to_be_removed = [callsign for (callsign, pos) in self.positions.items() if pos["updated"] < cutoff] for callsign in to_be_removed: self.removeLocation(callsign)
def command_is_runnable(self, command): tmp_dir = Config.get()["temporary_directory"] cmd = shlex.split(command) try: process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=tmp_dir) return process.wait() != 32512 except FileNotFoundError: return False
def deleteDevice(self): if self.device_id is None: return self.send_response("device not found", code=404) config = Config.get() sdrs = config["sdrs"] del sdrs[self.device_id] # need to overwrite the existing key in the config since the layering won't capture the changes otherwise config["sdrs"] = sdrs config.store() return self.send_redirect("{}settings/sdr".format(self.get_document_root()))
def __init__(self): super().__init__( Config.get(), "receiver_name", "receiver_location", "receiver_asl", "receiver_gps", "photo_title", "photo_desc", )
def store(self): # need to overwrite the existing key in the config since the layering won't capture the changes otherwise config = Config.get() sdrs = config["sdrs"] # a uuid should be unique, so i'm not sure if there's a point in this check if self.device_id in sdrs: raise ValueError("device {} already exists!".format(self.device_id)) sdrs[self.device_id] = self.data_layer config["sdrs"] = sdrs super().store()
def decoding_depth(self, mode): pm = Config.get() # mode-specific setting? if "wsjt_decoding_depths" in pm and mode in pm["wsjt_decoding_depths"]: return pm["wsjt_decoding_depths"][mode] # return global default if "wsjt_decoding_depth" in pm: return pm["wsjt_decoding_depth"] # default when no setting is provided return 3
def __init__(self, dsp, source, profile: AudioChopperProfile): self.dsp = dsp self.source = source self.profile = profile self.tmp_dir = Config.get()["temporary_directory"] self.wavefile = None self.wavefilename = None self.switchingLock = threading.Lock() self.timer = None (self.outputReader, self.outputWriter) = Pipe()
def handle_request(self): config = Config.get() if "webadmin_enabled" not in config or not config["webadmin_enabled"]: self.send_response("Web Admin is disabled", code=403) return if self.authentication.isAuthenticated(self.request): super().handle_request() else: target = "/login?{0}".format( parse.urlencode({"ref": self.request.path})) self.send_redirect(target)
def findKey(challenge): def parseKey(keyString): try: return Key(keyString) except KeyException as e: logger.error(e) keys = [parseKey(keyString) for keyString in Config.get()['receiver_keys']] keys = [key for key in keys if key is not None] matching_keys = [key for key in keys if key.source == challenge.source and key.id == challenge.id] if matching_keys: return matching_keys[0] return None
def getReceiverInformation(self): pm = Config.get() callsign = pm["pskreporter_callsign"] locator = Locator.fromCoordinates(pm["receiver_gps"]) decodingSoftware = "OpenWebRX " + openwebrx_version body = [ b for s in [callsign, locator, decodingSoftware] for b in self.encodeString(s) ] body = self.pad(body, 4) body = bytes(Uploader.receieverDelimiter + list((len(body) + 4).to_bytes(2, "big")) + body) return body
def _receiveDeviceEvent(changes): for key, source in changes.items(): if source is PropertyDeleted: if key in Services.handlers: Services.handlers[key].shutdown() del Services.handlers[key] if key in Services.schedulers: Services.schedulers[key].shutdown() del Services.schedulers[key] else: Services.schedulers[key] = ServiceScheduler(source) if Config.get()["services_enabled"]: Services.handlers[key] = ServiceHandler(source)