Hauptmenü

Developer Guide

Begonnen von Syrex-o, 23 April 2020, 13:19:07

Vorheriges Thema - Nächstes Thema

Syrex-o

FhemNative Developer Guide:

Hallo zusammen,
Falls jemand Interesse hat eine eigene Komponente für FhemNative zu schreiben, der kann diesen Guide verwenden.
Jedoch sollte etwas Grudwissen über Angular, Ionic und Typescript vorhanden sein.

Für den Start:
1. Repository von Github ziehen:
git pull
2. nach Development/FhemNative navigieren und
npm install
Dann habt ihr alle notwendigen Pakete und könnt starten.

Live Development:
FhemNative kann über electron als Live Umgebung funktionieren. So könnt ihr code schreiben, speichern und das Fenster wird automatisch neu geladen.
Dafür einfach in Development/FhemNative
npm run electron:dev
Dann könnt ihr über das Electron Fenster bei view die Developer Tools anzeigen.

Komponente erstellen:
Als Beispiel dient im folgenden die Button Komponente.

Um eine Komponente in FhemNative zu erstellen, benötigt es nur ein paar Bausteine.
Erstellt einen Ordner in fhem-components mit dem Namen: fhem-"Name der Komponente"
Anschließend werden 3 files benötigt:

- fhem-button.component.ts
- fhem-button.component.html
- fhem-button.component.scss


...component.ts
In der Typescript Datei wird definiert, wie die Komponente funktionieren soll.
Als erstes werden ein paar Imports von Angular benötigt:

import { Component, Input, NgModule, OnInit, OnDestroy } from '@angular/core';


Anschließend werden die default Komponenten und Directives importiert:
import { ComponentsModule } from '../../components.module';

Nun können die nötigen Services importiert werden, die eure Komponente benötigt.

Wollt ihr eine Komponente erstellen, die mit FHEM spricht, braucht ihr:
import { FhemService } from '../../../services/fhem.service';

Wollt ihr eine Komponente erstellen, die Einstellungen von FhemNative benötigt, braucht ihr:
import { SettingsService } from '../../../services/settings.service';

Wollt ihr eine Komponente erstellen, die native Events ausführen kann, braucht ihr:
import { NativeFunctionsService } from '../../../services/native-functions.service';

Es gibt noch weitere Services, die je nach bedarf importiert werden können.

Must have Input() Werte
Jede Komponente benötigt ein paar "Pflicht-Inputs":

@Input() ID: string;

// position information
@Input() width: string;
@Input() height: string;
@Input() top: string;
@Input() left: string;
@Input() zIndex: string;

So wird die Komponente in einzelnen Räumen gefunden und bewegt. Die ID erstellt sich automatisch beim anlegen.

Um FhemNative nun zu helfen, was eure Komponente so an Einstellungen braucht, dient die getSettings() Funktion.
So könnt ihr bestimmte Attribute definieren, die dann beim Komponente erstellen/bearbeiten in (inputs/switches/selects) umgewandelt werden.

static getSettings() {
return {
name: 'Button',
type: 'fhem',
inputs: [
{variable: 'data_device', default: ''},
{variable: 'data_reading', default: 'state'},
{variable: 'data_setReading', default: ''},
{variable: 'data_getOn', default: 'on'},
{variable: 'data_getOff', default: 'off'},
{variable: 'data_setOn', default: 'on'},
{variable: 'data_setOff', default: 'off'},
{variable: 'data_label', default: ''},
{variable: 'data_sendCommand', default: ''},
{variable: 'data_borderRadius', default: '5'},
{variable: 'data_borderRadiusTopLeft', default: '5'},
{variable: 'data_borderRadiusTopRight', default: '5'},
{variable: 'data_borderRadiusBottomLeft', default: '5'},
{variable: 'data_borderRadiusBottomRight', default: '5'},
{variable: 'data_iconSize', default: '20'},
{variable: 'icon_iconOn', default: 'add-circle'},
{variable: 'icon_iconOff', default: 'add-circle'},
{variable: 'bool_data_iconOnly', default: false},
{variable: 'bool_data_customBorder', default: false},
{variable: 'style_iconColorOn', default: '#86d993'},
{variable: 'style_iconColorOff', default: '#86d993'},
{variable: 'style_buttonColor', default: '#86d993'},
{variable: 'style_labelColor', default: '#fff'},
{variable: 'arr_data_style', default: 'standard,NM-IN-standard,NM-OUT-standard'}
],
dependencies: {
data_iconSize: { dependOn: 'bool_data_iconOnly', value: false },
data_borderRadius: { dependOn: 'bool_data_customBorder', value: false },
data_borderRadiusTopLeft: { dependOn: 'bool_data_customBorder', value: true },
data_borderRadiusTopRight: { dependOn: 'bool_data_customBorder', value: true },
data_borderRadiusBottomLeft: { dependOn: 'bool_data_customBorder', value: true },
data_borderRadiusBottomRight: { dependOn: 'bool_data_customBorder', value: true },
// neumorph dependencies
style_buttonColor: { dependOn: 'arr_data_style', value: 'standard' }
},
dimensions: {minX: 30, minY: 30}
};
}


