class RTKLIB: # we will save RTKLIB state here for later loading state_file = "/home/reach/.reach/rtk_state" def __init__(self, socketio, enable_led = True, rtkrcv_path = None, config_path = None, str2str_path = None, gps_cmd_file_path = None, log_path = None): # default state for RTKLIB is "rover single" self.state = "rover" # we need this to broadcast stuff self.socketio = socketio # these are necessary to handle rover mode self.rtkc = RtkController(rtkrcv_path, config_path) self.conm = ConfigManager(config_path) # this one handles base settings self.s2sc = Str2StrController(str2str_path, gps_cmd_file_path) # take care of serving logs self.logm = LogManager(log_path) # basic synchronisation to prevent errors self.semaphore = Semaphore() # we need this to send led signals self.enable_led = enable_led if self.enable_led: self.led = ReachLED() # broadcast satellite levels and status with these self.server_not_interrupted = True self.satellite_thread = None self.coordinate_thread = None # we try to restore previous state # in case we can't, we start as rover in single mode self.loadState() def launchRover(self, config_name = None): # config_name may be a name, or a full path # if the parameter contains "/", then we consider it a full path # else, we will be looking for it one directory higher than the rtkrcv bin self.semaphore.acquire() print("Attempting to launch rtkrcv...") if config_name == None: res = self.rtkc.launch() else: res = self.rtkc.launch(config_name) if res < 0: print("rtkrcv launch failed") elif res == 1: print("rtkrcv launch successful") self.state = "rover" elif res == 2: print("rtkrcv already launched") self.state = "rover" self.saveState() if self.enable_led: self.updateLED() print("Rover mode launched") self.semaphore.release() return res def shutdownRover(self): self.stopRover() self.semaphore.acquire() print("Attempting rtkrcv shutdown") res = self.rtkc.shutdown() if res < 0: print("rtkrcv shutdown failed") elif res == 1: print("rtkrcv shutdown successful") self.state = "inactive" elif res == 2: print("rtkrcv already shutdown") self.state = "inactive" self.saveState() if self.enable_led: self.updateLED() print("Rover mode shutdown") self.semaphore.release() return res def startRover(self): self.semaphore.acquire() print("Attempting to start rtkrcv...") res = self.rtkc.start() if res == -1: print("rtkrcv start failed") elif res == 1: print("rtkrcv start successful") print("Starting coordinate and satellite broadcast") elif res == 2: print("rtkrcv already started") # start fresh data broadcast self.server_not_interrupted = True if self.satellite_thread is None: self.satellite_thread = Thread(target = self.broadcastSatellites) self.satellite_thread.start() if self.coordinate_thread is None: self.coordinate_thread = Thread(target = self.broadcastCoordinates) self.coordinate_thread.start() self.saveState() if self.enable_led: self.updateLED() self.semaphore.release() return res def stopRover(self): self.semaphore.acquire() print("Attempting to stop RTKLIB...") res = self.rtkc.stop() if res == -1: print("rtkrcv stop failed") elif res == 1: print("rtkrcv stop successful") elif res == 2: print("rtkrcv already stopped") self.server_not_interrupted = False if self.satellite_thread is not None: self.satellite_thread.join() self.satellite_thread = None if self.coordinate_thread is not None: self.coordinate_thread.join() self.coordinate_thread = None self.saveState() if self.enable_led: self.updateLED() self.semaphore.release() return res def launchBase(self): # due to the way str2str works, we can't really separate launch and start # all the configuration goes to startBase() function # this launchBase() function exists to change the state of RTKLIB instance # and to make the process for base and rover modes similar self.semaphore.acquire() self.state = "base" self.saveState() if self.enable_led: self.updateLED() print("Base mode launched") self.semaphore.release() def shutdownBase(self): # due to the way str2str works, we can't really separate launch and start # all the configuration goes to startBase() function # this shutdownBase() function exists to change the state of RTKLIB instance # and to make the process for base and rover modes similar self.stopBase() self.semaphore.acquire() self.state = "inactive" self.saveState() if self.enable_led: self.updateLED() print("Base mode shutdown") self.semaphore.release() def startBase(self, rtcm3_messages = None, base_position = None, gps_cmd_file = None): self.semaphore.acquire() print("Attempting to start str2str...") if not self.rtkc.started: res = self.s2sc.start(rtcm3_messages, base_position, gps_cmd_file) if res < 0: print("str2str start failed") elif res == 1: print("str2str start successful") elif res == 2: print("str2str already started") else: print("Can't start str2str with rtkrcv still running!!!!") self.saveState() if self.enable_led: self.updateLED() self.semaphore.release() return res def stopBase(self): self.semaphore.acquire() print("Attempting to stop str2str...") res = self.s2sc.stop() if res == -1: print("str2str stop failed") elif res == 1: print("str2str stop successful") elif res == 2: print("str2str already stopped") self.saveState() if self.enable_led: self.updateLED() self.semaphore.release() return res def readConfigBase(self): self.semaphore.acquire() print("Got signal to read base config") self.socketio.emit("current config base", self.s2sc.readConfig(), namespace = "/test") self.semaphore.release() def writeConfigBase(self, config): self.semaphore.acquire() print("Got signal to write base config") self.s2sc.writeConfig(config) print("Restarting str2str...") res = self.s2sc.stop() + self.s2sc.start() if res > 1: print("Restart successful") else: print("Restart failed") self.saveState() if self.enable_led: self.updateLED() self.semaphore.release() return res def writeConfigRover(self, config): # config dict must include config_name field self.semaphore.acquire() if "config_file_name" not in config: config_file = None else: config_file = config["config_file_name"] print("Got signal to write rover config to file " + config_file) self.conm.writeConfig(config_file, config) self.conm.updateAvailableConfigs() # send available configs to the browser self.socketio.emit("available configs", {"available_configs": self.conm.available_configs}, namespace="/test") self.semaphore.release() def loadConfigRover(self, config_file = None): # we might want to write the config, but dont need to load it every time self.semaphore.acquire() if config_file == None: config_file == self.conm.default_rover_config print("Loading config " + config_file) # loading config to rtkrcv if self.rtkc.loadConfig(config_file) < 0: print("ERROR: failed to load config!!!") print("abort load") self.semaphore.release() return -1 print("load successful!") print("Now we need to restart rtkrcv for the changes to take effect") if self.rtkc.started: print("rtkrcv is already started, we need to do a simple restart!") res = self.rtkc.restart() if res == 3: print("Restart successful") print(config_file + " config loaded") elif res == 1: print("rtkrcv started instead of restart") elif res < 1: print("ERROR: rtkrcv restart failed") self.semaphore.release() self.saveState() return res else: print("We were not started before, so we need to perform a full start") self.semaphore.release() return self.startRover() def readConfigRover(self, config): self.semaphore.acquire() if "config_file_name" not in config: config_file = None else: config_file = config["config_file_name"] print("Got signal to read the rover config") print("Sending rover config " + config_file) # read from file self.conm.readConfig(config_file) # send to the browser self.socketio.emit("current config rover", self.conm.buffered_config.items, namespace="/test") self.semaphore.release() def shutdown(self): # shutdown whatever mode we are in. stop broadcast threads # clean up broadcast and blink threads self.server_not_interrupted = False self.led.blinker_not_interrupted = False if self.coordinate_thread is not None: self.coordinate_thread.join() if self.satellite_thread is not None: self.satellite_thread.join() if self.led.blinker_thread is not None: self.led.blinker_thread.join() # shutdown base or rover if self.state == "rover": return self.shutdownRover() elif self.state == "base": return self.shutdownBase() # otherwise, we are inactive return 1 def deleteConfig(self, config_name): # pass deleteConfig to conm print("Got signal to delete config " + config_name) self.conm.deleteConfig(config_name) self.conm.updateAvailableConfigs() # send available configs to the browser self.socketio.emit("available configs", {"available_configs": self.conm.available_configs}, namespace="/test") print(self.conm.available_configs) def resetConfigToDefault(self, config_name): # pass reset config to conm print("Got signal to reset config " + config_name) self.conm.resetConfigToDefault(config_name) self.conm.updateAvailableConfigs() # send available configs to the browser self.socketio.emit("available configs", {"available_configs": self.conm.available_configs}, namespace="/test") print(self.conm.available_configs) def saveState(self): # save current state for future resurrection: # state is a list of parameters: # rover state example: ["rover", "started", "reach_single_default.conf"] # base state example: ["base", "stopped", "input_stream", "output_stream"] state = {} # save "rover", "base" or "inactive" state state["state"] = self.state if self.state == "rover": started = self.rtkc.started elif self.state == "base": started = self.s2sc.started elif self.state == "inactive": started = False state["started"] = "yes" if started else "no" # dump rover state state["rover"] = {"current_config": self.rtkc.current_config} # dump rover state state["base"] = { "input_stream": self.s2sc.input_stream, "output_stream": self.s2sc.output_stream, "rtcm3_messages": self.s2sc.rtcm3_messages, "base_position": self.s2sc.base_position, "gps_cmd_file": self.s2sc.gps_cmd_file } print("DEBUG saving state") print(str(state)) with open(self.state_file, "w") as f: json.dump(state, f, sort_keys = True, indent = 4) return state def byteify(self, input): # thanks to Mark Amery from StackOverFlow for this awesome function if isinstance(input, dict): return {self.byteify(key): self.byteify(value) for key, value in input.iteritems()} elif isinstance(input, list): return [self.byteify(element) for element in input] elif isinstance(input, unicode): return input.encode('utf-8') else: return input def getState(self): # get the state, currently saved in the state file print("Trying to read previously saved state...") try: f = open(self.state_file, "r") except IOError: # can't find the file, let's create a new one with default state print("Could not find existing state, Launching default single rover mode...") return 1 else: print("Found existing state...trying to decode...") try: json_state = json.load(f) except ValueError: # could not properly decode current state print("Could not decode json state. Launching single rover mode as default...") f.close() return 1 else: print("Decoding succesful") f.close() # convert unicode strings to normal json_state = self.byteify(json_state) print("That's what we found:") print(str(json_state)) return json_state def loadState(self): # get current state json_state = self.getState() if json_state == 1: # we dont need to load as we were forced to start # as default single rover due to corrupt/missing state file self.launchRover() # for the first start, just let it be green self.updateLED("green") return print("Now loading the state printed above... ") # first, we restore the base state, because no matter what we end up doing, # we need to restore base state self.s2sc.input_stream = json_state["base"]["input_stream"] self.s2sc.output_stream = json_state["base"]["output_stream"] self.s2sc.rtcm3_messages = json_state["base"]["rtcm3_messages"] self.s2sc.base_position = json_state["base"]["base_position"] self.s2sc.gps_cmd_file = json_state["base"]["gps_cmd_file"] if json_state["state"] == "rover": saved_config = json_state["rover"]["current_config"] if saved_config == "": saved_config = None self.launchRover(saved_config) if json_state["started"] == "yes": self.startRover() elif json_state["state"] == "base": self.launchBase() if json_state["started"] == "yes": self.startBase() else: # in case we are inactive self.launchRover() print(str(json_state["state"]) + " state loaded") def sendState(self): # send current state to every connecting browser state = self.getState() self.conm.updateAvailableConfigs() state["available_configs"] = self.conm.available_configs print("Available configs to send: ") print(str(state["available_configs"])) self.socketio.emit("current state", state, namespace = "/test") def updateLED(self, pattern = None): # this forms a distinctive and informative blink pattern showing following info: # network_status/rtk_mode/started?/solution_status # network: self-hosted AP or connected? green/blue # rtk mode: rover or base? blue/magenta # started: yes or no? green/red # solution status: -, single, float, fix? red/cyan/yellow/green blink_pattern = [] delay = 0.5 # get wi-fi connection status for the first signal cmd = ["configure_edison", "--showWiFiMode"] cmd = " ".join(cmd) proc = Popen(cmd, stdout = PIPE, shell = True, bufsize = 2048) out = proc.communicate() out = out[0].split("\n")[0] if out == "Master": blink_pattern.append("green") elif out == "Managed": blink_pattern.append("blue") if self.state == "base": blink_pattern.append("magenta") if self.s2sc.started: # we have a started base blink_pattern.append("green") else: # we have a stopped base blink_pattern.append("red") # for now, the base doesn't have solution blink_pattern.append("off") elif self.state == "rover": blink_pattern.append("blue") if self.rtkc.started: # we have a started rover blink_pattern.append("green") status_pattern_dict = { "fix": "green,off", "float": "yellow,off", "single": "cyan,off", "-": "read,off" } # we need to acquire RtkController in case it's currently updating info dict self.rtkc.semaphore.acquire() current_rover_solutuon_status = self.rtkc.info.get("solution_status", "") self.rtkc.semaphore.release() # if we don't know this status, we just pass blink_pattern.append(status_pattern_dict.get(current_rover_solutuon_status, "off")) else: # we have a stopped rover blink_pattern.append("red") # we are not started, meaning no status just yet blink_pattern.append("off") # sync color for better comprehension blink_pattern.append("white") # concatenate all that into one big string blink_pattern = ",off,".join(blink_pattern) + ",off" if pattern is not None: blink_pattern = pattern if blink_pattern: # check blink_pattern contains something new if blink_pattern != self.led.current_blink_pattern: # if we decided we need a new pattern, then start blinking it self.led.startBlinker(blink_pattern, delay) # thread workers for broadcasing rtkrcv status # this function reads satellite levels from an exisiting rtkrcv instance # and emits them to the connected browser as messages def broadcastSatellites(self): count = 0 while self.server_not_interrupted: # update satellite levels self.rtkc.getObs() if count % 10 == 0: print("Sending sat rover levels:\n" + str(self.rtkc.obs_rover)) print("Sending sat base levels:\n" + str(self.rtkc.obs_base)) self.socketio.emit("satellite broadcast rover", self.rtkc.obs_rover, namespace = "/test") self.socketio.emit("satellite broadcast base", self.rtkc.obs_base, namespace = "/test") count += 1 time.sleep(1) # this function reads current rtklib status, coordinates and obs count def broadcastCoordinates(self): count = 0 while self.server_not_interrupted: # update RTKLIB status self.rtkc.getStatus() if count % 10 == 0: print("Sending RTKLIB status select information:") print(self.rtkc.info) self.socketio.emit("coordinate broadcast", self.rtkc.info, namespace = "/test") if self.enable_led: self.updateLED() count += 1 time.sleep(1)
class RTKLIB: # we will save RTKLIB state here for later loading state_file = "/home/reach/.reach/rtk_state" def __init__(self, socketio, enable_led = True, path_to_rtkrcv = None, path_to_configs = None, path_to_str2str = None, path_to_gps_cmd_file = None): # default state for RTKLIB is "inactive" self.state = "inactive" # we need this to broadcast stuff self.socketio = socketio # these are necessary to handle base mode self.rtkc = RtkController(path_to_rtkrcv) self.conm = ConfigManager(path_to_configs) # this one handles base settings self.s2sc = Str2StrController(path_to_str2str, path_to_gps_cmd_file) # basic synchronisation to prevent errors self.saveState() self.semaphore = Semaphore() # we need this to send led signals self.enable_led = enable_led if self.enable_led: self.led = ReachLED() # broadcast satellite levels and status with these self.server_not_interrupted = True self.satellite_thread = None self.coordinate_thread = None # we try to restore previous state self.loadState() def launchRover(self, config_name = None): # config_name may be a name, or a full path # if the parameter contains "/", then we consider it a full path # else, we will be looking for it one directory higher than the rtkrcv bin self.semaphore.acquire() print("Attempting to launch rtkrcv...") if config_name == None: res = self.rtkc.launch() else: res = self.rtkc.launch(config_name) if res < 0: print("rtkrcv launch failed") elif res == 1: print("rtkrcv launch successful") self.state = "rover" elif res == 2: print("rtkrcv already launched") self.state = "rover" self.saveState() if self.enable_led: self.updateLED() print("Rover mode launched") self.semaphore.release() return res def shutdownRover(self): self.stopRover() self.semaphore.acquire() print("Attempting rtkrcv shutdown") res = self.rtkc.shutdown() if res < 0: print("rtkrcv shutdown failed") elif res == 1: print("rtkrcv shutdown successful") self.state = "inactive" elif res == 2: print("rtkrcv already shutdown") self.state = "inactive" self.saveState() if self.enable_led: self.updateLED() print("Rover mode shutdown") self.semaphore.release() return res def startRover(self): self.semaphore.acquire() print("Attempting to start rtkrcv...") res = self.rtkc.start() if res == -1: print("rtkrcv start failed") elif res == 1: print("rtkrcv start successful") print("Starting coordinate and satellite broadcast") elif res == 2: print("rtkrcv already started") # start fresh data broadcast self.server_not_interrupted = True if self.satellite_thread is None: self.satellite_thread = Thread(target = self.broadcastSatellites) self.satellite_thread.start() if self.coordinate_thread is None: self.coordinate_thread = Thread(target = self.broadcastCoordinates) self.coordinate_thread.start() self.saveState() if self.enable_led: self.updateLED() self.semaphore.release() return res def stopRover(self): self.semaphore.acquire() print("Attempting to stop RTKLIB...") res = self.rtkc.stop() if res == -1: print("rtkrcv stop failed") elif res == 1: print("rtkrcv stop successful") elif res == 2: print("rtkrcv already stopped") self.server_not_interrupted = False if self.satellite_thread is not None: self.satellite_thread.join() self.satellite_thread = None if self.coordinate_thread is not None: self.coordinate_thread.join() self.coordinate_thread = None self.saveState() if self.enable_led: self.updateLED() self.semaphore.release() return res def launchBase(self): # due to the way str2str works, we can't really separate launch and start # all the configuration goes to startBase() function # this launchBase() function exists to change the state of RTKLIB instance # and to make the process for base and rover modes similar self.semaphore.acquire() self.state = "base" self.saveState() if self.enable_led: self.updateLED() print("Base mode launched") self.semaphore.release() def shutdownBase(self): # due to the way str2str works, we can't really separate launch and start # all the configuration goes to startBase() function # this shutdownBase() function exists to change the state of RTKLIB instance # and to make the process for base and rover modes similar self.stopBase() self.semaphore.acquire() self.state = "inactive" self.saveState() if self.enable_led: self.updateLED() print("Base mode shutdown") self.semaphore.release() def startBase(self, rtcm3_messages = None, base_position = None, gps_cmd_file = None): self.semaphore.acquire() print("Attempting to start str2str...") if not self.rtkc.started: res = self.s2sc.start(rtcm3_messages, base_position, gps_cmd_file) if res < 0: print("str2str start failed") elif res == 1: print("str2str start successful") elif res == 2: print("str2str already started") else: print("Can't start str2str with rtkrcv still running!!!!") self.saveState() if self.enable_led: self.updateLED() self.semaphore.release() return res def stopBase(self): self.semaphore.acquire() print("Attempting to stop str2str...") res = self.s2sc.stop() if res == -1: print("str2str stop failed") elif res == 1: print("str2str stop successful") elif res == 2: print("str2str already stopped") self.saveState() if self.enable_led: self.updateLED() self.semaphore.release() return res def readConfigBase(self): self.semaphore.acquire() print("Got signal to read current base config") self.socketio.emit("current config base", self.s2sc.readConfig(), namespace = "/test") self.semaphore.release() def writeConfigBase(self, config): self.semaphore.acquire() print("Got signal to write current base config") self.s2sc.writeConfig(config) print("Restarting str2str...") res = self.s2sc.stop() + self.s2sc.start() if res > 1: print("Restart successful") else: print("Restart failed") self.saveState() self.semaphore.release() return res def writeConfigRover(self, config): # config dict must include config_name field self.semaphore.acquire() print("Got signal to write current rover config") if "config_file_name" not in config: config_file = None else: config_file = config["config_file_name"] self.conm.writeConfig(config_file, config) print("Reloading with new config...") res = self.rtkc.loadConfig(self.rtkc.current_config) + self.rtkc.restart() if res == 2: print("Restart successful") elif res == 1: print("rtkrcv started instead of restart") elif res == -1: print("rtkrcv restart failed") self.saveState() self.semaphore.release() return res def readConfigRover(self, config): self.semaphore.acquire() if "config_file_name" not in config: config_file = None else: config_file = config["config_file_name"] print("Got signal to read the current rover config") self.conm.readConfig(config_file) # after this, to preserve the order of the options in the frontend we send a special order message print("Sending rover config order") options_order = {} # create a structure the corresponds to the options order for index, value in enumerate(self.conm.buff_dict_order): options_order[str(index)] = value # send the options order self.socketio.emit("current config rover order", options_order, namespace="/test") # send the options comments print("Sending rover config comments") self.socketio.emit("current config rover comments", self.conm.buff_dict_comments, namespace="/test") # now we send the whole config with values print("Sending rover config values") self.socketio.emit("current config rover", self.conm.buff_dict, namespace="/test") self.semaphore.release() def saveState(self): # save current state for future resurrection: # state is a list of parameters: # rover state example: ["rover", "started", "reach_single_default.conf"] # base state example: ["base", "stopped", "input_stream", "output_stream"] state = {} # save "rover", "base" or "inactive" state state["state"] = self.state if self.state == "rover": started = self.rtkc.started elif self.state == "base": started = self.s2sc.started elif self.state == "inactive": started = False state["started"] = "yes" if started else "no" # dump rover state state["rover"] = {"current_config": self.rtkc.current_config} # dump rover state state["base"] = { "input_stream": self.s2sc.input_stream, "output_stream": self.s2sc.output_stream, "rtcm3_messages": self.s2sc.rtcm3_messages, "base_position": self.s2sc.base_position, "gps_cmd_file": self.s2sc.gps_cmd_file } with open(self.state_file, "w") as f: json.dump(state, f, sort_keys = True, indent = 4) return state def byteify(self, input): # thanks to Mark Amery from StackOverFlow for this awesome function if isinstance(input, dict): return {self.byteify(key): self.byteify(value) for key, value in input.iteritems()} elif isinstance(input, list): return [self.byteify(element) for element in input] elif isinstance(input, unicode): return input.encode('utf-8') else: return input def readState(self): # load previously saved state # we assume this function is not to be run until the very end of __init__ of RTKLIB print("Trying to load previously saved state...") try: f = open(self.state_file, "r") except IOError: # can't find the file, let's create a new one with default state print("Could not find existing state, saving default...") self.saveState() return -1 else: print("Found existing state...") json_state = json.load(f) f.close() # convert unicode strings to normal json_state = self.byteify(json_state) return json_state def loadState(self): # load previously saved state # we assume this function is not to be run until the very end of __init__ of RTKLIB print("Trying to load previously saved state...") try: f = open(self.state_file, "r") except IOError: # can't find the file, let's create a new one with default state print("Could not find existing state, saving default...") return self.saveState() else: print("Found existing state...") json_state = json.load(f) f.close() # convert unicode strings to normal json_state = self.byteify(json_state) # first, we restore the base state, because no matter what we end up doing, # we need to restore base state self.s2sc.input_stream = json_state["base"]["input_stream"] self.s2sc.output_stream = json_state["base"]["output_stream"] self.s2sc.rtcm3_messages = json_state["base"]["rtcm3_messages"] self.s2sc.base_position = json_state["base"]["base_position"] self.s2sc.gps_cmd_file = json_state["base"]["gps_cmd_file"] if json_state["state"] == "rover": saved_config = json_state["rover"]["current_config"] if saved_config == "": saved_config = None self.launchRover(saved_config) if json_state["started"] == "yes": self.startRover() elif json_state["state"] == "base": self.launchBase() if json_state["started"] == "yes": self.startBase() print("State loaded") return json_state # if we are "inactive", don't do anything as this the default state def sendState(self): # send current state to every connecting browser state = self.loadState() self.socketio.emit("current state", state, namespace = "/test") def updateLED(self): blink_pattern = "" delay = 0.5 if self.state == "base": if self.s2sc.started: # we have a started base blink_pattern = "green,off,magenta,off" else: # we have a stopped base blink_pattern = "red,off,magenta,off" elif self.state == "rover": if self.rtkc.started: # we have a started rover status_pattern_dict = { "fix": "blue,off,green,off", "float": "blue,off,green,off,yellow,off", "single": "blue,off,yellow,off" } # we need to acquire RtkController in case it's currently updating info dict self.rtkc.semaphore.acquire() current_rover_solutuon_status = self.rtkc.info.get("solution_status", "") self.rtkc.semaphore.release() blink_pattern = status_pattern_dict.get(current_rover_solutuon_status, "blue,off") else: # we have a stopped rover blink_pattern = "blue,off,red,off" elif self.state == "inactive": blink_pattern = "yellow, off" delay = 1 if blink_pattern: # check blink_pattern contains something new if blink_pattern != self.led.current_blink_pattern: # if we decided we need a new pattern, then start blinking it self.led.startBlinker(blink_pattern, delay) # thread workers for broadcasing rtkrcv status # this function reads satellite levels from an exisiting rtkrcv instance # and emits them to the connected browser as messages def broadcastSatellites(self): count = 0 while self.server_not_interrupted: # update satellite levels self.rtkc.getObs() if count % 10 == 0: print("Sending sat rover levels:\n" + str(self.rtkc.obs_rover)) print("Sending sat base levels:\n" + str(self.rtkc.obs_base)) self.socketio.emit("satellite broadcast rover", self.rtkc.obs_rover, namespace = "/test") self.socketio.emit("satellite broadcast base", self.rtkc.obs_base, namespace = "/test") count += 1 time.sleep(1) # this function reads current rtklib status, coordinates and obs count def broadcastCoordinates(self): count = 0 while self.server_not_interrupted: # update RTKLIB status self.rtkc.getStatus() if count % 10 == 0: print("Sending RTKLIB status select information:") print(self.rtkc.info) self.socketio.emit("coordinate broadcast", self.rtkc.info, namespace = "/test") if self.enable_led: self.updateLED() count += 1 time.sleep(1)