Exemple #1
0
 def handle_node_check(self, data):
     """Handle alive message received from coap node."""
     node_id = data['id']
     node = MQTTNode(node_id)
     node.check_time = time.time()
     if node not in self.nodes:
         resources_topic = 'node/{}/resources'.format(node_id)
         yield from self.mqtt_client.subscribe([(resources_topic, QOS_1)])
         logger.debug("Subscribed to topic: {}".format(resources_topic))
         node_uid = str(uuid.uuid4())
         self.nodes.update(
             {node: {
                 'uid': node_uid,
                 'data': {
                     'protocol': PROTOCOL
                 }
             }})
         logger.debug("Available nodes: {}".format(self.nodes))
         self._on_message_cb(Msg.new_node(node_uid))
         self._on_message_cb(Msg.update_node(node_uid, "protocol",
                                             PROTOCOL))
         discover_topic = 'gateway/{}/discover'.format(node_id)
         yield from self.mqtt_client.publish(discover_topic,
                                             b"resources",
                                             qos=QOS_1)
         logger.debug("Published '{}' to topic: {}".format(
             "resources", discover_topic))
     else:
         data = self.nodes.pop(node)
         self.nodes.update({node: data})
     logger.debug("Available nodes: {}".format(self.nodes))
Exemple #2
0
 def fetch_nodes_cache(self, source):
     """Send cached nodes information."""
     logger.debug("Fetching cached information of registered nodes.")
     for _, node in self.nodes.items():
         self._on_message_cb(Msg.new_node(node['uid'], dst=source))
         for endpoint, value in node['data'].items():
             yield self._on_message_cb(
                 Msg.update_node(node['uid'], endpoint, value, dst=source))
Exemple #3
0
 def add_node(self, node):
     """Add a new node to the list of nodes and notify the broker."""
     node.set_resource_value('protocol', self.PROTOCOL)
     self.nodes.update({node.uid: node})
     self.send_to_broker(Message.new_node(node.uid))
     for res, value in node.resources.items():
         self.send_to_broker(Message.update_node(node.uid, res, value))
     yield self.discover_node(node)
Exemple #4
0
 def fetch_nodes_cache(self, source):
     """Send cached nodes information."""
     logger.debug(
         "Fetching cached information of registered nodes '{}'.".format(
             self.nodes))
     for _, value in self.nodes.items():
         self._on_message_cb(Msg.new_node(value['uid'], dst=source))
         for resource, data in value['data'].items():
             self._on_message_cb(
                 Msg.update_node(value['uid'], resource, data, dst=source))
Exemple #5
0
 def fetch_nodes_cache(self, source):
     """Send cached nodes information."""
     logger.debug("Fetching cached information of registered nodes.")
     for ws, node in self.nodes.items():
         self.send_to_broker(Message.new_node(node['uid'], dst=source))
         for endpoint, value in node['data'].items():
             self.send_to_broker(
                 Message.update_node(node['uid'],
                                     endpoint,
                                     value,
                                     dst=source))
Exemple #6
0
    def fetch_nodes_cache(self, client):
        """Send cached nodes information to a given client.

        :param client: the ID of the client
        """
        logger.debug(
            "Fetching cached information of registered nodes '{}'.".format(
                self.nodes))
        for node in self.nodes.values():
            self.send_to_broker(Message.new_node(node.uid, dst=client))
            for resource, value in node.resources.items():
                self.send_to_broker(
                    Message.update_node(node.uid, resource, value, dst=client))
Exemple #7
0
def test_new_node():
    serialized = Message.new_node('1234')

    assert serialized == Message.serialize({
        'type': 'new',
        'uid': '1234',
        'dst': 'all'
    })

    serialized = Message.new_node('1234', '5678')
    assert serialized == Message.serialize({
        'type': 'new',
        'uid': '1234',
        'dst': '5678'
    })
Exemple #8
0
    def send_data_to_node(self, data):
        """Forward received message data to the destination node.

        The message should be JSON and contain 'uid', 'path' and 'payload'
        keys.

        - 'uid' corresponds to the node uid (uuid)
        - 'path' corresponds to the CoAP resource on the node
        - 'payload' corresponds to the new payload for the CoAP resource.
        """
        uid = data['uid']
        endpoint = data['endpoint']
        payload = data['payload']
        logger.debug("Translating message ('{}') received to CoAP PUT "
                     "request".format(data))

        for node, _ in self.nodes.items():
            if self.nodes[node]['uid'] == uid:
                address = self.nodes[node]['data']['ip']
                logger.debug("Updating CoAP node '{}' resource '{}'".format(
                    self.nodes[node]['data']['ip'], endpoint))
                code, p = yield _coap_resource('coap://[{0}]/{1}'.format(
                    address, endpoint),
                                               method=PUT,
                                               payload=payload.encode('ascii'))
                if code == Code.CHANGED:
                    self.nodes[node]['data'][endpoint] = payload
                    yield self._on_message_cb(
                        Msg.update_node(uid, endpoint, payload))
                break
