Beispiel #1
0
    def update_sensor_source(self, sensor, source):
        priority = source_priority[source]
        watch = priority < signalk_priority # translate from pypilot -> signalk
        if watch:
            watch = self.period.value
        for signalk_path_conversion, pypilot_path in signalk_table[sensor].items():
            if type(pypilot_path) == type({}):
                for signalk_key, pypilot_key in pypilot_path.items():
                    pypilot_path = sensor + '.' + pypilot_key
                    if pypilot_path in self.last_values:
                        del self.last_values[pypilot_path]
                    self.client.watch(pypilot_path, watch)
            else:
                # remove any last values from this sensor
                pypilot_path = sensor + '.' + pypilot_path
                if pypilot_path in self.last_values:
                    del self.last_values[pypilot_path]
                self.client.watch(pypilot_path, watch)
        subscribe = priority >= signalk_priority

        # prevent duplicating subscriptions
        if self.subscribed[sensor] == subscribe:
            return
        self.subscribed[sensor] = subscribe

        if not subscribe:
            #signalk can't unsubscribe by path!?!?!
            subscription = {'context': '*', 'unsubscribe': [{'path': '*'}]}
            debug('signalk unsubscribe', subscription)
            self.ws.send(pyjson.dumps(subscription)+'\n')
        
        signalk_sensor = signalk_table[sensor]
        if subscribe: # translate from signalk -> pypilot
            subscriptions = []
            for signalk_path_conversion in signalk_sensor:
                signalk_path, signalk_conversion = signalk_path_conversion
                if signalk_path in self.signalk_last_msg_time:
                    del self.signalk_last_msg_time[signalk_path]
                subscriptions.append({'path': signalk_path, 'minPeriod': self.period.value*1000, 'format': 'delta', 'policy': 'instant'})
            self.subscriptions += subscriptions
        else:
            # remove this subscription and resend all subscriptions
            debug('signalk remove subs', signalk_sensor, self.subscriptions)
            subscriptions = []
            for subscription in self.subscriptions:
                for signalk_path_conversion in signalk_sensor:
                    signalk_path, signalk_conversion = signalk_path_conversion
                    if subscription['path'] == signalk_path:
                        break
                else:
                    subscriptions.append(subscription)
            self.subscriptions = subscriptions
            self.signalk_last_msg_time = {}
            
        subscription = {'context': 'vessels.self'}
        subscription['subscribe'] = subscriptions
        debug('signalk subscribe', subscription)
        self.ws.send(pyjson.dumps(subscription)+'\n')
Beispiel #2
0
    def onconnected(self):
        #print('connected to pypilot server', time.time())
        self.last_values_list = False

        # write config if connection succeeds
        try:
            file = open(self.configfilename, 'w')
            file.write(pyjson.dumps(self.config) + '\n')
            file.close()
            self.write_config = False
        except IOError:
            print('failed to write config file:', self.configfilename)
        except Exception as e:
            print('Exception writing config file:', self.configfilename, e)

        self.connection = LineBufferedNonBlockingSocket(
            self.connection_in_progress, self.config['host'])
        self.connection_in_progress = False
        self.poller = select.poll()
        self.poller.register(self.connection.socket, select.POLLIN)
        self.wwatches = {}
        for name, value in self.watches.items():
            self.wwatches[name] = value  # resend watches

        self.values.onconnected()
Beispiel #3
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
Beispiel #4
0
    def commit(self, state):
        """ Write out the state in JSON format to a temporary file and rename it into place """

        with tempfile.NamedTemporaryFile() as f:
            f.write(pyjson.dumps(state))
            f.flush()
            shutil.copyfile(f.name, self._state_file)
Beispiel #5
0
def success(name, device):
    global probes
    filename = pypilot_dir + name + 'device'
    print('serialprobe success:', filename, device)
    try:
        file = open(filename, 'w')
        file.write(pyjson.dumps(device) + '\n')
        file.close()

    except:
        print('serialprobe failed to record device', name)
Beispiel #6
0
 def send(self, value, block=False):
     t0 = time.time()
     try:
         data = pyjson.dumps(value)
         self.write(data + '\n')
         t1 = time.time()
         if t1 - t0 > .02:
             print('too long', t1 - t0, self.name, len(data))
         return True
     except Exception as e:
         print('failed to encode data socket!', self.name, e)
         return False
Beispiel #7
0
def success(name, device):
    global probes
    filename = pypilot_dir + name + 'device'
    print('serialprobe ' + _('success') + ':', filename, device)
    probes[name]['lastworking'] = device
    try:
        file = open(filename, 'w')
        file.write(pyjson.dumps(device) + '\n')
        file.close()

    except:
        print('serialprobe ' + _('failed to record device'), name)
