SVG-Webseitenkomponenten für IoT und Maker (Teil 2)
Veröffentlicht: 2022-03-10Wir haben also bereits Möglichkeiten, ein Menü mit SVG-Icons dynamisch zu laden, die auf Wunsch durch das Laden von Panels reagieren, aber die Icons waren keine eigentlichen Komponenten. Wir konnten einen einfachen Trick anwenden, indem wir das SVG für jedes Symbol einbrachten und es an die Vue-Anwendung weitergaben. Es war einfach genug, eine Liste von Symbolen zu erstellen, und jedes Symbol reagierte auf ähnliche Weise, abgesehen von kleinen Datenunterschieden. Durch den Datenunterschied war es möglich, den Namen eines Panels so an jedes Icon zu binden, dass der Handler für den Button-Klick des Icons diesen weitergeben konnte.
Wenn ein Panel in Form einer Vue-Komponente geladen wird, muss alles über das Panel und seine Komponenten geladen werden, Vorlagen, JavaScript und mehr. Die Aufgabe, nur das Laden des Panels zu verwalten, ist also größer als das, was wir bisher in dieser Diskussion erlebt haben.
Schauen wir uns an, wie Vue einen Hook für das asynchrone Laden bereitstellt. Der folgende Ausschnitt stammt aus dem Vue-Leitfaden.
Vue.component('async-example', function (resolve, reject) { setTimeout(function () { // Pass the component definition to the resolve callback resolve({ template: '<div>I am async!</div>' }) }, 1000) })
Der Leitfaden sagt uns, dass die Funktion setTimeout ein Beispiel dafür ist, wie die Synchronität mit Vue-Komponenten verwendet werden kann. Beachten Sie, dass dort, wo zuvor ein Objekt als zweiter Parameter für Vue.component
war, jetzt eine Funktion vorhanden ist, die als Factory-Funktion bezeichnet wird. Innerhalb des resolve
-Callbacks befindet sich eine Komponentendefinition, die zuvor der zweite Parameter für Vue.component
gewesen wäre.
Also musste ich dieses Beispiel eine Weile anstarren, bevor es für mich Sinn machte. Hier ist ein anderes Beispiel, das besser zu mir passt:
Vue.component('async-example', function (resolve, reject) { // Vue will call this function and promise itself to handle // it when it gets back with data. // this function can then call a promising object loader // here the 'loader' function is some abstract function. // Most likely the application will use 'fetch' // but it could be something else. loader('/my/resource/on/server.json'). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) => { handle it } );
Es scheint das Richtige zu sein, eine allgemeinere Funktion zu erstellen, um diese Form zu umgehen.
function componentLoader(c_name,resource_url) { Vue.component(c_name, function (resolve, reject) { loader(resource_url). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) => { handle it } ); }
Um also eine Komponente zu laden, benötigen wir im Allgemeinen nur eine Zeile wie die folgende:
componentLoader('ThermoPanel','./JSON/thermo-panel.json');
Also, was ist das JSON, das gerade geladen wird? Es kann alles über die Komponente enthalten. In diesem Fall kann es als Panel-Komponente Thermometer, Maschinenschalter, Schieber, Messgeräte und mehr enthalten. Während es schöner schien, die Komponententeile auf der Webseite zu belassen, könnte es tatsächlich besser funktionieren, das Unterkomponentenfeld zu verwenden, das sich im längeren Beispiel für „Thermo-Panel“ befindet, das wir zuvor erstellt haben, und auch für die anderen ähnlich konstruierten Paneele. Das JSON enthält eine vollständige Panel-Struktur.
Wenn der Leser jedoch den Funktionsaufruf von transformJSONToJSObject
bemerkt, wird er verstehen, dass JSON möglicherweise auf irgendeine Weise codiert ist, um den Transport zu vereinfachen und es einem Server zu erleichtern, die Definition zu handhaben. Schließlich enthält die Definition vollständige SVG-Vorlagen, Funktionsdefinitionen und andere JavaScript-Ausdrücke. Außerdem kann das JSON-Objekt mehr als nur die Panel-Definition enthalten, da einige Informationen einfach bei der Buchhaltung oder Validierung helfen können. Man kann also davon ausgehen, dass das Objekt nach Erhalt behandelt wird.
Was die Codierung betrifft, so können die vom Server eingehenden Daten auf verschiedene Weise codiert werden. Vielleicht wird es einfach URL-kodiert sein. Oder noch sicherer, es könnte verschlüsselt sein. Für diese Diskussion können wir einfach die URL-Codierung verwenden.
Einige der Tools, die zum Erstellen von Vue-Anwendungen verfügbar sind, kümmern sich zweifellos um die JSON-Transformation. Diese Diskussion hat jedoch bisher die Verwendung von Befehlszeilentools vermieden. Dieses Versäumnis ist nicht so schlimm, da wir auch Vue mit minimalen Ressourcen verwendet haben und nur ein Skript-Tag für den Verweis auf das CDN verwendet haben. Ich empfehle jedoch auf jeden Fall, sich die Kommandozeilen-Tools anzusehen, insbesondere für die Organisation von Projekten.
Wenn das JSON auf der Seite ankommt, muss keine Arbeit mehr unternommen werden, um die Teile abzurufen, vorausgesetzt, die Komponente ist vollständig mit Unterkomponenten zusammengesetzt. Wir können davon ausgehen, dass alle Komponenten für den Rest dieser Diskussion vollständig definiert eingehen werden. Das Zusammenstellen vollständiger Komponentenhierarchien erfordert jedoch irgendwann Befehlszeilentools.
Der SVG-Bearbeitungsprozess erfordert auch einige Arbeit. Die SVG-Bearbeitungsprozesse ermöglichen es einem Designer, ein Panel und alle Komponenten darauf zu zeichnen. Aber jede Unterkomponente muss identifiziert, in einer Gruppe aufgerufen oder mit einem Platzhalter versehen werden. Jeder Ansatz zur Verwendung der Zeichnung erfordert eine gewisse Behandlung des SVG, damit Vue-Komponenten-Tags die Gruppen oder Grafikelemente ersetzen können. Auf diese Weise kann jedes Künstler-Rendering zur Vorlage werden. Und die gezeichneten Unterkomponenten müssen in Vorlagen für Vue-Unterkomponenten zerlegt werden.
Diese Sparsamkeit widerspricht dem Arbeitsablauf der meisten JavaScript-Frameworks. Bei den Frameworks geht es um das Zusammenstellen von Seiten. Aber das Bearbeiten oder Zeichnen führt zu etwas, das bereits von einem Künstler zusammengestellt wurde. In der Praxis liefert das Ergebnis der Bearbeitung keine Textdatei, die direkt einer Framework-Komponentendefinition entspricht.
Mehr über den Bearbeitungsprozess kann in einer anderen Diskussion betrachtet werden. Es ist viel dran. Aber im Moment haben wir die Werkzeuge, die wir brauchen, um hierarchische Komponenten zu laden und sie zum Leben zu erwecken.
Die faule Anwendung
Für unseren IoT-Panel-Bau haben wir bereits eine Auswahlleiste, die auf Suchen reagiert. Und wir haben eine Möglichkeit, Komponenten zu laden, wenn wir sie brauchen. Wir müssen nur diese Teile verbinden. Und schließlich müssen wir dafür sorgen, dass die Panels erscheinen und zu arbeiten beginnen, wenn sie es tun.
Das verzögerte Laden von Panels, das durch den obigen asynchronen Code durchgeführt wird, liefert eine Skizze einer Idee. Aber zum Glück haben einige Leute experimentiert, um Wege zu finden, um sicherzustellen, dass alle Arten von Komponenten geladen werden können. Es gibt einen Codepen-Eintrag, der zeigt, wie Vue-Apps mit neuen Komponenten unterschiedlicher Typen aktualisiert werden. Das ist der Mechanismus, der zum Aktualisieren eines bestimmten Teils der Seite mit unterschiedlichen Paneltypen benötigt wird.
Mit der Möglichkeit, verschiedene Arten von Panels hinzuzufügen und mit einem einfachen Mechanismus zum Laden ihrer Definitionen, können wir endlich unsere Panel-Suchseite haben.
Hier ist der HTML-Code, den wir auf unserer Seite benötigen, damit die Vue-App Komponenten dynamisch einfügen kann:
<template v-for="(panel, index) in panelList"> <component :is="panel" :key="panel.name"></component> </template>
Das component
-Tag ist ein Vue-Meta-Tag. Siehe die Referenz für dynamische Komponenten. Die Eigenschaften, spezielle Attribute, die in diesem Fall für das component
-Tag verwendet werden, sind is und key. Das is
-Attribut existiert für dynamische Komponenten. Und der key
stellt sicher, dass die neuen Kinder unterschiedliche Identitäten haben und hilft Vue bei der Entscheidung, was gezeichnet werden soll.
„Kinder desselben gemeinsamen Elternteils müssen eindeutige Schlüssel haben. Doppelte Schlüssel verursachen Renderfehler.“
Das template
-Tag durchläuft Komponenten, die im panelList
-Datenfeld der Anwendung bereitgestellt werden.
Beginnend mit der Vue-Definition auf Anwendungsebene für die Symbol-App können wir also Änderungen vornehmen, um die panelList in die Datenelemente aufzunehmen. (Nennen wir es jetzt die PanelApp).
var panelApp = new Vue({ el: '#PanelApp', data: { iconList: [ // Where is the data? Still on the server. ], panelList: [ ], queryToken : "Thermo Batches" // picked a name for demo }, methods : { goGetPanel: function (pname) { // var url = panelURL(pname); // this is custom to the site. fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = decodeURIComponent(text); eval(pHat); // widgdef = object def, must be assignment pHat = widgdef; var pnameHat = pname + pcount++; pHat.name = pnameHat; // this is needed for the key this.panelList.push(pHat); // now it's there. }).catch( error => { /* handle it */ }); } } });
Neben dem Hinzufügen des Panels liegt goGetPanel
jetzt in einer Form vor, die zum Abrufen einer Komponentendefinition aus einer Datenbank oder einem anderen Speicher erforderlich ist. Die Serverseite muss darauf achten, JavaScript-Code im richtigen Format bereitzustellen. Wie das Objekt aussieht, wenn es vom Server kommt, haben wir bereits gesehen. Es ist die Art von Objekt, das als Parameter für Vue.component
verwendet wird.
Hier ist der vollständige Inhalt der Vue-App, die ein Menü als Suchergebnis und einen Ort zum Platzieren von Panels bereitstellt, die vom Server abgerufen werden, wenn der Benutzer auf ein Symbol klickt.
<div> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Request MCU Groups</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <button>Find All</button> <button>Find 5 Point</button> <button>Find 6 Point</button> </div> <!-- Here is a Vue loop for generating a lit --> <div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> <div class="entryart" > <template v-for="(panel, index) in panelList"> <component :is="panel" :key="panel.name" :ref="panel.name" ></component> </template> </div> </div>
Im letzten div
hat das component
-Tag jetzt einen ref
-Parameter, der an den Panel-Namen gebunden ist. Der ref-Parameter ermöglicht es der Vue-App, zu identifizieren, welche Komponente mit Daten aktualisiert werden soll, und hält die Komponenten getrennt. Die ref
Parameter ermöglichen unserer Anwendung auch den Zugriff auf die neuen dynamisch geladenen Komponenten.
In einer Testversion der Panel-App habe ich den folgenden Intervall-Handler:
setInterval(() => { var refall = panelApp.$refs; // all named children that panels for ( var pname in refall ) { // in an object var pdata = refall[pname][0]; // off Vue translation, but it's there. pdata.temp1 = Math.round(Math.random()*100); // make thermos jump around. pdata.temp2 = Math.round(Math.random()*100); } },2000)
Der Code bietet eine kleine Animation, die die Thermometer zufällig ändert. Jedes Panel verfügt über zwei Thermometer, und die App ermöglicht es dem Benutzer, weitere Panels hinzuzufügen. (In der endgültigen Version müssen einige Panels weggeworfen werden.) Auf die Refs wird mit panelApp.$refs
zugegriffen, einem Feld, das Vue anhand der refs
-Informationen im component
-Tag erstellt.
So sehen die zufällig springenden Thermometer in einem Schnappschuss aus:
Anschließen des Panels an das IoT-Gerät
Das letzte Stück Code ist also ein setInterval
-Test, der Thermometer alle zwei Sekunden mit zufälligen Werten aktualisiert. Aber wir wollen echte Daten von echten Maschinen einlesen. Dazu benötigen wir eine Form der Kommunikation.
Es gibt eine Vielzahl von Möglichkeiten. Aber verwenden wir MQTT, ein Pub/Sub-Nachrichtensystem. Unsere SPWA kann jederzeit Nachrichten von Geräten abonnieren. Wenn es diese Nachrichten erhält, kann der SPWA jede Nachricht an den entsprechenden Datenhandler für das Panel leiten, das dem in der Nachricht identifizierten Gerät zugeordnet ist.
Im Grunde müssen wir also setInterval
durch einen Response-Handler ersetzen. Und das wird für ein Panel sein. Wahrscheinlich möchten wir Panels Handlern zuordnen, während sie geladen werden. Und es liegt am Webserver, dafür zu sorgen, dass das richtige Mapping geliefert wird.
Sobald der Webserver und die SPWA die Seite betriebsbereit haben, muss sich der Webserver nicht mehr um die Nachrichtenübermittlung zwischen der Seite und dem Gerät kümmern. Das MQTT-Protokoll gibt einen Routing-Server für Pub/Sub an. Eine Reihe von MQTT-Servern wurde erstellt. Einige davon sind Open Source. Eine sehr beliebte ist Mosquito , und es gibt einige, die auf Basis von Node.js entwickelt wurden.
Der Prozess für die Seite ist einfach. Die SPWA abonniert ein Thema. Eine gute Version eines Themas ist eine Kennung für eine MCU, z. B. eine MAC-Adresse oder eine Seriennummer. Oder die SPWA könnte alle Temperaturmesswerte abonnieren. Aber dann müsste die Seite die Arbeit erledigen, die Nachrichten von allen Geräten zu filtern. Die Veröffentlichung in MQTT ist im Wesentlichen ein Broadcast oder Multicast.
Werfen wir einen Blick darauf, wie die SPWA mit MQTT verbunden wird.
MQTT auf dem SPWA initialisieren
Es stehen mehrere Client-Bibliotheken zur Auswahl. Eine ist zum Beispiel eine MQTT.js. Ein anderes ist Finsternis-Paho. Es gibt natürlich noch mehr. Lassen Sie uns Eclipse Paho verwenden, da es eine CDN-gespeicherte Version hat. Wir müssen nur die folgende Zeile zu unserer Seite hinzufügen:
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>
Der MQTT-Client muss sich mit einem Server verbinden, bevor er Nachrichten senden und empfangen kann. Daher müssen auch Zeilen, die die Verbindung herstellen, in das JavaScript aufgenommen werden. Wir können eine Funktion MQTTinitialize
hinzufügen, die den Client und die Antworten für die Verbindungsverwaltung und den Nachrichtenempfang einrichtet.
var messagesReady = false; var mqttClient = null; function MQTTinitialize() { mqttClient = new Paho.MQTT.Client(MQTTHostname, Number(MQTTPort), "clientId"); mqttClient.onMessageArrived = onMessageArrived; // connect the client mqttClient.connect({ onSuccess: () => { messagesReady = true; } }); // set callback handlers mqttClient.onConnectionLost = (response) => { // messagesReady = false; // if (response.errorCode !== 0) { console.log("onConnectionLost:"+response.errorMessage); } setTimeout(() => { MQTTinitialize() },1000); // try again in a second }; }
Abonnement einrichten
Wenn die Verbindung bereit ist, kann der Client Nachrichtenkanäle abonnieren, Nachrichten darauf senden usw. Nur ein paar Routinen können den größten Teil der Arbeit erledigen, die zum Verbinden von Panels mit den MQTT-Pfaden erforderlich ist.
Für die Panel-SPWA kann der Moment des Abonnements verwendet werden, um die Zuordnung zwischen dem Panel und dem Thema, der MCU-Kennung, herzustellen.
function panelSubcription(topic,panel) { gTopicToPanel[topic] = panel; gPanelToTopic[panel] = topic; mqttClient.subscribe(topic); }
Da eine MCU zu ihrem Thema veröffentlicht, erhält die SPWA eine Nachricht. Hier wird die Paho-Nachricht entpackt. Und dann wird die Nachricht in die Anwendungsmechanik weitergegeben.
function onMessageArrived(pmessage) { // var topic = pmessage.destinationName; var message = pmessage.payloadString; // var panel = gTopicToPanel[topic]; deliverToPanel(panel,message); }
Jetzt müssen wir also nur noch deliverToPanel
erstellen, das in etwa dem Intervall-Handler ähneln sollte, den wir zuvor hatten. Die Tafel ist jedoch eindeutig identifiziert, und nur die in der bestimmten Nachricht gesendeten verschlüsselten Daten können aktualisiert werden.
function deliverToPanel(panel,message) { var refall = panelApp.$refs; // all named children that panels var pdata = refall[panel][0]; // off Vue translation, but it's there. var MCU_updates = JSON.parse(message); for ( var ky in MCU_updates ) { pdata[ky] = MCU_updates[ky] } }
Diese deliverToPanel
Funktion ist abstrakt genug, um jede Panel-Definition mit einer beliebigen Anzahl von Datenpunkten für die Animation zu ermöglichen.
Nachrichten senden
Um die Anwendungsschleife zwischen der MCU und der SPWA zu vervollständigen, definieren wir eine Funktion zum Senden einer Nachricht.
function sendPanelMessage(panel,message) { var topic = gPanelToTopic[panel]; var pmessage = new Paho.MQTT.Message(message); pmessage.destinationName = topic; mqttClient.send(pmessage); }
Die sendPanelMessage
Funktion tut nichts anderes, als die Nachricht auf demselben Themenpfad zu versenden, den die SPWA abonniert hat.
Da wir planen, die Icon-Schaltflächen dafür verantwortlich zu machen, eine gewisse Anzahl von Panels für einen einzelnen Cluster von MCUs einzufügen, müssen wir uns um mehr als ein Panel kümmern. Aber wir denken daran, dass jedes Panel einer einzelnen MCU entspricht, also haben wir eine Eins-Eins-Zuordnung, für die wir zwei JavaScript-Zuordnungen für die Zuordnung und die Umkehrung verwenden können.
Also, wann senden wir Nachrichten? Normalerweise sendet die Panel-Anwendung eine Nachricht, wenn sie den Zustand der MCU ändern möchte.
Synchronisieren des Anzeigestatus (Vue) mit Geräten
Eines der großartigen Dinge an Vue ist, dass es sehr einfach ist, das Datenmodell mit der Aktivität des Benutzers zu synchronisieren, der Felder bearbeiten, auf Schaltflächen klicken, Schieberegler verwenden usw. kann. Man kann sicher sein, dass Schaltflächen und Felder geändert werden sofort in den Datenfeldern der Komponenten widerspiegeln.
Wir möchten jedoch, dass Änderungen Nachrichten an die MCU senden, sobald die Änderungen auftreten. Wir versuchen also, die Schnittstellenereignisse zu nutzen, die Vue steuern kann. Wir versuchen, auf ein solches Ereignis zu reagieren, aber erst, nachdem das Vue-Datenmodell mit dem aktuellen Wert bereit ist.
Ich habe eine andere Art von Panel erstellt, dieses mit einem ziemlich künstlerisch aussehenden Knopf (vielleicht inspiriert von Jackson Pollock). Und ich machte mich daran, es in etwas zu verwandeln, dessen Klick den Zustand an das Panel zurückmeldet, das es enthält. Das war kein so einfacher Prozess.
Eine Sache, die mich aus der Fassung brachte, war, dass ich einige Kuriositäten bei der Verwaltung von SVG vergessen hatte. Ich habe zuerst versucht, den Style-String so zu ändern, dass das display
des CSS-Styles entweder „None“ oder „something“ ist. Der Browser hat die Styles-Zeichenfolge jedoch nie umgeschrieben. Aber da das umständlich war, habe ich versucht, die CSS-Klasse zu ändern. Auch das hatte keine Auswirkung. Aber da ist das visibility
, an das sich die meisten von uns aus altem HTML (vielleicht Version 1.0) erinnern, das aber in SVG sehr aktuell ist. Und das funktioniert gut. Alles, was ich tun musste, war, das Click-Event der Schaltfläche zu propagieren.
Vue hat Eigenschaften entwickelt, die sich in eine Richtung ausbreiten, von Eltern zu Kind. Um also Daten in der Anwendung oder im Panel zu ändern, müssen Sie ein Änderungsereignis an das übergeordnete Element senden. Anschließend können Sie die Daten ändern. Die Änderung des Datenelements, das die Schaltfläche steuert, veranlasst Vue, die Eigenschaft zu aktualisieren, die sich auf die Sichtbarkeit des SVG-Elements auswirkt, das wir ausgewählt haben, um den Status anzuzeigen. Hier ist ein Beispiel:
Jede Instanz des verschnörkelten Schaltflächenfelds ist unabhängig. Einige sind also EIN und einige AUS.
Dieses SVG-Snippet enthält den seltsam aussehenden gelben Indikator:
<path :visibility="stateView" d="m -36.544616,12.266886 c 19.953088,17.062165 5.07961,-19.8251069 5.317463,8.531597 0.237853,28.356704 13.440044,-8.847959 -3.230451,10.779678 -16.670496,19.627638 14.254699,-2.017715 -11.652451,3.586456 -25.90715,5.60417 10.847826,19.889979 -8.095928,-1.546575 -18.943754,-21.436555 -1.177383,14.210702 -4.176821,-12.416207 -2.999438,-26.6269084 -17.110198,8.030902 2.14399,-8.927709 19.254188,-16.9586105 -19.075538,-8.0837048 9.448721,-5.4384245 28.52426,2.6452804 -9.707612,-11.6309807 10.245477,5.4311845 z" transform="translate(78.340803,6.1372042)" />
Die Sichtbarkeit wird durch stateView
, eine berechnete Variable, die den booleschen Zustand auf eine Zeichenfolge für SVG abbildet.
Hier ist die Definitionsvorlage für die Panel-Komponente:
<script type="text/x-template"> <div> <control-switch :state="bstate" v-on:changed="saveChanges" ></control-switch> <gauge :level="fluidLevel" ></gauge> </div> </script>
Und dies ist die JavaScript-Definition des Vue-Panels mit seinen untergeordneten Elementen als Unterkomponenten:
var widgdef = { data: function () { var currentPanel = { // at the top level, values controlling children bstate : true, fluidLevel : Math.round(Math.random()*100) } // return currentPanel }, template: '#mcu-control-panel-template', methods: { saveChanges: function() { // in real life, there is more specificity this.bstate = !this.bstate relayToMCU(this.name,"button",this.bstate) // to be defined } }, components: { 'control-switch' : { // the odd looking button props: ['state'], template: '#control-switch-template', // for demo it is in the page. computed: { // you saw this in the SVG above. stateView : function() { return ( this.state ) ? "visible" : "hidden" } }, methods : { // the button handler is in the SVG template at the top. stateChange : function () { // can send this.$emit('changed'); // tell the parent. See on the template instance } } }, 'gauge' : { // some other nice bit of SVG props: ['level'], template: '#gauge-template' } } }
Jetzt wurde also der Mechanismus für eine einzelne Schaltfläche, die in ein Bedienfeld eingebettet ist, ausgelegt. Und es muss einen Haken geben, um der MCU mitzuteilen, dass etwas passiert ist. Es muss sofort aufgerufen werden, nachdem der Datenstand der Panel-Komponente aktualisiert wurde. Lassen Sie es uns hier definieren:
function relayToMCU(panel,switchName,bstate) { var message = switchName + ':' + bstate // a on element parameter string. sendPanelMessage(panel,message) }
Da ist die Zustandsänderung auf dem Weg zur Hardware in nur zwei Codezeilen.
Dies ist jedoch ein ziemlich einfacher Fall. Jeder Schalter kann als Funktionsaufruf für eine Hardware in der Welt angesehen werden. Die Zeichenfolge kann also den Schalternamen und mehrere andere Datenelemente enthalten. Die Komponentenmethode, die Änderungen registriert, muss also eine benutzerdefinierte Behandlung enthalten, damit sie alle auf dem Panel eingestellten Datensätze zusammentragen und in einer Befehlszeichenfolge weitersenden kann. Sogar die Befehlszeichenfolge ist ein wenig einfach. Wenn die MCU ziemlich klein ist, muss die Befehlszeichenfolge möglicherweise in einen Code übersetzt werden. Wenn die MCU sehr viel Kapazität hat, könnte die Befehlszeichenfolge tatsächlich eine JSON-Struktur oder vielleicht alle Daten sein, die das Panel hostet.
In dieser Erörterung enthalten die Schaltflächen auf dem Icon-Panel den Namen des abzurufenden Panels. Das kann auch ziemlich vereinfacht werden. Es scheint sinnvoll, dass dieser Parameter für jedes Panel stehen kann, das in den Datenbanken eines Unternehmens gespeichert sein könnte. Aber vielleicht ist es eine Formel. Vielleicht sollten Informationen über das Panel um die Panel-Definition gewickelt werden, die wir vom Server erhalten. In jedem Fall können die Grundlagen leicht erweitert werden, sobald bestimmte Kopfschmerzen aus dem Weg sind, wie z. B. dafür zu sorgen, dass das SVG richtig auf Klicks reagiert.
Fazit
Diese Diskussion hat einige grundlegende Schritte und Entscheidungen dargelegt, die zur Realisierung einer Single Page Web App (SPWA) führen, die mit IoT-Geräten verbunden werden kann. Wir wissen jetzt, wie man Panels von einem Webserver erhält und sie in eine MCU-Schnittstelle umwandelt.
Es gibt noch viel mehr zu dieser Diskussion mit einigen anderen Diskussionen, die folgen können. Mit Vue zu beginnen, ist eine Sache, über die man nachdenken sollte. Aber dann ist da noch die ganze MCU-Geschichte, die wir nur kurz angerissen haben.
Insbesondere durch die Auswahl von MQTT als Kommunikationssubstrat gehen wir davon aus, dass IoT-Geräte am anderen Ende irgendwie von MQTT beherrscht werden können. Aber das muss nicht immer der Fall sein. Manchmal werden Gateways benötigt, wenn MQTT Zugriff auf ein Gerät mit seriellen Verbindungen oder Bluetooth erhalten soll. Oder vielleicht braucht man auf der Webseite nur WebSockets. Dennoch haben wir MQTT als Beispiel verwendet, um zu zeigen, wie Vue Daten sowohl empfangen als auch senden kann, während der Datenstatus mit den Geräten synchronisiert bleibt.
Wieder einmal haben wir nur einen Teil der Geschichte. Diesmal dient es der Synchronisierung, da die Seite in der Lage sein sollte, mit Warnungen umzugehen und den Benutzer zu belästigen, wenn etwas Kritisches passiert. Manchmal können Nachrichten verloren gehen. Also müssen wir einen Mechanismus für Bestätigungen haben.
Schließlich bin ich der Meinung, dass Vue das Aktualisieren von Daten nach Erhalt recht elegant macht. Das Senden der Zustandsänderungen ist jedoch nicht so einfach. Es scheint die Arbeit nicht viel einfacher zu machen als mit Vanilla JavaScript. Aber es gibt einen Weg und er macht Sinn.
Vielleicht kann eine saubere Bibliothek erstellt werden, um einen universellen Satz von Komponenten für alle Panels zu erstellen. Die Elemente zum Erstellen solcher Bibliotheken und deren Speicherung in einer Datenbank wurden kurz erwähnt. Möglicherweise müssen Tools entwickelt werden, die über das bloße Erstellen von SVG-Bildern hinausgehen. In jedem Fall gibt es wahrscheinlich viele Dinge, die für die nächsten Schritte getan werden können.