def set(self, msg, connection): t0 = time.monotonic() if self.connection == connection: # received new value from owner, inform watchers self.msg = msg if self.awatches: watch = self.awatches[0] if watch.period == 0: for connection in watch.connections: connection.write(msg) for watch in self.pwatches: if t0 >= watch.time: watch.time = t0 if watch.connections: # only insert if there are connections self.server_values.insert_watch(watch) self.pwatches = [] elif self.connection: # inform owner of change if we are not owner if 'writable' in self.info and self.info['writable']: name, data = msg.rstrip().split('=', 1) pyjson.loads(data) # validate data self.connection.write(msg) self.msg = False else: # inform key can not be set arbitrarily connection.write('error=' + self.name + ' is not writable\n')
def pypilotClientFromArgs(values, period=True, host=False): client = pypilotClient(host) if not client.connect(True): print('failed to connect to', host) exit(1) # set any value specified with path=value watches = {} sets = False for arg in values: if '=' in arg: name, value = arg.split('=', 1) try: # make string if it won't load pyjson.loads(value) except: value = pyjson.dumps(value) client.send(name + '=' + value + '\n') sets = True watches[name] = True else: name = arg watches[name] = period if sets: client.poll(1) #time.sleep(.2) # is this needed? for name in watches: client.watch(name, watches[name]) return client
def request_access(self): import requests if self.signalk_access_url: dt = time.monotonic() - self.last_access_request_time if dt < 10: return self.last_access_request_time = time.monotonic() try: r = requests.get(self.signalk_access_url) contents = pyjson.loads(r.content) print('signalk see if token is ready', self.signalk_access_url, contents) if contents['state'] == 'COMPLETED': if 'accessRequest' in contents: access = contents['accessRequest'] if access['permission'] == 'APPROVED': self.token = access['token'] print('signalk received token', self.token) try: f = open(token_path, 'w') f.write(self.token) f.close() except Exception as e: print('signalk failed to store token', token_path) else: self.signalk_access_url = False except Exception as e: print('signalk error requesting access', e) self.signalk_access_url = False return try: def random_number_string(n): if n == 0: return '' import random return str(int( random.random() * 10)) + random_number_string(n - 1) if self.uid.value == 'pypilot': self.uid.set('pypilot-' + random_number_string(11)) r = requests.post('http://' + self.signalk_host_port + '/signalk/v1/access/requests', data={ "clientId": self.uid.value, "description": "pypilot" }) contents = pyjson.loads(r.content) print('signalk post', contents) if contents['statusCode'] == 202 or contents['statusCode'] == 400: self.signalk_access_url = 'http://' + self.signalk_host_port + contents[ 'href'] print('signalk request access url', self.signalk_access_url) except Exception as e: print('signalk error requesting access', e) self.signalk_ws_url = False
def gps_json_loads(line): try: return pyjson.loads(line) except: pass act = '"activated"' i = line.index(act) j = line.index('Z', i) line = line[:i]+act+':"'+line[i+12:j+1]+'"'+line[j+1:] return pyjson.loads(line)
def set(self, msg, connection): try: name, data = msg.rstrip().split('=', 1) self.msg = pyjson.loads(data) if not (self.msg is False) and self.msg < 1024 or self.msg > 65535: raise Exception('port out of range') except Exception as e: connection.write('error=invalid udp_port:' + msg + e + '\n') return # remove any identical udp connection for socket in self.server.sockets: if socket.udp_port and ( socket.udp_port == self.msg or not self.msg ) and socket.address[0] == connection.address[0]: #print('remove old udp') socket.udp_port = False socket.udp_out_buffer = '' connection.udp_port = self.msg # output streams on this port for c in self.server.sockets: if c == connection: continue if c.address[0] == connection.address[ 0] and c.udp_port == connection.udp_port: print('remove duplicate udp connection') c.udp_socket.close() c.udp_port = False
def receive_signalk(self, msg): try: data = pyjson.loads(msg) except: print('signalk failed to parse msg:', msg) return if 'updates' in data: updates = data['updates'] for update in updates: source = 'unknown' if 'source' in update: source = update['source']['talker'] elif '$source' in update: source = update['$source'] if 'timestamp' in update: timestamp = update['timestamp'] if not source in self.signalk_values: self.signalk_values[source] = {} for value in update['values']: path = value['path'] if path in self.signalk_last_msg_time: if self.signalk_last_msg_time[path] == timestamp: debug('signalk skip duplicate timestamp', source, path, timestamp) continue self.signalk_values[source][path] = value['value'] else: debug('signalk skip initial message', source, path, timestamp) self.signalk_last_msg_time[path] = timestamp
def __init__(self, host=False): self.values = ClientValues(self) self.watches = {} self.wwatches = {} self.received = [] self.last_values_list = False if False: self.server = host host = '127.0.0.1' if host and type(host) != type(''): # host is the server object self.server = host self.connection = host.pipe() self.poller = select.poll() fd = self.connection.fileno() if fd: self.poller.register(fd, select.POLLIN) self.values.onconnected() return config = {} try: configfilepath = os.getenv('HOME') + '/.pypilot/' if not os.path.exists(configfilepath): os.makedirs(configfilepath) if not os.path.isdir(configfilepath): raise Exception(configfilepath + 'should be a directory') except Exception as e: print('os not supported') configfilepath = '/.pypilot/' self.configfilename = configfilepath + 'pypilot_client.conf' try: file = open(self.configfilename) config = pyjson.loads(file.readline()) file.close() except Exception as e: print('failed to read config file:', self.configfilename, e) config = {} if host: if ':' in host: i = host.index(':') config['host'] = host[:i] config['port'] = host[i + 1:] else: config['host'] = host if not 'host' in config: config['host'] = '127.0.0.1' if not 'port' in config: config['port'] = DEFAULT_PORT self.config = config self.connection = False # connect later self.connection_in_progress = False
def load_calibration(self): try: filename = Servo.calibration_filename print('loading servo calibration', filename) file = open(filename) self.calibration.set(pyjson.loads(file.readline())) except: print('WARNING: using default servo calibration!!') self.calibration.set(False)
def set(self, msg, connection): name, data = msg.rstrip().split('=', 1) watches = pyjson.loads(data) values = self.server_values.values for name in watches: if not name in values: # watching value not yet registered, add it so we can watch it values[name] = pypilotValue(self.server_values, name) values[name].watch(connection, watches[name])
def recv(self, timeout=0): self.recvdata() line = super(SocketNonBlockingPipeEnd, self).readline() if not line: return try: d = pyjson.loads(line.rstrip()) return d except Exception as e: print('failed to decode data socket!', self.name, e) print('line', line) return False
def recv(self, timeout=0): self.recvdata() line = self.b.line() if not line: return try: d = pyjson.loads(line.rstrip()) return d except Exception as e: print(_('failed to decode data socket!'), self.name, e) print('line', line) return False
def pypilotClientFromArgs(values, period=True, host=False): client = pypilotClient(host) if host: client.probed = True # dont probe if not client.connect(True): print(_('failed to connect to'), host) if not host and client.probewait(5): if not client.connect(True): print(_('failed to connect to'), client.config['host']) exit(1) else: print(_('no pypilot server found')) exit(1) # set any value specified with path=value watches = {} sets = False for arg in values: if '=' in arg: name, value = arg.split('=', 1) try: # make string if it won't load pyjson.loads(value) except: value = pyjson.dumps(value) client.send(name + '=' + value + '\n') sets = True watches[name] = True else: name = arg watches[name] = period if sets: client.poll(1) for name in watches: client.watch(name, watches[name]) return client
def read_last_working_devices(): global probes for filename in os.listdir(pypilot_dir): if filename.endswith('device'): name = filename[:-6] if name: try: file = open(pypilot_dir + filename, 'r') lastdevice = pyjson.loads(file.readline().rstrip()) file.close() # ensure lastdevice defines path and baud here if not name in probes: new_probe(name) probes[name]['lastworking'] = lastdevice[0], lastdevice[1] except: pass
def set(self, msg, connection): if isinstance(connection, LineBufferedNonBlockingSocket): connection.write('error=remote sockets not allowed to register\n') return n, data = msg.rstrip().split('=', 1) values = pyjson.loads(data) for name in values: info = values[name] if name in self.values: value = self.values[name] if value.connection: connection.write('error=value already held: ' + name + '\n') continue value.connection = connection value.info = info # update info value.watching = False if value.msg: connection.write(value.get_msg()) # send value value.calculate_watch_period() self.msg = 'new' continue value = pypilotValue(self, name, info, connection) if 'persistent' in info and info['persistent']: # when a persistant value is missing from pypilot.conf value.calculate_watch_period() #info['persistent'] = 'new' ??? if name in self.persistent_data: print('IS THIS POSSIBLE TO HIT?????') v = self.persistent_data[name] if isinstance(v, numbers.Number): v = float(v) # convert any numeric to floating point value.set(v, connection) # set persistent value self.persistent_values[name] = value self.values[name] = value self.msg = 'new' msg = False # inform watching clients of updated values for watch in self.awatches: for c in watch.connections: if c != connection: if not msg: msg = 'values=' + pyjson.dumps(values) + '\n' c.write(msg)
def lastworkingdevice(name): global lastworkingdevices if name in lastworkingdevices: return lastworkingdevices[name] filename = pypilot_dir + name + 'device' try: file = open(filename, 'r') lastdevice = pyjson.loads(file.readline().rstrip()) file.close() # ensure lastdevice defines path and baud here lastdevice = lastdevice[0], [lastdevice[1]] except: lastdevice = False lastworkingdevices[name] = lastdevice return lastdevice
def probe_signalk(self): print('signalk probe...', self.signalk_host_port) try: import requests except Exception as e: print('signalk could not import requests', e) print("try 'sudo apt install python3-requests' or 'pip3 install requests'") time.sleep(50) return try: r = requests.get('http://' + self.signalk_host_port + '/signalk') contents = pyjson.loads(r.content) self.signalk_ws_url = contents['endpoints']['v1']['signalk-ws'] + '?subscribe=none' except Exception as e: print('failed to retrieve/parse data from', self.signalk_host_port, e) time.sleep(5) return print('signalk found', self.signalk_ws_url)
def set(self, msg, connection): name, data = msg.rstrip().split('=', 1) values = pyjson.loads(data) for name in values: info = values[name] if name in self.values: value = self.values[name] if value.connection: connection.write('error=value already held: ' + name + '\n') continue value.connection = connection value.info = info # update info value.watching = False if value.msg: connection.write(value.get_msg()) # send value value.calculate_watch_period() self.msg = 'new' continue value = pypilotValue(self, name, info, connection) if 'persistent' in info and info['persistent']: value.calculate_watch_period() if name in self.persistent_data: v = self.persistent_data[name] if isinstance(v, numbers.Number): v = float(v) # convert any numeric to floating point value.set(v, connection) # set persistent value self.values[name] = value self.msg = 'new' msg = False # inform watching clients of updated values for watch in self.awatches: for c in watch.connections: if c != connection: if not msg: msg = 'values=' + pyjson.dumps(values) + '\n' c.write(msg)
def receive_signalk(self, msg): try: data = pyjson.loads(msg) except: print('failed to parse signalk msg:', msg) return if 'updates' in data: updates = data['updates'] for update in updates: source = 'unknown' if 'source' in update: source = update['source']['talker'] elif '$source' in update: source = update['$source'] if 'timestamp' in update: timestamp = update['timestamp'] if not source in self.signalk_values: self.signalk_values[source] = {} for value in update['values']: path = value['path'] if path in self.signalk_msgs_skip: self.signalk_values[source][path] = value['value'] else: self.signalk_msgs_skip[path] = True
def poll(self, timeout=0): if not self.connection: if self.connection_in_progress: events = self.poller_in_progress.poll(0) if events: fd, flag = events.pop() if not (flag & select.POLLOUT): # hung hup self.connection_in_progress.close() self.connection_in_progress = False return self.onconnected() return else: if not self.connect(False): time.sleep(timeout) return # inform server of any watches we have changed if self.wwatches: self.connection.write('watch=' + pyjson.dumps(self.wwatches) + '\n') #print('watch', watches, self.wwatches, self.watches) self.wwatches = {} # send any delayed watched values self.values.send_watches() if self.connection.fileno(): # flush output self.connection.flush() try: events = self.poller.poll(int(1000 * timeout)) except Exception as e: print('exception polling', e, os.getpid()) self.disconnect() return if not events: return # no data ready fd, flag = events.pop() if not (flag & select.POLLIN) or (self.connection and not self.connection.recvdata()): # other flags indicate disconnect self.disconnect() # recv returns 0 means connection closed return # read incoming data line by line while True: t0 = time.monotonic() line = self.connection.readline() if not line: return try: name, data = line.rstrip().split('=', 1) if name == 'error': print('server error:', data) continue value = pyjson.loads(data) except ValueError as e: print('client value error:', line, e) #raise Exception continue except Exception as e: print('invalid message from server:', line, e) raise Exception() if name in self.values.values: # did this client register this value self.values.values[name].set(value) else: self.received.append((name, value)) # remote value