NEWS
SONOFF NSPanel mit Lovelace UI
SONOFF NSPanel mit Lovelace UI
-
Wenn man erstmal verstanden hat wie es geht, dann ist es einfach und geht auch verdammt schnell. Ich habe über 3000 Zeilen "nur Config" und von der Struktur her ist das meiste auch in jedem NSPanel vorhanden.
Wie @TT-Tom schon korrekt erwähnt hat ist bei einem Info nur ein .ACTUAL vorhanden und das reicht auch aus. Also jedes Icon in einer cardGrid oder cardEntities ist genau ein Alias vom Gerätetyp XYZ.
Manche Alias Geräte-Typen wie z.B. eine Lampe haben mehrere Eigenschaften. Eine "Info" nicht. Die liefert genau einen Wert eines Datenpunktes und ist somit auch ein eigenes pageItem.
Wenn nun diverse Werte eines Gaszählers (hast ja eigentlich nie Infos zu den Datenpunkten geliefert) angezeigt werden sollen, dann ist jeder Wert des Gaszählers ein Alias vom Geräte-Typ Info.Bei den ganz komplexen Aliassen legen wir die ja automatisch an (z.B. Gerätetyp media bei der cardMedia)
Wenn ich einmal "Gaszähler" angelegt habe und dann wieder lösche (wegen meiner Probiererei) bekomme ich bei dem nächsten Anlegen von "Gaszähler" nicht mehr das Fenster angezeigt, wo ich die Datenpunkte auswählen kann. Dann wird gleich ein Gerät Gaszähler mit Icon angezeigt. Ich muss dann "Gaszähler 2" oder "Gaszähler neu" anlegen.
Ist manchmal so. Der Device-Manager ist leider nicht der perfekteste Adapter und eben auch an vielen Stellen fehlerbehaftet. Dummerweise auch der einzige der es "einfach" hinbekommt. Sollten irgendwo Reste eines Alias warum auch immer nach dem Löschen noch vorhanden sein, so lassen sich diese auch unter Objekte alias.0... löschen.
Wenn man die Rollen, Channels und der Aliasse erst einmal verstanden hat, kann man sie auch per Hand anlegen. Aber auch da gibt es genügend Fallstricke. Würde also weiterhin den Geräte-Manager verwenden. Wenn etwas nicht geht, dann einfach hier eine Frage stellen. Habe zu fast jedem Alias mittlerweile raus, wie man die Bug's (auch wenn es langsam nervt) umgeht und dennoch zu einem positiven Ergebnis kommt

Da der Alias-Manager nun etwas sehr komplex und ebenfalls alles andere als intuitiv ist, würde ich dir die Erstellung dort ebenfalls nicht empfehlen...
Ich denke nach der ganzen Probiererei, wird es in einem hohen Tempo vorwärts gehen...

@armilar
Es funktioniert immer noch nicht.
Ich habe im Tab "Geräte" unter NSPanel - 1 einen Ordner mit dem Namen "Gaszähler" angelegt.
Dann unter diesem Ordner "Gaszähler" ein Gerät mit dem Namen "Verbrauch Heute" und als Typ"Info" Das Gerät wird angelegt, aber es erscheint kein Fenster wo ich die Verknüpfung mit dem Datenpunkt aus Javascript - Gaszähler - Verbrauch Heute herstellen kann.
Das Fenster ist aber gestern schon erschienen. Warum heute nicht? Irgendetwas läuft noch schief.
Inzwischen reagiert der ganze IOBroker nicht mehr, weder mit Browser noch über Putty.
Bald brauche ich nicht nur dieses Forum, sondern auch die Telefonseelsorge
Jetzt muss ich erstmal den ioBroker wieder in Gange bringen... -
@armilar
Es funktioniert immer noch nicht.
Ich habe im Tab "Geräte" unter NSPanel - 1 einen Ordner mit dem Namen "Gaszähler" angelegt.
Dann unter diesem Ordner "Gaszähler" ein Gerät mit dem Namen "Verbrauch Heute" und als Typ"Info" Das Gerät wird angelegt, aber es erscheint kein Fenster wo ich die Verknüpfung mit dem Datenpunkt aus Javascript - Gaszähler - Verbrauch Heute herstellen kann.
Das Fenster ist aber gestern schon erschienen. Warum heute nicht? Irgendetwas läuft noch schief.
Inzwischen reagiert der ganze IOBroker nicht mehr, weder mit Browser noch über Putty.
Bald brauche ich nicht nur dieses Forum, sondern auch die Telefonseelsorge
Jetzt muss ich erstmal den ioBroker wieder in Gange bringen... -
@tt-tom Gerne:

