Example #1
0
    def read_property(self, td, name, timeout=None):
        """Reads the value of a Property on a remote Thing.
        Returns a Future."""

        if name not in td.properties:
            raise FormNotFoundException()

        form = pick_form(td, td.get_property_forms(name),
                         WebsocketSchemes.list())

        if not form:
            raise FormNotFoundException()

        ws_url = form.resolve_uri(td.base)
        ref_id = uuid.uuid4().hex

        try:
            yield self._init_conn(ws_url, ref_id)

            msg_req = WebsocketMessageRequest(
                method=WebsocketMethods.READ_PROPERTY,
                params={"name": name},
                msg_id=uuid.uuid4().hex)

            condition = yield self._send_message(ws_url, msg_req)

            timeout = datetime.timedelta(seconds=timeout) if timeout else None
            cond_res = yield condition.wait(timeout=timeout)

            if not cond_res:
                raise ClientRequestTimeout

            self._raise_message(ws_url, msg_req.id)
        finally:
            yield self._stop_conn(ws_url, ref_id)
Example #2
0
    def on_property_change(self, td, name):
        """Subscribes to property changes on a remote Thing.
        Returns an Observable."""

        if name not in td.properties:
            # noinspection PyUnresolvedReferences
            return Observable.throw(FormNotFoundException())

        form = pick_form(td, td.get_property_forms(name),
                         WebsocketSchemes.list())

        if not form:
            # noinspection PyUnresolvedReferences
            return Observable.throw(FormNotFoundException())

        ws_url = form.resolve_uri(td.base)

        msg_req = WebsocketMessageRequest(
            method=WebsocketMethods.ON_PROPERTY_CHANGE,
            params={"name": name},
            msg_id=uuid.uuid4().hex)

        def on_next(observer, msg_item):
            init_name = msg_item.data["name"]
            init_value = msg_item.data["value"]
            init = PropertyChangeEventInit(name=init_name, value=init_value)
            observer.on_next(PropertyChangeEmittedEvent(init=init))

        subscribe = self._build_subscribe(ws_url, msg_req, on_next)

        # noinspection PyUnresolvedReferences
        return Observable.create(subscribe)
Example #3
0
    def on_event(self, td, name):
        """Subscribes to an event on a remote Thing.
        Returns an Observable."""

        if name not in td.events:
            # noinspection PyUnresolvedReferences
            return Observable.throw(FormNotFoundException())

        form = pick_form(td, td.get_event_forms(name), WebsocketSchemes.list())

        if not form:
            # noinspection PyUnresolvedReferences
            return Observable.throw(FormNotFoundException())

        ws_url = form.resolve_uri(td.base)

        msg_req = WebsocketMessageRequest(method=WebsocketMethods.ON_EVENT,
                                          params={"name": name},
                                          msg_id=uuid.uuid4().hex)

        def on_next(observer, msg_item):
            observer.on_next(EmittedEvent(init=msg_item.data, name=name))

        subscribe = self._build_subscribe(ws_url, msg_req, on_next)

        # noinspection PyUnresolvedReferences
        return Observable.create(subscribe)
Example #4
0
    def on_event(self, td, name, qos=QOS_0):
        """Subscribes to an event on a remote Thing.
        Returns an Observable."""

        forms = td.get_event_forms(name)

        href = self._pick_mqtt_href(td,
                                    forms,
                                    op=InteractionVerbs.SUBSCRIBE_EVENT)

        if href is None:
            raise FormNotFoundException()

        parsed_href = self._parse_href(href)

        broker_url = parsed_href["broker_url"]
        topic = parsed_href["topic"]

        def next_item_builder(msg_data):
            return EmittedEvent(init=msg_data.get("data"), name=name)

        subscribe = self._build_subscribe(broker_url=broker_url,
                                          topic=topic,
                                          next_item_builder=next_item_builder,
                                          qos=qos)

        # noinspection PyUnresolvedReferences
        return Observable.create(subscribe)
Example #5
0
    def on_property_change(self, td, name, qos=QOS_0):
        """Subscribes to property changes on a remote Thing.
        Returns an Observable"""

        forms = td.get_property_forms(name)

        href = self._pick_mqtt_href(td,
                                    forms,
                                    op=InteractionVerbs.OBSERVE_PROPERTY)

        if href is None:
            raise FormNotFoundException()

        parsed_href = self._parse_href(href)

        broker_url = parsed_href["broker_url"]
        topic = parsed_href["topic"]

        def next_item_builder(msg_data):
            msg_value = msg_data.get("value")
            init = PropertyChangeEventInit(name=name, value=msg_value)
            return PropertyChangeEmittedEvent(init=init)

        subscribe = self._build_subscribe(broker_url=broker_url,
                                          topic=topic,
                                          next_item_builder=next_item_builder,
                                          qos=qos)

        # noinspection PyUnresolvedReferences
        return Observable.create(subscribe)
