Skip to content

Commit 836ab1c

Browse files
authored
Merge pull request #76 from eclipse-thingweb/request-thing-description
feat: implement requestThingDescription method
2 parents 6c415fe + e5b5745 commit 836ab1c

File tree

11 files changed

+374
-145
lines changed

11 files changed

+374
-145
lines changed

README.md

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,54 +36,49 @@ You can then use the package in your project by adding
3636

3737
## Usage
3838

39-
Below you can find a very basic example for reading a status from a Thing (using the
40-
`coap.me` test server).
41-
To do so, a Thing Description JSON string is first parsed and turned into a
42-
`ThingDescription` object, which is then passed to a WoT runtime created by a
43-
`Servient` with CoAP support.
39+
Below you can find a basic example for incrementing and reading the value of a
40+
counter Thing, which is part of the
41+
[Thingweb Online Things](https://www.thingweb.io/services).
42+
43+
In the example, we first create a WoT runtime using a `Servient` with CoAP
44+
support.
45+
With the runtime, we then retrieve a TD (using the `requestThingDescription()`
46+
method) and consume it (using the `consume()` method), creating a
47+
`ConsumedThing` object,
48+
Afterward, the actual interactions with the counter are performed by calling the
49+
`invokeAction()` and `readProperty()` methods on the `ConsumedThing`.
4450

4551
```dart
4652
import 'package:dart_wot/dart_wot.dart';
4753
4854
Future<void> main(List<String> args) async {
49-
final CoapClientFactory coapClientFactory = CoapClientFactory();
5055
final servient = Servient(
51-
protocolClients: [coapClientFactory]
56+
clientFactories: [
57+
CoapClientFactory(),
58+
],
5259
);
5360
final wot = await servient.start();
5461
55-
final thingDescriptionJson = '''
56-
{
57-
"@context": "http://www.w3.org/ns/td",
58-
"title": "Test Thing",
59-
"base": "coap://coap.me",
60-
"security": ["nosec_sc"],
61-
"securityDefinitions": {
62-
"nosec_sc": {
63-
"scheme": "nosec"
64-
}
65-
},
66-
"properties": {
67-
"status": {
68-
"forms": [
69-
{
70-
"href": "/hello"
71-
}
72-
]
73-
}
74-
}
75-
}
76-
''';
77-
78-
final thingDescription = ThingDescription(thingDescriptionJson);
62+
final url = Uri.parse('coap://plugfest.thingweb.io/counter');
63+
print('Requesting TD from $url ...');
64+
final thingDescription = await wot.requestThingDescription(url);
65+
7966
final consumedThing = await wot.consume(thingDescription);
80-
final status = await consumedThing.readProperty("status");
67+
print(
68+
'Successfully retrieved and consumed TD with title '
69+
'"${thingDescription.title}"!',
70+
);
71+
72+
print('Incrementing counter ...');
73+
await consumedThing.invokeAction('increment');
74+
75+
final status = await consumedThing.readProperty('count');
8176
final value = await status.value();
82-
print(value);
77+
print('New counter value: $value');
8378
}
8479
```
8580

86-
A more complex example can be found in the `example` directory.
81+
More complex examples can be found in the `example` directory.
8782

8883
## Additional information
8984

example/example.dart

Lines changed: 12 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -8,126 +8,28 @@
88

99
import 'package:dart_wot/dart_wot.dart';
1010

11-
final Map<String, BasicCredentials> basicCredentials = {
12-
'urn:test': BasicCredentials('rw', 'readwrite'),
13-
};
14-
15-
Future<BasicCredentials?> basicCredentialsCallback(
16-
Uri uri,
17-
Form? form, [
18-
BasicCredentials? invalidCredentials,
19-
]) async {
20-
final id = form?.thingDescription.identifier;
21-
22-
return basicCredentials[id];
23-
}
24-
2511
Future<void> main(List<String> args) async {
26-
final coapClientFactory = CoapClientFactory();
27-
final httpClientFactory =
28-
HttpClientFactory(basicCredentialsCallback: basicCredentialsCallback);
29-
final mqttClientFactory = MqttClientFactory();
30-
3112
final servient = Servient(
3213
clientFactories: [
33-
coapClientFactory,
34-
httpClientFactory,
35-
mqttClientFactory,
14+
CoapClientFactory(),
3615
],
3716
);
38-
3917
final wot = await servient.start();
4018

41-
const thingDescriptionJson = '''
42-
{
43-
"@context": "http://www.w3.org/ns/td",
44-
"title": "Test Thing",
45-
"id": "urn:test",
46-
"base": "coap://coap.me",
47-
"security": ["auto_sc"],
48-
"securityDefinitions": {
49-
"auto_sc": {
50-
"scheme": "auto"
51-
}
52-
},
53-
"properties": {
54-
"status": {
55-
"forms": [
56-
{
57-
"href": "/hello"
58-
}
59-
]
60-
},
61-
"status2": {
62-
"observable": true,
63-
"forms": [
64-
{
65-
"href": "mqtt://test.mosquitto.org:1884",
66-
"mqv:filter": "test",
67-
"op": ["readproperty", "observeproperty"],
68-
"contentType": "text/plain"
69-
}
70-
]
71-
}
72-
},
73-
"actions": {
74-
"toggle": {
75-
"forms": [
76-
{
77-
"href": "mqtt://test.mosquitto.org:1884",
78-
"mqv:topic": "test",
79-
"mqv:retain": true
80-
}
81-
]
82-
}
83-
}
84-
}
85-
''';
19+
final url = Uri.parse('coap://plugfest.thingweb.io/counter');
20+
print('Requesting TD from $url ...');
21+
final thingDescription = await wot.requestThingDescription(url);
8622

87-
final thingDescription = ThingDescription(thingDescriptionJson);
8823
final consumedThing = await wot.consume(thingDescription);
89-
final status = await consumedThing.readProperty('status');
90-
final value = await status.value();
91-
print(value);
92-
final subscription = await consumedThing.observeProperty(
93-
'status2',
94-
(data) async {
95-
final value = await data.value();
96-
print(value);
97-
},
24+
print(
25+
'Successfully retrieved and consumed TD with title '
26+
'"${thingDescription.title}"!',
9827
);
9928

100-
await consumedThing.invokeAction('toggle', 'Hello World!');
101-
await consumedThing.invokeAction('toggle', 'Hello World!');
102-
await consumedThing.invokeAction('toggle', 'Hello World!');
103-
await consumedThing.invokeAction('toggle', 'Hello World!');
104-
await subscription.stop();
29+
print('Incrementing counter ...');
30+
await consumedThing.invokeAction('increment');
10531

106-
final thingUri = Uri.parse(
107-
'https://raw.githubusercontent.com/w3c/wot-testing'
108-
'/b07fa6124bca7796e6ca752a3640fac264d3bcbc/events/2021.03.Online/TDs'
109-
'/Oracle/oracle-Festo_Shared.td.jsonld',
110-
);
111-
112-
final thingDiscovery = wot.discover(thingUri);
113-
114-
await for (final thingDescription in thingDiscovery) {
115-
final consumedDiscoveredThing = await wot.consume(thingDescription);
116-
print(
117-
'The title of the fetched TD is '
118-
'${consumedDiscoveredThing.thingDescription.title}.',
119-
);
120-
}
121-
122-
await consumedThing.invokeAction('toggle', 'Bye World!');
123-
await consumedThing.readAndPrintProperty('status2');
124-
print('Done!');
125-
}
126-
127-
extension ReadAndPrintExtension on ConsumedThing {
128-
Future<void> readAndPrintProperty(String propertyName) async {
129-
final output = await readProperty(propertyName);
130-
final value = await output.value();
131-
print(value);
132-
}
32+
final status = await consumedThing.readProperty('count');
33+
final value = await status.value();
34+
print('New counter value: $value');
13335
}

example/mqtt_example.dart

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright 2023 Contributors to the Eclipse Foundation. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
//
5+
// SPDX-License-Identifier: BSD-3-Clause
6+
7+
// ignore_for_file: avoid_print
8+
9+
import 'package:dart_wot/dart_wot.dart';
10+
11+
const thingDescriptionJson = '''
12+
{
13+
"@context": "https://www.w3.org/2022/wot/td/v1.1",
14+
"title": "Test Thing",
15+
"id": "urn:test",
16+
"base": "coap://coap.me",
17+
"security": ["auto_sc"],
18+
"securityDefinitions": {
19+
"auto_sc": {
20+
"scheme": "auto"
21+
}
22+
},
23+
"properties": {
24+
"status": {
25+
"observable": true,
26+
"forms": [
27+
{
28+
"href": "mqtt://test.mosquitto.org:1884",
29+
"mqv:filter": "test",
30+
"op": ["readproperty", "observeproperty"],
31+
"contentType": "text/plain"
32+
}
33+
]
34+
}
35+
},
36+
"actions": {
37+
"toggle": {
38+
"input": {
39+
"type": "string"
40+
},
41+
"forms": [
42+
{
43+
"href": "mqtt://test.mosquitto.org:1884",
44+
"mqv:topic": "test",
45+
"mqv:retain": true
46+
}
47+
]
48+
}
49+
}
50+
}
51+
''';
52+
53+
final Map<String, BasicCredentials> basicCredentials = {
54+
'urn:test': BasicCredentials('rw', 'readwrite'),
55+
};
56+
57+
Future<BasicCredentials?> basicCredentialsCallback(
58+
Uri uri,
59+
Form? form, [
60+
BasicCredentials? invalidCredentials,
61+
]) async {
62+
final id = form?.thingDescription.identifier;
63+
64+
return basicCredentials[id];
65+
}
66+
67+
Future<void> main(List<String> args) async {
68+
final servient = Servient(
69+
clientFactories: [
70+
MqttClientFactory(basicCredentialsCallback: basicCredentialsCallback),
71+
],
72+
);
73+
74+
final wot = await servient.start();
75+
76+
final thingDescription = ThingDescription(thingDescriptionJson);
77+
final consumedThing = await wot.consume(thingDescription);
78+
await consumedThing.readAndPrintProperty('status');
79+
80+
final subscription = await consumedThing.observeProperty(
81+
'status',
82+
(data) async {
83+
final value = await data.value();
84+
print(value);
85+
},
86+
);
87+
88+
await consumedThing.invokeAction('toggle', 'Hello World!');
89+
await consumedThing.invokeAction('toggle', 'Hello World!');
90+
await consumedThing.invokeAction('toggle', 'Hello World!');
91+
await consumedThing.invokeAction('toggle', 'Hello World!');
92+
await subscription.stop();
93+
94+
await consumedThing.invokeAction('toggle', 'Bye World!');
95+
await consumedThing.readAndPrintProperty('status');
96+
print('Done!');
97+
}
98+
99+
extension ReadAndPrintExtension on ConsumedThing {
100+
Future<void> readAndPrintProperty(String propertyName) async {
101+
final output = await readProperty(propertyName);
102+
final value = await output.value();
103+
print(value);
104+
}
105+
}

lib/src/binding_coap/coap_client.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,4 +538,12 @@ final class CoapClient implements ProtocolClient {
538538
yield content;
539539
}
540540
}
541+
542+
@override
543+
Future<Content> requestThingDescription(Uri url) async => _sendRequest(
544+
url,
545+
coap.RequestMethod.get,
546+
form: null,
547+
accept: coap.CoapMediaType.applicationTdJson,
548+
);
541549
}

