Komponenty strony internetowej SVG dla IoT i twórców (część 2)

Opublikowany: 2022-03-10
Szybkie podsumowanie ↬ Projektując interfejsy dla stron internetowych IoT, zawsze mamy wiele możliwości. W poprzedniej części tego artykułu Richard Leddy rzucił światło na znaczenie IoT oraz na to, jak Vue.js może być używany do hostowania grup interfejsów IoT człowiek-maszyna. Dzisiaj przyjrzyjmy się bliżej panelom z leniwym ładowaniem i tym, jak synchronizować stan Vue z urządzeniami.

Mamy więc już sposoby na dynamiczne ładowanie menu ikon SVG, które reagują na ładowanie paneli, jeśli sobie tego życzymy, ale ikony nie były rzeczywistymi komponentami. Udało nam się zastosować prostą sztuczkę polegającą na wprowadzeniu SVG dla każdej ikony i przekazaniu jej do aplikacji Vue. Wygenerowanie listy ikon było dość proste, a każda ikona reagowała w podobny sposób, z wyjątkiem niewielkich różnic w danych. Różnica danych umożliwiła powiązanie nazwy panelu z każdą ikoną w taki sposób, aby obsługa kliknięcia przycisku ikony mogła ją przekazać.

Kiedy panel jest ładowany w postaci komponentu Vue, wszystko na temat panelu i jego komponentów musi zostać załadowane, szablony, JavaScript i inne. Tak więc praca polegająca na zarządzaniu ładowaniem panelu jest większa niż to, z czym spotkaliśmy się do tej pory w tej dyskusji.

Przyjrzyjmy się sposobowi, w jaki Vue udostępnia hak do ładowania asynchronicznego. Poniższy fragment pochodzi z przewodnika Vue.

 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) })

Z przewodnika dowiadujemy się, że funkcja setTimeout jest przykładem wykorzystania synchroniczności z komponentami Vue. Zauważ, że tam, gdzie wcześniej był obiekt jako drugi parametr Vue.component , teraz jest funkcja, która jest określana jako funkcja fabryczna. W wywołaniu zwrotnym resolve znajduje się definicja komponentu, która wcześniej byłaby drugim parametrem Vue.component .

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Musiałem więc wpatrywać się w ten przykład przez chwilę, zanim miał dla mnie sens. Oto kolejny przykład, który bardziej mi odpowiada:

 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 } );

Wydaje się, że należy zrobić bardziej ogólną funkcję, aby obejść ten formularz.

 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 } ); }

Tak więc, ogólnie rzecz biorąc, aby załadować komponent, potrzebowalibyśmy po prostu linii podobnej do następującej:

 componentLoader('ThermoPanel','./JSON/thermo-panel.json');

Więc teraz, jaki jest ładowany plik JSON? Może zawierać wszystko o komponencie. W tym przypadku, jako element panelu, może zawierać termometry, przełączniki maszynowe, suwaki, mierniki i inne. Chociaż wydawało się, że przyjemniej jest trzymać części składowe na stronie internetowej, w rzeczywistości może lepiej zadziałać użycie pola podkomponentów, które jest w dłuższym przykładzie dla „termo-panelu”, który stworzyliśmy wcześniej, a także dla innych podobnie skonstruowanych paneli. JSON będzie zawierał kompletną strukturę panelu.

Jeśli jednak czytelnik zauważy włączenie wywołania funkcji do transformJSONToJSObject , zrozumie, że JSON może być w jakiś sposób zakodowany, aby ułatwić transport i ułatwić serwerowi obsługę definicji. W końcu definicja będzie zawierać kompletne szablony SVG, definicje funkcji i inne wyrażenia JavaScript. Ponadto obiekt JSON może zawierać więcej niż tylko definicję panelu, ponieważ niektóre informacje mogą po prostu pomóc w księgowaniu lub walidacji. Można się więc spodziewać, że przy odbiorze obiekt zostanie poddany obróbce.

Jeśli chodzi o kodowanie, dane przychodzące z serwera mogą być kodowane na wiele sposobów. Być może będzie to po prostu zakodowany adres URL. Lub bezpieczniej, może być zaszyfrowany. W tej dyskusji możemy po prostu użyć kodowania adresów URL.

Niektóre z narzędzi dostępnych do tworzenia aplikacji Vue bez wątpienia obsługują transformację JSON. Ale w tej dyskusji do tej pory unikano używania narzędzi wiersza poleceń. To pominięcie nie jest takie złe, ponieważ użyliśmy również Vue z minimalnymi zasobami, używając tylko jednego tagu skryptu do odwoływania się do CDN. Jednak zdecydowanie polecam zapoznanie się z narzędziami wiersza poleceń, szczególnie do organizowania projektów.

