Zum Hauptinhalt springen

Modelle

Ein Modell ist die Form einer Sache in Yggio: die Felder, die die REST-API beim Anlegen oder Aktualisieren annimmt, und die Felder, die sie beim Lesen zurückgibt. Die API validiert jede Anfrage gegen diese Schemata, eine Anfrage, die nicht passt, wird also abgelehnt, bevor etwas gespeichert wird.

Entitäten dieser Modelle lassen sich über die REST-API abrufen, anlegen, ändern und löschen.

Jede angelegte Modellentität erhält ein _id für Verweise. Eine Id ist eine 24 Zeichen lange Hex-Zeichenkette (z. B. 507f1f77bcf86cd799439011).

Die Modelle​

ModellWas es ist
UserEin Konto
UsergroupEine Menge von Benutzern
IotnodeEin Gerät, physisch oder virtuell. Das zentrale Modell
ConnectorEine Verbindung zu einem Netzwerkserver oder externen System, über das Geräte hereinkommen
CalculationEin aus Gerätedaten abgeleiteter Wert
ZugriffsrechtWer eine Ressource erreicht, und auf welcher Stufe
ChannelEin ausgehendes Abonnement, das Aktualisierungen an Ihren Dienst schickt
BasicCredentialsSetEin Paar aus Benutzername und Passwort, das Integrationen verwenden
ReservedMqttTopicEin für ein Credentials Set reserviertes MQTT-Topic
LocationEin Ort auf der Karte, der Geräte gruppiert. Veraltet

Weitere Modelle existieren und sind über die API erreichbar - Dashboards, Geofences, Gerätegruppen, Berichte, Regeln, Bilder, Organisationen und mehr. Sie folgen denselben Konventionen wie die unten stehenden. Jedes davon ist außerdem eine Ressource, die Zugriffsrechte trägt; Zugriffsrechte listet die vollständige Menge der Ressourcentypen auf.

Das maßgebliche Schema​

Diese Seite beschreibt die Felder, die Sie am häufigsten verwenden werden. Das vollständige, aktuelle Schema für jeden Endpunkt steht in der Swagger UI. Sie wird neben der API gepflegt, statt aus ihr erzeugt zu werden, und kann einer neuen Änderung daher hinterherhinken - verhält sich ein Aufruf anders als Swagger zeigt, zählt der laufende Endpunkt.

Swagger ist auch der schnellste Weg zu sehen, was eine bestimmte Anfrage ablehnt: klappen Sie den Endpunkt auf, lesen Sie das Modell unter Request body, und nutzen Sie Try it out gegen Ihr eigenes Konto.

User​

Ein Benutzer ist ein Konto. Es wird für die Authentifizierung und für die Zugriffskontrolle auf andere Ressourcen verwendet. Konten liegen in Keycloak, dem Anmeldedienst, den Yggio nutzt, weshalb die Feldnamen unten Keycloaks Stil folgen und nicht dem sonst in Yggio üblichen.

{
username: String, // erforderlich
email: String,
firstName: String,
lastName: String,
phoneNumber: String, // E.164-Format, z. B. +46701234567
enabled: Boolean,
requiredActions: [String],
attributes: {
globalVisibility: String, // 'true' oder 'false', kein Boolean
language: String,
organization: [String],
roles: [String]
}
}

username ist beim Anlegen das einzige erforderliche Feld. phoneNumber muss im E.164-Format vorliegen. enabled steuert, ob sich das Konto anmelden darf. Ein Konto zu deaktivieren entfernt es nicht. requiredActions listet Aktionen auf, die Keycloak bei der nächsten Anmeldung erzwingt, etwa das Setzen eines Passworts. attributes enthält die Yggio-spezifischen Ergänzungen. Beachten Sie, dass globalVisibility hier liegt und nicht auf oberster Ebene, und als Zeichenkette 'true' oder 'false' gespeichert wird und nicht als Boolean. Es steuert, ob der Benutzername von anderen Yggio-Benutzern gefunden werden kann.

Es gibt kein password-Feld und keinen öffentlichen Endpunkt, um eines zu setzen. Passwörter liegen in Keycloak und werden entweder von Keycloak selbst bei der Anmeldung über requiredActions gesetzt, oder von Yggio, wenn eine Organisation ein Mitglied anlegt oder zurücksetzt.

Usergroup​

Eine Benutzergruppe ist eine Menge von Benutzern. Sie wird für zwei Dinge genutzt: um Zugriffsrechte an mehrere Personen zugleich zu vergeben, und um zu filtern, welche Apps ihre Mitglieder sehen.