lib/src/binding_http/http_client.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,4 +332,18 @@ final class HttpClient implements ProtocolClient {
332332

333333
yield encodedLinks;
334334
}
335+
336+
@override
337+
Future<Content> requestThingDescription(Uri url) async {
338+
final request = Request(HttpRequestMethod.get.methodName, url);
339+
const tdContentType = 'application/td+json';
340+
request.headers['Accept'] = tdContentType;
341+
342+
final response = await _client.send(request);
343+
344+
return Content(
345+
response.headers['Content-Type'] ?? tdContentType,
346+
response.stream,
347+
);
348+
}
335349
}

lib/src/binding_mqtt/mqtt_client.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,10 @@ final class MqttClient implements ProtocolClient {
251251
// TODO: implement discoverWithCoreLinkFormat
252252
throw UnimplementedError();
253253
}
254+
255+
@override
256+
Future<Content> requestThingDescription(Uri url) {
257+
// TODO: implement requestThingDescription
258+
throw UnimplementedError();
259+
}
254260
}

lib/src/core/protocol_interfaces/protocol_client.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,7 @@ abstract interface class ProtocolClient {
6262
void Function(Exception error)? error,
6363
required void Function() complete,
6464
});
65+
66+
/// Requests a Thing Description as [Content] from a [url].
67+
Future<Content> requestThingDescription(Uri url);
6568
}

0 commit comments

Comments
 (0)