Gdy JSON dotrze na stronę, biorąc pod uwagę, że komponent jest całkowicie złożony z podkomponentami, nie trzeba wykonywać więcej pracy, aby pobrać części. Możemy założyć, że wszystkie elementy będą w pełni zdefiniowane do końca tej dyskusji. Jednak złożenie kompletnych hierarchii komponentów będzie w pewnym momencie wymagało narzędzi wiersza poleceń.

Proces edycji SVG również będzie wymagał trochę pracy. Procesy edycji SVG pozwalają projektantowi narysować panel i wszystkie znajdujące się na nim komponenty. Ale każdy podkomponent musi być zidentyfikowany, wywołany w grupie lub przypisany do miejsca. Każde podejście do korzystania z rysunku wymaga pewnego potraktowania SVG, aby znaczniki komponentów Vue mogły zastąpić grupy lub elementy graficzne. W ten sposób każdy rendering artysty może stać się szablonem. Narysowane podkomponenty będą musiały zostać rozłożone na szablony dla podkomponentów Vue.

Ten rodzaj oszczędności jest sprzeczny z przepływem pracy większości frameworków JavaScript. Frameworki dotyczą składania stron. Ale edytowanie lub rysowanie daje coś, co artysta już zmontował. W praktyce wynik edycji nie zapewnia pliku tekstowego odpowiadającego bezpośrednio definicji komponentu frameworka.

Więcej o procesie edycji można rozważyć w innej dyskusji. Jest w tym wiele. Ale na razie mamy narzędzia, których potrzebujemy, aby załadować komponenty hierarchiczne i ożywić je.

Leniwa aplikacja

W przypadku naszej konstrukcji panelu IoT mamy już pasek wyboru, który odpowiada na wyszukiwania. I mamy sposób na ładowanie komponentów, kiedy ich potrzebujemy. Musimy tylko połączyć te części. I na koniec musimy się upewnić, że panele pojawią się i zaczną działać, kiedy to zrobią.

Leniwe ładowanie paneli wykonane przez powyższy kod asynchroniczny dostarcza szkicu pomysłu. Ale na szczęście niektórzy ludzie eksperymentowali, aby znaleźć sposoby na upewnienie się, że można załadować wszystkie rodzaje komponentów. Jest jeden wpis codepen, który pokazuje, jak zaktualizować aplikacje Vue o nowe komponenty różnych typów. Jest to mechanizm potrzebny do aktualizacji wyznaczonej części strony o różne typy paneli.

Dzięki możliwości dodawania różnego rodzaju paneli i prostemu mechanizmowi ładowania ich definicji, możemy wreszcie mieć naszą stronę wyszukiwania paneli.

Oto kod HTML, którego potrzebujemy na naszej stronie, aby aplikacja Vue mogła dynamicznie umieszczać komponenty:

 <template v-for="(panel, index) in panelList"> <component :is="panel" :key="panel.name"></component> </template>

Znacznik component to metatag Vue. Zobacz odniesienie do komponentów dynamicznych. Właściwości, atrybuty specjalne, używane w tym przypadku dla znacznika component to is i key. Atrybut is istnieje dla komponentów dynamicznych. A key zapewnia, że ​​nowe dzieci będą miały różne tożsamości i pomaga Vue zdecydować, co narysować.

„Dzieci tego samego wspólnego rodzica muszą mieć unikalne klucze. Zduplikowane klucze spowodują błędy renderowania.”

Znacznik template będzie przechodził przez komponenty podane w polu danych panelList aplikacji.

Tak więc, zaczynając od definicji Vue na poziomie aplikacji dla aplikacji ikony, możemy wprowadzić zmiany, aby uwzględnić panelList w elementach danych. (Nazwijmy to teraz 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 */ }); } } });

Oprócz dodania panelu, goGetPanel jest teraz w formie wymaganej do pobrania definicji komponentu z bazy danych lub innego sklepu. Strona serwera musi uważać na dostarczanie kodu JavaScript w odpowiednim formacie. Jeśli chodzi o wygląd obiektu pochodzącego z serwera, już to widzieliśmy. Jest to rodzaj obiektu używany jako parametr do Vue.component .

Oto pełna treść aplikacji Vue, która udostępnia menu jako wynik wyszukiwania i miejsce na umieszczenie paneli pobranych z serwera, gdy użytkownik kliknie ikonę.

 <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>

