Avnav Plugins
=== nicht für Android ===
Um die Funktionalität von AvNav erweitern zu können gibt es Plugins. Plugins können mit Python code den Server erweitern und sie können mit Java Script und Css die WebApp erweitern.
Jedes Plugin muss sich in einem eigenen Verzeichnis befinden. Dessen Name ist gleichzeitig der Plugin Name. Es gibt 2 Wurzelverzeichnisse, die AvNav nach Plugins durchsucht:
- "systemdir" - ein Verzeichnis für Plugins, die für alle Nutzer auf einem System installiert werden (z.B. als Pakete). Dieses ist /usr/lib/avnav/plugins.
- "userdir" - ein Verzeichnis für Plugins eines einzelnen Nutzers. Das befindet sich unterhalb des "datadir" - also auf dem pi /home/pi/avnav/data/plugins, sonst unter Linux $HOME/avnav/plugins.
Daneben gibt es noch ein internes Plugin Verzeichnis (builtin).
Grundsätzlich können die Server-Anteile an verschiedenen Stellen Daten aus AvNav lesen oder hineinschreiben. Die WebApp Anteile können im Allgemeinen dazu dienen, diese Daten dann z.B. anzuzeigen. Daneben können sie aber auch einfach weitere Anzeigen einbringen oder das Aussehen anpassen.
In einem Plugin Verzeichnis kann es bis zu 3 Dateien geben, die von AvNav beachtet werden (daneben natürlich weitere Dateien, die das Plugin selbst benötigt).
Diese sind:
- plugin.py - die Serveranteile des Plugins, optional
- plugin.js - die Java Script Anteile des Plugins, optional
- plugin.css - die CSS Anteile des Plugins, optional
Ein Beispiel für ein Plugin findet man auf GitHub.
Installation
Um ein eigenes plugin zu erzeugen kann man entweder eine zip Datei oder
ein debian Paket bereitstellen.
Wenn man eine zip Datei bereitstellt, sollte diese auf der obersten Ebene
genau einen Ordner mit dem Namen des plugins enthalten ("plugin" oder
"avnav" sollten nicht Bestandteil dieses Namens sein).
Ein Nutzer des Plugins muss dieses dann im Unterverzeichnis "plugins" des
AvNav Datenverzeichnisses auspacken (z.B. /home/pi/avnav/data/plugins auf
einem Raspberry Pi).
Auf diese Weise wird das plugin zu einem "user plugin".
Wenn man ein debian Paket bereitstellt, sollte es dem Namensschema
avnav-xxx-plugin folgen. Der Inhalt sollte in das Verzeichnis
/usr/lib/avnav/plugins/<pluginName> entpackt werden.
Ein solches plugin wird zu einem "system plugin".
Plugin Pakete sollten den Namen des plugins (d.h. denb Verzeichnis-Namen)
als Metadaten Feld mit dem Namen packages should contain the name of the
plugin (i.e. the directory name) as a meta data field "avnav-plugin"
enthalten.
Beispiel:
avnav-plugin: system-obp-plotterv3
Das unterstützt den AvNav Updater dabei festzustellen, ob ein
Plugin-Paket als Installationskandidat angezeigt werden soll oder nicht.
Wenn man ausserdem das Metdatenfeld "avnav-hidden" auf true setzt , wird
das Paket im Updater nur angezeigt, wenn das Plugin explizit enabled
wurde.
Liste von Plugins
- ocharts - Karten von o-charts
- ochartsng - Neue Implementierung für o-charts, S57 Karten
- Seatalk Remote - in Zusammenspiel mit der Fernbedienung von AK-Homberger
- History - Datenspeicherung und Anzeige
- Update
- Update von AvNav (und den dazugehörigen Paketen) ohne die
Kommandozeile nutzen zu müssen.
Konfig-Editor und Log-Viewer für AvNav - MapProxy - integriert MapProxy für Zugriff und Download verschiedener online Kartenquellen
- Obp-RC-Remote - plugin für die Nutzung der Fernbedienung von Christian
- Sail-Instrument-Plugin - Dekodierung und Berechnung von weiteren Kurs- und Winddaten,Sail Instrument
- rudder-angle - Anzeige des Ruderwinkels (über SignalK)
- Obp-PlotterV3 - Spezialfunktionen für den Open Boat Projects 10 Zoll Plotter (V3)
plugin.js
Im Java script code sind genau die gleichen Funktionen verfügbar wie unter nutzerspezifischer Java Script code beschrieben.
plugin.css
Im CSS code sind die gleichen Möglichkeiten vorhanden wie unter nutzerspezifisches CSS beschrieben.
plugin.py
Die Zeichnung gibt einen groben Überblick über die interne Struktur des AvNav Servers und die Punkte, an denen ein Plugin Daten auslesen oder einspeisen kann.
Punkt | Funktion | Beispiel |
A | Einspeisen von NMEA Daten in die interne Liste. Diese stehen dann
an allen Ausgängen zur Verfügung. Hinweis: Solche Daten stehen zunächst nicht für die WebApp zur Verfügung, solange es keinen Dekoder für diesen Datensatz gibt. |
Auslesen eines Sensors und Erzeugen des passenden NMEA0183 Datensatzes. |
B | Auslesen von empfangenen NMEA Daten. Hier können (ggf. mit einem Filter) alle in AvNav durchlaufenden NMEA Daten gelesen werden. | In Zusammenspiel mit Punkt "C" Dekodieren von NMEA Datensätzen |
C | Einspeisen von Daten in den internen Speicher von AvNav. Die Daten
im internen Speicher sind in einer Baumstruktur abgelegt. Jedes
Element ist durch einen Schlüssel der Form "a.b.c...." adressiert.
Beispiel: "gps.lat". Alle Schlüsselwerte, die mit "gps." starten, werden automatisch an die WebApp übertragen und sind dann dort unter "nav.gps...." verfügbar. (siehe Layout Editor und nutzerspezifisches Java Script). Schlüsselwerte müssen vorher durch das Plugin angemeldet werden, es ist nicht möglich, bereits im System genutzte Schlüssel zu überschreiben. Ausnahme: Der Nutzer konfiguriert für das Plugin den Wert "allowKeyOverride" auf true. |
Einspeisen eines von einem Sensor gelesenen Wertes - z.B. gps.temperature.outside oder von dekodierten NMEA Daten. |
D | Auslesen von Daten aus dem internen Speicher. | Berechnung neuer Daten und Einspeisung unter "C" - oder Weiterreichen an eine externe Verbindung. |
E | Bearbeiten von HTTP Requests | Die Java script Anteile können einen HTTP request senden, der im
python code bearbeitet werden kann. Anworten typischerweise in Json |
Ein Beispiel für eine plugin.py findet sich auf GitHub.
Damit das Plugin von AvNav erkannt wird, müssen folgende Voraussetzungen eingehalten werden:
- In plugin.py muss mindestens eine Klasse vorhanden sein (der Name sollte Plugin sein)
- Die Klasse muss eine statische Methode (@classmethod) mit dem Namen
pluginInfo haben, die ein dictionary zurückgibt.
* description (mandatory) * data: list of keys to be stored (optional) * path - the key - see AVNApi.addData, all pathes starting with "gps." will be sent to the GUI * description
Ein Beispiel könnte so aussehen:
@classmethod def pluginInfo(cls):
return { 'description': 'a test plugins', 'data': [ { 'path': 'gps.test', 'description': 'output of testdecoder', } ] } - Der Konstruktor der plugin Klasse muss einen Parameter erwarten.
Beim Aufruf wird hier eine Instanz des API übergeben, über das die Kommunikation mit AvNav erfolgt. - Die Klasse muss eine run Methode (ohne Parameter) besitzen.
Diese wird in einem eigenen Thread aufgerufen, nachdem die Initialisierung abgeschlossen ist.
Typischerweise wird diese Methode eine Endlosschleife enthalten, um die Plugin-Funktion zu realisieren.
Für das Plugin können in der avnav_server.xml Parameter konfiguriert werden, diese sind dann über das API (getConfigValue) abrufbar.
Plugin API
Am API stehen die folgenden Funktionen zur Verfügung
Funktion | Beschreibung |
log,debug,error | Logging Funktionen. Es werden Zeilen in die AvNav log Datei geschrieben. Man sollte für log und error vermeiden, solche Einträge in grosser Zahl zu schreiben, da sonst im Log potentiell wichtige Informationen verloren gehen (also z.B. nicht jede Sekunde ein Fehlereintrag...) |
getConfigValue | lies einen config Wert aus der avnav_server.xml. |
fetchFromQueue | Interface B: lies Daten aus der internen NMEA Liste. Ein Beispiel ist im API code vorhanden. Der filter Parameter funktioniert wie in der avnav_server.xml. |
addNMEA | Interface A: schreibe einen NMEA Datensatz in die interne Liste. Man kann AvNav die Prüfsummenberechnung überlassen und man kann auch eine Dekodierung in AvNav verhindern. Der Parameter source ist ein Wert, der in blackList parametern genutzt werden kann. |
addData | Interface C: schreibe einen Wert in den internen Speicher. Es können nur Werte geschrieben werden, deren Schlüssel in der Rückgabe der pluginInfo Methode vorhanden waren. |
getSingleValue | Interface D: lies einen Datenwert aus dem internen Speicher. Zur Zusammenfassung mehrerer solcher Lesevorgänge existiert die Funktion getDataByPrefix |
setStatus | Hier sollte der aktuelle Zustand des Plugins gesetzt werden. Das ist der Wert, der auf der Statusseite angezeigt wird. |
registerUserApp | Ein Plugin kann eine User App registrieren. Dafür nötig ist eine URL und eine Icon Datei. Die Icon Datei sollte mit im Plugin Verzeichnis liegen. In der URL kann $HOST verwendet werden, das wird dann durch die korrekte IP Adresse des AvNav Servers ersetzt. Beispiel im signalk Plugin. |
registerLayout | Falls das Plugin z.B. eigene Widgets mitbringt, ist es u.U. hilfreich ein vorbereitetes Layout mitzuliefern, das der Nutzer dann auswählen kann. Das Layout dazu nach der Erstellung mit dem Layout Editor herunterladen und im Plugin Verzeichnis speichern. Beispiel wieder im signalk Plugin. |
registerSettingsFile (since 20220225) |
Registrierung einer eigenen Einstellungsdatei (die vorher von der
Settingsseite aus exportiert werden kann). Der Dateiname (zweiter Parameter) ist relativ zum Plugin-Verzeichnis. Der Name (erster Parameter) wird dem Nutzer angezeigt. Within this file you can use $prefix$ in the layout name if you want to refer to a layout that you register from the same plugin. ...
This will refer to a layout that you registered with the name
"main"."layoutName": "$prefix$.main" .... |
getDataDir | Das Verzeichnis, in dem AvNav Daten ablegt |
registerChartProvider | Falls das Plugin Karten bereitstellt, wird hier ein callback registriert, der eine Liste der Karten zurückgibt. |
registerRequestHandler | Falls das Plugin HTTP requests bearbeiten soll (Interface E) muss
hier ein callback registriert werden, der den Request behandelt. Die
url für den Aufruf ist: <pluginBase>/api Dabei ist pluginBase der unter getBaseUrl zurückgegebene Wert. Die java script Anteile können die API url mit der Variable AVNAV_BASE_URL bilden: AVNAV_BASE_URL+"/api" Im einfachsten Fall kann die aufgerufene callback-Funktion ein dictionary zurückgeben, dieses wird als Json zurück gesendet. |
getBaseUrl | gib die Basis URL für das Plugin zurück |
registerUsbHandler (ab 20201227) |
registriert einen Callback für ein USB Gerät. Mit dieser
Registrierung wird AvNav mitgeteilt, dass es das USB Gerät nicht
beachten soll. Der Callback wird mit dem Device-Pfad für das Gerät
aufgerufen, wenn das Gerät erkannt wurde. Die USB-Id kann am einfachsten durch Beobachten der Status-Seite beim Einstecken des Gerätes ermittelt werden. Siehe auch AVNUsbSerialReader. Damit kann ein Plugin selbst einfach das Handling für ein spezielles Gerät übernehmen, Ein Beispiel findet sich auf GitHub. |
getAvNavVersion (ab 20210115) |
Aktuelle AvNav Version (int) |
saveConfigValues (ab 20210322) |
Speichere config Werte für das Plugin in avnav_server.xml. Der Parameter muss ein dictionary mit den Werten sein. Das Plugin muss sicherstellen, dass es später mit diesen Werten wieder starten kann. |
registerEditableParameters (ab 20210322) |
Registriert eine Liste mit config Werten, die zur Laufzeit
geändert werden können. Der erste Parameter ist eine Liste von
dictionaries mit den Parameter Beschreibungen, der zweite ein
callback, der bei Änderungen mit den geänderten Werten aufgerufen
wird (wird typischerweise saveConfigValues rufen). Die Syntax für die Parameter-Liste ist im Source Code beschrieben. |
registerRestart (ab 20210322) |
Registriere einen Stop Callback. Damit kann das Plugin disabled (deaktiviert) werden. |
unregisterUserApp (ab 20210322) |
Deregistriere eine User App. |
deregisterUsbHandler (ab 20210322) |
Deregistriere eine usb device id (siehe registerUsbHandler) |
shouldStopMainThread (ab 20210322) |
Kann in der Hauptschleife genutzt werden, um zu prüfen, ob das Plugin gestoppt werden soll. In jedem anderen Thread wird immer True zurück gegeben. |
sendRemoteCommand (ab 20230426) |
Sende ein Fernsteuerungskommando, siehe den Source Code für Details. |
registerSettingsFile (ab 20230426) |
Mache eine Datei mit gespeicherten Einstellungen bekannt. Diese kann vom Nutzer dann geladen werden. |
registerCommand (ab 20230426) |
Registriere ein Kommando, das von AvNav ausgeführt werden kann. Dieses kann z.B. dafür genutzt werden ein bereits vorhandenes Kommando zu ersetzen. Auch neue Kommandos sind möglich. Siehe den Source Code oder die AVNCommandHandler Konfiguration für Details. |
registerConverter (since 20240520) |
Registriere einen Karten-Konverter Für ein Beispiel siehe das ochartsng plugin |
deregisterConverter (since 20240520) |
Deregistriere einen Karten-Konverter |
Aktivieren und Verbergen von System Plugins
(ab 20230426)
Um plugins "unsichtbar" zu machen, die mit debian Paketen installiert
wurden, gibt es ein Script /usr/lib/avnav/plugin.sh.
Als root kann man dieses Script aufrufen um die Sichtbarkeit von system
plugins zu steuern und default Parameter zu setzen.
Ein Aufruf ohne Parameter bringt eine Hilfe mit den Aufruf-Optionen.
Spezialfunktionen für den Raspberry Pi
(ab 20230426)
Plugins die als debian Pakete für den Raspberry Pi erzeugt werden (system
plugins) können ein Shell Script "plugin-startup.sh" bereitstellen.
Dieses Script ermöglich es plugins, Systemparameter zu konfigurieren.
Es wird immer während des Bootprozesses des Systems aufgerufen.
Ob und mit welchen Parametern ein solches Script aufgerufen wird, hängt
von einem Parameter in der Datei /boot/avnav.conf ab (siehe Image
Vorbereitung). Der Parametername ist:
AVNAV_<PLUGIN>
Dabei ist <PLUGIN> der Pluginname (d.h. der Name seines
Verzeichnisses) übersetzt in Großbuchstaben (und ohne alle Zeichen ausser
0-9 und a-z).
Wenn dieser Parameter auf "yes" gesetzt ist, wird das Pluginscript
gerufen.
Es gibt 3 Aufruf-Varianten:
plugin-startup.sh enable
Dieser Aufruf findet beim ersten Boot mit dem Parameter in der avnav.conf
auf "yes" statt.
Das Plugin sollte jetzt alle notwendigen Änderungen am System vornehmen
(wenn möglich so, das sie auch später wieder rückgängig gemacht werden
können).
Typischerwe betrifft das Anpassungen /boot/config.txt oder anderen
Konfigurationsdateien.
Das Script sollte 1 zurückgeben, wenn ein Reboot nötig ist, sonst 0 oder
< 0 bei Fehlern.
Es gibt einige Helper Funktionen die im Script genutzt werden können. Diese Helper Funktionen bindet man mit
. "$AVNAV_SETUP_HELPER"
in das Script ein.
Die Umgebungsvariable AVNAV_SETUP_HELPER ist gesetzt, wenn das Script
aufgerufen wird.
Ein Beispiel findet man im obp-plotterv3-plugin.
plugin-startup.sh disable
Dieser Aufruf wird ausgeführt, wenn der Parameter in der avnav.conf von
yes auf einen anderen Wert geändert oder entfernt wird. Das Script sollte
die am System gemachten Änderungen - soweit möglich - wieder zurücknehmen.
Anmerkung: Da das Handling im Normalfall nur dazu vorgesehen ist, einmalig
bei der ersten Nutzung eines Images stattzufinden, ist es kein grosses
Problem, wenn Änderungen nicht zurückgenommen werden.
plugin.startup.sh [keine Parameter]
Dieser Aufruf erfolgt bei jedem boot. In diesem Falls sollten keine Einstellungen im System geändert werden - es könnte sonst sehr überraschend für den Nutzer sein, wenn bei einem beliebigen Startvorgang plötzlich Systemeinstellungen geändert werden. Es können aber beispielsweise notwendige Initialisierungen von Hardware vorgenommen werden.