Wenn ich mit dem Cursor über den Stift streiche, erscheint dort : "Ordner bearbeiten" bei anderen Geräten erscheint "Zustände bearbeiten" und ich kann ein Alias anlegen.
Bei anderen Geräten ist alles gut:

Schon merkwürdig. -
@doggie wenn ich das richtig sehe hast du dein Datenpunkt unter nspanel.1.gaszähler angelegt. findest du diesen unter Objekte im Alias nicht?
@tt-tom Ich habe noch weiter probiert:

Obwohl ich unter Gaszähler ein Gerät angelegt habe, erscheint es unter Geräte nicht.Unter Objekten erscheint garnichts:

Ich habe nochmal mit dem Alias-Manager "herumprobiert". Dort erscheinen einige Aliase, obwohl ich sie unter Geräten gelöscht habe. Nur, ein System kann ich nicht erkennen.
Ob es einen Fehler im ioBroker gibt?Der gleiche Zustand wie oben im Alias-Manager:

Verstehen tu ich das nicht.
-
@tt-tom Auch hier gibt es was zu sehen: Der Graph entwickelt sich langsam (aber stetig).

Danke auch hierfür und für die kräftige Hilfestellung.
Kleiner Wunsch von mir:const BucketName: string = 'storage_short';statt fest verdrahtetem "iobroker' noch mit einbauen. -
@tt-tom Ich habe noch weiter probiert:

Obwohl ich unter Gaszähler ein Gerät angelegt habe, erscheint es unter Geräte nicht.Unter Objekten erscheint garnichts:

Ich habe nochmal mit dem Alias-Manager "herumprobiert". Dort erscheinen einige Aliase, obwohl ich sie unter Geräten gelöscht habe. Nur, ein System kann ich nicht erkennen.
Ob es einen Fehler im ioBroker gibt?Der gleiche Zustand wie oben im Alias-Manager:

Verstehen tu ich das nicht.
Ich habe den Eindruck du hast den Zweck des Alias nicht wirklich verstanden...
Du suchst nach der Erstellung des Alias nach dem Datenpunkt des Gaszählers? ... Es ist genau anders herum.
- Zunächst brauchst du den Datenpunkt aus einem Adapter, der dir den Wert des Gaszählers anzeigt, den du im Panel darstellen willst.
- Jetzt öffnest du den Gerätemanger, vergibst einen Namen und wählst den Gerätetypen Info aus
- In dem Fenster, in dem der .ACTUAL erscheint ordnest du den Datenpunkt aus Punkt 1) zu.
speichern. Das wars...
In der Seitenvariable für den Gaszähler trägst du den eben erstellen Alias (ohne das .ACTUAL) ein.
fertig...
Da wird nichts im NSPanel-Verzeichnis wie aus Geisterhand erscheinen... Punkt 1 - 3 und fertig ist das Ding
-
öhm sorry Leute, scheinbar kann jeder das Wiki editieren, ich dachte der macht dann einen PR drauß, aber er hat es einfach gespeichert....
Bitte noch mal drüber schauen, aber bei mir läuft das schon seit ein paar Tagen problemlos: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Card-Definitionen-(Seiten)#typescript-für-influx2Hier das aktualisierte Skript:
- jetzt mit async/await
- kann mehrere States überwachen
- generiert sofort die States
- man muss nicht erst warten, bis ein neuer Wert kommt
- das ist gerade fürs Testen bisschen nervig
- Bucket ist konfigurierbar
const Debug = false; const NSPanel_Path = '0_userdata.0.NSPanel.1.'; const Path = NSPanel_Path + 'Influx2NSPanel.cardLChart.'; const InfluxInstance = 'influxdb.1'; const influxDbBucket = 'iobroker'; const numberOfHoursAgo = 24; const xAxisTicksEveryM = 60; const xAxisLabelEveryM = 240; // this records holds all sensors and their corresponding states which act as the data source for the charts // add all sensors which are to be displayed in this script, there is no need to use multiple scripts const sensors : Record<string, string> = {}; /* ↓ Id of the sensor ↓ Id of the data source for the charts */ sensors['deconz.0.Sensors.65.temperature'] = Path + 'buero_temperature'; sensors['deconz.0.Sensors.65.humidity'] = Path + 'buero_luftfeuchte'; // create data source for NsPanel on script startup Object.keys(sensors).forEach(async x => { await generateDateAsync(x, sensors[x]); }); // then listen to the sensors and update the data source states accordingly on({ id: Object.keys(sensors), change: 'any' }, async function (obj) { if (!obj.id) { return; } await generateDateAsync(obj.id, sensors[obj.id]); }); async function generateDateAsync(sensorId: string, dataPointId: string) { const query =[ 'from(bucket: "' + influxDbBucket + '")', '|> range(start: -' + numberOfHoursAgo + 'h)', '|> filter(fn: (r) => r["_measurement"] == "' + sensorId + '")', '|> filter(fn: (r) => r["_field"] == "value")', '|> drop(columns: ["from", "ack", "q"])', '|> aggregateWindow(every: 1h, fn: last, createEmpty: false)', '|> map(fn: (r) => ({ r with _rtime: int(v: r._time) - int(v: r._start)}))', '|> yield(name: "_result")'].join(''); if (Debug) console.log('Query: ' + query); const result : any = await sendToAsync(InfluxInstance, 'query', query); if (result.error) { console.error(result.error); return; } if (Debug) console.log(result); const numResults = result.result.length; let coordinates : string = ''; for (let r = 0; r < numResults; r++) { const list : string[] = [] const numValues = result.result[r].length; for (let i = 0; i < numValues; i++) { const time = Math.round(result.result[r][i]._rtime/1000/1000/1000/60); const value = Math.round(result.result[r][i]._value * 10); list.push(time + ":" + value); } coordinates = list.join("~"); if (Debug) console.log(coordinates); } const ticksAndLabelsList : string[] = [] const date = new Date(); date.setMinutes(0, 0, 0); const ts = Math.round(date.getTime() / 1000); const tsYesterday = ts - (numberOfHoursAgo * 3600); if (Debug) console.log('Iterate from ' + tsYesterday + ' to ' + ts + ' stepsize=' + (xAxisTicksEveryM * 60)); for (let x = tsYesterday, i = 0; x < ts; x += (xAxisTicksEveryM * 60), i += xAxisTicksEveryM) { if ((i % xAxisLabelEveryM)) ticksAndLabelsList.push('' + i); else { const currentDate = new Date(x * 1000); // Hours part from the timestamp const hours = "0" + String(currentDate.getHours()); // Minutes part from the timestamp const minutes = "0" + String(currentDate.getMinutes()); const formattedTime = hours.slice(-2) + ':' + minutes.slice(-2); ticksAndLabelsList.push(String(i) + "^" + formattedTime); } } if (Debug) console.log('Ticks & Label: ' + ticksAndLabelsList); if (Debug) console.log('Coordinates: ' + coordinates); await setOrCreate(dataPointId, ticksAndLabelsList.join("+") + '~' + coordinates, true); } async function setOrCreate(id : string, value : any, ack : boolean) { if (!(await existsStateAsync(id))) { await createStateAsync(id, value, { name: id.split('.').reverse()[0], desc: 'Sensor Values [~<time>:<value>]*', type: 'string', role: 'value', }); } else { await setStateAsync(id, value, ack); } } -
Ich habe den Eindruck du hast den Zweck des Alias nicht wirklich verstanden...
Du suchst nach der Erstellung des Alias nach dem Datenpunkt des Gaszählers? ... Es ist genau anders herum.
- Zunächst brauchst du den Datenpunkt aus einem Adapter, der dir den Wert des Gaszählers anzeigt, den du im Panel darstellen willst.
- Jetzt öffnest du den Gerätemanger, vergibst einen Namen und wählst den Gerätetypen Info aus
- In dem Fenster, in dem der .ACTUAL erscheint ordnest du den Datenpunkt aus Punkt 1) zu.
speichern. Das wars...
In der Seitenvariable für den Gaszähler trägst du den eben erstellen Alias (ohne das .ACTUAL) ein.
fertig...
Da wird nichts im NSPanel-Verzeichnis wie aus Geisterhand erscheinen... Punkt 1 - 3 und fertig ist das Ding
-
Guten morgen zusammen.
Vorab ein herzliches Dankeschön für die Arbeit die hier geleistet wird.
Ich bin neu in der Thematik NSpanel mit Lovelace UI und dank der Community hier schon verdammt weit gekommen. Allerdings habe ich ein paar Herausforderungen bei denen ihr bestimmt helfen könnt. Ich hoffe das es an dieser Stelle richtig ist, ansonsten lasst es mich wissen - danke
Ich habe im Forum schon gesucht aber nichts gefunden, evtl. liegt es an meiner Handhabung...Button1/2:
Ich habe die Rule2 definiert und auch im TS Script die entsprechenden Anpassungen für Toggle vorgenommen.
Wenn ich jetzt die Button betätige, dann wird auch entsprechend geschaltet, aber ich muss danach immer erst auf eine andere Page wechseln um erneut ein Toggle auszuführen.
Also konkretes Bsp.:
NSpanel ist im Screensaver. Drücke ich Button1 wird Licht eingeschaltet.
Drücke ich Button1 erneut, bleibt das Licht eingeschaltet.
Wecke ich das NSpanel auf und meine Startseite wird angezeigt, kann ich über Button1 das Licht wieder ausschalten.
Drücke ich im Startbildschirm wieder Button1, wird das LIcht nicht eingeschaltet.
Wechsel ich auf eine andere Seite oder aber es geht in den Screensaver, kann ich über Button1 das Licht wieder einschalten.Jemand eine Idee?
-
Guten morgen zusammen.
Vorab ein herzliches Dankeschön für die Arbeit die hier geleistet wird.
Ich bin neu in der Thematik NSpanel mit Lovelace UI und dank der Community hier schon verdammt weit gekommen. Allerdings habe ich ein paar Herausforderungen bei denen ihr bestimmt helfen könnt. Ich hoffe das es an dieser Stelle richtig ist, ansonsten lasst es mich wissen - danke
Ich habe im Forum schon gesucht aber nichts gefunden, evtl. liegt es an meiner Handhabung...Button1/2:
Ich habe die Rule2 definiert und auch im TS Script die entsprechenden Anpassungen für Toggle vorgenommen.
Wenn ich jetzt die Button betätige, dann wird auch entsprechend geschaltet, aber ich muss danach immer erst auf eine andere Page wechseln um erneut ein Toggle auszuführen.
Also konkretes Bsp.:
NSpanel ist im Screensaver. Drücke ich Button1 wird Licht eingeschaltet.
Drücke ich Button1 erneut, bleibt das Licht eingeschaltet.
Wecke ich das NSpanel auf und meine Startseite wird angezeigt, kann ich über Button1 das Licht wieder ausschalten.
Drücke ich im Startbildschirm wieder Button1, wird das LIcht nicht eingeschaltet.
Wechsel ich auf eine andere Seite oder aber es geht in den Screensaver, kann ich über Button1 das Licht wieder einschalten.Jemand eine Idee?
@florian-klante poste mal wie du
button1undbutton2in der Config konfiguriert hast und bist du dir sicher, dass deine zu schaltenden States wirklichbooleansind? Wichtig ist, dass die States, falls es Aliase sind, eine richtige Convert-Funktion haben um bspw. aus"true"eintruemachen zu können.So habe ich es bei mir:
button1: { mode: "toggle", page: null, entity: "alias.0.Rooms.Wohnzimmer.Stehlampe.SET", setValue: null }, button2: { mode: "toggle", page: null, entity: "alias.0.Rooms.Wohnzimmer.HueGradientLightStrips.ON", setValue: null }
-
öhm sorry Leute, scheinbar kann jeder das Wiki editieren, ich dachte der macht dann einen PR drauß, aber er hat es einfach gespeichert....
Bitte noch mal drüber schauen, aber bei mir läuft das schon seit ein paar Tagen problemlos: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Card-Definitionen-(Seiten)#typescript-für-influx2Hier das aktualisierte Skript:
- jetzt mit async/await
- kann mehrere States überwachen
- generiert sofort die States
- man muss nicht erst warten, bis ein neuer Wert kommt
- das ist gerade fürs Testen bisschen nervig
- Bucket ist konfigurierbar
const Debug = false; const NSPanel_Path = '0_userdata.0.NSPanel.1.'; const Path = NSPanel_Path + 'Influx2NSPanel.cardLChart.'; const InfluxInstance = 'influxdb.1'; const influxDbBucket = 'iobroker'; const numberOfHoursAgo = 24; const xAxisTicksEveryM = 60; const xAxisLabelEveryM = 240; // this records holds all sensors and their corresponding states which act as the data source for the charts // add all sensors which are to be displayed in this script, there is no need to use multiple scripts const sensors : Record<string, string> = {}; /* ↓ Id of the sensor ↓ Id of the data source for the charts */ sensors['deconz.0.Sensors.65.temperature'] = Path + 'buero_temperature'; sensors['deconz.0.Sensors.65.humidity'] = Path + 'buero_luftfeuchte'; // create data source for NsPanel on script startup Object.keys(sensors).forEach(async x => { await generateDateAsync(x, sensors[x]); }); // then listen to the sensors and update the data source states accordingly on({ id: Object.keys(sensors), change: 'any' }, async function (obj) { if (!obj.id) { return; } await generateDateAsync(obj.id, sensors[obj.id]); }); async function generateDateAsync(sensorId: string, dataPointId: string) { const query =[ 'from(bucket: "' + influxDbBucket + '")', '|> range(start: -' + numberOfHoursAgo + 'h)', '|> filter(fn: (r) => r["_measurement"] == "' + sensorId + '")', '|> filter(fn: (r) => r["_field"] == "value")', '|> drop(columns: ["from", "ack", "q"])', '|> aggregateWindow(every: 1h, fn: last, createEmpty: false)', '|> map(fn: (r) => ({ r with _rtime: int(v: r._time) - int(v: r._start)}))', '|> yield(name: "_result")'].join(''); if (Debug) console.log('Query: ' + query); const result : any = await sendToAsync(InfluxInstance, 'query', query); if (result.error) { console.error(result.error); return; } if (Debug) console.log(result); const numResults = result.result.length; let coordinates : string = ''; for (let r = 0; r < numResults; r++) { const list : string[] = [] const numValues = result.result[r].length; for (let i = 0; i < numValues; i++) { const time = Math.round(result.result[r][i]._rtime/1000/1000/1000/60); const value = Math.round(result.result[r][i]._value * 10); list.push(time + ":" + value); } coordinates = list.join("~"); if (Debug) console.log(coordinates); } const ticksAndLabelsList : string[] = [] const date = new Date(); date.setMinutes(0, 0, 0); const ts = Math.round(date.getTime() / 1000); const tsYesterday = ts - (numberOfHoursAgo * 3600); if (Debug) console.log('Iterate from ' + tsYesterday + ' to ' + ts + ' stepsize=' + (xAxisTicksEveryM * 60)); for (let x = tsYesterday, i = 0; x < ts; x += (xAxisTicksEveryM * 60), i += xAxisTicksEveryM) { if ((i % xAxisLabelEveryM)) ticksAndLabelsList.push('' + i); else { const currentDate = new Date(x * 1000); // Hours part from the timestamp const hours = "0" + String(currentDate.getHours()); // Minutes part from the timestamp const minutes = "0" + String(currentDate.getMinutes()); const formattedTime = hours.slice(-2) + ':' + minutes.slice(-2); ticksAndLabelsList.push(String(i) + "^" + formattedTime); } } if (Debug) console.log('Ticks & Label: ' + ticksAndLabelsList); if (Debug) console.log('Coordinates: ' + coordinates); await setOrCreate(dataPointId, ticksAndLabelsList.join("+") + '~' + coordinates, true); } async function setOrCreate(id : string, value : any, ack : boolean) { if (!(await existsStateAsync(id))) { await createStateAsync(id, value, { name: id.split('.').reverse()[0], desc: 'Sensor Values [~<time>:<value>]*', type: 'string', role: 'value', }); } else { await setStateAsync(id, value, ack); } }@theknut Danke für das Script. Jetzt habe ich das Problem, wo der Alias ins Spiel kommen soll. Es ist ja eigentlich gut beschrieben:
/* ↓ Id of the sensor ↓ Id of the data source for the charts */ sensors['deconz.0.Sensors.65.temperature'] = Path + 'buero_temperature';Damit konnte ich soweit umgehen. Aktuell Fragezeichen??
-
@florian-klante poste mal wie du
button1undbutton2in der Config konfiguriert hast und bist du dir sicher, dass deine zu schaltenden States wirklichbooleansind? Wichtig ist, dass die States, falls es Aliase sind, eine richtige Convert-Funktion haben um bspw. aus"true"eintruemachen zu können.So habe ich es bei mir:
button1: { mode: "toggle", page: null, entity: "alias.0.Rooms.Wohnzimmer.Stehlampe.SET", setValue: null }, button2: { mode: "toggle", page: null, entity: "alias.0.Rooms.Wohnzimmer.HueGradientLightStrips.ON", setValue: null }
@theknut ich habe es eigentlich so wie du auch.
Ich nutze für die Aliase den "Geräte verwalten" Adapter, daher bin ich etwas verwirrt über deinen Screenshot mit den Funktionen für Read/Write.
Boolean sollte der Shelly Switch sein.