W ostatnim div znacznik component ma teraz parametr ref powiązany z nazwą panelu. Parametr ref pozwala aplikacji Vue zidentyfikować, który komponent ma zostać zaktualizowany za pomocą danych, i oddziela komponenty. Parametry ref umożliwiają również naszej aplikacji dostęp do nowych, dynamicznie ładowanych komponentów.

W jednej testowej wersji aplikacji panelu mam następujący program obsługi interwałów:

 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)

Kod zapewnia małą animację, losowo zmieniając termometry. Każdy panel ma dwa termometry, a aplikacja pozwala użytkownikowi na dalsze dodawanie paneli. (W ostatecznej wersji niektóre panele muszą zostać wyrzucone.) Dostęp do refs uzyskuje się za pomocą panelApp.$refs , pola, które Vue tworzy na podstawie informacji refs w znaczniku component .

A więc tak wyglądają losowo przeskakujące termometry na jednym zrzucie:

Zbiór animowanych paneli dla jednego typu panelu (lub elementu) przedstawiający termometry.
Zbiór animowanych paneli dla jednego typu panelu (lub komponentu). (duży podgląd)

Podłączanie panelu do urządzenia IoT

Tak więc ostatnim fragmentem kodu jest test setInterval aktualizujący termometry o losowe wartości co dwie sekundy. Ale to, co chcemy zrobić, to wczytać rzeczywiste dane z prawdziwych maszyn. Aby to zrobić, będziemy potrzebować jakiejś formy komunikacji.

Istnieje wiele sposobów. Ale użyjmy MQTT, który jest systemem wiadomości pub/sub. Nasze SPWA może w dowolnym momencie subskrybować wiadomości z urządzeń. Po otrzymaniu tych komunikatów SPWA może skierować każdą wiadomość do odpowiedniego operatora danych dla panelu zmapowanego na urządzenie zidentyfikowane w komunikacie.

Więc zasadniczo to, co musimy zrobić, to zamienić setInterval na procedurę obsługi odpowiedzi. I to będzie dla jednego panelu. Prawdopodobnie chcemy mapować panele do modułów obsługi, gdy są ładowane. I to od serwera WWW zależy, czy dostarczone zostanie prawidłowe mapowanie.

Gdy serwer sieciowy i SPWA mają stronę gotową do działania, serwer sieciowy nie musi już zajmować się przesyłaniem wiadomości między stroną a urządzeniem. protokół MQTT określa serwer routingu do obsługi pub/sub. Powstało wiele serwerów MQTT. Niektóre z nich są open source. Jednym z bardzo popularnych jest Mosquito , a istnieje kilka opracowanych na szczycie Node.js.

Proces tworzenia strony jest prosty. SPWA subskrybuje temat. Jedną z dobrych wersji tematu jest identyfikator MCU, taki jak adres MAC lub numer seryjny. Lub SPWA może subskrybować wszystkie odczyty temperatury. Ale wtedy strona musiałaby wykonać pracę filtrowania wiadomości ze wszystkich urządzeń. Publikacja w MQTT to zasadniczo emisja lub multiemisja.

Przyjrzyjmy się, jak SPWA będzie współpracował z MQTT.

Inicjowanie MQTT na SPWA

Do wyboru jest kilka bibliotek klienckich. Jednym z nich jest na przykład MQTT.js. Innym jest zaćmienie paho. Oczywiście jest ich więcej. Użyjmy Eclipse Paho, ponieważ ma wersję przechowywaną w CDN. Wystarczy dodać do naszej strony następujący wiersz:

 <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>

Klient MQTT musi połączyć się z serwerem, zanim będzie mógł wysyłać i odbierać wiadomości. Tak więc wiersze konfigurujące połączenie również muszą być zawarte w JavaScript. Możemy dodać funkcję MQTTinitialize , która konfiguruje klienta i odpowiedzi do zarządzania połączeniami i odbierania wiadomości.

 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 }; }

Konfigurowanie subskrypcji

Gdy połączenie jest gotowe, klient może subskrybować kanały komunikatów, wysyłać na nich komunikaty itp. Tylko kilka procedur może wykonać większość pracy niezbędnej do połączenia paneli ze ścieżkami MQTT.

Dla panelu SPWA moment subskrypcji może posłużyć do ustalenia powiązania panelu z tematem, identyfikator MCU.

 function panelSubcription(topic,panel) { gTopicToPanel[topic] = panel; gPanelToTopic[panel] = topic; mqttClient.subscribe(topic); }