Example #6
0
    async def read_property(self, td, name, timeout=None):
        """Reads the value of a Property on a remote Thing."""

        href = self._pick_coap_href(td,
                                    td.get_property_forms(name),
                                    op=InteractionVerbs.READ_PROPERTY)

        if href is None:
            raise FormNotFoundException()

        coap_client = await aiocoap.Context.create_client_context()

        try:
            msg = aiocoap.Message(code=aiocoap.Code.GET, uri=href)
            request = coap_client.request(msg)

            try:
                response = await asyncio.wait_for(request.response,
                                                  timeout=timeout)
            except asyncio.TimeoutError:
                raise ClientRequestTimeout

            self._assert_success(response)

            prop_value = json.loads(response.payload).get("value")

            return prop_value
        finally:
            await coap_client.shutdown()
Example #7
0
    def write_property(self, td, name, value, timeout=None):
        """Updates the value of a Property on a remote Thing.
        Returns a Future."""

        con_timeout = timeout if timeout else self._connect_timeout
        req_timeout = timeout if timeout else self._request_timeout

        href = self.pick_http_href(td, td.get_property_forms(name))

        if href is None:
            raise FormNotFoundException()

        http_client = tornado.httpclient.AsyncHTTPClient()
        body = json.dumps({"value": value})

        try:
            http_request = tornado.httpclient.HTTPRequest(
                href, method="PUT", body=body,
                headers=self.JSON_HEADERS,
                connect_timeout=con_timeout,
                request_timeout=req_timeout)
        except HTTPTimeoutError:
            raise ClientRequestTimeout

        yield http_client.fetch(http_request)
Example #8
0
    def read_property(self, td, name, timeout=None):
        """Reads the value of a Property on a remote Thing.
        Returns a Future."""

        con_timeout = timeout if timeout else self._connect_timeout
        req_timeout = timeout if timeout else self._request_timeout

        href = self.pick_http_href(td, td.get_property_forms(name))

        if href is None:
            raise FormNotFoundException()

        http_client = tornado.httpclient.AsyncHTTPClient()

        try:
            http_request = tornado.httpclient.HTTPRequest(
                href, method="GET",
                connect_timeout=con_timeout,
                request_timeout=req_timeout)
        except HTTPTimeoutError:
            raise ClientRequestTimeout

        response = yield http_client.fetch(http_request)

        raise tornado.gen.Return(json.loads(response.body).get("value"))
Example #9
0
    async def write_property(self, td, name, value, timeout=None):
        """Updates the value of a Property on a remote Thing."""

        href = self._pick_coap_href(td,
                                    td.get_property_forms(name),
                                    op=InteractionVerbs.WRITE_PROPERTY)

        if href is None:
            raise FormNotFoundException()

        coap_client = await aiocoap.Context.create_client_context()

        try:
            payload = json.dumps({"value": value}).encode("utf-8")
            msg = aiocoap.Message(code=aiocoap.Code.PUT,
                                  payload=payload,
                                  uri=href)
            request = coap_client.request(msg)

            try:
                response = await asyncio.wait_for(request.response,
                                                  timeout=timeout)
            except asyncio.TimeoutError:
                raise ClientRequestTimeout

            self._assert_success(response)
        finally:
            await coap_client.shutdown()
Example #10
0
    def invoke_action(self, td, name, input_value, timeout=None):
        """Invokes an Action on a remote Thing.
        Returns a Future."""

        if name not in td.actions:
            raise FormNotFoundException()

        form = pick_form(td, td.get_action_forms(name),
                         WebsocketSchemes.list())

        if not form:
            raise FormNotFoundException()

        ws_url = form.resolve_uri(td.base)
        ref_id = uuid.uuid4().hex

        try:
            yield self._init_conn(ws_url, ref_id)

            msg_req = WebsocketMessageRequest(
                method=WebsocketMethods.INVOKE_ACTION,
                params={
                    "name": name,
                    "parameters": input_value
                },
                msg_id=uuid.uuid4().hex)

            condition = yield self._send_message(ws_url, msg_req)

            timeout = datetime.timedelta(seconds=timeout) if timeout else None
            cond_res = yield condition.wait(timeout=timeout)

            if not cond_res:
                raise ClientRequestTimeout

            self._raise_message(ws_url, msg_req.id)
        finally:
            yield self._stop_conn(ws_url, ref_id)