Exemple #9
0
    def discover_node(self, node, uid):
        """Discover resources available on a node."""
        coap_node_url = 'coap://[{}]'.format(node.address)
        if len(node.endpoints) == 0:
            logger.debug("Discovering CoAP node {}".format(node.address))
            code, payload = yield _coap_resource(
                '{0}/.well-known/core'.format(coap_node_url), method=GET)
            node.endpoints = _coap_endpoints(payload)

        endpoints = [
            endpoint for endpoint in node.endpoints
            if 'well-known/core' not in endpoint
        ]
        logger.debug("Fetching CoAP node resources: {}".format(endpoints))
        for endpoint in endpoints:
            elems = endpoint.split(';')
            path = elems.pop(0).replace('<', '').replace('>', '')

            try:
                code, payload = yield _coap_resource('{0}{1}'.format(
                    coap_node_url, path),
                                                     method=GET)
            except:
                logger.debug("Cannot discover ressource {} on node {}".format(
                    endpoint, node.address))
                return

            # Remove '/' from path
            path = path[1:]
            self._on_message_cb(Msg.update_node(uid, path, payload))
            self.nodes[node]['data'].update({path: payload})

        logger.debug(
            "CoAP node resources '{}' sent to broker".format(endpoints))
Exemple #10
0
 def handle_coap_post(self, address, endpoint, value):
     """Handle CoAP post message sent from coap node."""
     node = CoapNode(address)
     if node in self.nodes and endpoint in self.nodes[node]['data']:
         self.nodes[node]['data'][endpoint] = value
     self._on_message_cb(
         Msg.update_node(self.nodes[node]['uid'], endpoint, value))
Exemple #11
0
 def forward_data_from_node(self, node, resource, value):
     """Send data received from a node to the broker via the gateway."""
     logger.debug(
         "Sending data received from node '{}': '{}', '{}'.".format(
             node, resource, value))
     node.set_resource_value(resource, value)
     self.send_to_broker(Message.update_node(node.uid, resource, value))
Exemple #12
0
 def open(self):
     """Discover nodes on each opened connection."""
     self.set_nodelay(True)
     logger.debug("New node websocket opened")
     self.application.nodes.update(
         {self: {
             'uid': str(uuid.uuid4()),
             'data': {
                 'protocol': PROTOCOL
             }
         }})
     node_uid = self.application.nodes[self]['uid']
     self.application.send_to_broker(Message.new_node(node_uid))
     yield self.write_message(Message.discover_node())
     self.application.send_to_broker(
         Message.update_node(node_uid, 'protocol', PROTOCOL))
Exemple #13
0
 def on_message(self, raw):
     """Triggered when a message is received from the broker child."""
     message, reason = Message.check_message(raw)
     if message is not None:
         self.application.on_gateway_message(self, message)
     else:
         logger.debug("Invalid message, closing websocket")
         self.close(code=1003, reason="{}.".format(reason))
Exemple #14
0
 def reset_node(self, node, default_resources={}):
     """Reset a node: clear the current resource and reinitialize them."""
     node.clear_resources()
     node.set_resource_value('protocol', self.PROTOCOL)
     for resource, value in default_resources.items():
         node.set_resource_value(resource, value)
     self.send_to_broker(Message.reset_node(node.uid))
     self.discover_node(node)
Exemple #15
0
 def remove_ws(self, ws):
     """Remove websocket that has been closed."""
     if ws in self.clients:
         self.clients.pop(ws)
     elif ws in self.gateways.keys():
         # Notify clients that the nodes behind the closed gateway are out.
         for node_uid in self.gateways[ws]:
             self.broadcast(Message.out_node(node_uid))
         self.gateways.pop(ws)
Exemple #16
0
 def on_message(self, raw):
     """Triggered when a message is received from the web client."""
     message, reason = Message.check_message(raw)
     if message is not None:
         message.update({'src': self.uid})
         self.application.on_client_message(self, message)
     else:
         logger.debug("Invalid message, closing websocket")
         self.close(code=1003, reason="{}.".format(reason))