Die Gruppe selbst ist ein kleines Objekt:

{
_id: Id,
name: String, // erforderlich, 2 bis 60 Zeichen
owner: Id // erforderlich
}

name muss zwischen 2 und 60 Zeichen lang sein. owner verweist auf den Benutzer, dem die Gruppe gehört. Beim Anlegen einer Gruppe ist der Eigentümer der Benutzer, der sie angelegt hat.

Mitglieder und der App-Filter sind keine Felder dieses Objekts. Sie werden über eigene Endpunkte verwaltet, ein Anlege-Aufruf, der sie enthält, tut also nicht das, wonach es aussieht:

WasWie
Ein Mitglied hinzufügenPOST /usergroups/{groupId}/members
Ein Mitglied entfernenDELETE /usergroups/{groupId}/members/{memberId}
Die Mitglieder lesenDie Gruppe mit includeMembers=true per GET abrufen
Den App-Filter setzenPUT /usergroups/{groupId}/app-filter
Eine App erlaubenPOST /usergroups/{groupId}/app-filter
Eine App entfernenDELETE /usergroups/{groupId}/app-filter/{appId}

Iotnode​

Ein Iotnode ist üblicherweise die Abbildung eines physischen Geräts. Er kann aber auch ein virtuelles Gerät sein.

Das Iotnode-Modell ist bewusst offen. Nur wenige Felder liegen fest; alles andere, was ein Gerät meldet, wird daneben als Feld oberster Ebene gespeichert. Das ist es, was ein Modell einen Temperatursensor, einen Personenzähler und einen Wasserzähler tragen lässt, ohne ein Schema je Gerätetyp.

{
_id: Id, // von Yggio vergeben
name: String, // beim Anlegen erforderlich, nicht leer
description: String,
category: String,
connector: Id, // der Connector, über den das Gerät hereinkommt
reportedAt: Date,
updatedAt: Date,
rabbitRouting: Object,
// ...plus jedes Feld, das der Übersetzer des Geräts erzeugt hat
}

name ist erforderlich und muss eine nicht leere Zeichenkette sein. Es darf die Folge ~||~ nicht enthalten, die Yggio intern als Trennzeichen verwendet. description dient der Anzeige. category wird zum Gruppieren von Iotnodes verwendet, um das Filtern zu erleichtern. connector verweist auf den Connector, über den das Gerät hereinkommt. Er kann als Id oder als Objekt mit einem _id übergeben werden. reportedAt ist ein Zeitstempel, der angibt, wann der Iotnode zuletzt eine Meldung vom physischen Gerät erhalten hat. updatedAt ist ein Zeitstempel, der angibt, wann zuletzt irgendein Attribut geändert wurde (z. B. Name, Wert). rabbitRouting wird nur intern verwendet und sollte von externen Entwicklern nicht geändert werden.

Die Datenfelder​

Die Messfelder eines Iotnode sind nicht Teil dieses Modells. Sie werden vom Übersetzer des Geräts geschrieben, der die rohe Payload in Yggios kanonisches Datenmodell decodiert - temperature, relativeHumidity, batteryVoltage, co2 und so weiter, jeweils mit deklariertem Typ, Einheit und Größe.

Das ist beim Entwickeln gegen die API wichtig: erwarten Sie keine feste Menge an Wertfeldern, und erfinden Sie keine eigenen Namen für Werte, die ein Übersetzer bereits erzeugt. Die Übersetzer-API behandelt die Feldreferenz.

Da das Modell unbekannte Felder annimmt, wird ein falsch geschriebener Feldname gespeichert statt abgelehnt. Bei einem Gerät, dem ein Wert zu fehlen scheint, lohnt es sich, zuerst danach zu sehen.

Connector​

Ein Connector ist die Verbindung zwischen Yggio und dem System, über das Geräte hereinkommen: ein LoRaWAN-Netzwerkserver wie ChirpStack oder Netmore, eine Herstellercloud, oder ein generischer HTTP- oder MQTT-Feed. Yggio unterstützt 26 Integrationen.

{
_id: Id,
name: String, // erforderlich
integration: String, // erforderlich - welche Integration dies ist
flowIdentifier: String, // optional, wählt einen eigenen Flow
retentionPolicy: String,
protocols: Object, // protokollspezifische Einstellungen
uplink: {protocol: String},
downlink: {protocol: String},
// ...plus Felder, die der Integration eigen sind
}

