Skocz do zawartości

Tworzenie interfejsu sieciowego z wykorzystaniem ESP - część 2


Pomocna odpowiedź

Jak wspominałem w poprzedniej części, tym razem omówię trochę bardziej zaawansowane zagadnienia. Od razu zaznaczam że mogą się pojawić trochę bardziej zaawansowane pojęcia, będę starał się je w miarę przybliżyć, ale nie wykluczam że będzie konieczne zaczerpnięcie dodatkowej wiedzy z innych źródeł. Będę zasięgał do funkcji jakie daje nam uprzednio użyta biblioteka ESP Async Web Server i do nich się odwoływał. Omówię trzy problemy, a konkretnie, ich potencjalne zastosowanie, trudności jakie nas mogą napotkać oraz w jaki sposób można je zrealizować uwzględniając dostępne technologie. Przedstawione rozwiązania będą miały charaktery teoretyczny, bazujący na moich doświadczeniach. Nie ukrywam zatem, że niekoniecznie muszą być najlepsze.

Ten artykuł bierze udział w naszym konkursie! 🔥
Na zwycięzców czekają karty podarunkowe Allegro, m.in.: 2000 zł, 1000 zł i 500 zł.

konkurs_forbot_nagrody_1-350x147.png

Potrafisz napisać podobny poradnik? Opublikuj go na forum i zgłoś się do konkursu!
Czekamy na ciekawe teksty związane z elektroniką i programowaniem. Sprawdź szczegóły »

Co omówimy?

Tak jak wspominałem w poprzedniej części poruszę trzy poniższe zagadnienia:

  • jak można stworzyć prosty konfigurator urządzenia
  • jak zrealizować prostą przeglądarkę plików z możliwością ich pobierania i usuwania
  • jak zrealizować provisioning i co to właściwie jest

No to do roboty!

Konfigurator

W przypadku prostych projektów, czy niedużej ilości sztuk docelowego rozwiązania, może nie być to konieczny aspekt, aby móc konfigurować urządzenie w prosty sposób. Inaczej sprawa się przedstawia w sytuacji gdy chcemy rozwijać projekt typu open-source, tworzyć urządzenie które ma pracować w zależności od preferencji użytkownika, czy realizować duży projekt składający się z wielu urządzeń o podobnym działaniu. Warto zauważyć że nie zawsze docelowy „klient” może mieć wystarczające umiejętności programistyczne aby dostosować używany kod do jego potrzeb, jak również modyfikacja i skompilowanie dużego projektu pobranego z ogólnodostępnego repozytorium, może nieraz nas przyprawić o ból głowy. W takiej sytuacji korzystanie z graficznych konfiguratorów lub plików konfiguracyjnych zawierających tylko konkretne parametry może ułatwić nasze zadanie.

json160.gif.588288b59e644d6db6ab850eeef26a29.gif

W tym momencie z pomocą może nam przyjść format JSON którego to akronim możemy rozwinąć do JavaScript Object Notation. Jak już pewnie część z was zauważyła jego nazwa posiada w sobie „JavaScript”, nie bez przypadku, ponieważ powstał z myślą o korzystaniu wraz z nim. Zaletami tego formatu jest jest przede wszystkim łatwość wykorzystania po stronie przeglądarki, jest przyjazny do czytania przez człowieka, jak i jest bezproblemowo przetwarzany w innych językach jak C czy C++ z wykorzystaniem bibliotek jak cJSON czy też ArduinoJSON.

logo-1200.thumb.jpg.4d33dab0489191f7e863f5d36a1f21be.jpg

Przykładowa struktura pliku JSON wygląda jak niżej

{
    "glossary": {
        "title": "example glossary",
		"GlossDiv": {
            "title": "S",
			"GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
					"SortAs": "SGML",
					"GlossTerm": "Standard Generalized Markup Language",
					"Acronym": "SGML",
					"Abbrev": "ISO 8879:1986",
					"GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
						"GlossSeeAlso": ["GML", "XML"]
                    },
					"GlossSee": "markup"
                }
            }
        }
    }
}

Wydaje się raczej przyjaźniejszy dla oka niż analogiczna struktura XML

<!DOCTYPE glossary PUBLIC "-//OASIS//DTD DocBook V3.1//EN">
 <glossary><title>example glossary</title>
  <GlossDiv><title>S</title>
   <GlossList>
    <GlossEntry ID="SGML" SortAs="SGML">
     <GlossTerm>Standard Generalized Markup Language</GlossTerm>
     <Acronym>SGML</Acronym>
     <Abbrev>ISO 8879:1986</Abbrev>
     <GlossDef>
      <para>A meta-markup language, used to create markup
languages such as DocBook.</para>
      <GlossSeeAlso OtherTerm="GML">
      <GlossSeeAlso OtherTerm="XML">
     </GlossDef>
     <GlossSee OtherTerm="markup">
    </GlossEntry>
   </GlossList>
  </GlossDiv>
 </glossary>