Biorąc pod uwagę, że MCU publikuje na swój temat, SPWA otrzyma wiadomość. Tutaj wiadomość Paho jest rozpakowana. A następnie wiadomość jest przekazywana do mechaniki aplikacji.

 function onMessageArrived(pmessage) { // var topic = pmessage.destinationName; var message = pmessage.payloadString; // var panel = gTopicToPanel[topic]; deliverToPanel(panel,message); }

Więc teraz wszystko, co musimy zrobić, to stworzyć deliverToPanel , który powinien być trochę podobny do obsługi interwałów, którą mieliśmy wcześniej. Panel jest jednak wyraźnie zidentyfikowany, a aktualizowane mogą być tylko dane kluczowane przesłane w danym komunikacie.

 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] } }

Ta funkcja deliverToPanel jest wystarczająco abstrakcyjna, aby umożliwić dowolną definicję panelu z dowolną liczbą punktów danych do animacji.

Wysyłanie wiadomości

Aby zakończyć pętlę aplikacji między MCU a SPWA, definiujemy funkcję wysyłania wiadomości.

 function sendPanelMessage(panel,message) { var topic = gPanelToTopic[panel]; var pmessage = new Paho.MQTT.Message(message); pmessage.destinationName = topic; mqttClient.send(pmessage); }

Funkcja sendPanelMessage służy jedynie do wysyłania wiadomości na tej samej ścieżce tematycznej, którą subskrybuje SPWA.

Ponieważ planujemy, aby przyciski ikonek były odpowiedzialne za wprowadzanie pewnej liczby paneli dla pojedynczego klastra MCU, będzie więcej niż jeden panel, którym trzeba się zająć. Pamiętajmy jednak, że każdy panel odpowiada jednemu MCU, więc mamy mapowanie jeden-jeden, dla którego możemy użyć dwóch map JavaScript dla mapy i odwrotnej.

Kiedy więc wysyłamy wiadomości? Zwykle aplikacja panelu wysyła komunikat, gdy chce zmienić stan MCU.

Utrzymywanie stanu widoku (Vue) w synchronizacji z urządzeniami

Jedną z wielkich zalet Vue jest to, że bardzo łatwo jest zachować synchronizację modelu danych z aktywnością użytkownika, który może edytować pola, klikać przyciski, używać suwaków itp. Można być pewnym, że zmiany przycisków i pól będą być natychmiast odzwierciedlone w polach danych komponentów.

Ale chcemy, aby zmiany uruchamiały komunikaty do MCU, gdy tylko pojawią się zmiany. Dlatego staramy się wykorzystać zdarzenia interfejsu, którymi może zarządzać Vue. Staramy się odpowiedzieć na takie zdarzenie, ale dopiero po przygotowaniu modelu danych Vue z aktualną wartością.

Stworzyłem inny rodzaj panelu, ten z dość artystycznie wyglądającym przyciskiem (być może inspirowanym Jacksonem Pollockiem). I postanowiłem przekształcić go w coś, czego kliknięcie zgłasza stan z powrotem do panelu, który go zawiera. To nie był taki prosty proces.

Jedną rzeczą, która mnie wyrzuciła, jest to, że zapomniałem o niektórych dziwactwach związanych z zarządzaniem SVG. Najpierw próbowałem zmienić ciąg stylu, aby pole display stylu CSS miało wartość „Brak” lub „coś”. Ale przeglądarka nigdy nie przepisała ciągu stylów. Ale ponieważ było to kłopotliwe, spróbowałem zmienić klasę CSS. To też nie przyniosło efektu. Ale jest atrybut visibility , który większość z nas pamięta ze starego HTML (być może wersji 1.0), ale jest bardzo aktualny w SVG. I to działa dobrze. Wszystko, co musiałem zrobić, to sprawić, by zdarzenie kliknięcia przycisku się rozprzestrzeniło.

Vue zaprojektował właściwości, które rozchodzą się w jednym kierunku, z rodzica na dziecko. Czyli, aby zmienić dane w aplikacji lub w panelu, musisz wysłać zdarzenie zmiany do rodzica. Następnie możesz zmienić dane. Zmiana elementu danych kontrolującego przycisk powoduje, że Vue aktualizuje właściwość wpływającą na widoczność elementu SVG, który wybraliśmy do wskazania stanu. Oto przykład:

Więcej niż jeden typ panelu i więcej niż jedno wystąpienie animacji na typ.
Wreszcie zbiór różnych typów paneli, z których każdy ma instancje przypisane do oddzielnych jednostek MCU. (duży podgląd)

Każde wystąpienie panelu falistych przycisków jest niezależne. Więc niektóre są WŁĄCZONE, a niektóre WYŁĄCZONE.

Ten fragment SVG zawiera dziwnie wyglądający żółty wskaźnik:

 <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)" />

Widoczność jest wypełniana przez stateView , zmienną obliczaną, która mapuje wartość logiczną stanu na ciąg znaków dla SVG.