Example #11
0
    async def invoke_action(self, td, name, input_value, timeout=None):
        """Invokes an Action on a remote Thing."""

        href = self._pick_coap_href(td,
                                    td.get_action_forms(name),
                                    op=InteractionVerbs.INVOKE_ACTION)

        if href is None:
            raise FormNotFoundException()

        coap_client = await aiocoap.Context.create_client_context()

        try:
            invocation_id = await self._invocation_create(coap_client,
                                                          href,
                                                          input_value,
                                                          timeout=timeout)

            request_obsv, response_obsv = await self._invocation_observe(
                coap_client, href, invocation_id, timeout=timeout)

            invocation_status = json.loads(response_obsv.payload)

            now = time.time()

            while not invocation_status.get("done"):
                if timeout and (time.time() - now) > timeout:
                    raise ClientRequestTimeout

                response_obsv = await self._invocation_next(request_obsv,
                                                            timeout=timeout)
                invocation_status = json.loads(response_obsv.payload)

            if not request_obsv.observation.cancelled:
                request_obsv.observation.cancel()

            if invocation_status.get("error"):
                raise Exception(invocation_status.get("error"))
            else:
                return invocation_status.get("result")
        finally:
            await coap_client.shutdown()
Example #12
0
    def on_property_change(self, td, name):
        """Subscribes to property changes on a remote Thing.
        Returns an Observable"""

        href = self._pick_coap_href(td,
                                    td.get_property_forms(name),
                                    op=InteractionVerbs.OBSERVE_PROPERTY)

        if href is None:
            raise FormNotFoundException()

        def next_item_builder(payload):
            value = json.loads(payload).get("value")
            init = PropertyChangeEventInit(name=name, value=value)
            return PropertyChangeEmittedEvent(init=init)

        subscribe = self._build_subscribe(href, next_item_builder)

        # noinspection PyUnresolvedReferences
        return Observable.create(subscribe)
Example #13
0
    def on_event(self, td, name):
        """Subscribes to an event on a remote Thing.
        Returns an Observable."""

        href = self._pick_coap_href(td,
                                    td.get_event_forms(name),
                                    op=InteractionVerbs.SUBSCRIBE_EVENT)

        if href is None:
            raise FormNotFoundException()

        def next_item_builder(payload):
            if payload:
                data = json.loads(payload).get("data")
                return EmittedEvent(init=data, name=name)
            else:
                return None

        subscribe = self._build_subscribe(href, next_item_builder)

        # noinspection PyUnresolvedReferences
        return Observable.create(subscribe)
Example #14
0
    def on_property_change(self, td, name):
        """Subscribes to property changes on a remote Thing.
        Returns an Observable"""

        href = self.pick_http_href(td, td.get_property_forms(name), op=InteractionVerbs.OBSERVE_PROPERTY)

        if href is None:
            raise FormNotFoundException()

        def subscribe(observer):
            """Subscription function to observe property updates using the HTTP protocol."""

            state = {"active": True}

            @handle_observer_finalization(observer)
            @tornado.gen.coroutine
            def callback():
                http_client = tornado.httpclient.AsyncHTTPClient()
                http_request = tornado.httpclient.HTTPRequest(href, method="GET")

                while state["active"]:
                    try:
                        response = yield http_client.fetch(http_request)
                        value = json.loads(response.body).get("value")
                        init = PropertyChangeEventInit(name=name, value=value)
                        observer.on_next(PropertyChangeEmittedEvent(init=init))
                    except HTTPTimeoutError:
                        pass

            def unsubscribe():
                state["active"] = False

            tornado.ioloop.IOLoop.current().add_callback(callback)

            return unsubscribe

        # noinspection PyUnresolvedReferences
        return Observable.create(subscribe)