Benennung:
Damit FhemNative die Komponente finden kann, müsst ihr einen Namen vergeben.
Der gleiche Name muss anschließend in component-loader.service.ts unter fhemComponents mit dem Pfad eingetragen werden.

Type:
Damit FhemNative erkennt, was für eine Komponente gerade erstellt/bearbeitet wird, vergebt ihr einen type
Entweder fhem oder style
Komponenten mit type: 'fhem' werden beim Komponenten erstellen/bearbeiten auf der letzten Seite geprüft, um einen Hinweis zu geben, ob das device und reading existiert.

Inputs:
Für jede Input variable benötigt ihr eine Input() variable in der Komponente.
Für die Variablen gilt folgendes:

  • data_ --> erstellt ein Input Feld, dass der User füllen kann
  • arr_data_ --> erstellt eine Select box, bei der ein wert erlauft ist (als default müssen alle Möglichen Werte als string mitgegeben werden)
  • bool_data --> erstellt einen Switch für true/false Werte
  • icon_ --> erstellt einee Select box, die als Icon Auswahl dient (als default kann jedes Icon aus settings.service verwendet werden)
  • arr_icon_ --> erstellt eine Select box, die mehrer Icons als Eingabe erlaubt
  • style_ --> erstellt eine Select box, für die Farbauswahl
  • arr_style_ --> erstellt eine Select box, die mehrere Farben als Eingabe erlaubt

Dependencies:
Dependencies sind nicht notwendig, können jedoch dabei helfen, bestimmte Einstellungen nur anzuzeigen, wenn sie benötigt werden.
Bsp. Es wird nur ein Icon benötigt, wenn der User einen bestimmten Style der Komponente ausgewählt hat.
Dependencies funktionieren so:

data_borderRadius: { dependOn: 'bool_data_customBorder', value: false }

Als Object Attribut wird dabei angegeben, welche Einstellung verborgen werden soll, wenn eine Bedingung nicht erfüllt ist.
In diesem Beispiel, wird die Option data_borderRadius nur angezeigt, wenn die Option bool_data_customBorder auf false steht
Als value Parameter kann ebenfalls ein Array mit mehreren Werten angegeben werden.

Dimensions:
Hier teilt ihr FhemNative mit, mit welchen Dimensionen die Komponente erstellt werden soll.
dimensions: {minX: 30, minY: 30}

...component.html
In der HTML Datei könnt ihr eure Komponenten-Struktur definieren.
Damit FhemNative die Komponente richtig rendern kann und alle zusätzlichen Funktionen (move/resize/click) ermöglicht, benötigt ihr den:
<fhem-component-container></fhem-component-container>

Der Container dient als Begrenzung der Komponente und benötigt ein paar Attribute:
[specs]="{ID: ID, device: data_device, reading: data_reading, available: true, connected: true}"
In den specs könnt ihr definieren, wie der Container mit der Komponente umgehen soll.
In diesem Beispiel wird der Gerätename und das Reading übergeben. In Kombination mit den nachfolgenden Attribute findet FhemNative heraus, ob die Komponente gerendert werden soll.
Im Beispiel wird available: true und connected: true festgelegt.
Das bedeutet, dass die Komponente gerendert wird, wenn das device und reading vorhanden ist, oder eine Verbindung zu FHEM hergestellt ist.

