def test_coroutine(): wot = WoT(servient=servient) td_01_str = json.dumps(TD_DICT_01) td_02_str = json.dumps(TD_DICT_02) exposed_thing_01 = wot.produce(td_01_str) exposed_thing_02 = wot.produce(td_02_str) exposed_thing_01.expose() exposed_thing_02.expose() catalogue = yield fetch_catalogue(servient) assert len(catalogue) == 2 assert exposed_thing_01.thing.url_name in catalogue.get( TD_DICT_01["id"]) assert exposed_thing_02.thing.url_name in catalogue.get( TD_DICT_02["id"]) td_01_catalogue = yield fetch_catalogue_td(servient, TD_DICT_01["id"]) assert td_01_catalogue["id"] == TD_DICT_01["id"] assert td_01_catalogue["title"] == TD_DICT_01["title"] catalogue_expanded = yield fetch_catalogue(servient, expanded=True) num_props = len(TD_DICT_01.get("properties", {}).keys()) assert len(catalogue_expanded) == 2 assert TD_DICT_01["id"] in catalogue_expanded assert TD_DICT_02["id"] in catalogue_expanded assert len( catalogue_expanded[TD_DICT_01["id"]]["properties"]) == num_props
def test_duplicated_thing_names(servient): """A Servient rejects Things with duplicated IDs.""" description_01 = { "@context": [WOT_TD_CONTEXT_URL], "id": uuid.uuid4().urn, "title": Faker().sentence() } description_02 = { "@context": [WOT_TD_CONTEXT_URL], "id": uuid.uuid4().urn, "title": Faker().sentence() } description_03 = { "@context": [WOT_TD_CONTEXT_URL], "id": description_01.get("id"), "title": Faker().sentence() } description_01_str = json.dumps(description_01) description_02_str = json.dumps(description_02) description_03_str = json.dumps(description_03) wot = WoT(servient=servient) wot.produce(description_01_str) wot.produce(description_02_str) with pytest.raises(ValueError): wot.produce(description_03_str)
def test_discovery_method_local(): """All TDs contained in the Servient are returned when using the local discovery method without defining the fragment nor the query fields.""" servient = Servient(dnssd_enabled=False) wot = WoT(servient=servient) wot.produce(ThingFragment(TD_DICT_01)) wot.produce(ThingFragment(TD_DICT_02)) future_done, found = tornado.concurrent.Future(), [] def resolve(): len(found) == 2 and not future_done.done() and future_done.set_result( True) @tornado.gen.coroutine def test_coroutine(): thing_filter = ThingFilterDict(method=DiscoveryMethod.LOCAL) observable = wot.discover(thing_filter) subscription = observable.subscribe( on_next=lambda td_str: found.append(ThingDescription(td_str) ) or resolve()) yield future_done assert_equal_td_sequences(found, [TD_DICT_01, TD_DICT_02]) subscription.dispose() run_test_coroutine(test_coroutine)
async def main(td_url, sleep_time): """Subscribes to all events and properties on the remote Thing.""" wot = WoT(servient=Servient()) consumed_thing = await wot.consume_from_url(td_url) LOGGER.info("ConsumedThing: {}".format(consumed_thing)) subscriptions = [] def subscribe(intrct): LOGGER.info("Subscribing to: {}".format(intrct)) sub = intrct.subscribe( on_next=lambda item: LOGGER.info("{} :: Next :: {}".format(intrct, item)), on_completed=lambda: LOGGER.info("{} :: Completed".format(intrct)), on_error=lambda error: LOGGER.warning("{} :: Error :: {}".format(intrct, error))) subscriptions.append(sub) for name in consumed_thing.properties: if consumed_thing.properties[name].observable: subscribe(consumed_thing.properties[name]) for name in consumed_thing.events: subscribe(consumed_thing.events[name]) await asyncio.sleep(sleep_time) for subscription in subscriptions: LOGGER.info("Disposing: {}".format(subscription)) subscription.dispose()
async def fetch_consumed_thing(td_url, protocol): """Gets the remote Thing Description and returns a ConsumedThing.""" clients = [build_protocol_client(protocol)] wot = WoT(servient=Servient(clients=clients)) consumed_thing = await wot.consume_from_url(td_url) return consumed_thing
def start(self): """Starts the servers and returns an instance of the WoT object.""" with (yield self._servient_lock.acquire()): self.refresh_forms() yield [server.start() for server in six.itervalues(self._servers)] self._start_catalogue() yield self._start_dnssd() self._is_running = True raise tornado.gen.Return(WoT(servient=self))
def test_discovery_fragment(): """The Thing filter fragment attribute enables discovering Things by matching TD fields.""" servient = Servient(dnssd_enabled=False) wot = WoT(servient=servient) wot.produce(ThingFragment(TD_DICT_01)) wot.produce(ThingFragment(TD_DICT_02)) def first(thing_filter): """Returns the first TD discovery for the given Thing filter.""" future_done, found = tornado.concurrent.Future(), [] def resolve(): not future_done.done() and future_done.set_result(True) @tornado.gen.coroutine def discover_first(): observable = wot.discover(thing_filter) subscription = observable.subscribe( on_next=lambda td_str: found.append(ThingDescription(td_str) ) or resolve()) yield future_done subscription.dispose() assert len(found) raise tornado.gen.Return(found[0]) return tornado.ioloop.IOLoop.current().run_sync( discover_first, timeout=TIMEOUT_DISCOVER) fragment_td_pairs = [({ "name": TD_DICT_01.get("name") }, TD_DICT_01), ({ "version": { "instance": "2.0.0" } }, TD_DICT_02), ({ "id": TD_DICT_02.get("id") }, TD_DICT_02), ({ "security": [{ "scheme": "psk" }] }, TD_DICT_01)] for fragment, td_expected in fragment_td_pairs: td_found = first( ThingFilterDict(method=DiscoveryMethod.LOCAL, fragment=fragment)) assert_equal_tds(td_found, td_expected)
def test_coroutine(): wot = WoT(servient=servient) td_01_str = json.dumps(TD_DICT_01) td_02_str = json.dumps(TD_DICT_02) wot.produce(td_01_str).expose() wot.produce(td_02_str) catalogue = yield fetch_catalogue(servient) assert len(catalogue) == 1 assert TD_DICT_01["id"] in catalogue
def test_produce_model_consumed_thing(): """Things can be produced from ConsumedThing instances.""" servient = Servient() wot = WoT(servient=servient) td_str = json.dumps(TD_EXAMPLE) consumed_thing = wot.consume(td_str) exposed_thing = wot.produce(consumed_thing) assert exposed_thing.id == consumed_thing.td.id assert exposed_thing.name == consumed_thing.td.name assert len(exposed_thing.properties) == len(consumed_thing.td.properties) assert len(exposed_thing.actions) == len(consumed_thing.td.actions) assert len(exposed_thing.events) == len(consumed_thing.td.events)
def test_produce_model_thing_template(): """Things can be produced from ThingTemplate instances.""" thing_id = Faker().url() thing_name = Faker().sentence() thing_template = ThingFragment({"id": thing_id, "name": thing_name}) servient = Servient() wot = WoT(servient=servient) exp_thing = wot.produce(thing_template) assert servient.get_exposed_thing(thing_id) assert exp_thing.id == thing_id assert exp_thing.name == thing_name
def test_produce_model_str(): """Things can be produced from TD documents serialized to JSON-LD string.""" td_str = json.dumps(TD_EXAMPLE) thing_id = TD_EXAMPLE.get("id") servient = Servient() wot = WoT(servient=servient) assert wot.servient is servient exp_thing = wot.produce(td_str) assert servient.get_exposed_thing(thing_id) assert exp_thing.thing.id == thing_id assert_exposed_thing_equal(exp_thing, TD_EXAMPLE)
def test_produce_from_url(td_example_tornado_app): """ExposedThings can be created from URLs that provide Thing Description documents.""" app_port = find_free_port() td_example_tornado_app.listen(app_port) url_valid = "http://localhost:{}/".format(app_port) url_error = "http://localhost:{}/{}".format(app_port, Faker().pystr()) wot = WoT(servient=Servient()) @tornado.gen.coroutine def test_coroutine(): exposed_thing = yield wot.produce_from_url(url_valid) assert exposed_thing.thing.id == TD_EXAMPLE.get("id") with pytest.raises(Exception): yield wot.produce_from_url(url_error) run_test_coroutine(test_coroutine)
async def main(): wot = WoT(servient=Servient()) consumed_thing = await wot.consume_from_url( 'http://127.0.0.1:9090/urn-dev-wot-example-coffee-machine-97e83de1-f5c9-a4a0-23b6-be918d3a22ca' ) LOGGER.info('Consumed Thing: {}'.format(consumed_thing)) # Read property allAvailableResources allAvailableResources = await consumed_thing.read_property( 'allAvailableResources') LOGGER.info( 'allAvailableResources value is: {}'.format(allAvailableResources)) # Now let's change water level to 80 allAvailableResources['water'] = 80 await consumed_thing.write_property('allAvailableResources', allAvailableResources) # And see that the water level has changed allAvailableResources = await consumed_thing.read_property( 'allAvailableResources') LOGGER.info('allAvailableResources value after change is: {}'.format( allAvailableResources)) # It's also possible to set a client-side handler for observable properties consumed_thing.properties['maintenanceNeeded'].subscribe( on_next=lambda data: LOGGER.info( f'Value changed for an observable property: {data}'), on_completed=LOGGER.info( 'Subscribed for an observable property: maintenanceNeeded'), on_error=lambda error: LOGGER.info( f'Error for an observable property maintenanceNeeded: {error}')) # Now let's make 3 cups of latte! makeCoffee = await consumed_thing.invoke_action('makeDrink', { 'drinkId': 'latte', 'size': 'l', 'quantity': 3 }) if makeCoffee.get('result'): LOGGER.info('Enjoy your drink! \n{}'.format(makeCoffee)) else: LOGGER.info('Failed making your drink: {}'.format(makeCoffee)) # See how allAvailableResources property value has changed allAvailableResources = await consumed_thing.read_property( 'allAvailableResources') LOGGER.info( 'allAvailableResources value is: {}'.format(allAvailableResources)) # Let's add a scheduled task scheduledTask = await consumed_thing.invoke_action( 'setSchedule', { 'drinkId': 'espresso', 'size': 'm', 'quantity': 2, 'time': '10:00', 'mode': 'everyday' }) LOGGER.info(f'{scheduledTask["message"]} \n{scheduledTask}') # See how it has been added to the schedules property schedules = await consumed_thing.read_property('schedules') LOGGER.info('schedules value is: \n{}'.format( json.dumps(schedules, indent=2))) # Let's set up a handler for outOfResource event consumed_thing.events['outOfResource'].subscribe( on_next=lambda data: LOGGER.info(f'New event is emitted: {data}'), on_completed=LOGGER.info('Subscribed for an event: outOfResource'), on_error=lambda error: LOGGER.info( f'Error for an event outOfResource: {error}')) # Keep the client awake unless explicitly stopped while True: await asyncio.sleep(1)
async def main(): wot = WoT(servient=Servient()) consumed_thing = await wot.consume_from_url(sys.argv[1]) print("ConsumedThing: {}".format(consumed_thing))