integration wählt den Typ und entscheidet, welche weiteren Felder gelten, der Rest des Rumpfs unterscheidet sich also je Integration. Lesen Sie die genaue Form der von Ihnen verwendeten unter Connectors in Swagger, und siehe Connectoren für das, was jeder tut.

Calculation​

Eine Berechnung leitet einen Wert aus Gerätedaten ab und schreibt ihn als Feld zurück, sodass er wie jeder andere Wert dargestellt, berichtet und alarmiert werden kann.

Es gibt zwei Formen, gewählt über type:

typeWas sie tut
lastValueAggregiert den jüngsten Wert eines oder mehrerer Quellgeräte
windowAggregiert ein Zeitfenster von Messwerten einer einzelnen Quelle

Beide tragen eine source (was gelesen wird), ein destination (wohin das Ergebnis geschrieben wird), die Aggregationsmethode, und einen optionalen Zeitplan zur automatischen Aktualisierung. Die vollständige Feldliste je Form steht in Swagger unter Calculations, als CalculationLastValue und CalculationWindowed.

Zugriffsrecht​

Ein Zugriffsrecht gewährt einem Subjekt eine Zugriffsstufe auf eine Ressource. Es ist kein Feld der Ressource; es ist ein eigener Datensatz, der über /access-rights angelegt und entfernt wird.

{
resourceType: String, // 'device', 'dashboard', 'image', ...
resourceId: Id, // die _id der Ressource, 24 Zeichen hex
subjectType: String, // 'singleton', 'group' oder 'orgUnit'
subjectId: Id, // eine Keycloak-UUID bei 'singleton', eine 24-stellige Hex-_id bei 'group'
scope: [String] // 'admin', 'write', 'read', 'peek'
}

subjectType ist singleton für einen einzelnen Benutzer, group für eine Benutzergruppe, oder orgUnit für eine Organisationseinheit. Singleton ist der Begriff der Zugriffs-Engine: jeder Benutzer wird auf eine Gruppe aus einem abgebildet, was es erlaubt, Benutzern, Gruppen und Einheiten über denselben Mechanismus Zugriff zu geben. Das Control Panel sendet singleton, und user wird als Alias dafür akzeptiert.

Die beiden Arten von Id sind nicht austauschbar. Ein Benutzer wird über seine Keycloak-Id identifiziert, die eine UUID ist; eine Gruppe über ihre eigene _id, eine 24-stellige Hex-Zeichenkette wie jede andere Yggio-Ressourcen-Id.

Ein Endpunkt weicht davon ab. GET /access-rights/subject/{id} nimmt in seinem Query-Parameter subjectType nur user oder group entgegen und verwendet standardmäßig user.

Jeder Ressourcentyp in Yggio kann Zugriffsrechte tragen, auch die ohne Oberfläche dafür. Siehe Zugriffsrechte für die Ressourcentypen und was jede Stufe erlaubt.

Channel​

Ein Channel schickt Aktualisierungen an einen externen Dienst, wenn sich Gerätedaten ändern. Die Nachricht trägt das Gerät sowie die Angabe, welche Attribute aktualisiert wurden.

{
name: String,

// genau ein Ziel
iotnode: Id,
deviceGroup: Id,

// genau ein Protokoll
http: {url: String, headers: Object},
mqtt: {type: String, recipient: Id},
azureIotHub: {connectionString: String},
desigoCC: {...},
deltaControls: {...},
vyer: {...}
}

Beim Anlegen werden zwei Regeln geprüft, und beide sind eine häufige Ursache für eine abgelehnte Anfrage:

  • Genau ein Ziel. Entweder iotnode oder deviceGroup, nie beides und nie keines. Ein Channel auf einer Gerätegruppe folgt der Gruppe, später hinzugefügte Geräte sind also ohne neuen Channel abgedeckt.
  • Genau ein Protokoll. Keines oder mehr als eines zu setzen wird abgelehnt, mit einer Meldung, die die gefundenen nennt. Die sechs oben sind die, die die Protokollauswahl anbietet.

name ist optional. http.url muss eine gültige URL sein. Nachrichten werden dorthin per POST gesendet. http.headers ist ein optionales Objekt mit zusätzlichen HTTP-Headern, die bei jeder Anfrage mitgesendet werden. Für Basic Auth fügen Sie einen Authorization-Header mit Basic <base64> hinzu, wobei <base64> die Base64-Kodierung von username:password ist. Ein Authorization-Header ist nur schreibend: er wird beim Anlegen und Aktualisieren angenommen, aber nie von der API zurückgegeben. mqtt.type ist entweder keycloakUser oder basicCredentialsSet, und mqtt.recipient ist die Id desjenigen von beiden.