Exemple #17
0
def test_update_node(value):
    serialized = Message.update_node('1234', 'test', 'value')

    assert serialized == Message.serialize({
        'type': 'update',
        'uid': '1234',
        'endpoint': 'test',
        'data': 'value',
        'dst': 'all'
    })

    serialized = Message.update_node('1234', 'test', value, '5678')
    assert serialized == Message.serialize({
        'type': 'update',
        'uid': '1234',
        'endpoint': 'test',
        'data': value,
        'dst': '5678'
    })
Exemple #18
0
 def check_dead_nodes(self):
     """Check and remove nodes that are not alive anymore."""
     to_remove = [
         node for node in self.nodes.keys()
         if int(time.time()) > node.check_time + self.max_time
     ]
     for node in to_remove:
         uid = self.nodes[node]['uid']
         self.nodes.pop(node)
         logger.debug("Removing inactive node {}".format(uid))
         self._on_message_cb(Msg.out_node(uid))
Exemple #19
0
 def handle_coap_check(self, address, reset=False):
     """Handle check message received from coap node."""
     node = CoapNode(address)
     node.check_time = time.time()
     if node not in self.nodes:
         # This is a totally new node: create uid, initialized cached node
         # send 'new' node notification, 'update' notification.
         node_uid = str(uuid.uuid4())
         self.nodes.update({
             node: {
                 'uid': node_uid,
                 'data': {
                     'ip': address,
                     'protocol': PROTOCOL
                 }
             }
         })
         self._on_message_cb(Msg.new_node(node_uid))
         self._on_message_cb(Msg.update_node(node_uid, "ip", address))
         self._on_message_cb(Msg.update_node(node_uid, "protocol",
                                             PROTOCOL))
         self.discover_node(node, node_uid)
     elif reset:
         # The data of the node need to be reset without removing it. This
         # is particularly the case after a reboot of the node or a
         # firmware update of the node that triggered the reboot.
         node_uid = self.nodes[node]['uid']
         self.nodes[node]['data'] = {}
         self.nodes[node]['data'].update({
             'ip': address,
             'protocol': PROTOCOL
         })
         self._on_message_cb(Msg.reset_node(node_uid))
         self.discover_node(node, node_uid)
     else:
         # The node simply sent a check message to notify that it's still
         # online.
         data = self.nodes.pop(node)
         self.nodes.update({node: data})
Exemple #20
0
 def handle_coap_alive(self, address):
     """Handle alive message received from coap node."""
     node = CoapNode(address)
     node.check_time = time.time()
     if node not in self.nodes:
         node_uid = str(uuid.uuid4())
         self.nodes.update({
             node: {
                 'uid': node_uid,
                 'data': {
                     'ip': address,
                     'protocol': 'coap'
                 }
             }
         })
         self._on_message_cb(Msg.new_node(node_uid))
         self._on_message_cb(Msg.update_node(node_uid, "ip", address))
         self._on_message_cb(Msg.update_node(node_uid, "protocol", 'coap'))
         self.discover_node(node, node_uid)
     else:
         data = self.nodes.pop(node)
         self.nodes.update({node: data})
Exemple #21
0
 def on_node_message(self, ws, message):
     """Handle a message received from a node websocket."""
     if message['type'] == "update":
         logger.debug("New update message received from node websocket")
         for key, value in message['data'].items():
             if key in self.nodes[ws]['data']:
                 self.nodes[ws]['data'][key] = value
             else:
                 self.nodes[ws]['data'].update({key: value})
             self.send_to_broker(
                 Message.update_node(self.nodes[ws]['uid'], key, value))
     else:
         logger.debug("Invalid message received from node websocket")
Exemple #22
0
 def check_dead_nodes(self):
     """Check and remove nodes that are not alive anymore."""
     to_remove = [node for node in self.nodes.keys()
                  if int(time.time()) > node.check_time + self.max_time]
     for node in to_remove:
         asyncio.get_event_loop().create_task(
             self._disconnect_from_node(node))
         for resource in node.resources:
             pass
         uid = self.nodes[node]['uid']
         self.nodes.pop(node)
         logger.info("Removing inactive node {}".format(uid))
         logger.debug("Available nodes {}".format(self.nodes))
         self._on_message_cb(Msg.out_node(uid))
