def set_server_transport(self, value): """save the GpsGate server transport - ('tcp' or 'xml')""" value = clean_string(value).lower() if self.gps_gate_transport != value: if value == 'xml': raise NotImplementedError("GpsGate XML transport - not yet") elif value != 'tcp': raise ValueError("GpsGate - only TCP transport supported") self.gps_gate_transport = value self.logger.info("GpsGate: Setting Transport:{}".format(value))
def set_username(self, value: str): """ Set the user-name used with GpsGate Server. There don't seem to be any 'rules' about what makes a valid user-name. Insure is string, remove extra quotes, etc. """ value = clean_string(value) if self.client_username != value: self.client_username = value self.logger.info("GpsGate: Setting user name:{}".format(value))
def run_router_app(app_base, adjust_seconds): """ :param CradlepointAppBase app_base: prepared resources: logger, cs_client :param float adjust_seconds: :return: """ replay_file_name = DEF_REPLAY_FILE section = "gps" if section in app_base.settings: # then load dynamic values temp = app_base.settings[section] if "replay_file" in temp: replay_file_name = clean_string(temp["replay_file"]) if not os.path.isfile(replay_file_name): app_base.logger.error( "Replay file({}) not found".format(replay_file_name)) raise FileNotFoundError app_base.logger.info( "Replay file is named:{}".format(replay_file_name)) backup_file_name = replay_file_name + '.bak' app_base.logger.info( "Backup file is named:{}".format(backup_file_name)) os.rename(src=replay_file_name, dst=backup_file_name) file_in = open(backup_file_name, "r") file_out = open(replay_file_name, "w") while True: # loop forever # this is a dictionary dict_in = read_in_line(file_in) if dict_in is None: app_base.logger.warning("Close Replay file") break else: dict_in["offset"] += adjust_seconds result = '{"offset":%d, "data":"%s"},\n' % (dict_in["offset"], dict_in["data"]) file_out.write(result) file_in.close() file_out.close() return 0
def set_client_name(self, name: str, version=None): """ Set client name. if version is none, then we assume name is like "my tool 1.4" 7 try to parse off the ending float. TODO At the moment, this routine assumes version is like x.y, with y being only 1 digit. So 1.2 is okay, but 1.22 is not """ change = False name = clean_string(name) if version is None: # assume version is on end of name! name = name.split(' ') if len(name) <= 1: # then is a single work/token - assume version 1.0 version = 1.0 name = name[0] else: if name[-1].find('.') >= 0: version = name[-1] name.pop(-1) else: version = 1.0 name = ' '.join(name) if isinstance(version, int): version = float(version) if isinstance(version, float): version = str(version) if self.client_name != name: self.client_name = name change = True if self.client_version != version: self.client_version = version change = True if change and self.logger is not None: self.logger.info( "GpsGate: Setting client name:{} version:{}".format( self.client_name, self.client_version))
def run_router_app(app_base): """ :param CradlepointAppBase app_base: prepared resources: logger, cs_client :return: """ # logger.debug("Settings({})".format(sets)) # handle the GPS_GATE protocol gps_gate = GpsGate(app_base.logger) # process the SETTINGS file section = "gps_gate" if section not in app_base.settings: # this is unlikely! app_base.logger.warning( "Aborting: No [%s] section in settings.ini".format(section)) return -1 else: # then load dynamic values temp = app_base.settings[section] app_base.logger.debug("[{}] section = {}".format(section, temp)) # settings for our LISTENER for router GPS output buffer_size = int(temp.get("buffer_size", DEF_BUFFER_SIZE)) # check on our localhost port (not used, but to test) config = GpsConfig(app_base) host_ip, host_port = config.get_client_info() if "host_ip" in temp: # then OVER-RIDE what the router told us app_base.logger.warning("Settings OVER-RIDE router host_ip") value = clean_string(temp["host_ip"]) app_base.logger.warning("was:{} now:{}".format(host_ip, value)) host_ip = value if "host_port" in temp: # then OVER-RIDE what the router told us app_base.logger.warning("Settings OVER-RIDE router host_port") value = parse_integer(temp["host_port"]) app_base.logger.warning("was:{} now:{}".format(host_port, value)) host_port = value app_base.logger.debug("GPS source:({}:{})".format(host_ip, host_port)) del config # settings defining the GpsGate interactions if "gps_gate_url" in temp: gps_gate.set_server_url(temp["gps_gate_url"]) if "gps_gate_port" in temp: gps_gate.set_server_port(temp["gps_gate_port"]) if "gps_gate_transport" in temp: gps_gate.set_server_transport(temp["gps_gate_transport"]) if "username" in temp: gps_gate.set_username(temp["username"]) if "password" in temp: gps_gate.set_password(temp["password"]) if "server_version" in temp: gps_gate.set_server_version(temp["server_version"]) if "client" in temp: gps_gate.set_client_name(temp["client"]) if "IMEI" in temp: gps_gate.set_imei(temp["IMEI"]) elif "imei" in temp: # handle upper or lower case, just because ... gps_gate.set_imei(temp["imei"]) # we can pre-set the filters here, but Gpsgate may try to override if "distance_filter" in temp: gps_gate.nmea.set_distance_filter(temp["distance_filter"]) if "time_filter" in temp: gps_gate.nmea.set_time_filter(temp["time_filter"]) if "speed_filter" in temp: gps_gate.nmea.set_speed_filter(temp["speed_filter"]) if "direction_filter" in temp: gps_gate.nmea.set_direction_filter(temp["direction_filter"]) if "direction_threshold" in temp: gps_gate.nmea.set_direction_threshold(temp["direction_threshold"]) # check the cell modem/gps sources wan_data = ActiveWan(app_base) # app_base.logger.info("WAN data {}".format(wan_data['active'])) value = wan_data.get_imei() if gps_gate.client_imei is None: # only take 'live' value if setting.ini was NOT included gps_gate.set_imei(value) else: app_base.logger.warning( "Using settings.ini IMEI, ignoring cell modem's value") if not wan_data.supports_gps(): app_base.logger.warning( "cell modem claims no GPS - another source might exist") if wan_data.get_live_gps_data() in (None, {}): app_base.logger.warning("cell modem has no last GPS data") else: app_base.logger.debug("GPS={}".format(wan_data.get_live_gps_data())) while True: # define the socket resource, including the type (stream == "TCP") address = (host_ip, host_port) app_base.logger.info("Preparing GPS Listening on {}".format(address)) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # attempt to actually lock resource, which may fail if unavailable # (see BIND ERROR note) try: sock.bind(address) except OSError as msg: app_base.logger.error("socket.bind() failed - {}".format(msg)) # technically, Python will close when 'sock' goes out of scope, # but be disciplined and close it yourself. Python may warning # you of unclosed resource, during runtime. try: sock.close() except OSError: pass # we exit, because if we cannot secure the resource, the errors # are likely permanent. return -1 # only allow 1 client at a time sock.listen(3) while True: # loop forever app_base.logger.info("Waiting on TCP socket %d" % host_port) client, address = sock.accept() app_base.logger.info("Accepted connection from {}".format(address)) # for cellular, ALWAYS enable TCP Keep Alive (see KEEP ALIVE note) sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # set non-blocking so we can do a manual timeout (use of select() # is better ... but that's another sample) # client.setblocking(0) while True: app_base.logger.debug("Waiting to receive data") data = client.recv(buffer_size) # data is type() bytes, to echo we don't need to convert # to str to format or return. if data: data = data.decode().split() # gps.start() for line in data: try: pass # result = gps.parse_sentence(line) # if not result: # break except ValueError: app_base.logger.warning( "Bad NMEA sentence:[{}]".format(line)) raise # gps.publish() # app_base.logger.debug( # "See({})".format(gps.get_attributes())) # client.send(data) else: break time.sleep(1.0) app_base.logger.info("Client disconnected") client.close() # since this server is expected to run on a small embedded system, # free up memory ASAP (see MEMORY note) del client gc.collect() return 0
def run_client(): global base_app obj = protocol.GpsGate(base_app.logger) # base_app.logger.debug("sets:{}".format(base_app.settings)) # set a few defaults imei = "353547060660845" gps_gate_url = "64.46.40.178" gps_gate_port = 30175 if "gps_gate" in base_app.settings: # then we do have a customer config temp = base_app.settings["gps_gate"] # check on our localhost port (not used, but to test) config = GpsConfig(base_app) host_ip, host_port = config.get_client_info() if "host_ip" in temp: # then OVER-RIDE what the router told us base_app.logger.warning("Settings OVER-RIDE router host_ip") value = clean_string(temp["host_ip"]) base_app.logger.warning("was:{} now:{}".format(host_ip, value)) host_ip = value if "host_port" in temp: # then OVER-RIDE what the router told us base_app.logger.warning("Settings OVER-RIDE router host_port") value = parse_integer(temp["host_port"]) base_app.logger.warning("was:{} now:{}".format(host_port, value)) host_port = value base_app.logger.debug("GPS source:({}:{})".format(host_ip, host_port)) del config # check on our cellular details config = ActiveWan(base_app) imei = config.get_imei() if "imei" in temp: # then OVER-RIDE what the router told us base_app.logger.warning("Settings OVER-RIDE router IMEI") value = clean_string(temp["imei"]) base_app.logger.warning("was:{} now:{}".format(imei, value)) imei = value del config if "gps_gate_url" in temp: # load the settings.ini value gps_gate_url = clean_string(temp["gps_gate_url"]) if "gps_gate_port" in temp: # load the settings.ini value gps_gate_port = parse_integer(temp["gps_gate_port"]) obj.set_imei(imei) obj.set_server_url(gps_gate_url) obj.set_server_port(gps_gate_port) # we never need these! # obj.set_username('Admin') # obj.set_password(':Vm78!!') sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) sock.settimeout(2.0) address = (obj.gps_gate_url, obj.gps_gate_port) base_app.logger.info( "Preparing to connect on TCP socket {}".format(address)) # attempt to actually lock the resource, which may fail if unavailable # (see CONNECT ERROR note) try: sock.connect(address) except OSError as msg: base_app.logger.error("socket.connect() failed - {}".format(msg)) return -1 # first test - try our user name: # Req = $FRLIN,, Admin,12Ne*14\r\n # Rsp = $FRERR,AuthError,Wrong username or password*56\r\n # second test - try our IMEI: # Req = $FRLIN,IMEI,353547060660845,*47\r\n # Rsp = $FRSES,75*7F\r\n # expect Req = $FRLIN,IMEI,353547060660845,*47\r\n request = obj.get_next_client_2_server() base_app.logger.debug("Req({})".format(request)) sock.send(request) # expect Rsp = $FRSES,75*7F\r\n try: response = sock.recv(1024) base_app.logger.debug("Rsp({})".format(response)) result = obj.parse_message(response) if not result: base_app.logger.debug("parse result({})".format(result)) except socket.timeout: base_app.logger.error("No response - one was expected!") return -1 # expect Req = $FRVER,1,1,Cradlepoint 1.0*27\r\n request = obj.get_next_client_2_server() base_app.logger.debug("Req({})".format(request)) sock.send(request) # expect Rsp = $FRVER,1,1,GpsGate Server 3.0.0.2583*3E\r\n try: response = sock.recv(1024) base_app.logger.debug("Rsp({})".format(response)) result = obj.parse_message(response) if not result: base_app.logger.debug("parse result({})".format(result)) except socket.timeout: base_app.logger.error("No response - one was expected!") return -1 # expect Req = $FRCMD,,_getupdaterules,Inline*1E request = obj.get_next_client_2_server() base_app.logger.debug("Req({})".format(request)) sock.send(request) # expect Rsp = $FRRET,User1,_getupdaterules,Nmea,2*07 try: response = sock.recv(1024) base_app.logger.debug("Rsp({})".format(response)) result = obj.parse_message(response) if not result: base_app.logger.debug("parse result({})".format(result)) except socket.timeout: base_app.logger.error("No response - one was expected!") return -1 # now we LOOP and process the rules! while True: # expect Rsp = $FRVAL,DistanceFilter,500.0*67 try: response = sock.recv(1024) base_app.logger.debug("Rsp({})".format(response)) result = obj.parse_message(response) if not result: base_app.logger.debug("parse result({})".format(result)) except socket.timeout: base_app.logger.error("No response - jump from loop!") break # expect Req = b"$FRWDT,NMEA*78" request = obj.get_next_client_2_server() base_app.logger.debug("Req({})".format(request)) sock.send(request) # this message has NO response! # our fake data, time-fixed to me NOW request = fix_time_sentence("$GPGGA,094013.0,4334.784909,N,11612.7664" + "48,W,1,09,0.9,830.6,M,-11.0,M,,*60") request = request.encode() base_app.logger.debug("Req({})".format(request)) sock.send(request) # this message has NO response! time.sleep(2.0) sock.close() return 0
def set_server_url(self, value): """save the GpsGate server URL""" value = clean_string(value) if self.gps_gate_url != value: self.gps_gate_url = value self.logger.info("GpsGate: Setting Server URL:{}".format(value))
def set_imei(self, value): """make string, remove extra quotes, etc""" value = clean_string(value) if self.client_imei != value: self.client_imei = value self.logger.info("GpsGate: Setting IMEI:{}".format(value))
def set_password(self, value): """make string, remove extra quotes, etc""" value = clean_string(value) if self.client_password != value: self.client_password = value self.logger.info("GpsGate: Setting new PASSWORD:****")
def run_router_app(app_base): """ :param CradlepointAppBase app_base: prepared resources: logger, cs_client :return: """ # logger.debug("Settings({})".format(sets)) replay_file_name = DEF_REPLAY_FILE try: # use Router API to fetch any configured data config = GpsConfig(app_base) host_ip, host_port = config.get_client_info() del config except CradlepointRouterOffline: host_ip = None host_port = 0 section = "gps" if section in app_base.settings: # then load dynamic values temp = app_base.settings[section] # check on our localhost port (not used, but to test) if "host_ip" in temp: # then OVER-RIDE what the router told us app_base.logger.warning("Settings OVER-RIDE router host_ip") value = clean_string(temp["host_ip"]) app_base.logger.warning("was:{} now:{}".format(host_ip, value)) host_ip = value if "host_port" in temp: # then OVER-RIDE what the router told us app_base.logger.warning("Settings OVER-RIDE router host_port") value = parse_integer(temp["host_port"]) app_base.logger.warning("was:{} now:{}".format(host_port, value)) host_port = value if "replay_file" in temp: replay_file_name = clean_string(temp["replay_file"]) app_base.logger.debug("GPS destination:({}:{})".format(host_ip, host_port)) if not os.path.isfile(replay_file_name): app_base.logger.error( "Replay file({}) not found".format(replay_file_name)) raise FileNotFoundError app_base.logger.info("Replay file is named:{}".format(replay_file_name)) # define the socket resource, including the type (stream == "TCP") address = (host_ip, host_port) app_base.logger.info("Will connect on {}".format(address)) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(address) file_han = None start_time = time.time() try: while True: # loop forever if file_han is None: # reopen the file file_han = open(replay_file_name, "r") start_time = time.time() # this line_in = read_in_line(file_han) if line_in is None: app_base.logger.warning("Close Replay file") file_han.close() break else: wait_time = start_time + line_in['offset'] now = time.time() if wait_time > now: delay = wait_time - now app_base.logger.debug("Delay %0.1f sec" % delay) time.sleep(delay) nmea_out = gps_nmea.fix_time_sentence(line_in['data']).strip() nmea_out += '\r\n' app_base.logger.debug("out:{}".format(nmea_out)) sock.send(nmea_out.encode()) time.sleep(0.1) finally: app_base.logger.info("Closing client socket") sock.close() return 0
def run_router_app(app_base): """ :param CradlepointAppBase app_base: prepared resources: logger, cs_client :return: """ # logger.debug("Settings({})".format(sets)) # first, confirm no other function using serial value = SerialRedirectorConfig(app_base) value.refresh() if value.enabled(): app_base.logger.error("Serial Redirector Function is Active!") app_base.logger.error("Aborting SDK application") return -3 app_base.logger.debug("Good: Serial Redirector Function is Disabled.") value = SerialGpsConfig(app_base) value.refresh() if value.enabled(): app_base.logger.error("Serial GPS Echo Function is Active!") app_base.logger.error("Aborting SDK application") return -4 app_base.logger.debug("Good: Serial GPS Function is Disabled.") value = SerialGPIOConfig(app_base) value.refresh() if value.enabled(): app_base.logger.error("Serial GPIO Function is Active!") app_base.logger.error("Aborting SDK application") return -5 app_base.logger.debug("Good: Serial GPIO Function is Disabled.") server_loop = ModbusBridge() server_loop.logger = app_base.logger if "modbus_ip" in app_base.settings: temp = app_base.settings["modbus_ip"] if "host_ip" in temp: # assume is string of correct format server_loop.host_ip = clean_string(temp["host_ip"]) if "host_port" in temp: # force to integer server_loop.host_port = parse_integer(temp["host_port"]) if "idle_timeout" in temp: # support seconds, or like '5 min' duration = TimeDuration(clean_string(temp["idle_timeout"])) server_loop.idle_timeout = duration.get_seconds() if "protocol" in temp: value = validate_ia_protocol(clean_string(temp["protocol"])) if value not in (IA_PROTOCOL_MBTCP, IA_PROTOCOL_MBRTU, IA_PROTOCOL_MBASC): raise ValueError("Invalid IP-packed Modbus Protocol {}".format( type(value))) server_loop.host_protocol = value if "modbus_serial" in app_base.settings: temp = app_base.settings["modbus_serial"] if "port_name" in temp: server_loop.serial_name = clean_string(temp["port_name"]) if "baud_rate" in temp: server_loop.serial_baud = parse_integer(temp["baud_rate"]) if "parity" in temp: server_loop.serial_baud = parse_integer(temp["baud_rate"]) if "protocol" in temp: value = validate_ia_protocol(clean_string(temp["protocol"])) # confirm is serial, so RTU or ASCII if value not in (IA_PROTOCOL_MBRTU, IA_PROTOCOL_MBASC): raise ValueError("Invalid Serial Modbus Protocol {}".format( type(value))) server_loop.serial_protocol = value # this should run forever try: result = server_loop.run_loop() except KeyboardInterrupt: result = 0 return result
def run_router_app(app_base): """ :param CradlepointAppBase app_base: prepared resources: logger, cs_client :return: """ buffer_size = DEF_BUFFER_SIZE replay_file_name = DEF_REPLAY_FILE # use Router API to fetch any configured data config = GpsConfig(app_base) host_ip, host_port = config.get_client_info() del config section = "gps" if section in app_base.settings: # then load dynamic values temp = app_base.settings[section] # check on our localhost port (not used, but to test) if "host_ip" in temp: # then OVER-RIDE what the router told us app_base.logger.warning("Settings OVER-RIDE router host_ip") value = clean_string(temp["host_ip"]) app_base.logger.warning("was:{} now:{}".format(host_ip, value)) host_ip = value if "host_port" in temp: # then OVER-RIDE what the router told us app_base.logger.warning("Settings OVER-RIDE router host_port") value = parse_integer(temp["host_port"]) app_base.logger.warning("was:{} now:{}".format(host_port, value)) host_port = value if "buffer_size" in temp: buffer_size = parse_integer(temp["buffer_size"]) if "replay_file" in temp: replay_file_name = clean_string(temp["replay_file"]) app_base.logger.debug("GPS source:({}:{})".format(host_ip, host_port)) # make sure our log file exists & is empty file_han = open(replay_file_name, "w") file_han.write("[\n") file_han.close() address = (host_ip, host_port) while True: # define the socket resource, including the type (stream == "TCP") app_base.logger.info("Preparing GPS Listening on {}".format(address)) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # attempt to actually lock resource, which may fail if unavailable # (see BIND ERROR note) try: sock.bind(address) except OSError as msg: app_base.logger.error("socket.bind() failed - {}".format(msg)) # technically, Python will close when 'sock' goes out of scope, # but be disciplined and close it yourself. Python may warning # you of unclosed resource, during runtime. try: sock.close() except OSError: pass # we exit, because if we cannot secure the resource, the errors # are likely permanent. return -1 # only allow 1 client at a time sock.listen(3) while True: # loop forever start_time = time.time() app_base.logger.info("Waiting on TCP socket %d" % host_port) client, address = sock.accept() app_base.logger.info("Accepted connection from {}".format(address)) # for cellular, ALWAYS enable TCP Keep Alive (see KEEP ALIVE note) sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # set non-blocking so we can do a manual timeout (use of select() # is better ... but that's another sample) # client.setblocking(0) while True: app_base.logger.debug("Waiting to receive data") data = client.recv(buffer_size) # data is type() bytes, to echo we don't need to convert # to str to format or return. if data: # assume we have multiple sentences per segment recv'd data = data.decode().split() print("data:{}".format(data)) file_han = open(replay_file_name, "a") offset = int(time.time() - start_time) for line in data: result = '{"offset":%d, "data":"%s"},\n' % (offset, line) file_han.write(result) app_base.logger.debug("Wrote at offset:{}".format(offset)) else: break time.sleep(1.0) app_base.logger.info("Client disconnected") client.close() # since this server is expected to run on a small embedded system, # free up memory ASAP (see MEMORY note) del client gc.collect() return 0