button2: { mode: 'toggle', page: null, entity: 'alias.0.Licht.Aussenbeleuchtung.SET', setValue: null },Es funktioniert ja auch der Toggle, ich muss halt nur immer erst einen anderen Befehl ausführen. Danach schaltet er dann auch den anderen Zustand auf dem Button wieder.
Kann es sein das bei der Rule2 was falsch ist? Ich habe da den Standard genommen.{"Rule2":{"State":"ON","Once":"OFF","StopOnError":"OFF","Length":189,"Free":322,"Rules":"on Button1#state do Publish SmartHome/%topic%/tele/RESULT {"CustomRecv":"event,button1"} endon on Button2#state do Publish SmartHome/%topic%/tele/RESULT {"CustomRecv":"event,button2"} endon"}}
-
@theknut ich habe es eigentlich so wie du auch.
Ich nutze für die Aliase den "Geräte verwalten" Adapter, daher bin ich etwas verwirrt über deinen Screenshot mit den Funktionen für Read/Write.
Boolean sollte der Shelly Switch sein.

button2: { mode: 'toggle', page: null, entity: 'alias.0.Licht.Aussenbeleuchtung.SET', setValue: null },Es funktioniert ja auch der Toggle, ich muss halt nur immer erst einen anderen Befehl ausführen. Danach schaltet er dann auch den anderen Zustand auf dem Button wieder.
Kann es sein das bei der Rule2 was falsch ist? Ich habe da den Standard genommen.{"Rule2":{"State":"ON","Once":"OFF","StopOnError":"OFF","Length":189,"Free":322,"Rules":"on Button1#state do Publish SmartHome/%topic%/tele/RESULT {"CustomRecv":"event,button1"} endon on Button2#state do Publish SmartHome/%topic%/tele/RESULT {"CustomRecv":"event,button2"} endon"}}
@florian-klante
zeig mal bitte die Seite MQTT Einstellungen aus dem verwendeten MQTT Adapter. -
@florian-klante
zeig mal bitte die Seite MQTT Einstellungen aus dem verwendeten MQTT Adapter.@ticaki meinst du diese?

-
@ticaki meinst du diese?

@florian-klante
so siehts in der anleitung aus

Ist zwar nicht logisch, weil ich verstehe das so das er nur bei Änderungen dinge verschickt, aber scheinbar aktualisiert er states dann nur bei veränderungen. Zumindest ist dein Fehler 100% ein raus filtern wegen wiederholter gleicher nachricht.
-
@florian-klante
so siehts in der anleitung aus

Ist zwar nicht logisch, weil ich verstehe das so das er nur bei Änderungen dinge verschickt, aber scheinbar aktualisiert er states dann nur bei veränderungen. Zumindest ist dein Fehler 100% ein raus filtern wegen wiederholter gleicher nachricht.
@ticaki aus welcher Anleitung hast du das?
-
@ticaki aus welcher Anleitung hast du das?
-
@ticaki großartig, jetzt funktioniert es.
Kaum macht man es richtig...
herzlichen Dank!