Exemple #23
0
    def on_client_message(self, ws, message):
        """Handle a message received from a client."""
        logger.debug("Handling message '{}' received from client websocket."
                     .format(message))
        if message['type'] == "new":
            logger.info("New client connected: {}".format(ws.uid))
            if ws.uid not in self.clients.keys():
                self.clients.update({ws.uid: ws})
        elif message['type'] == "update":
            logger.debug("New message from client: {}".format(ws.uid))

        # Simply forward this message to satellite gateways
        logger.debug("Forwarding message {} to gateways".format(message))
        for gw in self.gateways:
            gw.write_message(Message.serialize(message))
Exemple #24
0
    def handle_node_update(self, topic_name, data):
        """Handle CoAP post message sent from coap node."""
        _, node_id, resource = topic_name.split("/")
        node = MQTTNode(node_id)
        value = data['value']
        if node in self.nodes:
            if resource in self.nodes[node]['data']:
                # Add updated information to cache
                self.nodes[node]['data'][resource] = value
            else:
                self.nodes[node]['data'].update({resource: value})

        # Send update to broker
        self._on_message_cb(
            Msg.update_node(self.nodes[node]['uid'], resource, value))
Exemple #25
0
    def on_gateway_message(self, ws, message):
        """Handle a message received from a gateway.

        This method redirect messages from gateways to the right destinations:
        - for freshly new information initiated by nodes => broadcast
        - for replies to new client connection => only send to this client
        """
        logger.debug(
            "Handling message '{}' received from gateway.".format(message))
        if message['type'] == "new":
            # Received when notifying clients of a new node available
            if not message['uid'] in self.gateways[ws]:
                self.gateways[ws].append(message['uid'])

            if message['dst'] == "all":
                # Occurs when an unknown new node arrived
                self.broadcast(Message.serialize(message))
            elif message['dst'] in self.clients.keys():
                # Occurs when a single client has just connected
                self.send_to_client(message['dst'], Message.serialize(message))
        elif (message['type'] == "out"
              and message['uid'] in self.gateways[ws]):
            # Node disparition are always broadcasted to clients
            self.gateways[ws].remove(message['uid'])
            self.broadcast(Message.serialize(message))
        elif (message['type'] == "update"
              and message['uid'] in self.gateways[ws]):
            if message['dst'] == "all":
                # Occurs when a new update was pushed by a node:
                # require broadcast
                self.broadcast(Message.serialize(message))
            elif message['dst'] in self.clients.keys():
                # Occurs when a new client has just connected:
                # Only the cached information of a node are pushed to this
                # specific client
                self.send_to_client(message['dst'], Message.serialize(message))
Exemple #26
0
 def on_message(self, raw):
     """Triggered when a message is received from the broker child."""
     if not self.authentified:
         if verify_auth_token(raw, self.application.keys):
             logger.info("Gateway websocket authentication verified")
             self.authentified = True
             self.application.gateways.update({self: []})
         else:
             logger.info("Gateway websocket authentication failed, "
                         "closing.")
             self.close()
     else:
         message, reason = Message.check_message(raw)
         if message is not None:
             self.application.on_gateway_message(self, message)
         else:
             logger.debug("Invalid message, closing websocket")
             self.close(code=1003, reason="{}.".format(reason))
Exemple #27
0
def main(args):
    """Main function."""
    try:
        ws = websocket.create_connection("ws://{}:{}/node".format(
            args.host, args.port))
    except ConnectionRefusedError:
        print("Cannot connect to ws://{}:{}".format(args.host, args.port))
        return

    init_node(ws)
    while True:
        try:
            msg = ws.recv()
        except:
            print("Connection closed")
            break
        else:
            print(msg)
            if msg == Message.discover_node():
                init_node(ws)
            else:
                msg = json.loads(msg)
                if msg['payload'] == '1':
                    ws.send(
                        json.dumps({
                            'type': 'update',
                            'data': {
                                'led': '1'
                            }
                        }))
                else:
                    ws.send(
                        json.dumps({
                            'type': 'update',
                            'data': {
                                'led': '0'
                            }
                        }))
Exemple #28
0
 async def discover_node(self, node):
     for ws, uid in self.node_mapping.items():
         if node.uid == uid:
             await ws.write_message(Message.discover_node())
             break
Exemple #29
0
 def send_alive(self):
     self.send_to_broker(Message.gateway_alive())
Exemple #30
0
 def remove_node(self, node):
     """Remove the given node from known nodes and notify the broker."""
     self.nodes.pop(node.uid)
     logger.debug("Remaining nodes {}".format(self.nodes))
     self.send_to_broker(Message.out_node(node.uid))