Oto szablon definicji komponentu panelu:

 <script type="text/x-template"> <div> <control-switch :state="bstate" v-on:changed="saveChanges" ></control-switch> <gauge :level="fluidLevel" ></gauge> </div> </script>

Oto definicja JavaScript panelu Vue z jego elementami potomnymi jako podkomponentami:

 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' } } }

Tak więc teraz został opracowany mechanizm pojedynczego przycisku osadzonego w panelu. I musi być haczyk do informowania MCU, że coś się wydarzyło. Musi zostać wywołany natychmiast po zaktualizowaniu stanu danych komponentu panelu. Zdefiniujmy to tutaj:

 function relayToMCU(panel,switchName,bstate) { var message = switchName + ':' + bstate // a on element parameter string. sendPanelMessage(panel,message) }

Zmiana stanu na drodze do sprzętu w zaledwie dwóch linijkach kodu.

Ale to dość prosty przypadek. Każdy przełącznik może być postrzegany jako wywołanie funkcji do części sprzętu na świecie. Tak więc ciąg może zawierać nazwę przełącznika i kilka innych elementów danych. Tak więc metoda komponentu, która rejestruje zmiany, będzie musiała mieć pewną niestandardową obsługę, aby mogła zebrać wszystkie elementy danych na panelu i wysłać je w jednym ciągu poleceń. Nawet ciąg poleceń jest trochę prosty. Jeśli MCU jest dość mały, ciąg polecenia może wymagać przetłumaczenia na kod. Jeśli MCU ma duże możliwości, ciąg poleceń może w rzeczywistości być strukturą JSON lub być może wszystkimi danymi hostowanymi przez panel.

W tej dyskusji przyciski na panelu ikon zawierają nazwę panelu do pobrania. To również może być dość uproszczone. Wydaje się sensowne, że ten parametr może oznaczać dowolny panel, który może być przechowywany w bazach danych przedsiębiorstw. Ale może to jakaś formuła. Być może informacje o panelu powinny być owinięte wokół definicji panelu, którą otrzymujemy z serwera. W każdym razie podstawy można łatwo rozwinąć, gdy znikną pewne bóle głowy, na przykład sprawić, by SVG prawidłowo reagował na kliknięcia.

Wniosek

W tej dyskusji przedstawiono kilka podstawowych kroków i decyzji, które prowadzą do realizacji aplikacji sieci Web z jedną stroną (SPWA), która może łączyć się z urządzeniami IoT. Teraz wiemy, jak pobrać panele z serwera WWW i zamienić je w interfejs MCU.

W tej dyskusji jest znacznie więcej, z kilkoma innymi dyskusjami, które mogą nastąpić. Rozpoczęcie od Vue to jedna rzecz do przemyślenia. Ale jest też cała historia MCU, o której tylko pokrótce poruszyliśmy.

W szczególności, wybierając MQTT jako podłoże komunikacyjne, zakładamy, że urządzenia IoT po drugiej stronie mogą w jakiś sposób być rządzone przez MQTT. Ale nie zawsze tak jest. Czasami bramy są potrzebne, jeśli MQTT ma uzyskać dostęp do urządzenia z łączami szeregowymi lub Bluetooth. A może wszystko, czego kiedykolwiek potrzebujesz na stronie internetowej, to WebSockets. Niemniej jednak użyliśmy MQTT jako przykładu, aby pokazać, jak Vue może zarówno odbierać, jak i wysyłać dane, zachowując jednocześnie stan danych zsynchronizowany z urządzeniami.

Po raz kolejny mamy tylko część historii. Tym razem jest to synchronizacja, ponieważ strona powinna radzić sobie z alertami i niepokoić użytkownika, jeśli dzieje się coś krytycznego. Czasami wiadomości mogą się zgubić. Musimy więc mieć mechanizm potwierdzeń.

Wreszcie, moim zdaniem, Vue sprawia, że ​​aktualizacja danych po ich otrzymaniu jest dość elegancka. Ale wysyłanie zmian stanu nie jest takie proste. Nie wydaje się, aby praca była o wiele prostsza niż przy użyciu waniliowego JavaScriptu. Ale jest sposób i ma to sens.

Być może można zbudować czystą bibliotekę, aby stworzyć uniwersalny zestaw komponentów dla wszystkich paneli. Pokrótce wspomniano o elementach tworzenia takich bibliotek i przechowywania ich w bazie danych. Konieczne może być opracowanie narzędzi, które wykraczają poza samo tworzenie obrazów SVG. W każdym razie jest prawdopodobnie wiele rzeczy, które można zrobić w kolejnych krokach.