Folgende Attribute können verwendet werden:
Wenn die Bedingung zutrifft, wird die Komponente gerendert.

  • available --> wenn device und reading vorhanden sind
  • connected --> wenn eine Verbindung zu FHEM besteht
  • offline --> Komponente wird immer sofort gerendert

Wenn eure Komponente von FHEM Werten abhängt, macht es sinn dem Container das device mitzugeben, sobald es verfügbar ist:
[fhemDevice]="fhemDevice"

Alle Informationen über die Position der Komponente werden einfach an den Container weitergeleitet:
[position]="{width: width, height: height, top: top, left: left, zIndex: zIndex}"

Zuletzt müsst ihr die Minimalbreite und Minimalhöhe definieren. Diese sorgen dafür, dass eine Komponente beim "resizen" nicht kleiner als diese Werte werden kann.

Anschließend sollte die eigentliche Komponenten-Struktur in einen eigenen Container mit einerclass gepackt werden. Diese wird in der scss benötigt.
<button class="button"></button>

...component.scss
In der scss Datei wird der Style der Komponente definiert.
Als erstes benötigt ihr dafür die class die ihr definiert habt:

:host{
    .button{
        width: inherit;
        height: inherit;
    }
}

Die width und height Optionen sorgen dafür, dass die Komponente die Größe des übergeordneten Containers übernimmt.
Anschließend könnt ihr normalen "Style-code" schreiben.

Verbindung zu FHEM:
Damit eure Komponente Informationen von FHEM erhalten kann, benötigt ihr die getDevice() Funktion.

this.fhem.getDevice(this.ID, this.data_device, (device)=>{
this.getState(device);
}).then(device=>{
this.getState(device);
});

So wird das device, dass vom User vergeben wurde von FHEM abgefragt. Die ID wird benötigt, damit die Komponente Updates erhalten kann.
Der then teil der Funktion wird ausgeführt, sobald die Informationen von FHEM abgeholt worden sind. Diese könnt ihr dann weiter verarbeiten.
Im callback kommen die Informationen an, wenn sich Werte des definierten Geräts geändert haben.

Ich hoffe das reicht erst einmal als Einstieg. Alles weitere ergänze ich mit der Zeit.

Beste Grüße und viel Spaß beim erstellen eigener FhemNative Komponenten.

Syrex-o

Schon jemand, der sich Mal an einer eigenen Komponte versucht hat ?

P.S. Da gibt ein keine doofe Fragen

Rollo

Hallo Syrex-o

das FhemNative Frontend ist eine hervorragende Ergänzung für den FHEM Server.
Das Konzept gefällt mir außerordentlich gut, sodass ich jetzt auch mal versuche, eigene FhemNative Komponenten zu bauen.
Die Entwicklungsumgebung (serve:web:fhem-native-desktop) funktioniert perfekt.
Dabei bin ich auf ein Problem gestoßen, das auch bei den bereits vorhandenen Komponenten besteht.
Beim allerersten Aufruf des Frontends  erscheinen stets die Fehlermeldungen wie z.B.  "Fhem Gerät nicht gefunden" oder "Kein HTML text gefunden".
Bei einem erneuten Klick  auf den Raum und bei allen weiteren Funktionen sind die Daten dann vorhanden.

Die Ursache für dieses Verhalten glaube ich im Coding von "handleWebsocketEvents" (Betriebsart "websocket") im Programm fhem.service.ts (Zeile 344-347 im RC3.0) gefunden zu haben.
Dort wird die Abfrage "msg.payload.num === listDevices.length" geprüft, und nur wenn das zutrifft, wird die Observer-Variable "deviceListSub" getriggert.
listDevices wird aber bei jedem Aufruf dieser Methode  vor dieser Überprüfung als leeres Array neu deklariert, ist also leer.
"msg.payload.num" dagegen ist eine Zahl, die der Anzahl der vorher abgefragten Devices (im vorhergehenden list Befehl) entspricht. Nur wenn man genau ein Device verwendet, funktioniert das Ganze wie es soll.

Hab ich da etwas falsch verstanden, oder handelt es sich um einen Fehler?
Vielen Dank für ein kurzes Feedback.
Rollo

