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
| Modell | Was es ist |
|---|---|
| User | Ein Konto |
| Usergroup | Eine Menge von Benutzern |
| Iotnode | Ein Gerät, physisch oder virtuell. Das zentrale Modell |
| Connector | Eine Verbindung zu einem Netzwerkserver oder externen System, über das Geräte hereinkommen |
| Calculation | Ein aus Gerätedaten abgeleiteter Wert |
| Zugriffsrecht | Wer eine Ressource erreicht, und auf welcher Stufe |
| Channel | Ein ausgehendes Abonnement, das Aktualisierungen an Ihren Dienst schickt |
| BasicCredentialsSet | Ein Paar aus Benutzername und Passwort, das Integrationen verwenden |
| ReservedMqttTopic | Ein für ein Credentials Set reserviertes MQTT-Topic |
| Location | Ein 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:
| Was | Wie |
|---|---|
| Ein Mitglied hinzufügen | POST /usergroups/{groupId}/members |
| Ein Mitglied entfernen | DELETE /usergroups/{groupId}/members/{memberId} |
| Die Mitglieder lesen | Die Gruppe mit includeMembers=true per GET abrufen |
| Den App-Filter setzen | PUT /usergroups/{groupId}/app-filter |
| Eine App erlauben | POST /usergroups/{groupId}/app-filter |
| Eine App entfernen | DELETE /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:
type | Was sie tut |
|---|---|
lastValue | Aggregiert den jüngsten Wert eines oder mehrerer Quellgeräte |
window | Aggregiert 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
iotnodeoderdeviceGroup, 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/v1oderyggio/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.