BasicCredentialsSet​

Ein BasicCredentialsSet ist ein Paar aus Benutzername und Passwort, mit dem sich ein Gerät oder eine Integration authentifiziert. Es wird verwendet, wenn MQTT-Nachrichten an Yggio gesendet werden, und als Empfänger eines MQTT-Channels.

{
username: String, // erforderlich
password: String // erforderlich
}

username darf keine UUID sein; diese Form ist reserviert und wird abgelehnt. password wird beim Eingang gesalzen und gehasht und nie von der API zurückgegeben.

ReservedMqttTopic​

Ein ReservedMqttTopic reserviert ein MQTT-Topic und verbindet es mit einem BasicCredentialsSet, sodass nur diese Anmeldedaten darauf veröffentlichen können.

{
topic: String, // erforderlich
basicCredentialsSetId: Id // erforderlich
}

basicCredentialsSetId muss auf ein existierendes Credentials Set verweisen; der Anlege-Aufruf prüft das.

topic wird validiert, und drei Regeln entscheiden, ob es angenommen wird:

  • Es darf nicht mit / beginnen.
  • Es muss mit einem der erlaubten Wurzel-Topics beginnen: yggio/generic/v2, yggio/axis/v1, yggio/beijerix/v1, yggio/hubitat/v1 oder yggio/push/v1.
  • Es muss ein Unter-Topic unterhalb dieser Wurzel ergänzen. Die Wurzel allein ist keine Reservierung.

yggio/generic/v2/mein-gebaeude wird also angenommen, während yggio/generic/v2 und mein-gebaeude/sensoren es nicht werden. Die Fehlermeldung nennt die erlaubten Wurzeln.

Location (veraltet)​

Das Location-Modell liegt dem Location Manager zugrunde, der veraltet ist. Es ist hier für diejenigen dokumentiert, die es noch verwenden. Bauen Sie keine neuen Integrationen darauf. Es gruppiert Iotnodes und bindet sie an einen Ort auf der Weltkarte.

Location-Datenstruktur:

{
name: String, // erforderlich
description: String,
user: Id, // erforderlich
lat: Number, // erforderlich
lng: Number, // erforderlich
icon: String,
defaultLayer: LocationLayer, // erforderlich
layers: [LocationLayer],
version: Number
}

name ist erforderlich und wird gegen einen Zeichensatz geprüft: Buchstaben, Ziffern, die schwedischen Zeichen åäöÅÄÖ, Leerzeichen, Unterstriche und Bindestriche. Andere Zeichen werden mit "is not a valid location name" abgelehnt. description dient der Anzeige. user verweist auf den Benutzer, der den Ort angelegt hat, und ist erforderlich. lat und lng sind erforderliche Koordinaten dafür, wo der Ort auf der Welt liegt. defaultLayer ist erforderlich und ist die Ebene, die beim Öffnen eines Orts zuerst gezeigt wird. layers enthält die übrigen. Siehe LocationLayer unten.

LocationLayer​

LocationLayer dient dazu, Objekte (Iotnodes) an einem Ort zu gruppieren. Beispiel: ist ein Ort ein Gebäude, lässt sich ein LocationLayer als Stockwerk in diesem Gebäude verstehen.

{
name: String,
items: [LocationItem],
image: String, // Pfad zum Hintergrundbild
left: Number, // Position des Bildes, 0 bis 100
top: Number,
width: Number, // Größe des Bildes, 50 bis 200
height: Number
}

name akzeptiert denselben Zeichensatz wie der Name des Orts. image ist die Hintergrundzeichnung, auf der die Objekte platziert werden, etwa ein Grundriss, und left, top, width und height positionieren und dimensionieren sie.

LocationItem​

LocationItem ist eine Hülle für einen einzelnen Iotnode an einem Ort.

{
deviceId: Id, // erforderlich
type: String,
size: String,
top: Number,
left: Number,
valueDisplay: String,
locationItemControl: {icon: String}
}

deviceId verweist auf einen Iotnode und ist das einzige erforderliche Feld. top und left platzieren das Objekt auf der Ebene, und size, type und valueDisplay steuern, wie es gezeichnet wird und welchen Wert es zeigt.