Syrex-o

Schön, dass sich hier auch mal jemand meldet  ;)

Wenn FhemNative weitere Entwickler bekommt, freut mich das umso mehr.

Zitat
Die Ursache für dieses Verhalten glaube ich im Coding von "handleWebsocketEvents" (Betriebsart "websocket") im Programm fhem.service.ts (Zeile 344-347 im RC3.0) gefunden zu haben.
Dort wird die Abfrage "msg.payload.num === listDevices.length" geprüft, und nur wenn das zutrifft, wird die Observer-Variable "deviceListSub" getriggert.
listDevices wird aber bei jedem Aufruf dieser Methode  vor dieser Überprüfung als leeres Array neu deklariert, ist also leer.
"msg.payload.num" dagegen ist eine Zahl, die der Anzahl der vorher abgefragten Devices (im vorhergehenden list Befehl) entspricht. Nur wenn man genau ein Device verwendet, funktioniert das Ganze wie es soll.

Scheint schlüssig für mich. Denke ich dran, wenn ich FhemNative in die neue Struktur umziehe.

Aktuell gibt es ja leider keine ordentliche Developer Doku.
Wenn du aktuell damit klar kommst, umso besser.

In Zukunft werden Komponenten etwas anders funktionieren. Das ändert aber am grundsätzlichen Handling für den Developer recht wenig. Wenn du also eine Komponente für FhemNative erstellt, portiere ich Sie gern direkt in die neue Struktur.

Grüße

Rollo

Hallo Syrex-o,

meine heutige Anfrage zur Nichtsichtbarkeit der Html Komponente bei Dark Theme konnte ich durch folgende Änderung in fhem-html-component.scss beheben: color: var(--text-a);
Dann schaltet sich die Textfarbe automatisch um.

Generelle Frage: Ändert sich bei der Vorgehensweise von selbstgebauten Komponenten  etwas in der Version 4.x.x ?

Vielen Dank



Syrex-o

Zitat von: Rollo am 16 Mai 2023, 14:23:20Hallo Syrex-o,

meine heutige Anfrage zur Nichtsichtbarkeit der Html Komponente bei Dark Theme konnte ich durch folgende Änderung in fhem-html-component.scss beheben: color: var(--text-a);
Dann schaltet sich die Textfarbe automatisch um.

Generelle Frage: Ändert sich bei der Vorgehensweise von selbstgebauten Komponenten  etwas in der Version 4.x.x ?

Vielen Dank


Ich habe gerade ein neues Release an den Store übergeben.
Ich habe noch ein paar mehr Optionen direkt mit eingebaut.

Den Developer Guide habe ich bisher noch nicht aktualisiert  :(
Es hat sich einiges getan und Komponenten können jetzt aus meiner Sicht noch viel einfacher erstellt werden.
Möchtest du eigene Komponenten schreiben?

Guides und Doku Elemente auf fhemnative.de sind auch sehr gerne gesehen  ;)

Rollo

Hallo Syrex-o,

ich habe schon vor einiger Zeit eine Komponente gebastelt, eine Rolladensteuerung.
hier noch in der Version  3 RC3.
Du darfst diesen Dateianhang nicht ansehen. 

In der neuen Version hab ich es noch nicht ganz zum Laufen gebracht, aber es fehlen nur noch paar CSS Anpassungen, da jetzt alles mehr responsive ist.

Es macht richtig Spaß damit zu arbeiten.

Viele Grüße


Syrex-o

Zitat von: Rollo am 23 Mai 2023, 14:12:09Hallo Syrex-o,

ich habe schon vor einiger Zeit eine Komponente gebastelt, eine Rolladensteuerung.
hier noch in der Version  3 RC3.
Du darfst diesen Dateianhang nicht ansehen. 

In der neuen Version hab ich es noch nicht ganz zum Laufen gebracht, aber es fehlen nur noch paar CSS Anpassungen, da jetzt alles mehr responsive ist.

Es macht richtig Spaß damit zu arbeiten.

Viele Grüße



Wenn du soweit bist, kannst du die Steuerung gern im Github als Merge Request einchecken?
Dann können andere deine Arbeit auch verwenden.

VG