Api Gateway für die Zugriffsteuerung des Fablabs über Odoo und openHAB
Note: This work in progress. Everything is still in flux and things may not work as expected
-
Installer (Windows, macOS) / Manuell (Linux) https://nodejs.org/en/download/current/
-
Node Version Manager (nvm) https://nodejs.org/en/
Node Version >= 11.1.0
$ npm install
- Unter ./config/ eine Kopie von "default.sample.json" anlegen und zu "default.json" umbenennen
- Die jeweiligen Parameter anpassen
$ npm run test
Info: Die Tests sind nach einem größeren Refactoring nur zum Teil funktional
$ npm run dev
Info: Startet einen development Server mit live reloading
Führt den letzten build im Ordner "dist" aus, falls vorhanden.
$ npm start
Nach dem Clonen dieses Repos, für den intialen build und für das erneute builden und starten:
$ npm run prod
- openHAB Docker
- odoo Docker
- Hat Postgres als abhängigkeit
- MongoDB Docker
- Beinhaltet bei der Verwendung des vorgeschlagenen docker-compose files
mongo-express
(ähnliche wie phpMyAdmin für MySQL). Welches im folgenden bei der Erstellung der nötigen Collections und Dokumente sehr hilfreich ist
- Beinhaltet bei der Verwendung des vorgeschlagenen docker-compose files
Hier empfiehlt sich der Einfachheit halber die Verwendung von docker-compose
. Die verlinkten Seiten aus dem Docker Hub bieten fertige Vorlagen für docker-compose files an. Im Falle von odoo bindet dies auch Postgres mit ein
- Addon installieren
openHAB kommt mit einer REST API. der nachfolgende Schritt vereinfacht lediglich das Arbeiten mit dieser.
- Rest API Documentation installieren
- Addons -> Misc -> REST Documentation
- Things konfigurieren (z.B. zWave Steckdosen)
- Thing Channel (z.B. Switch) einem Item zuweisen. Openhab Doku: link
- Entwicklermodus im odoo Frontend öffnen
- Im Kontext Menü unter Felder anzeigen, folgende Felder anlegen
- x_RFID_Card_UUID , Type: String
- x_hadSecurityBriefing , Type: Boolean
- Reiter in der Kundenkarteikarte mit Fablab spezifischen Feldern anlegen
- Entwicklermodus öffnen
- Im Kontext Menü unter Edit View: Formular, im XML des Views das Elternelement
<notebook colspan="4">
um folgendes Pageelement erweitern:
<page name="fablab_settings" string="Fablab Einstellungen">
<group name="container_row_3">
<group string="Sicherheit">
<field name="x_hadSecurityBriefing"/>
</group>
<group string="Zugangsmedium">
<field name="x_RFID_Card_UUID"/>
</group>
</group>
</page>
- Artikel als Serviceleistung anlegen unter
Lager->Stammdaten->Produkte
- Die odoo Artikel ID lässt sich aus der URL in der Stammdatenansicht des Produktes entnehmen
- Datenbank in MongoDB erstellen
- Collections anlegen
- Collections aus dem Order
mongo-sample-collections
importieren
- Collections aus dem Order
- Die Collection
devices
enthält Devices- Diese sind mit den in openhab angelegeten
Items
abzugleichen. Die Referenz für das openhab Item, ist dessen Name. Dieser ist in derdevices
Collection imactor
Object unterindentifier
einzutragen. Weitere Devices einfach in Form neuer Dokumente anlegen
- Diese sind mit den in openhab angelegeten
productID
in der CollectionproductReferences
durch die Artikel ID des zuvor angelegten Artikels ersetzen.
- Datei
default.sample.json
zweimal duplizieren- Eine Version wird in
development.json
umbenannt. Diese Version beinhaltet die Konfiguration für die Entwicklungsumgebung - Die zweite Version wird in
production.json
umbenannt. Sie enthält die Konfiguration für die Produktivumgebung.
- Eine Version wird in
- Im Falle von
npm run dev
wird die Konfigurationdevelopment.json
. Fürnpm start
undnpm run prod
wird die Konfigurationproduction.json
geladen. - Konfigurationsdateien anpassen
Folgende Grafik zeigt die grobe Systemarchitektur:
Folgende Grafik zeigt die Schichten und Komponenten der Software
- place ----1:n---> device
- deviceBooking ---1:1---> device
- producReference ---1:n---> device
- accessDevice ---1:1---> place
Grafik folgt
POST /auth/app
Gibt bei erfolgreicher Authentifizierung einen Token für das Zugriffsgerät (Gerät) zurück
Key | Value |
---|---|
content-type | application/x-www-form-urlencoded |
deviceID=[DeviceIdentifier]&apiKey=[APIKey]
Der API Key wird in der Config gesetzt. Device Identifier ist momentan noch hardcoded auf "AccessDevice1". Die Authentifizierung der Zugriffsgeräte ist bestand architektureller Veränderungen. Der Plan ist hier, dass Geräte einem Place zugewiesen werden und jeweils einen eigenen API erhalten
Der API Key wird in der Entität AccessDevice
in der Datenbank gesetzt.
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXZpY2VJRCI6IkFjY2Vzc0RldmljZTEiLCJpYXQiOjE1NTQ3MDI5NzN9.80jRaKvmxVsunwk5sg2fmj3290EQ5G2KxIdZPVmNtRY",
"deviceID": "AccessDevice1"
}
POST /auth/user
Erzeugt ein intermediate Token für das Buchen eines Gerätes (Gültigkeit 20 Sekunden), in der ein Gerät gebucht werden kann
Key | Value |
---|---|
content-type | application/x-www-form-urlencoded |
userID=[UserUUID]&apiKey=[ApiKey]
[UserUUID] in odoo hinterlegte RFID_UUID, [APIKey] wie oben
{
"user": {
"id": 7,
"name": "Fabian Meyer",
"userID": "9D909C1E",
"hasSecurityBriefing": true
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NywibmFtZSI6IkZhYmlhbiBNZXllciIsInhfaXNBZG1pbiI6dHJ1ZSwidXNlcklEIjoiOUQ5MDlDMUUiLCJoYXNTZWN1cml0eUJyaWVmaW5nIjp0cnVlLCJpYXQiOjE1NTQ3MDM4NzEsImV4cCI6MTU1NDcwMzg5MX0.pCofejKs9O5KzsP9g95EJshtkHJYbvrpqnl9IuykZZE"
}
GET /device/:id
Gibt ein einzelnes Device mit der ID :id
zurück. Bei der :id
handelt es sich um die ObjectID aus der MongoDB
Key | Value |
---|---|
Authorization | Bearer [Token] |
[Token] ist der unter /auth/app
erworbene Token
{
"device": {
"_id": "5c95e60985c19400095d7d6d",
"deviceName": "3D Drucker 2",
"productReferenceID": "5c9c623a85c19400095d7d79",
"isOutOfOrder": false,
"actor": {
"identifier": "3_Drucker_2",
"platformIdentifier": "openhab"
}
}
}
GET /devices/?id=[deviceID1]&id=[deviceID2]
Gibt alle in der query variable id
angefragten Devices als Array zurück. Bei dem Wert von id
handelt es sich um die ObjectID aus der MongoDB
Key | Value |
---|---|
Authorization | Bearer [Token] |
[Token] ist der unter /auth/app
erworbene Token
[
{
"_id": "5c95e60985c19400095d7d6d",
"deviceName": "3D Drucker 2",
"productReferenceID": "5c9c623a85c19400095d7d79",
"isOutOfOrder": false,
"actor": {
"identifier": "3D_Drucker_2",
"platformIdentifier": "openhab"
}
},
{
"_id": "5c95e67e85c19400095d7d73",
"deviceName": "3D Drucker 4",
"productReferenceID": "5c9c623a85c19400095d7d79",
"isOutOfOrder": false,
"actor": {
"identifier": "3D_Drucker_4",
"platformIdentifier": "openhab"
}
}
]
GET /place/:id
Gibt den Place mit der ID :id
zurück. Bei der :id
handelt es sich um die ObjectID aus der MongoDB. Ein Place beinhaltet einen Array von Positions. Jede Position besteht aus einem Device und seinen Koordinaten.
Key | Value |
---|---|
Authorization | Bearer [Token] |
[Token] ist der unter /auth/app
erworbene Token
{
"_id": "5c9c63fe85c19400095d7d7b",
"placeName": "Regal 1",
"placeLabel": "Regal 1",
"placeType": "shelf",
"positions": [
{
"deviceID": "5c95e60985c19400095d7d6d",
"coordinates": [
0,
1
]
},
{
"deviceID": "5c95e67e85c19400095d7d73",
"coordinates": [
1,
1
]
},
{
"deviceID": "5c95e69c85c19400095d7d75",
"coordinates": [
2,
0
]
},
{
"deviceID": "5c95e6a785c19400095d7d77",
"coordinates": [
0,
0
]
}
]
}
GET /booking/:id
Gibt die Buchung mit der ID :id
zurück. Bei der :id
handelt es sich um die ObjectID aus der MongoDB.
Key | Value |
---|---|
Authorization | Bearer [Token] |
[Token] ist der unter /auth/app
erworbene Token
{
"_id": "5ca0b960544bb57d50f6aa3f",
"deviceID": "5c95e67e85c19400095d7d73",
"userUID": "9D909C1E",
"startTime": 1554037088
}
GET /bookings/?deviceID=[deviceID1]&deviceID=[deviceID2]
Gibt alle Buchungen der in der query variable deviceID
angefragten Devices als Array zurück. Bei dem Wert von deviceID
handelt es sich um die ObjectID aus der MongoDB des jeweiligen Devices.
Key | Value |
---|---|
Authorization | Bearer [Token] |
[Token] ist der unter /auth/app
erworbene Token
[
{
"_id": "5ca0b779544bb57d50f6aa3d",
"deviceID": "5c95e60985c19400095d7d6d",
"userUID": "9D909C1E",
"startTime": 1554036601
},
{
"_id": "5ca0b960544bb57d50f6aa3f",
"deviceID": "5c95e67e85c19400095d7d73",
"userUID": "9D909C1E",
"startTime": 1554037088
}
]
startime
ist ein Unix Timestamp
POST /booking
Erzeugt eine Buchung in der Datenbank (MongoDB) und gibt ein JSON Objekt der id der angelegten Buchung zurück
Key | Value |
---|---|
Authorization | Bearer [Token] |
Accept | application/json |
Content-Type | application/json |
[Token] ist der unter /auth/app
erworbene Token
{
deviceID: deviceID,
userUID: userID,
intermediateToken: intermediateToken
}
deviceID
ist die ObjectID (_id) des Devices aus MongoDB. userUID
die in odoo hinterlegte RFID UUID. intermediateToken
ist der über die Route /auth/user
bezogene Token.
{
"status": "OK",
"bookingID": "5cab7dad3bc0285e7a838865"
}
DELETE /booking/:id
Beendet eine Buchung mit der ID :id
und erzeugt eine Rechnung in odoo
Key | Value |
---|---|
Authorization | Bearer [Token] |
Accept | application/json |
Content-Type | application/json |
[Token] ist der unter /auth/app
erworbene Token
{
intermediateToken: [intermediateToken]
}
intermediateToken
ist der über die Route /auth/user
bezogene Token.
{
"status": "OK"
}
- POST, DELETE und PUT Routen für alle MongoDB Entitäten
- Schemavaliierung der Requests (Valdierung von JSON Schemata und Form von Form Parametern)
- Fehlende Fehlermeldungen Ergänzen
- Unit-/Integrationtests vervollständigen
- Verwaltungsoberfläche (z.B. zum Anlegen von Devices, Produktreferenzen, Places usw.)
- Debug Logs hinzufügen
- Odoo hinter Interface verstecken (Zu Abstraktion im Service Layer)
- Stromverbrauch aus openhab abfragen und mit in der Rechnung vermerken
- Docker Image für das API-Gateway bauen
- Init Script erstellen (Zur Vereinfachung des initalen Setups)
- Websocket für Realtimekokmmunikation implementieren (Push Benachtichtigungen für die App/Zugriffsgerät)
- Erstellte Rechnung in Odoo bestätigen
- App/Zugriffsgerät als Entität in MongoDB anlegen und separate API Keys hinterlegen. App Authentifitierung anpassen
- Beendigung eines Nutzungsvorgangs erkennen (z.B. Ende des 3D Drucks durch geringeren Strom verbauch)
- Fehlermeldung für das Nichtfinden von Dokumenten in der DB überarbeiten (Hier wird besipielsweise im Fall eines leeren DB Results kein 404 zurückgegeben)
- JSON Responses vereinheitlichen (Keine Verschachtelten JSON wie z.B.
{ devices: { key: value ... } }
beiGET /device/:id
. Stattdessen{ key: value }
) - To be continued
GNU GPLv3 - see LICENSE file