Skip to content

Commit

Permalink
updates to documentation and minor bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
FadySalama committed Feb 8, 2024
1 parent 1bdbf08 commit df02d81
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 11 deletions.
30 changes: 24 additions & 6 deletions WoT/SimpleHTTPConsumer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ public async Task<IInteractionOutput<T>> ReadProperty<T>(string propertyName, In
}
}

public async Task WriteProperty<T>(string propertyName, T value, InteractionOptions? options)
public async Task WriteProperty<T>(string propertyName, T value, InteractionOptions? options = null)
{
var properties = this._td.Properties;
Form form;
Expand Down Expand Up @@ -267,7 +267,7 @@ public async Task<ISubscription> ObserveProperty<T>(string propertyName, Action<
if (listener.GetType() == typeof(Action))
throw new TypeError("listener for event " + propertyName + " specified is not a function.");

if (_activeSubscriptions.ContainsKey(propertyName))
if (_activeObservations.ContainsKey(propertyName))
throw new NotAllowedError("Event " + propertyName + " has an already active subscription.");

if (!_td.Properties.TryGetValue(propertyName, out propertyAffordance))
Expand Down Expand Up @@ -322,7 +322,7 @@ public async Task<ISubscription> ObserveProperty<T>(string propertyName, Action<
if (listener.GetType() == typeof(Action))
throw new TypeError("listener for event " + propertyName + " specified is not a function.");

if (_activeSubscriptions.ContainsKey(propertyName))
if (_activeObservations.ContainsKey(propertyName))
throw new NotAllowedError("Event " + propertyName + " has an already active subscription.");

if (!_td.Properties.TryGetValue(propertyName, out propertyAffordance))
Expand Down Expand Up @@ -606,9 +606,7 @@ public async Task<ISubscription> SubscribeEvent<T>(string eventName, Action<IInt
/// <summary>
/// Indicates if there are active subscriptions for observations or events
/// </summary>
/// <value>
/// wether there are active subscriptions
/// </value>
/// <value>there are active subscriptions</value>
public bool HasActiveListeners { get => _activeObservations.Count > 0 || _activeSubscriptions.Count > 0; }


Expand Down Expand Up @@ -672,6 +670,16 @@ protected Form FindSuitableForm(Form[] forms, string op, string scheme, Interact
return form;
}

public void AddObservation(string name, Subscription sub)
{
_activeObservations.Add(name, sub);
}

public void AddSubscription(string name, Subscription sub)
{
_activeSubscriptions.Add(name, sub);
}

public void RemoveObservation(string name)
{
_activeObservations.Remove(name);
Expand Down Expand Up @@ -864,6 +872,16 @@ public Subscription(SubscriptionType type, string name, InteractionAffordance in
_active = true;
tokenSource = new CancellationTokenSource();
_cancellationToken = tokenSource.Token;
switch(_type)
{
case SubscriptionType.Event:
_thing.AddSubscription(_name, this);
break;
case SubscriptionType.Observation:
_thing.AddObservation(_name, this);
break;
}

}

public bool Active => _active;
Expand Down
7 changes: 6 additions & 1 deletion WoT/WoT.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
<PackageId>WoT.Net</PackageId>
<Product>WoT.Net</Product>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/tum-esi/WoT.Net</PackageProjectUrl>
<PackageProjectUrl>https://tum-esi.github.io/WoT.Net/</PackageProjectUrl>
<Description>A .NET Standard 2.0 implementation of the W3C Web of Things (WoT) Scripting API</Description>
<RepositoryUrl>https://github.com/tum-esi/WoT.Net</RepositoryUrl>
<PackageIcon>wot_dot_net_logo.png</PackageIcon>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageTags>Web of Things; WoT; IoT; HTTP</PackageTags>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>

<ItemGroup>
Expand All @@ -29,6 +30,10 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Include="docGeneration\images\wot_dot_net_logo.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>

<ItemGroup>
Expand Down
182 changes: 181 additions & 1 deletion WoT/docGeneration/docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -1 +1,181 @@
# Getting Started
# Getting Started

To interact with a Consumed Thing, perform the following step:

* Install package using NuGet and bring namespaces into scope

```csharp
using WoT;
using WoT.Definitions;
using WoT.Implementation;
```

* Instantiate a new ``SimpleHTTPConsumer``

```csharp
SimpleHTTPConsumer consumer = new SimpleHTTPConsumer();
```

* The ``consumer`` can either request the TD from an HTTP URL or can consume a TD string stored in a file or that is hard coded. To request at TD from an HTTP URL, do

```csharp
ThingDescription td = await consumer.RequestThingDescription("http://plugfest.thingweb.io:8083/testthing");
```

* To convert a TD string to a ``ThingDescription`` object, do

```csharp
string tdString = "{...}";
ThingDescription td = JSONConvert.Deserialize<ThingDescription>(tdString);
```

* The ``consumer`` can now consume the TD object to provide interaction capabilities

```csharp
SimpleConsumedThing consumedThing = await consumer.Consume(td) as SimpleConsumedThing;
```

* Reading a property works as follows

```csharp
// Read a boolean
bool boolean = await (await consumedThing.ReadProperty<bool>("bool")).Value();
Console.WriteLine("Read a boolean: " + boolean);
// Read an integer
int integer = await (await consumedThing.ReadProperty<int>("int")).Value();
Console.WriteLine("Read an integer: " + integer);
// Read a number
float number = await (await consumedThing.ReadProperty<float>("num")).Value();
Console.WriteLine("Read a number: " +number);
// Read a string
string str = await (await consumedThing.ReadProperty<string>("string")).Value();
Console.WriteLine("Read a string: " + str);
// Read an array
object[] array = await (await consumedThing.ReadProperty<object[]>("array")).Value();
Console.WriteLine("Read a string: " + JsonConvert.SerializeObject(array));
// Read an object
Dictionary<string, object> obj = await (await consumedThing.ReadProperty<Dictionary<string, object>>("object")).Value();
Console.WriteLine("Read a string: " + JsonConvert.SerializeObject(obj));
```

> [!NOTE]
> The JSON Schema types (``"null"``, ``"boolean"``, ``"integer"``, ``"number"``, ``"string"``, ``"array"``, ``"object"``) are mapped in C# according to the [TD Specification](https://www.w3.org/TR/wot-thing-description11) as follows:
> * ``"null"`` &rarr; ``null``
> * ``"boolean"`` &rarr; ``bool``
> * ``"integer"`` &rarr; ``int``
> * ``"number"`` &rarr; ``double``
> * ``"string"`` &rarr; ``string``
> * ``"array"`` &rarr; ``T[]`` or ``List<T>``
> * ``"object"`` &rarr; ``Dictionary<string,T>``

* Writing a property looks as follows:

```csharp
await consumedThing.WriteProperty<int>("int", 5);
```

* Invoking actions:

```csharp
// Invoke Action with no input and no output
await consumedThing.InvokeAction("void-void");

// Invoke Action with an input and no output
await consumedThing.InvokeAction("int-void", 1);

// Invoke Action with no input but an output
int output = await (await consumedThing.InvokeAction<int>("void-int")).Value();
Console.WriteLine("Output of 'void-int' action was: " + output);

// Invoke Action with an input and an output
int output2 = await (await consumedThing.InvokeAction<int, int>("int-int", 4)).Value();
Console.WriteLine("Output of 'void-int' action was: " + output2);
```

* Subscribing to events:

```csharp
var sub = await consumedThing.SubscribeEvent<int>("on-int", async (output) =>
{
Console.WriteLine("Event:");
Console.WriteLine(await output.Value());
Console.WriteLine("---------------------");
});
// Stop subscription
sub.stop()
```

Here is the full example:

```csharp
using Newtonsoft.Json;
using WoT;
using WoT.Definitions;
using WoT.Implementation;

SimpleHTTPConsumer consumer = new SimpleHTTPConsumer();
ThingDescription td = await consumer.RequestThingDescription("http://plugfest.thingweb.io:8083/testthing");
SimpleConsumedThing consumedThing = await consumer.Consume(td) as SimpleConsumedThing;

// Read a boolean
bool boolean = await (await consumedThing.ReadProperty<bool>("bool")).Value();
Console.WriteLine("Read a boolean: " + boolean);
// Read an integer
int integer = await (await consumedThing.ReadProperty<int>("int")).Value();
Console.WriteLine("Read an integer: " + integer);
// Read a number
float number = await (await consumedThing.ReadProperty<float>("num")).Value();
Console.WriteLine("Read a number: " +number);
// Read a string
string str = await (await consumedThing.ReadProperty<string>("string")).Value();
Console.WriteLine("Read a string: " + str);
// Read an array
object[] array = await (await consumedThing.ReadProperty<object[]>("array")).Value();
Console.WriteLine("Read a string: " + JsonConvert.SerializeObject(array));
// Read an object
Dictionary<string, object> obj = await (await consumedThing.ReadProperty<Dictionary<string, object>>("object")).Value();
Console.WriteLine("Read a string: " + JsonConvert.SerializeObject(obj));


// Invoke Action with no input and no output
await consumedThing.InvokeAction("void-void");

// Invoke Action with an input and no output
await consumedThing.InvokeAction("int-void", 1);

// Invoke Action with no input but an output
int output = await (await consumedThing.InvokeAction<int>("void-int")).Value();
Console.WriteLine("Output of 'void-int' action was: " + output);

// Invoke Action with an input and an output
int output2 = await (await consumedThing.InvokeAction<int, int>("int-int", 4)).Value();
Console.WriteLine("Output of 'void-int' action was: " + output2);

if (consumedThing != null)
{

// Subscribe to Event
var sub = await consumedThing.SubscribeEvent<int>("on-int", async (output) =>
{
Console.WriteLine("Event:");
Console.WriteLine(await output.Value());
Console.WriteLine("---------------------");
});

var task = Task.Run(async () =>
{
Console.WriteLine("Here");
Console.WriteLine(consumedThing.HasActiveListeners);
while (consumedThing.HasActiveListeners) {
// Write an int
await consumedThing.WriteProperty<int>("int", 5);
await Task.Delay(TimeSpan.FromSeconds(1));
}
return;
});

Task stopTask = Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith(async (task) => { await sub.Stop(); });
await task;
}
Console.WriteLine("Done");
```
41 changes: 40 additions & 1 deletion WoT/docGeneration/docs/introduction.md
Original file line number Diff line number Diff line change
@@ -1 +1,40 @@
# Introduction
# Introduction

A .NET Standard 2.0 implementation of the W3C Web of Things (WoT) [Scripting API](https://www.w3.org/TR/wot-scripting-api/), inspired by [node-wot](https://github.com/eclipse-thingweb/node-wot)

## What is the W3C Web of Things (WoT)?

The [W3C Web of Things](https://www.w3.org/WoT/) is a standardization effort that aims to facilitate the interoperability between the highly fragmented IoT technologies.
Instead of imposing new technologies, WoT aims to provide a standardized model for modeling and describing the capabilities and the network/web interface that any
IoT entity is providing. In the context of WoT, the capabilities of any entity are modeled as one of three interaction affordances:

* **Property Affordances**: representing data sources or sinks that can be read or written to.
* **Action Affordances**: representing operations that usually take longer or may physically affect the environment.
* **Event Affordances**: representing any notifications or streams and the means to subscribe to them.

Each entity is then capable of describing its own WoT interface using a standardized description format called the [Thing Description (TD)](https://www.w3.org/TR/wot-thing-description11/),
a JSON-LD document that is both highly human- and machine-readable and contains the entity's WoT model and any additional related metadata.

## Library Structure

The library is structured as follows:

* ### ``WoT`` namespace

Top-level namespace of the library which includes all definitions of the conformance class interfaces as described in the [WoT Scripting API](https://www.w3.org/TR/wot-scripting-api/). These are ``Cosumer``, ``Producer`` and ``Discovery``. These interfaces can be implemented to extend the capabilities of the stack.

* ### ``WoT.Definitions`` namespace

This namespace includes all interfaces and classes required for defining the ``ThingDescription`` class as described in the [TD Specification](https://www.w3.org/TR/wot-thing-description11/). This class is used as a cornerstone for building the rest of the library.

* ### ``WoT.Implementation`` namespace

This namespace includes all implementations of the interfaces defined in ``WoT`` namespace. These implementations provide the capability of implementing and/or interacting with WoT Entities.

* ### ``WoT.Errors`` namespace

This namespace contains definitions of all errors (exceptions) defined in the context of WoT

* ### ``WoT.TDHelpers`` namespace

This namespace contains all ``JSONConverter``s and needed to serialize and deserialize the TD.
4 changes: 2 additions & 2 deletions WoT/docGeneration/images/WoT_DoT_Net_Logo_no_background.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified WoT/docGeneration/images/wot_dot_net_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit df02d81

Please sign in to comment.