<- Startseite / Anleitungen / Smarthome / ioBroker
ioBroker - FAQ Adapter Entwicklung
Kurze Antworten zu Fragen, die sich bei der Adapterentwicklung immer wieder stellen. Gesammelte Infos aus der ioBroker Development Gruppe, der Doku und eigenen Erfahrungen.
Passwort verschlüsselt speichern
Beispiel aus dem Circuit Adapter (angepasste Version vom ioBroker.meross Adapter von Apollon77).
Das Passwort wird im Ciruit Adapter unter adapter.config.client_secret
gespeichert. Unter index-m.html
(HTML Seite für die Adaptereinstellungen) lautet die ID id="client_secret"
.
Passwort verschlüsseln, Anpassungen main()
decrpyt() Funktion am Anfang der main.js
:
function decrypt(key, value) {
let result = "";
for (let i = 0; i < value.length; ++i) {
result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
}
adapter.log.debug("client_secret decrypt ready");
return result;
}
2
3
4
5
6
7
8
Im Adapter-Objekt wird die Funktion onReady() angesprungen, sobald der Adapter bereit zum Start ist:
const adapter = utils.adapter({
name: "circuit",
// The ready callback is called when databases are connected and adapter received configuration.
// start here!
ready: onReady, // Main method defined below for readability
2
3
4
5
6
Funktion onReady()
. Von dort wird dann die eigentliche Hauptfunktion (hier main()
) aufgerufen, sobald das Passwort entschlüsselt wurde:
//*********************************************************************
//* onReady (Adapter Ready)
//*********************************************************************
// entschlüsselt das gespeicherte Secret und startet main()
function onReady() {
adapter.log.debug("ready - Adapter: databases are connected and adapter received configuration");
adapter.log.silly("config.client_secret verschlüsselt: " + adapter.config.client_secret);
adapter.getForeignObject("system.config", (err, obj) => {
if (obj && obj.native && obj.native.secret) {
//noinspection JSUnresolvedVariable
adapter.config.client_secret = decrypt(obj.native.secret, adapter.config.client_secret);
} else {
//noinspection JSUnresolvedVariable
adapter.config.client_secret = decrypt("Zgfr56gFe87jJOM", adapter.config.client_secret);
}
main();
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Bei aktuellen ioBroker Versionen wird mit dem individuellen Secret der Installation (obj.native.secret
) verschlüsselt. Bei älteren Versionen wird in dem Beispiel der Schlüssel Zgfr56gFe87jJOM
verwendet.
Passwort verschlüsseln, Anpassungen index_m.html
Neue Funktionen encrypt()
, decrypt()
und Austausch der Funktion loadHelper()
aus dem Adapter-Template:
<script type="text/javascript">
var secret;
function encrypt(key, value) {
var result = '';
for(var i = 0; i < value.length; ++i) {
result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
}
return result;
}
function decrypt(key, value) {
var result = '';
for(var i = 0; i < value.length; ++i) {
result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
}
return result;
}
// the function loadSettings has to exist ...
function loadHelper(settings, onChange) {
// example: select elements with id=key and class=value and insert value
if (!settings) return;
if (settings.electricityPollingInterval === undefined) settings.electricityPollingInterval = 20;
$('.value').each(function () {
var $key = $(this);
var id = $key.attr('id');
if (id === 'client_secret') {
settings[id] = decrypt(secret, settings[id]);
}
if ($key.attr('type') === 'checkbox') {
// do not call onChange direct, because onChange could expect some arguments
$key.prop('checked', settings[id]).change(function() {
onChange();
});
} else {
// do not call onChange direct, because onChange could expect some arguments
$key.val(settings[id]).change(function() {
onChange();
}).keyup(function() {
onChange();
});
}
});
onChange(false);
// function Materialize.updateTextFields(); to reinitialize all the Materialize labels on the page if you are dynamically adding inputs.
M.updateTextFields();
}
// This will be called by the admin adapter when the settings page loads
function load(settings, onChange) {
socket.emit('getObject', 'system.config', function (err, obj) {
secret = (obj.native ? obj.native.secret : '') || 'Zgfr56gFe87jJOM';
loadHelper(settings, onChange);
});
onChange(false);
}
// This will be called by the admin adapter when the user presses the save button
function save(callback) {
// example: select elements with class=value and build settings object
var obj = {};
$('.value').each(function () {
var $this = $(this);
var id = $this.attr('id');
if ($this.attr('type') === 'checkbox') {
obj[id] = $this.prop('checked');
} else {
var value = $this.val();
if (id === 'client_secret') {
value = encrypt(secret, value);
}
obj[id] = value;
}
});
callback(obj);
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Das Eingabefeld für das Passwort (oder hier: client_secret):
<div class="col s6 input-field">
<input type="password" class="value" id="client_secret" />
<label for="client_secret" class="translate">Client Secret</label>
</div>
2
3
4
Adapter soll sich selbst beenden
Der eigene Adapter kann sich selbst beenden (gestoppt werden), wenn man "system.adapter." + adapter.namespace + ".alive"
auf false
setzt.
Die Funktion wird mit adapter.setForeignState("system.adapter." + adapter.namespace + ".alive", false);
aufgerufen.
geplant zu Adapter soll sich selbst beenden
Adapter wird beendet, startet aber von selbst wieder neu, wenn der ANwender in den Einstellungen was ändert:
adapter.terminate(reason)
adapter.stop()
disable ist im Gegensatz zu stop() aber garantiert immer definiert:
adapter.disable()
Adapter startet sich selbst neu
Geplant:
adapter.restart()
Aktuell:
Adapter aus sich selbst heraus neustarten
Github: Funktion aus dem xbox Adapter
function restartAdapter() {
adapter.getForeignObject('system.adapter.' + adapter.namespace, (err, obj) => {
if (obj) adapter.setForeignObject('system.adapter.' + adapter.namespace, obj);
});
} // endFunctionRestartAdapter
2
3
4
5
Neue Adapterinstanz gestoppt installieren
Im Standard wird eine neue Adapterinstanz direkt gestartet. Möchte man eine neue Instanz im Stop-Zustand hinzufügen, muss in der io-package.json
der Wert "common.enabled=false"
gesetzt werden.
Namespace Adapter
adapter.namespace
gibt den Adapternamen inkl. der Instanz aus, z.B. circuit.0
.
Verbindungszustand des Adapters unter Instanzen anzeigen
Unter Admin/Adapter/Instanzen wird mit einem farbigen Kreis der Zustand eines Adapters angezeigt.
Farbe | Bedeutung der Farbe |
---|---|
grau | Adapter ist ausgeschaltet |
grün | Adapter ist aktiv und funktioniert |
gelb | Adapter ist aktiv, hat aber keine Verbindung zum verwendeten Dienst |
rot | Adapter ist angeschaltet, ist aber ohne Funktion (Fehler) |
Die Zustände grau, grün und rot werden grundsätzlich von ioBroker über den js-controller bestimmt. Den Verbindungszustand gelb zu einem Dienst, den der Adapter bedienen möchte, muss vom Entwickler des Adapters eingebaut werden.
Der Verbindungszustand wird über das Objekt info.connection
signalisiert, welches man in der io-packages.json
einrichten und dann im Adapter, je nach Zustand, ändern kann.
Part innerhalb der io-packages.json
:
{
"common": {
"instanceObjects": [{
"_id": "info.connection",
"type": "state",
"common": {
"role": "indicator.connected",
"name": "If communication with circuit works",
"type": "boolean",
"read": true,
"write": false,
"def": false
},
"native": {}
}]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Beispiel für den Verbindungszustand in der main.js
aus dem Circuit Adapter:
client.addEventListener("connectionStateChanged", function (evt) {
if(evt.state === "Connected") {
adapter.setState("info.connection", true, true);
adapter.log.debug("Adapterfarbe: grün");
} else {
adapter.setState("info.connection", false, true);
adapter.log.debug("Adapterfarbe: gelb");
}
});
2
3
4
5
6
7
8
9
10
Das Beispiel passt für den Circuit Adapter
Achtung!
Das Beispiel aus der main.js
passt genau für die Funktion vom Circuit SDK. An welcher Stelle der Status gesetzt wird hängt vom jeweiligem Adapter ab und muss vom Entwickler entsprechend eingebaut werden.
Die Beschreibung zu info.connection findet man in der ioBroker Doku.
Adapter Informationen unabhängig von config und states speichern
ungeprüft
Tipp wurde nicht geprüft.
1.)
Erstelle ein state..
"adapter.0.info.objects"
dort speichern und lesen.
2.)
Best practice wäre ein State in info.wieauchimmer oder file im iobroker-Data/namespace. Siehe smartvisu bzw History Adapter Influxdb hat auch was drin wo nicht geschriebene Daten gespeichert und beim nächsten Start wieder geladen werden.
JSON Objekt zur Übersetzung erstellen
Unter https://translator.iobroker.in ist der ioBroker Translator erreichbar, der eine Unterstützung bei der Übersetzung in neun Sprachen bietet.
Der Text muss in Englisch eingegeben werden und wird dann automatisch per Google Translate in acht weiteren Sprachen übersetzt.
Das erstellte JSON Objekt kann in die Zwischenablage kopiert werden und dann z.B. in die io-packages.json
und für den Admin in die Datei word.js
an den entsprechenden Stellen einkopiert werden.
Den eingestellten Loglevel des Adapters abfragen
Den Loglevel, unter dem der eigene Adapter läuft kann man über adapter.log.level
abfragen.