Wykorzystując format JSON jesteśmy w stanie definiować konkretne parametry i odczytywać je z pamięci w celu modyfikacji parametrów naszych funkcji. W ten sposób możemy umożliwić np. proste ustawianie hasła do docelowej sieci WiFi, serwera gdzie chcemy przesyłać dane, czy np. klucza wybranego przez nas API z którego korzystamy.

{
    "ssid": "nazwa sieci",
    "password": "haslo sieci",  
    "mqtt-broker": "nasz.broker",
}

Jako że format JSON jest bardzo przyjazny w użytkowaniu wraz z JavaScriptem, możemy łatwo tworzyć formularze które będą tworzyć gotowy plik i przesyłać do naszego urządzenia.

Na poniższym zdjęciu widzimy niezbyt urodziwie sformatowany plik konfiguracyjny drukarki 3D w postaci pliku JSON, można go pobrać i wyedytować w zewnętrznym edytorze, dzięki temu możemy skonfigurować drukarkę bez konieczności modyfikacji oprogramowania.

json.thumb.png.d7d02221ba552bb473a95b5488133cab.png

Przeglądarka plików

266580741_Zrzutekranu2021-03-03133245.thumb.png.a263dccbc366aab50e622249fc9bb765.png

Przeglądarka plików z drukarki 3D

Gdy wykonujemy urządzenie pomiarowe które zapisuje pliki, bądź jego działanie opiera się na różnych plikach, np. profile pracy urządzenia. W takiej sytuacji bardzo przydatna jest możliwość wgrywania plików, jak i podgląd co tam ukrywa w swojej pamięci nasz elektroniczny potworek. Tutaj z pomocą przyjdą nam metody HTTP. Do pobierania plików użyteczna będzie metoda GET, do wysyłania POST, zaś do usuwanie DELETE. Dociekliwe osoby pewnie zauważą, że próbując zrealizować przeglądarkę plików z wykorzystaniem analogicznych metod jak w pierwszej części, pojawia się problem iż liczba plików jest zmienna, a dla każdego pliku powinniśmy oddzielnie zainicjować obsługę zapytań. O ile w teorii moglibyśmy skanować po uruchomieniu naszą pamięć w poszukiwaniu plików i kilkukrotnie powtarzać proces inicjacji zapytania dla każdego wykrytego pliku, to w praktyce byśmy byli zmuszeni do resetu urządzenia po każdej zmianie w pamięci (dodaniu bądź usunięciu pliku). Na szczęście biblioteka ta przewiduje takie sytuacje i posiada funkcję:

 AsyncWebServer::serveStatic()

Funkcja ta działa w taki sposób iż mamy dostęp do całej pamięci, w ten sposób nie musimy martwić się o inicjowanie obsługi zapytań do każdego pliku, musimy jedynie znać ścieżkę która do niego prowadzi, resztą zajmie się biblioteka. Z pewnością ułatwia to pracę oraz korzystnie wpływa na wydajność programu. Szczególnie gdy mamy stronę składającą się z wielu plików .css .js czy też plików graficznych. Ponadto wybaczy nam to błędy gdybyśmy zapomnieli uruchomić obsługę dla wybranego pliku, a nasza strona by niepoprawnie działała.

Jak wspomniałem, wykorzystując funkcję serveStatic() wystarczy że znać będziemy położenie pliku który chcemy znaleźć. Pytanie, skąd wiedzieć jak się nasz plik nazywa lub jakie mamy pliki dostępne? Teoretycznie możemy strzelać, szanse, jeżeli znamy systematykę nazywania plików, mogą być nawet większe niż trafienie 6 w totolotka, w innym wypadku może być krucho. W tym momencie z pomocą przyjdzie nam JSON.

jsoon.thumb.png.354133cb74d4676eb13cdf7069045584.png

Zarówno biblioteka obsługująca SPIFFS czy też karty SD, bazuje na bibliotece FS.h, która nam pozwala na poziomie mikrokontrolera przeskanować pamięć i wskazać „ścieżki” poszczególnych plików. Teraz zostaje kwestia skąd użytkownik ma wiedzieć jakie ma dostępne pliki. W takiej sytuacji możemy wysłać zapytanie do serwera o to, aby nam zwrócił listę plików, serwer na podstawie zawartości pamięci wygeneruje nam listę w postaci pliku JSON i ją odeśle. Skrypt po stronie klienta będzie mógł nam wygenerować listę odnośników do poszczególnych plików w pamięci. Z tego punktu jesteśmy w stanie w miarę swobodnie manipulować plikami w pamięci urządzenia.

Warto zwrócić uwagę również na kwestie bezpieczeństwa w takim rozwiązaniu. Jeżeli mamy np. plik konfiguracyjny w pamięci SPIFFS w którym zawarte są np. dane do logowania do sieci WiFi czy też API, jest ryzyko iż w łatwy sposób mogą zostać wykradzione, szczególnie jeżeli planujemy urządzenie włączyć do sieci publicznej. Oczywiście na każdy problem jest rozwiązanie, lepsze lub gorsze, ale dalsze rozważania tego problemu zostawiam do własnej analizy 🙂