Example #15
0
    def on_event(self, td, name):
        """Subscribes to an event on a remote Thing.
        Returns an Observable."""

        href = self.pick_http_href(td, td.get_event_forms(name))

        if href is None:
            raise FormNotFoundException()

        def subscribe(observer):
            """Subscription function to observe events using the HTTP protocol."""

            state = {"active": True}

            @handle_observer_finalization(observer)
            @tornado.gen.coroutine
            def callback():
                http_client = tornado.httpclient.AsyncHTTPClient()
                http_request = tornado.httpclient.HTTPRequest(href, method="GET")

                while state["active"]:
                    try:
                        response = yield http_client.fetch(http_request)
                        payload = json.loads(response.body).get("payload")
                        observer.on_next(EmittedEvent(init=payload, name=name))
                    except HTTPTimeoutError:
                        pass

            def unsubscribe():
                state["active"] = False

            tornado.ioloop.IOLoop.current().add_callback(callback)

            return unsubscribe

        # noinspection PyUnresolvedReferences
        return Observable.create(subscribe)
Example #16
0
    def invoke_action(self, td, name, input_value, timeout=None):
        """Invokes an Action on a remote Thing.
        Returns a Future."""

        con_timeout = timeout if timeout else self._connect_timeout
        req_timeout = timeout if timeout else self._request_timeout

        now = time.time()

        href = self.pick_http_href(td, td.get_action_forms(name))

        if href is None:
            raise FormNotFoundException()

        body = json.dumps({"input": input_value})
        http_client = tornado.httpclient.AsyncHTTPClient()

        try:
            http_request = tornado.httpclient.HTTPRequest(
                href, method="POST",
                body=body,
                headers=self.JSON_HEADERS,
                connect_timeout=con_timeout,
                request_timeout=req_timeout)
        except HTTPTimeoutError:
            raise ClientRequestTimeout

        response = yield http_client.fetch(http_request)
        invocation_url = json.loads(response.body).get("invocation")

        @tornado.gen.coroutine
        def check_invocation():
            parsed = parse.urlparse(href)

            invoc_href = "{}://{}/{}".format(
                parsed.scheme,
                parsed.netloc,
                invocation_url.lstrip("/"))

            invoc_http_req = tornado.httpclient.HTTPRequest(
                invoc_href, method="GET",
                connect_timeout=con_timeout,
                request_timeout=req_timeout)

            self._logr.debug("Checking invocation: {}".format(invocation_url))

            try:
                invoc_res = yield http_client.fetch(invoc_http_req)
            except HTTPTimeoutError:
                self._logr.debug("Timeout checking invocation: {}".format(invocation_url))
                raise tornado.gen.Return((False, None))

            status = json.loads(invoc_res.body)

            if status.get("done") is False:
                raise tornado.gen.Return((False, None))

            if status.get("error") is not None:
                raise tornado.gen.Return((True, Exception(status.get("error"))))
            else:
                raise tornado.gen.Return((True, tornado.gen.Return(status.get("result"))))

        while True:
            done, result = yield check_invocation()

            if done:
                raise result
            elif timeout and (time.time() - now) > timeout:
                raise ClientRequestTimeout
Example #17
0
    def invoke_action(self,
                      td,
                      name,
                      input_value,
                      timeout=None,
                      qos_publish=QOS_2,
                      qos_subscribe=QOS_1):
        """Invokes an Action on a remote Thing.
        Returns a Future."""

        timeout = timeout if timeout else self._timeout_default
        ref_id = uuid.uuid4().hex

        href = self._pick_mqtt_href(td, td.get_action_forms(name))

        if href is None:
            raise FormNotFoundException()

        parsed_href = self._parse_href(href)
        broker_url = parsed_href["broker_url"]

        topic_invoke = parsed_href["topic"]
        topic_result = ActionMQTTHandler.to_result_topic(topic_invoke)

        try:
            yield self._init_client(broker_url, ref_id)
            yield self._subscribe(broker_url, topic_result, qos_subscribe)

            input_data = {"id": uuid.uuid4().hex, "input": input_value}

            input_payload = json.dumps(input_data).encode()

            yield self._publish(broker_url, topic_invoke, input_payload,
                                qos_publish)

            ini = time.time()

            while True:
                self._logr.debug(
                    "Checking invocation topic: {}".format(topic_result))

                if timeout and (time.time() - ini) > timeout:
                    self._logr.warning(
                        "Timeout invoking Action: {}".format(topic_result))
                    raise ClientRequestTimeout

                msg_match = self._next_match(
                    broker_url, topic_result,
                    lambda item: item[1].get("id") == input_data.get("id"))

                if not msg_match:
                    yield self._wait_on_message(broker_url, topic_result)
                    continue

                msg_id, msg_data, msg_time = msg_match

                if msg_data.get("error", None) is not None:
                    raise Exception(msg_data.get("error"))
                else:
                    raise tornado.gen.Return(msg_data.get("result"))
        finally:
            yield self._disconnect_client(broker_url, ref_id)