Beispiel #8
0
 def get_msg(self):
     if not self.msg or self.msg == 'new':
         msg = 'values={'
         notsingle = False
         for name in self.values:
             if name in self.internal:
                 continue
             info = self.values[name].info
             if not info:  # placeholders that are watched
                 continue
             if notsingle:
                 msg += ','
             msg += '"' + name + '":' + pyjson.dumps(info)
             notsingle = True
         self.msg = msg + '}\n'
         #print('values len', len(self.msg))
     return self.msg
Beispiel #9
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)
Beispiel #10
0
    def send_signalk(self):
        # see if we can produce any signalk output from the data we have read
        updates = []
        for sensor in signalk_table:
            if sensor != 'imu' and (not sensor in self.last_sources or\
                                    source_priority[self.last_sources[sensor]]>=signalk_priority):
                #debug('signalk skip send from priority', sensor)
                continue

            for signalk_path_conversion, pypilot_path in signalk_table[
                    sensor].items():
                signalk_path, signalk_conversion = signalk_path_conversion
                if type(pypilot_path) == type(
                    {}):  # single path translates to multiple pypilot
                    keys = self.last_values_keys[signalk_path]
                    # store keys we need for this signalk path in dictionary
                    for signalk_key, pypilot_key in pypilot_path.items():
                        key = sensor + '.' + pypilot_key
                        if key in self.last_values:
                            keys[key] = self.last_values[key]

                    # see if we have the keys needed
                    v = {}
                    for signalk_key, pypilot_key in pypilot_path.items():
                        key = sensor + '.' + pypilot_key
                        if not key in keys:
                            break
                        v[signalk_key] = keys[key] * signalk_conversion
                    else:
                        updates.append({'path': signalk_path, 'value': v})
                        self.last_values_keys[signalk_path] = {}
                else:
                    key = sensor + '.' + pypilot_path
                    if key in self.last_values:
                        v = self.last_values[key] * signalk_conversion
                        updates.append({'path': signalk_path, 'value': v})

        if updates:
            # send signalk updates
            msg = {'updates': [{'$source': 'pypilot', 'values': updates}]}
            debug('signalk updates', msg)
            try:
                self.ws.send(pyjson.dumps(msg) + '\n')
            except Exception as e:
                print('signalk failed to send', e)
                self.disconnect_signalk()
Beispiel #11
0
 def send(self, value, block=False):
     if not self.pollout.poll(0):
         if not self.sendfailok:
             print('failed send', self.name)
     t0 = time.time()
     try:
         data = pyjson.dumps(value) + '\n'
         os.write(self.w, data.encode())
         t1 = time.time()
         self.flush()
         t2 = time.time()
         if t2-t0 > .024:
             print('too long send nonblocking pipe', t1-t0, t2-t1, self.name, len(data))
         return True
     except Exception as e:
         if not self.sendfailok:
             print('failed to encode data pipe!', self.name, e)
         return False
Beispiel #12
0
 def send(self, value, block=False, maxdt=.025):
     if 0:
         if not self.pollout.poll(0):
             if not self.sendfailok:
                 print('failed poll send', self.name)
     t0 = time.monotonic()
     try:
         data = pyjson.dumps(value) + '\n'
         data = data.encode()
         t1 = time.monotonic()
         os.write(self.w, data)
         t2 = time.monotonic()
         if t2 - t0 > maxdt:
             print('too long send nonblocking pipe', t1 - t0, t2 - t1,
                   self.name, len(data))
         return True
     except Exception as e:
         print("failed send ex", t0, time.monotonic(), e)
         if not self.sendfailok:
             print('failed to encode data pipe!', self.name, e)
         return False
Beispiel #13
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
Beispiel #14
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)
Beispiel #15
0
    def load(self):
        self.persistent_data = {}
        try:
            self.load_file(open(default_persistent_path))
        except Exception as e:
            print('failed to load', default_persistent_path, e)
            # log failing to load persistent data
            persist_fail = os.getenv('HOME') + '/.pypilot/persist_fail'
            file = open(persist_fail, 'a')
            file.write(str(time.time()) + ' ' + str(e) + '\n')
            file.close()

            try:
                self.load_file(open(default_persistent_path + '.bak'))
                return
            except Exception as e:
                print('backup data failed as well', e)
            return

        # backup persistent_data if it loaded with success
        file = open(default_persistent_path + '.bak', 'w')
        file.write(pyjson.dumps(self.persistent_data) + '\n')
        file.close()
