Ejemplo n.º 1
0
    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')
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
 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)
Ejemplo n.º 9
0
 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])
Ejemplo n.º 10
0
 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
Ejemplo n.º 11
0
 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
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
    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)
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
    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)
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
 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
Ejemplo n.º 19
0
    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