Example #18
0
    def write_property(self,
                       td,
                       name,
                       value,
                       timeout=None,
                       qos_publish=QOS_2,
                       qos_subscribe=QOS_1,
                       wait_ack=True):
        """Updates the value of a Property on a remote Thing.
        Due to the MQTT binding design this coroutine yields as soon as the write message has
        been published and will not wait for a custom write handler that yields to another coroutine
        Returns a Future."""

        timeout = timeout if timeout else self._timeout_default
        ref_id = uuid.uuid4().hex

        href_write = self._pick_mqtt_href(td,
                                          td.get_property_forms(name),
                                          op=InteractionVerbs.WRITE_PROPERTY)

        if href_write is None:
            raise FormNotFoundException()

        parsed_href_write = self._parse_href(href_write)
        broker_url = parsed_href_write["broker_url"]

        topic_write = parsed_href_write["topic"]
        topic_ack = PropertyMQTTHandler.to_write_ack_topic(topic_write)

        try:
            yield self._init_client(broker_url, ref_id)
            yield self._subscribe(broker_url, topic_ack, qos_subscribe)

            write_data = {
                "action": "write",
                "value": value,
                "ack": uuid.uuid4().hex
            }

            write_payload = json.dumps(write_data).encode()

            yield self._publish(broker_url, topic_write, write_payload,
                                qos_publish)

            if not wait_ack:
                return

            ini = time.time()

            while True:
                self._logr.debug(
                    "Checking write ACK topic: {}".format(topic_ack))

                if timeout and (time.time() - ini) > timeout:
                    self._logr.warning(
                        "Timeout writing Property: {}".format(topic_ack))
                    raise ClientRequestTimeout

                msg_match = self._next_match(
                    broker_url, topic_ack,
                    lambda item: item[1].get("ack") == write_data.get("ack"))

                if msg_match:
                    break

                yield self._wait_on_message(broker_url, topic_ack)
        finally:
            yield self._disconnect_client(broker_url, ref_id)
Example #19
0
    def read_property(self,
                      td,
                      name,
                      timeout=None,
                      qos_publish=QOS_1,
                      qos_subscribe=QOS_1):
        """Reads the value of a Property on a remote Thing.
        Returns a Future."""

        timeout = timeout if timeout else self._timeout_default
        ref_id = uuid.uuid4().hex

        forms = td.get_property_forms(name)

        href_read = self._pick_mqtt_href(td,
                                         forms,
                                         op=InteractionVerbs.READ_PROPERTY)

        href_obsv = self._pick_mqtt_href(td,
                                         forms,
                                         op=InteractionVerbs.OBSERVE_PROPERTY)

        if href_read is None or href_obsv is None:
            raise FormNotFoundException()

        parsed_href_read = self._parse_href(href_read)
        parsed_href_obsv = self._parse_href(href_obsv)

        topic_read = parsed_href_read["topic"]
        topic_obsv = parsed_href_obsv["topic"]

        broker_read = parsed_href_read["broker_url"]
        broker_obsv = parsed_href_obsv["broker_url"]

        try:
            yield self._init_client(broker_read, ref_id)
            broker_obsv != broker_read and (yield self._init_client(
                broker_obsv, ref_id))

            yield self._subscribe(broker_obsv, topic_obsv, qos_subscribe)

            read_time = time.time()
            read_payload = json.dumps({"action": "read"}).encode()

            yield self._publish(broker_read, topic_read, read_payload,
                                qos_publish)

            ini = time.time()

            while True:
                self._logr.debug(
                    "Checking property update topic: {}".format(topic_obsv))

                if timeout and (time.time() - ini) > timeout:
                    self._logr.warning(
                        "Timeout reading Property: {}".format(topic_obsv))
                    raise ClientRequestTimeout

                msg_match = self._next_match(broker_obsv, topic_obsv,
                                             lambda item: item[2] >= read_time)

                if not msg_match:
                    yield self._wait_on_message(broker_obsv, topic_obsv)
                    continue

                msg_id, msg_data, msg_time = msg_match

                raise tornado.gen.Return(msg_data.get("value"))
        finally:
            yield self._disconnect_client(broker_read, ref_id)
            broker_obsv != broker_read and (yield self._disconnect_client(
                broker_obsv, ref_id))