Provisioning

Provisioning może brzmieć bardzo nietypowo dla większości osób, nawet tych co znają język angielski. Posiłkując się Wikipedią można to określić jako proces polegający na przygotowywaniu sieci w taki sposób, aby po wykonaniu pewnych operacji, nadać jej nowe funkcjonalności. Wciąż może to brzmieć trochę niejasno. Praktycznym przykładem który przychodzi mi do głowy, aczkolwiek może nie być do końca poprawnym, jest sytuacja, gdy jesteśmy np. w centrum handlowym i chcemy skorzystać z dostępnej sieci WiFi. Zazwyczaj podłączenie się do tej sieci skutkuje wyskoczeniem nam okna przeglądarki, gdzie musimy zaakceptować regulamin, aby móc korzystać z sieci. Czyli w pewien sposób jesteśmy zmuszeni dokonać pewnej konfiguracji, aby otrzymać możliwość dostępu do internetu.

Dużo lepszy przykładem takiego zabiegu jest to o czym będę pisał poniżej.

Przychodzi do nas nowe urządzenie, np. asystent głosowy w postaci głośnika. Chcemy jak najszybciej zacząć cieszyć się z jego korzystania, ale najpierw musimy podłączyć do sieci. Część osób która orientuje się w temacie powie żeby skorzystać np. z WPS. Niestety taka opcja może budzić pewne obiekcje pod względem bezpieczeństwa, a po drugie musimy mieć fizyczny dostęp do urządzenia. Inną opcją jest podłączenie urządzenia np. do komputera poprzez port USB i jego konfiguracja, to z pewnością by wiązało się z koniecznością pobrania oprogramowania bądź przygotowania pliku konfiguracyjnego, a dla osoby mniej obeznanej może być problematyczne. Trzecią opcją jest provisioning, uruchamiamy urządzenie, pojawia się nowa sieć WiFi utworzona przez urządzenie, łączymy się do niej za pomocą np. smartfona, wyskakuje nam okno przeglądarki, podajemy dane sieci, akceptujemy i mamy skonfigurowaną sieć. Urządzenie jest gotowe do pracy. Analogiczną procedurę można też wykonać np. z wykorzystaniem bluetooth i aplikacji na telefon.

1925932524_Zrzutekranu2021-03-03134129.thumb.png.61f9aad192925540cab9a8bad3bb0020.png

Przykład autorskiej realizacji

Aby zrealizować taki proces i był on jak najbardziej zautomatyzowany, czyli po podłączeniu się do urządzenia, pokazuje się nam okno konfiguracji, musimy zrealizować dwa główne etapy. Po pierwsze nasze urządzenie musi być uruchomione jako punkt dostępu (Acces Point), po drugie uruchomić serwer DNS w naszym urządzeniu, odpowiednio go konfigurując. Oczywiście musimy również dodać obsługę naszego interfejsu oraz komunikacji z urządzeniem w celu wymiany danych. W tym momencie zachęcam do samodzielnej lektury dokumentacji bibliotek oraz sieci w celu poszukania, jak to zrealizować oraz przekonania się, że wcale nie trzeba dedykowanych bibliotek do realizacji takiego zadania, które wbrew pozorom takie straszne nie jest 🙂 Podpowiem tylko że w przypadku provisioningu, najlepiej stronę do obsługi konfiguracji zrobić możliwie prostą oraz aby zawierała się w jednym pliku .html.

Podsumowanie

Cieszę się znów jeżeli tu dotarłeś. Wbrew pozorom jest całkiem obszerny materiał. W tym momencie zakończę moje wywody głównie oparte na własnych doświadczeniach oraz mojej wiedzy. Jak już niejednokrotnie wspominałem, nie muszą to być najlepsze rozwiązania, jak i nie są to wszystkie możliwe rozwiązania. Jest to bardzo szeroki temat i myślę że lekką ręką można by było napisać na ten temat książkę i to tylko starając się opisywać temat w sposób przyjazny przeciętnemu czytelnikowi. Starałem się korzystać z jak najbardziej przyjaznego języka, część kwestii to skróty myślowe, które uważam że w miarę rzeczowo oddają tematykę poszczególnych problemów. Liczę że większych błędów merytorycznych nie popełniłem (ale za stylistyczne czy gramatyczne nie mogę ręczyć :)), z chęcią przyjmę wszelkie uwagi odnośnie poprawności treści. Jeżeli byłoby zainteresowanie kontynuacją tematu, myślę że znajdę trochę kwestii wartych poruszenia przy realizacji takich zagadnień, a może nawet rozważę przedstawienie realizacji jednego z problemów.

M. S.

  • Lubię! 2
Link to post
Share on other sites

@AlcoMatt dziękuję za kolejny ciekawy artykuł! Wpis został zaakceptowany i jest od teraz dostępny publicznie 🙂

  • Lubię! 1
Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.