KWH40 issueshttps://git.rwth-aachen.de/groups/kwh40/-/issues2023-11-08T20:06:09+01:00https://git.rwth-aachen.de/kwh40/s3i/-/issues/49cannot import name 'Iterable' from 'collections'2023-11-08T20:06:09+01:00Lukas Schreibercannot import name 'Iterable' from 'collections'When running S3I in Python 3.10+, the following error message appears:
```python
>>> import s3i
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/ifos/mambaforge/envs/hsm/lib/python3.11/site-packages...When running S3I in Python 3.10+, the following error message appears:
```python
>>> import s3i
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/ifos/mambaforge/envs/hsm/lib/python3.11/site-packages/s3i/__init__.py", line 1, in <module>
from s3i.identity_provider import IdentityProvider
File "/home/ifos/mambaforge/envs/hsm/lib/python3.11/site-packages/s3i/identity_provider.py", line 6, in <module>
from jwt.algorithms import RSAPSSAlgorithm
File "/home/ifos/mambaforge/envs/hsm/lib/python3.11/site-packages/jwt/__init__.py", line 19, in <module>
from .api_jwt import (
File "/home/ifos/mambaforge/envs/hsm/lib/python3.11/site-packages/jwt/api_jwt.py", line 4, in <module>
from collections import Iterable, Mapping
ImportError: cannot import name 'Iterable' from 'collections' (/home/ifos/mambaforge/envs/hsm/lib/python3.11/collections/__init__.py)
>>>
```
This is due to a deprecation in the Python standard library that has only been patched in `pyjwt 1.7.0`. S3I currently requires `pyjwt 1.6.1` exactly.
GitLab didn't let me fork the repo (needed for putting in a PR), so I'll propose the needed change here:
Change [this line](https://git.rwth-aachen.de/kwh40/s3i/-/blame/master/pyproject.toml#L20) to require a higher version, e.g. `pyjwt "2.8.0"` if that doesn't cause any problems.https://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/12S3I data model v32023-09-14T08:33:22+02:00Jiahang ChenS3I data model v3Summarized based on the previous issues #5 #10 #11, we propose here the version of the new S3I Directory information model V3.
![XLN1Rjim3BthAuHifmvsMlGmmAUYpO05Gu0XoN8PUb1j9jOgIveaPms6_VieoNPS9qvEbgZt7acHb1-iOyRLbI34ld99ZR90YEDE05tTp-c...Summarized based on the previous issues #5 #10 #11, we propose here the version of the new S3I Directory information model V3.
![XLN1Rjim3BthAuHifmvsMlGmmAUYpO05Gu0XoN8PUb1j9jOgIveaPms6_VieoNPS9qvEbgZt7acHb1-iOyRLbI34ld99ZR90YEDE05tTp-cCEP2LAa08khcd2NqIp5ewusndM4L87hRhaiiT_Kie_KIPvXimbYkPKUkCFmZsWZcsy4AT-UTjcjuzXqDUW7Hyoy5aT3wB1Cag64Y0pGtNhg_T](/uploads/89119b8c7303afe0a717d96a9ced20c6/XLN1Rjim3BthAuHifmvsMlGmmAUYpO05Gu0XoN8PUb1j9jOgIveaPms6_VieoNPS9qvEbgZt7acHb1-iOyRLbI34ld99ZR90YEDE05tTp-cCEP2LAa08khcd2NqIp5ewusndM4L87hRhaiiT_Kie_KIPvXimbYkPKUkCFmZsWZcsy4AT-UTjcjuzXqDUW7Hyoy5aT3wB1Cag64Y0pGtNhg_T.png)
And an example harvester meta model:
```json
{
"thingId": "s3i:4711",
"policyId": "s3i:4711",
"attributes":{
"apiVersion": "3.0",
"dataModel": "fml40",
"name": "Harvester",
"description": "Meta model of example harvester",
"type": "component",
"publicKey": "xxasrgrgs",
"roles": ["fml40::Harvester"],
"values": {
"ml40::Location": {
"description": "Geolocation of Harvester",
"valueSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"longitude": {"type": "double"},
"latitude": {"type": "double"}
}
},
"endpoints": [
{
"uri": "amqp://:ACCESS_TOKEN@rabbitmq.s3i.vswf.dev:5672/s3i?exchange=demo.exchange?routingKey=s3ibs://s3i:4711",
"contentType": "application/json",
"isMessageBased": true,
"requestSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "s3i-b get value request",
"type": "object",
"properties": {
"identifier": {"type": "string"},
"sender": {"type": "string"},
"receivers": {
"type": "array",
"items": {"type": "string"}
},
"attributePath": {"type": "string"},
"replyingToEndpoint": {"type": "string"},
"messageType": {"type": "string"}
}
},
"responseSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "s3i-b get value reply",
"type": "object",
"properties": {
"identifier": {"type": "string"},
"sender": {"type": "string"},
"receivers": {
"type": "array",
"items": {"type": "string"}
},
"value": {"type": "double"},
"replyingToEndpoint": {"type": "string"}
}
}
},
{
"uri": "https://broker.s3i.vswf.dev/s3ibs://s3i:4711",
"contentType": "application/json",
"methods": ["POST"],
"isMessageBased": true,
"requestSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "s3i-b get value request",
"type": "object",
"properties": {
"identifier": {"type": "string"},
"sender": {"type": "string"},
"receivers": {
"type": "array",
"items": {"type": "string"}
},
"attributePath": {"type": "string"},
"replyingToEndpoint": {"type": "string"},
"messageType": {"type": "string"}
}
}
},
{
"uri": "https://broker.s3i.vswf.dev/s3ibs://s3i:4711",
"contentType": "application/json",
"methods": ["GET"],
"isMessageBased": true,
"responseSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "s3i-b get value reply",
"type": "object",
"properties": {
"identifier": {"type": "string"},
"sender": {"type": "string"},
"receivers": {
"type": "array",
"items": {"type": "string"}
},
"value": {"type": "double"},
"replyingToEndpoint": {"type": "string"}
}
}
}
]
}
},
"services": {
"fml40::AcceptsFellingJob/accept": {
"description": "ForestML 4.0 accept felling job request",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"job": {
"type": "object",
"properties": {
"identifier": "string",
"cuttingLength": "number"
}
}
}
},
"outputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"ok": {
"type": "boolean"
}
}
},
"endpoints": [
{
"uri": "amqp://:ACCESS_TOKEN/rabbitmq.s3i.vswf.dev/s3i:5672?exchange=demo.exchange?routingKey=s3ibs://s3i:4711",
"contentType": "application/json",
"isMessageBased": true,
"requestSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"description": "s3i-b service request",
"properties": {
"identifier": {"type": "string"},
"sender": {"type": "string"},
"receivers": {
"type": "array",
"items": {"type": "string"}
},
"serviceType": {"type": "string"},
"parameters": "#/services/fml40::AcceptsFellingJob/accept/inputSchema",
"replyingToEndpoint": {"type": "string"}
}
},
"responseSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"description": "s3i-b service reply",
"properties": {
"identifier": {"type": "string"},
"sender": {"type": "string"},
"receivers": {
"type": "array",
"items": {"type": "string"}
},
"serviceType": {"type": "string"},
"results": {
"type": "object",
"properties": {
"ok": {
"type": "boolean"
}
}
},
"replyToMessage": {"type": "string"}
}
}
}
]
}
},
"events": {
"s3i:4711.newLocation": {
"description": "event emitted if location changed",
"eventSchema":{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"identifier": {"type": "string"},
"sender": {"type": "string"},
"topic": {"type": "string"},
"timestamp": {"type": "number"},
"messageType": {"type": "string"},
"content": {
"type": "object",
"properties": "#/values/ml40::Location/valueSchema"
}
}
},
"endpoints": [
{
"uri": "amqp://:ACCESS_TOKEN/rabbitmq.s3i.vswf.dev/s3i:5672?exchange=event_exchange?routingKey=s3i:4711newLocation",
"contentType": "application/json",
"isMessageBased": true
}
]
}
},
"linksToPerson": {
"ownedBy": {
"targets": ["s3i:forest_owner_müller_4711"]
}
},
"linksToThing": {
"controlledBy": {
"targets": ["s3i:fbz_4711"]
},
"child": {
"targets": ["s3i:smart_forestry_hsm_dummy_harvester_4711"]
}
}
}
}
```Jiahang ChenJiahang Chenhttps://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/11Extend S3I service (and value?) description in the directory with schema info...2023-09-07T15:02:48+02:00Anil Riza BektasExtend S3I service (and value?) description in the directory with schema informationBased on the [proposed extension](https://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/4) to include S3I events in the S3I Directory model, the current parameter description for services should be adapted in a similar fashion. A typical ser...Based on the [proposed extension](https://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/4) to include S3I events in the S3I Directory model, the current parameter description for services should be adapted in a similar fashion. A typical service description currently looks like the following:
```json
{
"serviceType": "thingServiceType",
"endpoints": ["s3ibs://s3i:1234"],
"parameterTypes": {
"identifier": "string"
},
"resultTypes": {
"result": "boolean"
}
}
```
With respect to the proposed event scheme, a service description could look like the following:
```json
{
"endpoints": [
{
"uri": "s3ib://rabbitmq.s3i.vswf.dev:5672/s3i/demo.exchange/s3i:1234",
}
],
"serviceType": "thingServiceType",
"description": "This service ...",
"parameters": {
"dataformat": "json",
"schemaType": "JSONSchema",
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "???",
"description": "JSON Schema for the parameter field of this ServiceRequest",
"properties": {
"idenifier": { "type": "number" },
}
}
},
"results": {
"dataformat": "json",
"schemaType": "JSONSchema",
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "???",
"description": "JSON Schema for the results field of this ServiceRequest",
"properties": {
"result": { "type": "boolean" },
}
}
}
}
```
Some questions remain:
- What would the "title" field represent?
- How can we describe more complex dataTypes, e.g. fml40 documents instead of a "nummber" or "string"? Should the document be breaken down to a JSON schema and inserted at the respective field. Should the fml40 document schema be avaialable somewhere else to comprehend the structure?
- With rising amount of services, this description enlarges the model size rapidly. Is this in conflict with the size of the ditto?
- All the questions from above also apply for values and their respective description.Anil Riza BektasJiahang ChenAnil Riza Bektashttps://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/10Removing redundancies when using fml402023-09-07T15:02:48+02:00Anil Riza BektasRemoving redundancies when using fml40The current fml40 reference implementation follows the approach to include functionalities as features.
A typical directory entry with the functionality `fml40::AcceptsFellingJobs` would then look like the following:
```json
{
"thing...The current fml40 reference implementation follows the approach to include functionalities as features.
A typical directory entry with the functionality `fml40::AcceptsFellingJobs` would then look like the following:
```json
{
"thingId": "s3i:1234",
"policyId": "s3i:1234",
"attributes": {
"ownedBy": "abcde",
"allEndpoints": [
"s3ibs://s3i:1234",
],
"name": "Chainsaw",
"thingStructure": {
"class": "ml40::Thing",
"links": [
{
"association": "roles",
"target": {
"class": "fml40::Chainsaw"
}
},
{
"association": "features",
"target": {
"class": "fml40::AcceptsFellingJobs"
}
}
]
}
}
}
```
These functionalities essentially act as services of the DT. Yet, this description only allows for an understanding among DT which use the fml40 reference implementation. In order to be conform with other DT in the S3I which are not based on fml40, there had to be a mapping to a S3I::Service.
I see the requirement to map fml40 functionalities to appropiate S3I services, when updating the directory entry from the fml40 reference implementation. Of course, this makes the feature of the functionality itself redundant. IMO this can be left out. Due to current discussions about S3I Events ([#2](https://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/2), [#4](https://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/4#note_1961968)), this should also be applied to events in the future.
In fml40 we functionalites may include various methods (see [here](https://git.rwth-aachen.de/kwh40/fml40-reference-implementation/-/blob/master/ml/fml40/features/functionalities/accepts_felling_jobs.py)). As of my understanding each method would represent an individual service in the s3i directory. The functionality acts as a namespace in this case.
Following the example from above, the correct directory entry without redundant features would look like the following.
```json
{
"thingId": "s3i:1234",
"policyId": "s3i:1234",
"attributes": {
"ownedBy": "abcde",
"allEndpoints": [
"s3ibs://s3i:1234",
],
"name": "Chainsaw",
"thingStructure": {
"class": "ml40::Thing",
"services": [
{
"serviceType": "fml40::AcceptsFellingJobs/acceptJob",
"endpoints": [
"s3ibs://s3i:1234"
],
"parameterTypes": {
"job": "fml40::FellingJob"
},
"resultTypes": {
"result": "boolean"
}
},
{
"serviceType": "fml40::AcceptsFellingJobs/queryJobStatus",
"endpoints": [
"s3ibs://s3i:1234"
],
"parameterTypes": {
"identifier": "string"
},
"resultTypes": {
"result": "fml40::JobStatus"
}
},
{
"serviceType": "fml40::AcceptsFellingJobs/removeJob",
"endpoints": [
"s3ibs://s3i:1234"
],
"parameterTypes": {
"identifier": "string"
},
"resultTypes": {
"result": "boolean"
}
},
]
"links": [
{
"association": "roles",
"target": {
"class": "fml40::Chainsaw"
}
}
]
}
}
}
```
Still to be discussed at this point would be the description of resultTypes in fml40. The description of resultTypes in the S3I directory assumes the result to be sent in a json e.g. like this example:
```json
{
"sender": "s3i;123",
"identifier": "s3i:123abc",
"serviceType": "fml40:AcceptsFellingJobs/acceptJob",
"results": {
"result": true,
},
"messageType": "serviceReply"
}
```Anil Riza BektasJiahang ChenAnil Riza Bektashttps://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/9Erstes Konzept für allgemeine LoRa-Nutzung im S³I-Kontext2023-02-22T17:15:51+01:00Artem Andreewitsch BliznyukErstes Konzept für allgemeine LoRa-Nutzung im S³I-Kontext## Grundlagen und Motivation
Im Rahmen verschiedener Forschungsprojekte kam die Frage nach der Nutzung von LoRa (Long Range) Kommunikation auf. LoRa ist eine neuere Funktechnologie, welche es ermöglicht (batteriebetriebene) Geräte (vor ...## Grundlagen und Motivation
Im Rahmen verschiedener Forschungsprojekte kam die Frage nach der Nutzung von LoRa (Long Range) Kommunikation auf. LoRa ist eine neuere Funktechnologie, welche es ermöglicht (batteriebetriebene) Geräte (vor allem Sensoren) über lange Distanzen verbinden. Die Reichweite und der kleine Energieverbrauch werden durch Nutzung von geringen Bandbreiten und geringen Bitraten (und den schlauen Funkansatz selber) ermöglicht.
Da das S³I eine möglichst flexible IoT-Plattform sein soll und bereits gängige Kommunikationsprotokolle wie OPC-UA, MQTT, HTTP oder AMQP unterstützt, liegt es nahe, auch solche sich im IoT-Bereich immer mehr verbreitende Technologie zu integrieren.
Hierbei gibt es einige Besonderheiten bei der Nutzung von LoRa, welche nicht aus den Augen gelassen werden dürfen:
- _Niedrige Übertragungsraten_: Durch die besondere Übertragungsart erreicht LoRa je nach benötigter Reichweite/Signal-to-Noise Ratio eine theoretische Übertragungsrate im Kilo**bit** Bereich. Dies wird durch rechtliche Bestimmungen in Deustchland noch mehr geschmälert, da man auf den erlaubten Funkbändern nur 1% der Sendezeit (z.B. insgesamt 14,4min pro 24h) nutzen kann - in anderen Worten sprechen wir von Übertragungsraten im dreistelligem **Bit**bereich.
- _Sendeverhalten der Geräte_: LoRa-Geräte werden in drei Klassen nach ihrem Sende- und Empfangsverhalten eingeteilt:
* Class A: Diese Geräte können nur in einem kurzen Zeitfenster empfangen nachdem sie selber gesendet haben. Danach können diese bis zum nächsten Senden nicht angesprochen werden.
* Class B: Diese Geräte haben regelmäßige kurze Zeitfenster für Empfang von Nachrichten. Verbraucht mehr Energie als Class A.
* Class C: Diese Geräte sind durchgänging auf Empfang (außer sie senden selber). Verbraucht am meisten Energie und sollte am besten nicht Batteriebetrieben laufen.
Je nach Klasse kann es somit zu großen Latenzen in der Kommunikation zu einem LoRa-Gerät hin kommen, wenn es nicht kontinuierlich auf Empfang ist.
- _Abhängigkeit von Gateways_: Durch die besondere Funktechnologie **muss** es besondere Gateways geben, welche LoRa-Funk empfangen können und in andere Formate übersetzen können.
- _Management eines LoRaWANs_: Sobald man für eine größere Abdeckung mit LoRa mehrere Gateways benutzt, welche verschiedene Geräte empfangen, braucht man einen Network Server um das LoRaWAN Protokoll umsetzten zu können, welches das entstandene Netzwerk verwaltet.
Eine "klassische" LoRaWAN-Architektur sieht somit folgendermaßen aus:
![grafik](/uploads/0b8857ed1ef764d5823aabb62782a3cc/grafik.png)
Mehrere Gateways können verschiedene Endgeräte empfangen, übersetzen die Nachrichten und leiten diese über bekannte TCP/IP basierte Kommunikation an einen zentralen **Network Server**. Zu seinen Aufgaben gehören:
- Entschlüsselung von Nachrichten
- Deduplikation von Nachrichten
- Empfangen von Downlink-Nachrichten an seine Endgeräte
- Routing von Downstream-Nachrichten
- Adaptive Einstellung der Datenraten der Geräte
- Überwachung des Gerätestatus
- Überprüfung neuer Geräteanmeldungen
- Loggen von Nachrichten
- Weiterleiten von Nachrichten an entsprechende Application Servers
Es gibt verschiedene (meist kommerzielle) Anbieter von solchen Network Servern, jedoch um den Open Source Grundgedanken des S³Is zu erhalten ist **Chirpstack** der aktuelle Kandidat um LoRa an das S³I anzubinden. Dieser ist eine Open Source Implementierung des Network Servers, welcher verschiedene Gateway-Typen unterstützt und APIs zur Integration gängiger Kommunikationsprotokolle ermöglicht. Die Chirpstack-Architektur sieht folgerndermaßen aus:
![grafik](/uploads/1fb6598c4a6fc6060c62cf6762c35a16/grafik.png)
Für unsere Anwendung der interessanteste Aspekt ist die Unterstützung von HTTP und MQTT (in der nächsten Version auch AMQP) Integrationen der Application Server, in unserem Fall das S³I und dessen Teilnehmer. Wir sehen somit, dass die eigentliche LoRa-Kommunikation eigentlich nur am Ende zwischen den Endgeräten und Gateways stattfindet und der Network Server und die folgenden Application Servers über "normale" TCP/IP basierte Protokolle reden.
## Integrationskonzept mit LoRa-Adapter
Das Konzept basiert auf einem neuen LoRa-Adapter der Zugriff auf das Repository hat und per MQTT zum Chirpstack vermittelt. Er ist eine Art "Übersetzer" zwischen Strukturen und Funktionalitäten von S³I und deren Varianten in der LoRa-Welt. Das Konzept soll anhand von mehreren Szenarios erläutert werden um die funktionsweise des Adapters besser nachvollziehen zu können.
### Szenario 1: Thing mit Eigenschaften welche über LoRa empfangen werden:
In diesem Szenario gibt es ein im Directory (und ggf. Repositiory) gewohnt definiertes Thing, welches ein Temperatursensor repräsentiert. Dessen aktueller Wert wird über einen per LoRa angebundenen echten Temperatursensor gesetzt.
Jedes LoRa Endgerät hat eine eindeutige devEUI, das Thing hat seine thingId. Es muss somit eine Komponente geben, welche die Zuordnung von der devEUI zur Thing-ID kennt. Wenn der Sensor zum LoRaWAN hinzugefügt wird, muss also dessen devEUI an den Adapter weitergegeben werden. Ein Nutzer müsste dann die Zuordnung beim Erstellen des Things definieren. Gleichzeitig wird von Chirpstack ein MQTT Topic für das neue Endgerät erstellt auf welches der Adapter hört. Wenn nun ein neuer Messwert gesendet wird, sendet Chirpstack diesen als Event unter dem entsprechenden Topic. Der Adapter filtert nach dem Eventtyp und wenn der Uplink registriert wurde, sucht der Adapter die passende thingId zu dem devEUI des Uplinks aus, authentifiziert sich regulär, findet die Endpoints des Things im Repository und stellt einen _SetValueRequest_ mit dem empfangenen Messwert.
![grafik](/uploads/578575f9f43ef31c7645aab4a9a0c0e7/grafik.png)
Die Konfiguration zu Beginn würde folgendermaßen aussehen:
1) Erstellen eines Device-Profils im Chirpstack mit entsprechendem Codec. Dieser wird entweder vom Hersteller bereitgestellt oder muss bei eigenen Sensoren selber erstellt werden. --> Binäres Payload wird in definiertes JSON-Objekt übersetzt. Beispielhaftes Ergebnis:
![grafik](/uploads/205df40dda0f4b3c7a9574f6e447236b/grafik.png)
2) Der Sensor meldet sich im LoRa-Netzwerk an --> Join-Event wird im Join-Topic `application/APPLICATION_ID/device/DEV_EUI/event/join` mit seiner devEUI gesendet. Beispiel Join-Event: ![grafik](/uploads/b9f541590fd42ac517b52fd4c858393c/grafik.png)
3) Der LoRa-Adapter merkt sich die **devEUI** und das **Device-Profil** als "offene Devices". Alle eingesetzten Device-Profile müssen zuvor im LoRa-Adapter aufgelistet und ihre Codecs bekannt sein.
4) Der Nutzer registriert das Thing und es bekommt seine thingId im Directory.
5) Der LoRa-Adapter präsentiert dem Nutzer seine offene Devices und der Nutzer weist die richtige thingId zu.
6) Der LoRa-Adapter kann nun das Thing und seine Attribute in der Directory nachsehen. Durch das bekannte Device-Profil, weiß der Adapter welche JSON-Felder mit Daten er erwarten kann. Diese müssen als letztes vom Nutzer den gefundenen Attributen des Things zugeordnet werden. --> Abbildung von LoRa-Nachrichteninhalten auf entsprechende attributePaths des Things um bei neuen LoRa-Nachrichten die korrekten SetValueRequests stellen zu können.
### Szenario 2: Kommunikation mit einem Thing über LoRa
In diesem Szenario soll ein Thing auf der "Edge" exsitieren und nur per LoRa erreichbar sein. Er bietet einen Dienst an und ein anderer Teilnehmer möchte den Dienst nutzen.
Für ein Thing, dass über LoRa erreicht werden soll, muss ein **besonderer Endpoint** im Directory angegeben werden. Da man den Umweg über den LoRa-Adapter + Chirpstack nehmen muss, haben wir keine direkte Adresse wie in S³I-B, OPC-UA oder ähnlichem. Sattdessen ist seine Adresse so etwas wie lora://[thingId]. Wenn wir nun ein ServiceRequest an etwas mit lora://[thingId] senden, sollen diese automatisch an den LoRa-Adapter gesendet werden. Dieser kann die mitgelieferte thingId einer devEUI zuordnen (Die Korresondenz wurde beim Hinzufügen des jeweiligen LoRa-Knotens ja von einem Nutzer definiert). Dieser kann nun auf dem korrekten Topic einen Downlink posten, welcher von Chirpstack an die jeweilige Adresse bei der nächsten Möglichkeit gesendet wird. (Durch die verschiedenen Geräteklassen kann es jedoch zu großen Latenzen kommen) Dabei muss sich der LoRa-Adapter merken welche Adresse auf welche ServiceReply wartet, damit die Senderadresse nicht per LoRa "rumgeschleppt" werden muss. Im Payload des Downlinks müssen deswegen möglichst kompakt (Base64 encoding z.B.) die Art des Requests und ggf. die übergebenen KeyValues gelistet werden.
Aktuell gibt es mit GetValue, SetValue, DeleteAttribute, CreateAttribute vier vordefinierte Requests und individuell gestaltbare ServiceRequests. Falls ein Service angeboten wird muss dies neben der devEUI Zuordnung ebenfalls vom LoRa-Adapter festgehalten werden und einer Nummer zugeordnet werden. Somit kann die Art der Nachricht z.B. im ersten Byte des Payloads definiert werden (4 Arten AttributeValueMessages + bis zu 251 mögliche angebotene Services pro Thing). Wird dann per LoRa an den Service Provider gesendet, dieser decodiert sie und erkennt die Anfrage und Parameter. Daraus wird eine Antwort gestaltet, welche durch den entsprechenden Codec des Device-Profils. Diese wird ähnlich wie der Downlink (Nachrichtenart + Werte) formuliert und wie in Szenario 1 als Uplink gesendet. Wenn die Antwort dann auf dem jeweiligen Topic veröffentlicht wird, kann der LoRa-Adapter die vorher festgehaltenen offenen ServiceRequests auflösen und die entsprechenden ServiceReplies formulieren.
**ServiceRequest:**
![grafik](/uploads/8dcd7c46aedd3bc4300910c51a4245bb/grafik.png)
**ServiceReply:**
![grafik](/uploads/0efce56e53f7eceef5c2e03311a75987/grafik.png)
### Szenario 3: Edge Thing fragt Informationen ab
Tbd
### Szenario 4: User Interaktion per HMI
Tbdhttps://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/8Ein Konzept für Integration von Ad-hoc-Netzwerke in ein lokal zentralisiertes...2023-02-28T10:00:22+01:00Jiahang ChenEin Konzept für Integration von Ad-hoc-Netzwerke in ein lokal zentralisiertes, global dezentralisierte IoTDie bisherige WH4.0-mäßige Kommunikation erfolgt über das zentrale S³I. Im Vergleich zu den zentralen Ansätzen ermöglichen dezentralen Ansätze mehr Privatsphäre und Autonomie, weil kein einzelner Benutzer oder Knoten die vollständige Kon...Die bisherige WH4.0-mäßige Kommunikation erfolgt über das zentrale S³I. Im Vergleich zu den zentralen Ansätzen ermöglichen dezentralen Ansätze mehr Privatsphäre und Autonomie, weil kein einzelner Benutzer oder Knoten die vollständige Kontrolle über das gesamte System haben können/dürfen. Darüber hinaus sind dezentrale Systeme vergleichsmäßig widerstandsfähiger gegen Datenverluste oder Hardwareausfälle (Single Point of Failure), da die Daten, insbesondere sensitive Identitätsdaten, dezentral oder auf mehrere Knoten verteilt gespeichert werden können. Ein weiterer technischer Grund in Bezug auf forstliche Anwendungsszenarien besteht in die geringe Mobilfunkverfügbarkeit im heutigen Wald, sodass eine Verbindung mit der zentralen IoT-Infrastruktur nicht steig möglich ist. Somit wird im Rahmen von Smart Forestry angestrebt, die Kommunikation Schritte für Schritte zu dezentralisieren.
Abbildung 18 illustriert das erarbeitete Konzept für eine lokal zentralisierte, global dezentralisierte Kommunikationsarchitektur für Smart Forestry. Wesentliche Komponenten in diesem Konzept sind unter anderem eine zentrale IoT-Infrastruktur (S³I), und mehreren lokal zentralisierten IoT-Infrastrukturen. In der zentralen IoT-Infrastruktur werden sowohl nach dem aktuellen Stand des WH4.0-Konzepts die Identitäten sowie Metainformationen der bestehenden WH4.0-Dinge, als auch die Metadaten der lokal zentralisierten IoT-Infrastrukturen gespeichert. Bedarfsorientiert kann jeder Organisation, z.B. BaySF-Produktionsteam, oder jedem Referenzszenario, z.B. Motormanueller Holzernte eine lokale IoT-Infrastruktur zugewiesen werden. Damit wird eine lokale, IoT-mäßige Kommunikation zwischen den in mit der Infrastruktur vernetzten WH4.0-Dinge realisiert. Darüber hinaus können lokal zentralisierte IoT-Infrastrukturen mit einem Internetzugang ausgestattet werden, über diesen ein Zugriff von außen auf die dortigen WH4.0-Dinge ermöglicht wird. Aus diesem Grund wird das Konzept als „lokal zentralisiert, global dezentralisiert“ bezeichnet.
![image](/uploads/9da44dd21a1eb7681e6fd5ecb72b8764/image.png)
Abbildung 18: Gesamte Kommunikationsarchitektur für Smart Forestry
### 5.2 Kommunikationsinfrastruktur
Die in diesem Abschnitt diskutierte Kommunikationsinfrastruktur bezieht sich nur auf die externe Vernetzung zwischen den WH4.0-Dingen. D.h. wie die Vernetzung innerhalb eines WH4.0-Dings erfolgt, z.B. wie ein Harvester-Kopf mit dem Bordcomputer kommuniziert, ist davon unabhängig. Strukturell werden in Unterkapitel 5.2.1 sowie 5.2.2 die End-to-End-Kommunikation von WH4.0-Dingen dargestellt. Am Ende wird der Aspekt „Cloud-Fähigkeit“ untersucht und dafür ein Konzept erarbeitet.
#### 5.2.1 Ad-hoc-Netzwerke
Drahtlose Kommunikation im Wald erfolgt klassischerweise sehr dynamisch. Typischerweise kann die Konnektivität der Maschinen durch die Bewegung im Wald abgeschwächt oder verhindert werden. Außerdem wird die Kommunikation unter anderem stark durch die Wetteränderung beeinflusst. Zur Maximierung der Erreichbarkeit und Flexibilität von WH4.0-Dingen, werden mehrere Ad-hoc-Netzwerke aufgebaut, in denen WH4.0-Dinge als dynamische Knoten gekapselt werden und die Funkstrecken (eine direkte drahtlose kommunikationstechnische Verbindung zwischen WH4.0-Ding) in Unabhängigkeit von einer vorkonfigurierten Netzwerkinfrastruktur selbsttätig aufbauen und konfigurieren können. Die Ad-hoc-Netzwerke können durch die zugewiesenen Access Point(s) miteinander bzw. mit der (lokal,) zentralisierten IoT-Infrastruktur vernetzt werden. In dem Sinne ergibt sich dann ein Mesh-Netzwerk. In Smart Forestry wird untersucht, wie eine WH4.0-mäßige Kommunikation in Ad-hoc-Netzwerken stattfindet bzw. in die gesamte Kommunikationsarchitektur (siehe Abbildung 18) integriert werden kann. Die Auswahl der verwendeten Funktechnologie bzw. Ad-hoc-Protokolle werden hingegen wenig berücksichtigt. Hierbei liegt der Fokus hauptsächlich auf die Kommunikation „innerhalb eines Ad-hoc-Netzwerks“ (siehe Kapitel 5.2.1.3) und „von mehreren Ad-hoc-Netzwerken über lokal zentralisierten IoT-Infrastruktur“ (siehe Kapitel 5.2.1.4).
##### 5.2.1.1 Registrierung
Für den Aufbau eines Ad-hoc-Netzwerks muss Vorkonfiguration getätigt werden, sowohl auf der lokalen Ebene (z.B. Netzwerk implementieren, ggf. Access Point aufsetzen) als auch auf der IoT-Ebene (z.B. Identität für das Netzwerk anlegen und Metainformation in die (lokal,) zentrale IoT-Infrastruktur schreiben). Die in diesem Abschnitt involvierte Registrierung bezieht sich auf die Vorkonfiguration des Ad-hoc-Netzwerks auf der IoT-Ebene. Dies ist in Abbildung 19 dargestellt. Im WH4.0-Kontext agiert das gesamte Ad-hoc-Netzwerk als spezielles WH4.0-Ding. Dementsprechend werden dem Ad-hoc-Netzwerk bei der Registrierung eine Identität und Metainformationen angelegt. In Abbildung 19 wird eine beispielhafte Metainformation von dem Netzwerk 4711 gezeigt, in dem unter anderem spezifiziert wird,
- wie es benannt wird (im Fall der Kommunikation via WiFi wäre es die SSID) via „name“
- ggf. wie das Password zu dem SSID ist via „psk“
- welche Endpoint(s) verfügbar sind, sodass ein Zugriff von außen möglich ist via „allEndpoints“
- und welche Node(s) in dem Netzwerk enthalten sind via „nodes“.
![image](/uploads/909f8ccb2d08d198d0761e0eeb3497d4/image.png)
Abbildung 19: Registrierungsprozess eines Ad-hoc-Netzwerks als spezielles WH4.0-Ding
Diese Informationen können dann zum Verbindungsaufbau mit einem Ad-hoc-Netzwerk und eine Kommunikation innerhalb eines Ad-hoc-Netzwerks oder über mehrere Netzwerke hinweg nützlich sein.
##### 5.2.1.2 Teilnahme an einem Ad-hoc-Netzwerk
Unter der Teilnahme von WH4.0-Dingen an einem Ad-hoc-Netzwerk wird ein kommunikationstechnischer Verbindungsaufbau mit dem Netz verstanden, siehe Abbildung 20. Dafür sind diverse Informationen über das Netzwerk relevant, z.B. SSID und Password für ein Ad-hoc-Netzwerk mit WiFi.
![image](/uploads/5c59dacb46b34026e639a3363e0a1252/image.png)
Abbildung 20: Teilnahme an ein bestehendes Ad-hoc-Netzwerk
Zur Vereinfachung des Verbindungsaufbaus können die relevante Information in Smart Forestry durch die folgenden Möglichkeiten verfügbar gemacht werden:
- Besteht ein Internetzugang für den Teilnehmer, sucht er nach einem Ad-hoc-Netzwerk im Directory-Service.
- Besteht kein Internetzugang für den Teilnehmer, sucht er vor Ort im Wald nach einem Schild, worauf die relevante Information zum Verbindungsaufbau mit dem Ad-hoc-Netzwerk dargestellt ist.
Nach dem kompletten Verbindungsaufbau werden die Metainformationen des Teilnehmers in das gesamte Netzwerk verbreitet, insbesondere sein Public Key, ID und Name.
##### 5.2.1.3 Kommunikation innerhalb eines Ad-hoc-Netzwerks
Die Nutzung eines Ad-hoc-Netzwerks unterstützt WH4.0-Dinge bei der Kommunikation, insbesondere, wenn Sie im selben Moment keine Verbindung zum Internet haben oder einen Echtzeit-mäßigen Datenaustausch ermöglichen wollen.
Wie in Kapitel 2.4.2 vorgestellt stehen dazu proaktive und reaktive Routing-Protokolle zur Auswahl. Für eine Anwendung im Wald wird empfohlen, ein Tabellen-getriebenes proaktives Protokoll auszuwählen, z.B. Optimized Link State Routing Protocol (OLSR, siehe Kapitel 2.4.2.1). In dem Fall wird das Routing nur nach Bedarf betrieben, sodass im Netzwerk niemals ein Flooding passieren kann. Damit ergibt sich eine effiziente Vernetzung im (Kommunikations)ressourcen-beschränkt Wald.
Abbildung 21 zeigt eine schematische Darstellung des Prozesses für einen Nachrichtenversand innerhalb eines Ad-hoc-Netzwerks. Im Allgemeinen lassen sich die Kommunikationsschritte als Entdeckung, Auswahl, Wartung und Repräsentieren (siehe Kapitel 2.4.1) zusammenfassen. Hierbei wird nicht spezifiziert, was für Ad-hoc-Protokoll genau umgesetzt werden soll, sondern die Entscheidung lässt sich bei allen beteiligten WH4.0-Dingen treffen. Jeder Knoten (hier z.B. der Sender und der Receiver) repräsentiert ein WH4.0-Ding, von dem signierte Nachrichten im S³I-B-Format versendet, weitergeleitet oder empfängt werden. Die Authentifizierung bei dem Nachrichtempfänger erfolgt zwecks Vereinfachung des Prozesses lediglich durch die Verifizierung der Signatur.
![image](/uploads/ec2243fe4c1884ae3177e9a2efa13acc/image.png)
Abbildung 21: Nachrichtenversand innerhalb eines Ad-hoc-Netzwerks
##### 5.2.1.4 Kommunikation von mehreren Ad-hoc-Netzwerken über (lokal,) zentralen IoT-Infrastruktur
Ein Ad-hoc-Netzwerk kann mit einem oder mehreren Access Points ausgestattet werden. Darüber können verschiedene lokale Ad-hoc-Netzwerke miteinander vernetzt und zu einem Mesh-Netzwerk gestaltet werden. Unter der Nutzung von der (lokal, ) zentralisierten S³I-Infrastruktur lässt sich eine IoT-mäßige Vernetzung zwischen WH4.0-Dingen aus verschiedenen Ad-hoc-Netzwerke ermöglichen (siehe Abbildung 22), in denen ein Access Point zusätzlich als Gateway agiert, der dann die auszutauschenden Nachrichten zwischen verschiedenen Protokollen übersetzt.
![image](/uploads/73e3be955109161b46f4325343353a45/image.png)
Abbildung 22: vernetzte Ad-hoc-Netzwerke über die zentrale S³I-Infrastruktur
Abbildung 24 zeigt einen Nachrichtenversand über die zentrale S³I-Infrastruktur. Hierzu wird insbesondere ausdetailliert spezifiziert, wie Ad-hoc-Netzwerke mit einem AMQP-Broker (S³I-Broker) integriert werden. Insgesamt wird eine Broker-Queue jedem Access Point zugewiesen. Auf diese werden dann alle Nachrichten an das Netzwerk, welchem der Access Point gehört, zwischengespeichert. Darüber hinaus wird ein Topic-Exchange im Broker angelegt, der dann die gesendeten Nachrichten sortiert nach dem angegebenen Routing-Key an die entsprechende Queue weitergeleitet. Beim Nachrichtenversand muss die Nachricht verschlüsselt und signiert werden. Abbildung 23 spezifiziert wie ein Routing Key, die beim Nachrichtenversand angegeben werden muss, aufgebaut wird.
<img src="/uploads/2b37ca279434e8c39cfd0035b49f07aa/image.png" width="30%" height="30%">
Abbildung 23: Routing Key
![image](/uploads/f732bfae09d30b7950df8fa7945d7ecc/image.png)
Abbildung 24: Nachrichtenversand über mehrere Ad-hoc-Netzwerke hinweg bis zur zentralen IoT-Infrastrukturhttps://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/7S3I Gruppenkonzept2022-12-01T02:02:41+01:00Ahmed OsmanS3I GruppenkonzeptDas Gruppenkonzept wurde schon in der Datei „S3I Standpunkt Security“ eingeführt. Ein wichtiger Punkt war, das Gruppen analog zu Personen als WH4.0-Komponente aufgenommen werden. D.h. zu jeder Gruppe gehören drei Einträge: Eintrag vom zu...Das Gruppenkonzept wurde schon in der Datei „S3I Standpunkt Security“ eingeführt. Ein wichtiger Punkt war, das Gruppen analog zu Personen als WH4.0-Komponente aufgenommen werden. D.h. zu jeder Gruppe gehören drei Einträge: Eintrag vom zugehörigen DZ bzw. Thing im S3I-Directory, dessen ThingIdenitity im S3I-Idenitity und die GroupIdentity im S3I-IdentityProvider.
Für die Implementierung auf der Seite des IdentityProviders werden die Gruppen von Keycloak verwendet.
Folgende Punkte müssen jedoch beachtet werden:
- Es soll erkennbar sein, ob der DZ einer Gruppe oder eine Person zugehört.
- Der „owner“ der DZ ist die Gruppe selbst, die mit einer eigenen ID identifiziert wird. Zusätzlich muss deshalb einen Admin existieren, der die Gruppe verwaltet.
- Die Gruppenmitglieder sollen aufgelistet werden.
Der Vorschlag wäre group-spezifische Attribute einzuführen (auf der Ebene von Ditto-Attributen):
- **representGroup**-Attribut, der explizit darauf hinweist, dass der DZ eine Gruppe repräsentiert.
- **groupMembers**-Attribut für das Auflisten der Gruppenmitglieder.
- **name**-Attribut kann (weiterhin) als Gruppenname verwendet werden.
- Gruppen können konkrete **roles** haben.
- **adriminstratedBy**-Attribut weist auf Gruppenadmin hinzu. Dieser kann Gruppenmitglieder anlegen und schreibend auf die GroupIdentity in Keycloak zugreifen.
```
{
"thingId": "s3i:6b1c90d0-0234-4ce7-9094-06ec2259dd5c",
"policyId": "s3i:6b1c90d0-0234-4ce7-9094-06ec2259dd5c",
"attributes": {
"representsGroup": "fb53c22f-48a6-42ad-a611-3fb9f000e718",
"administratedBy": "ab53c22f-22b6-42ad-a611-2fb9f111e718",
"name": "FBZ",
"type": "compenent",
"roles": [],
"groupMembers": []
}
}
```
API
- **POST /groups**: Erstellt Gruppe in Keycloak und die zugehörige DZ (mit den entsprechenden Directory-Eintrag). Aufrufende Person ist Gruppenadmin.
- **GET /groups/{group_id}**: Gibt die „GroupIdentity“ zurück. Soll von allen Gruppenmitglieder durchführbar sein.
- (Optional) **PUT /groups/{group_id}**: Aktualisiere bzw. Bearbeite GroupIdentity
- **PUT /groups/{group_id}/persons/{person_name}**: Füge die Person die Gruppe hinzu (die GroupIdentity, groupMemebers-Attribut im Directory-Eintrag, Policy müssen aktualisiert werden). Kann nur vom Gruppenadmin (administratedby-Attribut) durchgeführt werden.
- Zusätzlich: **PUT /groups/{group_id}/persons/{person_list}**: Mehrere Personen in einem Aufruf hinzufügen. personal_list ist eine komma-gentrennte Liste von person_name.
Beispiel Workflow
1. Person erstellt Gruppe und wird zum Gruppenadmin.
1. Fügt neue Gruppenmitglieder hinzu. S3I-Config-API checkt ob Gruppenadmin, aktualisiert „groupMembers“ im Directory-Eintrag, gibt die neue Gruppenmitglieder lesende Rechte auf dem Directory-Eintrag (durch das Aktualisieren vom Policy) und fügt die Mitglieder in Keycloaks Gruppe hinzu.https://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/6Should S3I Directory data model also express security scheme?2022-11-26T12:20:04+01:00Jiahang ChenShould S3I Directory data model also express security scheme?Metadata is also supposed to describe the configuration of a security mechanism. Although the main mechanism used in the S3I is OAuth 2.0 and the required URLs should be documented somewhere else, we should also include this information ...Metadata is also supposed to describe the configuration of a security mechanism. Although the main mechanism used in the S3I is OAuth 2.0 and the required URLs should be documented somewhere else, we should also include this information in the directory data model, like what WoT also did [1]. So far, I modeled PKIScheme and APIKeyScheme as well, because they are currently being used or will be used for some S3I communication use cases, like encrypted S3I-B messages and LoRa packages.
![Unbenannt](/uploads/e637c495e3a4593d5867c5860399ae3a/Unbenannt.PNG)
[1]: https://www.w3.org/TR/2020/REC-wot-thing-description-20200409/#sec-security-vocabulary-definitionJiahang ChenJiahang Chenhttps://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/5Should the S3I Directory entry reflect the structure of the real Thing?2023-09-07T15:02:48+02:00Jan Lucas ReitzShould the S3I Directory entry reflect the structure of the real Thing?As we discussed in todays S3I weekly, we should reconsider what information should be stored in the S3I directory and specifically if nested Objects are the way to go.
I believe there is general agreement, that the S3I Directory should ...As we discussed in todays S3I weekly, we should reconsider what information should be stored in the S3I directory and specifically if nested Objects are the way to go.
I believe there is general agreement, that the S3I Directory should contain the interface specifications of Things. That is their available Values/Services/Events with information on how to access them like protocol, dataformat, schema and Endpoints.
## Current
The current directory data model encourages modeling the directory entry after the physical or logical structure of the real Thing by requiring at least one object.
We also encourage this via the usage of ml4.0 and its mapping to the directory data model.
This practice:
- exposes the Things physical or logical structure, which I consider implementation
- makes the directory entry more verbose and I would argue more convoluted
We also run into these technical issues:
- Ditto imposes a document size limit of 100kb. Entries describing forest things currently exceed this limit. This is not due to the nested object structure, but to the granularity of modeling the structure.
- Addressing of nested documents can be problematic, due to list indices.
**Request for Feedback**: Is this a fair assessment of the status quo? Am I missing issues?
```mermaid
classDiagram
class Event
Event : TBD
Event *-- Endpoint : endpoints
class Link
Link : association string
Link o-- Thing : targetThing 0..1
Link *-- Object : target 0..1
class Thing
Thing : name string
Thing : identifier ID
Thing : ...
Thing *-- Object : thingStructure 0..1
Thing o-- Thing : childThings
class Object
Object : class string
Object : identifier ID
Object *-- Endpoint : endpoints
Object *-- Value : values
Object *-- Service : services
Object *-- Event : events
Object *-- Link : links
class Endpoint
Endpoint : uri string
class Value
Value *-- Endpoint : endpoints
class Service
Service *-- Endpoint : endpoints
```
## Flat data model without S3I::Object
I suggest that a flat directory data model, i.e. without nested objects, is a simpler yet sufficient way to describe Things. In my mind a Thing is something that is individually addressable.
- If for some reason a component of a large system, like the engine of a harvester, should be individually addressable, i.e. with its own data processing system that is connected to the S3I, it can be modelled as a seperate thing with `"thingType": "component"` and linked to and from the parent.
- If a component is not individually addressable there is no reason to model it separately, as all requests go the parent system.
Note that the properties `"defaultHmi"` and `"childThings"` can be normal `Link`s now.
```mermaid
classDiagram
class Link
Link : association string
Link o-- Thing : targetThing
class Thing
Thing : name string
Thing : identifier ID
Thing : ...
Thing *-- Value : values
Thing *-- Service : services
Thing *-- Event : events
Thing *-- Link : links
Thing *-- Endpoint : endpoints
class Endpoint
Endpoint : uri string
class Value
Value *-- Endpoint : endpoints
class Service
Service *-- Endpoint : endpoints
class Event
Event : TBD
Event *-- Endpoint : endpoints
```https://git.rwth-aachen.de/kwh40/fml40-reference-implementation/-/issues/18add Querys for Timber Trading Organisation2022-11-17T11:10:34+01:00Sebastian-Bloemeke-RIF-evadd Querys for Timber Trading OrganisationSebastian-Bloemeke-RIF-evSebastian-Bloemeke-RIF-evhttps://git.rwth-aachen.de/kwh40/fml40-reference-implementation/-/issues/17add Handling of Timber Lists2022-11-17T11:10:13+01:00Sebastian-Bloemeke-RIF-evadd Handling of Timber ListsSebastian-Bloemeke-RIF-evSebastian-Bloemeke-RIF-evhttps://git.rwth-aachen.de/kwh40/fml40-reference-implementation/-/issues/16add Classes from DigiKomForst project2022-11-17T11:09:41+01:00Sebastian-Bloemeke-RIF-evadd Classes from DigiKomForst projectadd Values and Functionalities from DigiKomForst projectadd Values and Functionalities from DigiKomForst projectSebastian-Bloemeke-RIF-evSebastian-Bloemeke-RIF-evhttps://git.rwth-aachen.de/kwh40/s3i_doc/-/issues/4Extend S3I Directory Model to allow describing Events2023-08-30T12:04:01+02:00Jan Lucas ReitzExtend S3I Directory Model to allow describing EventsAfter the introduction of Events to the S3I-B protocol we now need a way to describe them in the directory.
This proposal includes the addition of a new type, `S3I::Event` and changing the way `S3I::Endpoint`s are assigned.
To subscrib...After the introduction of Events to the S3I-B protocol we now need a way to describe them in the directory.
This proposal includes the addition of a new type, `S3I::Event` and changing the way `S3I::Endpoint`s are assigned.
To subscribe to an Event via AMQP, for example, you need the address of the broker instance (`rabbitmq.s3i.vswf.dev:5672`), the virtual host (vhost, e.g. `s3i`), the name of the exchange (e.g. `eventExchange`) and the routing key (e.g. `s3i:someId.eventName`).
Events using MQTT would require the broker instance and a topic.
It is possible to encode this information in a single url.
We currently omit a lot of this information. This works, because the SDKs have this information hardcoded. I believe we should explicitly state this everytime.
```json
// Current (Omits Broker address, virtual host and exchange)
{
"uri": "s3ib://someid"
}
// Proposed: State all information explicitly
{
"uri": "s3ib://rabbitmq.s3i.vswf.dev:5672/s3i/eventExchange/s3i:1234.newStrainGaugeMeasurement",
}
```
**Change**
`S3I::Object/Value/Service`: The current data model has an aggregation relationship between `S3I::Object/Value/Service` and `S3I::Endpoint`.
To my knowledge json does not offer a way to realize this relationship without further fields.
This problem has not occured in practice, because we never defined endpoints for individual `S3I::Value` or `S3I::Service`.
A single default endpoint was sufficient, because all messages were directly routed to the things queue.
I feel it would be much simpler to instead have a composition relationship between `S3I::Object/Value/Service` and `S3I::Endpoint`.
```json
// Current
{
?
}
// Proposed
{
"endpoints": [
]
}
```
Consequently, I propose renaming the property `S3I::Thing::allEndpoints` to `S3I::Thing::endpoints`, since it doesn't include all endpoints any more.
Likewise, there is no clear way of realizing the `S3I::Thing::defaultEndpoint` relationship. I propose removing this, and treating the endpoints under `S3I::Thing::endpoints` as default.
**Addition**
With these changes we can now introduce the new type `S3I::Event`. Like `S3I::Object/Value/Service` it has endpoints.
I also propose the fields `name`, `description`, `dataformat`, `schemaType` and `schema`.
I believe `dataformat` helps if someone decides to format his/her event body in something other than JSON.
As a guideline, we should assume as little as possible and be explicit about as much as possible.
The proposed `schemaType` and `schema` fields are in this spirit.
In practice, a clear description of the contents of events, or any message actually, would have been incredibly helpful.
Too many times did some message exchange not work because the case of some key wasn't matching (e.g. `min` vs. `Min`).
The example below contains a [JSON Schema](https://json-schema.org/understanding-json-schema/basics.html#basics), which I find suitable, but I don't think this should be constrained.
Therefore the `schema` field can be any object in my mind.
I'm looking forward to comments on this issue.
```json
{
"endpoints": [
{
"uri": "s3ib://rabbitmq.s3i.vswf.dev:5672/s3i/eventExchange/s3i:1234.newStrainGaugeMeasurement",
}
],
"name": "newStrainGaugeMeasurement",
"description": "This event is emitted if ...",
"dataformat": "json",
"schemaType": "JSONSchema",
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "newStrainGaugeMeasurement",
"description": "JSON Schema for content field of this EventMessage",
"properties": {
"stretch": { "type": "number" },
"force": { "type": "number" },
"displacement": {
"type": "array",
"items": { "type": "number" }
}
}
}
}
```
I currently don't have access to EA, so I'm posting a reduced UML Graphic of the proposed data model via mermaid. I will replace this as soon as possible.
```mermaid
classDiagram
Root *-- Thing : things
Root : apiVersion string
Thing *-- Object : thingStructure 0..1
Object *-- Endpoint : endpoints
Object *-- Value : values
Object *-- Service : services
Object *-- Event : events
Value *-- Endpoint : endpoints
Service *-- Endpoint : endpoints
Event *-- Endpoint : endpoints
Thing *-- Endpoint : endpoints
Endpoint : uri string
Event : name string
Event : description string
Event : dataformat string
Event : schemaType string
Event : schema object
```
**Complete example**
```json
{
"name": "Real Cantilever",
"thingId": "s3i:9e3a89d9-8c5d-41cf-90fc-9aaf7325aca4",
"policyId": "s3i:9e3a89d9-8c5d-41cf-90fc-9aaf7325aca4",
"defaultEndpoint": "s3ib://s3i:9e3a89d9-8c5d-41cf-90fc-9aaf7325aca4",
"type": "component",
"thingStructure": {
"class": "Cantilever",
"id": "1234",
"services" : [
{
"serviceType": "setConfiguration",
"parameterTypes": {
"length": "number",
"width": "number",
"height": "number",
"thickness": "number",
"geometryType":"string",
"materialType":"string",
"sensorPosition": "number",
"calibrationOffset": "number",
"calibrationScaling": "number"
},
"resultTypes": {
"ok": "bool"
},
}
],
"events": [
{
"endpoints": [
{
"uri": "s3ib://rabbitmq.s3i.vswf.dev:5672/s3i/eventExchange/s3i:1234.newStrainGaugeMeasurement"
}
],
"name": "newStrainGaugeMeasurement",
"description": "This event is emitted if ...",
"dataformat": "json",
"schemaType": "JSONSchema",
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "newStrainGaugeMeasurement",
"description": "JSON Schema for content field of this EventMessage",
"properties": {
"stretch": { "type": "number" },
"force": { "type": "number" },
"displacement": {
"type": "array",
"items": { "type": "number" }
}
}
}
}
]
}
}
```
The proposed change from `S3I::Thing::allEndpoints` to `S3I::Thing::endpoints` and restructuring of `S3I::Endpoint` are breaking changes.
I suggest collecting these, along with other pending changes and work towards a new api version.
We haven't increased the api version with the position paper `2.0`, so I suggest directly increasing to `3.0` alongside the new documentation.Jan Lucas ReitzJan Lucas Reitzhttps://git.rwth-aachen.de/kwh40/s3i/-/issues/48Complete the demo code2022-11-07T10:04:26+01:00GromeTTComplete the demo codehttps://git.rwth-aachen.de/kwh40/s3i/-/issues/47Move file test_even.py to demo folder2022-11-07T10:04:15+01:00GromeTTMove file test_even.py to demo folderhttps://git.rwth-aachen.de/kwh40/s3i/-/issues/45Display test coverage on gitlab2022-11-07T10:05:33+01:00GromeTTDisplay test coverage on gitlabFollowing tasks have to be done:
+ [ ] enable badge in web ui
+ [x] setup ci for coverage
+ [x] document coverage usage in CONTRIBUTING.md
+ [x] with poetry
+ [x] without poetryFollowing tasks have to be done:
+ [ ] enable badge in web ui
+ [x] setup ci for coverage
+ [x] document coverage usage in CONTRIBUTING.md
+ [x] with poetry
+ [x] without poetry0.6.5GromeTTGromeTThttps://git.rwth-aachen.de/kwh40/s3i/-/issues/44Complete tetsing of class IdentityProvider2022-11-06T18:06:50+01:00GromeTTComplete tetsing of class IdentityProviderSkipped, because I don't know how to test infinite loop, yet. First idea, move real code into separate function and mark remaining code with no coverage.Skipped, because I don't know how to test infinite loop, yet. First idea, move real code into separate function and mark remaining code with no coverage.0.6.5https://git.rwth-aachen.de/kwh40/s3i/-/issues/43Complete tesing of module event_system2022-11-05T21:51:31+01:00GromeTTComplete tesing of module event_systemSkipped tests, because I don't know how classes work.Skipped tests, because I don't know how classes work.0.6.5https://git.rwth-aachen.de/kwh40/s3i/-/issues/42Assert the file content in key.expor..() tests2022-11-05T21:46:39+01:00GromeTTAssert the file content in key.expor..() testsCurrently, tests are only checking if the mocked `open` function has been called. To make sure that the write process has been successfully executed, the file content has to be validated, too.Currently, tests are only checking if the mocked `open` function has been called. To make sure that the write process has been successfully executed, the file content has to be validated, too.0.6.5https://git.rwth-aachen.de/kwh40/s3i/-/issues/41Complete testing of class BrokerAMQP2022-11-05T21:50:50+01:00GromeTTComplete testing of class BrokerAMQPSkipped testing because I'm not sure how to test with asyncio properly.Skipped testing because I'm not sure how to test with asyncio properly.0.6.5GromeTTGromeTT