Beispiel #16
0
    def send_signalk(self):
        # see if we can produce any signalk output from the data we have read
        updates = []
        for sensor in signalk_table:
            for signalk_path_conversion, pypilot_path in signalk_table[
                    sensor].items():
                signalk_path, signalk_conversion = signalk_path_conversion
                if signalk_path in self.signalk_msgs:
                    continue
                if type(pypilot_path) == type(
                    {}):  # single path translates to multiple pypilot
                    v = {}
                    for signalk_key, pypilot_key in pypilot_path.items():
                        key = sensor + '.' + pypilot_key
                        if not key in self.last_values:
                            break
                        v[signalk_key] = self.last_values[
                            key] * signalk_conversion
                    else:
                        updates.append({'path': signalk_path, 'value': v})
                        self.signalk_msgs[signalk_path] = True
                else:
                    key = sensor + '.' + pypilot_path
                    if key in self.last_values:
                        v = self.last_values[key] * signalk_conversion
                        updates.append({'path': signalk_path, 'value': v})
                        self.signalk_msgs[signalk_path] = True

        if updates:
            # send signalk updates
            msg = {'updates': [{'$source': 'pypilot', 'values': updates}]}
            #print('signalk updates', msg)
            try:
                self.ws.send(pyjson.dumps(msg) + '\n')
            except Exception as e:
                print('signalk failed to send', e)
                self.disconnect_signalk()
Beispiel #17
0
 def save_calibration(self):
     file = open(Servo.calibration_filename, 'w')
     file.write(pyjson.dumps(self.calibration))
Beispiel #18
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
Beispiel #19
0
 def get_msg(self):
     ret = pyjson.dumps(self.wvalues)
     self.wvalues = {}
     return ret
Beispiel #20
0
    def poll(self, timeout=0):
        # server is in subprocess
        if self.process != 'main process':
            if not self.process:
                self.init_process()
            return

        t0 = time.monotonic()
        if t0 >= self.values.persistent_timeout:
            self.values.store()
            dt = time.monotonic() - t0
            if dt > .1:
                print('persistent store took too long!', time.monotonic() - t0)
                return

        if timeout:
            timeout *= 1000  # milliseconds

        timeout = .1
        events = self.poller.poll(timeout)
        while events:
            event = events.pop()
            fd, flag = event

            connection = self.fd_to_connection[fd]
            if connection == self.server_socket:
                connection, address = connection.accept()
                if len(self.sockets) == max_connections:
                    print('pypilot server: max connections reached!!!',
                          len(self.sockets))
                    self.RemoveSocket(self.sockets[0])  # dump first socket??
                socket = LineBufferedNonBlockingSocket(connection, address)
                print('server add socket', socket.address)

                self.sockets.append(socket)
                fd = socket.fileno()
                socket.cwatches = {
                    'values': True
                }  # server always watches client values

                self.fd_to_connection[fd] = socket
                self.poller.register(fd, select.POLLIN)
            elif flag & (select.POLLHUP | select.POLLERR | select.POLLNVAL):
                if not connection in self.sockets:
                    print('internal pipe closed, server exiting')
                    exit(0)
                self.RemoveSocket(connection)
            elif flag & select.POLLIN:
                if fd in self.fd_to_pipe:
                    if not connection.recvdata():
                        continue
                    line = connection.readline(
                    )  # shortcut since poll indicates data is ready
                    while line:
                        self.values.HandlePipeRequest(line, connection)
                        line = connection.readline()

                    continue
                if not connection.recvdata():
                    self.RemoveSocket(connection)
                    continue
                while True:
                    line = connection.readline()
                    if not line:
                        break
                    try:
                        self.values.HandleRequest(line, connection)
                    except Exception as e:
                        connection.write('error=invalid request: ' + line)
                        try:
                            print('invalid request from connection', e, line)
                        except Exception as e2:
                            print('invalid request has malformed string', e,
                                  e2)

        if not self.multiprocessing:
            # these pipes are not pollable as they are implemented as a simple buffer
            for pipe in self.pipes:
                while True:
                    line = pipe.readline()
                    if not line:
                        break
                    self.values.HandlePipeRequest(line, pipe)

        # send periodic watches
        self.values.send_watches()

        # send watches
        for connection in self.sockets + self.pipes:
            if connection.cwatches:
                connection.write('watch=' + pyjson.dumps(connection.cwatches) +
                                 '\n')
                connection.cwatches = {}

        # flush all sockets
        for socket in self.sockets:
            socket.flush()
        while True:
            for socket in self.sockets:
                if not socket.socket:
                    print('server socket closed from flush!!')
                    self.RemoveSocket(socket)
                    break
            else:
                break

        for pipe in self.pipes:
            pipe.flush()
Beispiel #21
0
 def get_msg(self):
     return pyjson.dumps(self.value)