Projekt KWS – webová vizualizace a ovládání (nejen) pro Arduino pomocí ESP8266

kwswittyZ diskuze pod článkem o webové kamerce vyplynul zájem o firmware do ESP8266, který by plnil tyto funkce:

Poskytnutí webového serveru pro vizualizaci proměnných, možnost zpětného ovládání/přenosu dat. Vše má komunikovat přes jednoduchý sériový protokol například s deskou Arduino UNO. Z nedostatku invence jsem projekt nazval KWS, neboli Karlův Webový Systém. Slíbil jsem, že se pokusím do víkendu navrhnout nějaké řešení a zde Vám tedy předkládám první alfa verzi, co jsem vymyslel…

Můj návrh spočívá ve vytvoření a udržování seznamu proměnných, jejich hodnot a informace o stáří poslední hodnoty na straně jedné a odeslání nových povelů na straně druhé. O správu proměnných se stará modul variables.cpp, který udržuje seznam s hodnotami a aktualizuje stáří. Proměnné jsou jednak definovány uživatelem (seznam je v souboru variables.txt, uloženém na SPIFFS a jednak jde o systémové proměnné, které vrací informace o stavu systému. Jedná se o:

version – vrací jméno běžícího skriptu a informace o času překladu

uptime – vrací délku běhu od zapnutí napájení, nebo restartu

heap – vrací velikost volné paměti RAM v modulu ESP8266

Zvláštní místo pak zaujímá proměnná send, která sice nic nevrací, ale za to zajistí odeslání povelů směrem do podřízeného systému.

Tímto se dostáváme k protokolu sériového portu – tento je obsluhován a realizován v modulu comm.cpp . Protože jsem si nebyl jistý, jakým způsobem bude komunikace probíhat (některým aplikacím můžou vadit počáteční zprávy, které proběhnou na standardním sériovém portu ESP8266 při  náběhu skriptu), vytvořil jsem komunikační třídu tak, že jako komunikační port lze použít jakéhokoliv potomka třídy Stream. Znamená to tedy, že můžeme použít objekt Serial, SoftwareSerial, ale také WiFiTCPSocket.

O vizualizaci se pak stará webový server s možností generování dynamického obsahu, uložený v souboru cgiws.cpp . Server dokáže servírovat různé datové typy přímo z SPIFFS a soubory s příponou .shtml interpretuje a vytváří tak dynamický obsah.

Syntaxe shtml je následující:

Do odpovědi serveru vloží obsah určeného souboru (využití zejména pro hlavičky a patičky HTML stránek), nezapomeňte prosím, že soubory na SPIFFS začínají kořenovým adresářem.

Do odpovědi serveru je vložena hodnota, kterou aktuálně obsahuje zadaná proměnná.

Umožňuje změnit typ vraceného dokumentu – jde o to, že standardně se vrací stránka, generovaná dynamicky jako text/html. Pokud ovšem budeme potřebovat vrátit XML, nebo JSON pro použití v AJAXu, je třeba typ dokumentu změnit.

Místo hodnoty proměnné se do výstupního souboru uloží stáří v milisekundách. Stářím se rozumí čas od poslední aktualizace a v našem případě je tato hodnota určena zejména pro případné zobrazení varování o stáří, nebo zešednutí neplatné/staré hodnoty.

Příklady použití jednotlivých klíčových slov je možné najít v souborech v adresáři data v projektu.

Poslední částí je pak způsob/možnost, jak na webový server nahrát nový obsah. Možnosti jsou celkem tři.

První možností je vytvoření a nahrání celého souborového systému přímo z prostředí Arduina pomocí nástroje Sketch Data Upload (instalujte z Githubu Arduino ESP8266 poslední verzi nástroje ESP8266FS – poslední verze již umí nahrávání přes OTA), která se nachází v menu Nástroje.

sdu

Další možností je připojení přes FTP server, uživatelské jméno esp8266 a heslo esp8266 – rychlost není největší, ale soubory kopírovat lze.

Poslední možností je pak webové rozhraní, které jsem převzal z příkladu FSBrowser, ale nijak příliš jsem ho netestoval.

Na závěr – ještě předtím, než vás pustím ke stahování jedno upozornění – vývoj Arduina pro ESP8266 má stále překotný průběh – co v jedné verzi jádra přeložit šlo, tak ve verzi další už jít nemusí. Proto uvádím verze, použité při psaní a testování:

Arduino IDE: 1.6.7, instalace portable

ESP8266 Core: 2.1.0-rc2 (Staging)

Přikládám kompletní adresář projektu a upravenou knihovnu FTP serveru (číslo verze jsem posunul). Náměty na případné vylepšení jsou vítány v diskuzi…

ESP8266FtpServer
ESP8266FtpServer
ESP8266FtpServer.zip
9.0 KiB
804 Downloads
Detaily
Kws V2
Kws V2
kws_V2.zip
18.4 KiB
755 Downloads
Detaily

37 komentářů u „Projekt KWS – webová vizualizace a ovládání (nejen) pro Arduino pomocí ESP8266“

  1. Tak to je větší dílo než sem čekal….
    Akorát problém. Che to po mě při kompilaci streaming.h
    Kde ho získám?
    Karel

  2. Tak jsem to zakomentoval a asi nikde nechybí, nebo jo?
    Akorát stránka vypadá jinak než ta tvoje, a ještě bych asi potřeboval popis pro blbce, jak nastavit ty proměnný a co posílat do esp, aby se mi to zobrazovalo.
    Neuvěřitelný co dokáže modulek za 50Kč ve spolupráci s někým schopným….

    1. Streaming je jedna z doplňkových knihoven Arduina https://www.arduino.cc/en/Reference/Libraries , kterou používám, když jsem líný psát například:
      Serial.print(“Tohle je hodnota “);
      Serial.print(analogRead(A0))ů
      Serial.println(” analogoveho vstupu 0.”);
      Se streaming to napíšu takhle:
      Serial << "Tohle je hodnota " << analogRead(A0) << " analogoveho vstupu 0.\r\n"; V projektu KWS je to pozůstatek mého ladění. Vím, že by si celý projekt zasloužil podstatné rozšíření dokumentace - například jsem zapoměl napsat, že na h_t_t_p://[ip adresa]/dav se vypíše přehledná diagnostická tabulka se všemi proměnnými, jejich aktuálními hodnotami a stářím... ale k dotazům: Postupuj takto - do souboru variables.txt si napiš seznam proměnných, které chceš mít modifikovatelné z UNa a dostupné pro vizualizaci na webu (tyto se pak objeví také v diagnostice). Napiš si do nějakého jiného souboru (třeba ktest.shtml) tohle: [html][body] Obsah promenne: %! ...... sem napiš jméno některé ze zadaných proměnných, které jsi napsal do variables.txt [/body][/html] }nejdou sem umístit tagy HTML, takže si uprav závorky [] na "zobáky" Všechno ulož do souborového systému na ESP, restartuj ESP (tedy pokud jsi dělal změny ve variables.txt) a do prohlížeče pak zadej h_t_t_p://[adresa ESP]/ktest.shtml - mělo by to vypsat aktuální hodnotu Tvé proměnné - vzhledem k tomu, že ještě nebyla zadaná, tak bude prázdná, takže ji nastav sériovým portem... Kruci - edituju to už po třetí a nedokážu sem umístit HTML tagy...

      1. Soubor jsem vytvořil, variables. txt upravil, ale asi chybka, na kterou nemůžu přijít, html mi vypisuje: Obsah promenne: Undefined variable: Ump.
        Undefined variable: d0.
        /dav mi ty proměnné ukazuje, ale prázdné, jak by měly vypadat data na sériovém portu? zkouším Ump=1235, d0 2354 crlf,
        Ump 3412 do2123 crlf a nedaří se mi. rychlost mám správně, 115200.

        1. protokol jsem udělal hodně primitivní:
          ;[promenna]”[hodnota]”
          takže pro proměnnou d0 to vypadá takhle:
          ;d0″150″
          Co je důležitý, tak je třeba dodržet upper/lower case (jako v Linuxu)…

          1. Jo data naweb už dostanu, ještě trochu návod jak na druhou stranu, tj z webu na sériovej port, to by se mohlo hodit i ostatním..

          2. No na to slouží proměnná “send” – pokud v GET, nebo POST použiješ jakýkoliv parametry, tak když je na webové shtml stránce použitá proměnná send, tak se všechny parametrové páry postupně odešlo na sériový port ve stejném formátu, jako při příjmu. Udělej si třeba soubor posli.shtml, který bude obsahovat jen
            %! send
            a pak zkus v prohlížeči h_t_t_p://[adresa serveru]/posli.shtml?d0=150
            na sériovém portu by mělo vyskočit
            ;d0″150″ + cr + lf

  3. Podla obrazka vidim ze modul WIFI Witty uz dorazil. Aky je v porovnani s WeMos D1 mini? Ktory z tychto ulta low cost modulov objednavat?

    1. Ano, Witty dorazil, ale je těžké říct, který je lepší – na Witty jsou zase nesmyslně blokované výstupy tou tříbarevnou LED a analogový vstup tím fotoodporem. Zase je super, že to tlačítko na Witty není Reset, ale uživatelské tlačítko… Ach jo 🙁 Jo a dokumentace k Wemos je podstatně lepší, než k Witty…

  4. Ahoj,
    zkouším pochopit program a ztroskotal jsem hned na Comm(Stream &comms): _comms(comms), _ReceiveState(RS_STARTHUNT) {}

    Co je to class snad rozumím, ale ten kod mi není jasný.
    Kde se nabraly _comms a comms _ReceiveState ?
    Dík

    1. Ahoj,
      je to normální zápis inicializace vnitřních proměnných z konstruktoru (http://kmlinux.fjfi.cvut.cz/~fabiadav/cecko/poznamky-k-jazyku-c_plus_plus/konstruktor-a-destruktor) a zmiňované proměnné se vzaly ze sekce private v třídě Comm (ty s podtržítkem). Proměnná comms bez podtržítka je pak parametr, předaný při použití objeku Comm. Možná jsem to mohl napsat přehledněji tím, že bych sekci private uvedl před sekci public.

  5. Díky za info, snad jsem to pochopil. Ovšem class variable se struct už je příliš silné kafe.
    Program funguje tak, že si načte proměnné z definičního souboru, v LOOP je aktualizuje přes seriový port a pomocí parsace stránek shtml je doplňuje do stránky.
    Ale kde je kod obsluhující: h_t_t_p://[adresa serveru]/posli.shtml?d0=150 ???
    Děkuji

    1. No on celý tenhle projekt by si zasloužil nejspíš obrázkové vyjádření, ale moje grafické schopnosti připomínají spíš opičí fresky. Nicméně tohle dokážu popsat – trik je v tom, že uvnitř souboru posli.shtml je tag send ( %! send ). Tento tag je interpretovaný v hlavním modulu kws.ino a způsobí odeslání všech parametrů POST/GET dotazu jako párů na komunikační linku. Tady jedna poznámka – zde jem měl v původním projektu chybu, která způsobovala restart ESP modulu a myslím, že jsem ještě neuveřejnil nápravu, což udělám do konce týdne…

  6. Pořád nechápu. Jako to vars.create(“send”, Send); // odeslani ridicich parametru na vystup
    To je jako ono? Nic jiného tam nevidím. Jak to může něco odeslat?

    1. Ano, to je ono. Pokud se v interpretovanem SHTML vyskytne tento tag, tak se zavola jeho obsluha, ktera udela to, ze vsechny parametry, predane webovemu serveru se odeslou do komunikacni vrstvy jako vystup. V tomto specialnim pripade se send nechova jako promenna (do HTML vystupu se vraci dummy text “Sent…” tusim), ale jako vykonny trigger…. Ahaaa – ted jsem to pochopil, co vlastne nechapete: Takze definice tech promennych neni jen tak – ze souboru se definuji “obycejne” promenne, ktere dokazou jen odeslat svuj obsah, ale kdyz se podivate do protoypovych funkci ve tride variables, tak uvidite, ze promenne muzete vytvorit i takove, ktere nevraci svoji hodnotu, ktera je nastavena funkci setVal, ale volaji prirazenou metodu, ktera zajisti nejakou funkci a vrati opet “nejaky” obsah.

  7. Zdravím. Už je mi to sice trochu blbé se pořád ptát. Ale, já mám pořád představu funkce, která vychází z Vašeho YAFET.
    Kdybych zadal:
    h_t_t_p://[adresa serveru]/posli?d0=150
    tak bude v kodu:
    Server.on(“/posli”,handle);

    void handle()
    {
    Serial.print(“d0”);
    Serial.print(Server.arg(“d0”);
    }
    To pořád nevidím ve Vašem řešení. když se používá SPIFFS, tak by to mělo být asi v principu stejné.
    Máte funkci loadFromFS, kde se parsují data.
    Pořád nevidím, kde se zavolá něco jako ten můj kod. Seriál.print (u Vás comm). Navíc ta funkce loadFromFS je použita jenom v handleNotFound a když se zavolá /edit.
    Takže kdy se to volá je mi taky záhadou.
    Ty variables jsem nějak vytušil, že tak fungují. Ale kde je ta Seriál.print (comm) přiřazena a zavolána, to pořád nevidím.
    V příkladech jsou vždy třídy a struktury tak krásně jednoduše popsané, ale vy je máte vyšperkované (z ukazatele na ukazetel se mi lehce orosí čelo 🙂 a tak nějak nemůžu rozklíčovat funkci programu.
    Děkuji

    1. Takze pokud pouziju Vas priklad, ale upravim ho tak, jak funguje KWS:
      kdyz zadate h.t.t.p://…../posli.shtml?d0=150, tak se v KWS v modulu cgiws zjisti dle pripony, ze se odesila interpretovany HTML, takze spusti interpretaci. Kdyz v posli.shtml narazi na :! send, tak spusti metodu send ve kws.ino, ktera projde vsechny zadane argumenty weboveho dotazu a odesle je komunikacnimu modulu. Ten kod, ktery vola vykonnou funkci je ziskany takto:
      cgiws.cpp interpretuje .shtml, narazi na tag :! send a zavola vars.getVal(…), ve variables.cpp v metode getVal(…) se najde promenna “send” a zjisti se, ze ma prirazenou vykonavaci funkci fn, ktera se zavola var->fn() no a timhle se dostane rizeni do funkce send(), ktera je definovana v kws.ino.

  8. Jo tááák. Díky moc, konečně chápu.
    A jenom ten můj dotaz ohledně loadFromFS . Jak to, že se to vůbec interpretuje, když ta funkce loadFromFS je použita jenom v handleNotFound a když se zavolá /edit. Bych očekával, že to bude nějaký základní handle.

    1. Webový server v ESP pracuje tak, že pokud najde odpovídající handler pro URI, tak ho spustí. Pokud ho nenajde, tak se pokusí spustit onNotFound a tam si můžeme dělat, co potřebujeme. Je tedy logické, že pokud server nenašel handler, tak se pokusíme mu naservírovat soubor z SPIFFS, popřípadě ho interpretovat.

    1. Jak je to s tím restatrtem ESP? já to testuju, a nic takovýho se mi neděje. posílám data na obě strany a zatím OK.
      Jako testovací modul mám nodemcu1.0, za cca 130Kč, je s tím celkem pěkná práce, jenom si musím dopsat popisy na vývody, je to jinak než v IDE, ale to je malý problém.
      Na ESP01 jsem si zbastlil mezikus s tlačítkem reset, spínačem na programování a konektorem pro převodník na usb. Jenom mi nefunguje OTA, – IDE jej nenachází – rád bych to vyřešil než to vestavím do krabice do zdi, abych to mohl případně ještě trochu vyladit. (A nebo se v tom už přestat vrtat).

      1. Chyba spočívá v tom, že v kws.ino je metoda static char *Send(void), ale chybí mi tam return tempStrBuff; , takže to může za určitých okolností spadnout na vyjímku. Ohledně OTA – potřebuji verzi IDE a Core. Předpokládám, že jde o tu nodemcu desku (na ESP-01 to nepojede, protože má jen 512kB flash paměti a OTA vyžaduje minimálně 1MB).
        Právě jsem na server uložil opravenou verzi, takže už by mělo být všechno Ok…

        1. Zkoušel jsem to bez úspěchu s obojím, s Nodemcu(ESP12e) i ESP-01.
          Mám IDE 1.6.5., a v ad. board manageru řádek : http://arduino.esp8266.com/stable/package_esp8266com_index.json
          jak se zjistí verze CORE netuším.
          Když jsem cca před měsícem zkoušel IDE 1.6.7, tak mi ESP vůbec nechodilo, musel jsem se vrátit k této verzi.
          Jak se dá zjistit velikost paměti v tom esp8266-01? nebo je to jistě u všech jenom 512kB? V každým případě když jsem to do toho esp01 naládoval, tak žádný hlášení o nedostatku paměti neproběhlo.

          1. No nevím o tom, že by ESP-01 mělo víc paměti, než 512kB. Zjistit se to dá pomocí ESP.getFlashChipRealSize(). Verze jádra je zase vidět v IDE v Manažéru desek. Co přesně “nechodilo” na 1.6.7? Pro počáteční rozhýbání OTA doporučuji zkusit nejdříve některý z příkladů ArduinoOTA. Potom se dá pokračovat…

  9. Chtěl jsem si vyzkoušet tento projekt a hlásí mi tuto chybu:

    kws:27: error: ‘WifiConfig’ does not name a type

    WifiConfig wifi; // konfigurace ESP modulu

    Vůbec netuším, co s tím.
    Použil jsem knihovnu: wct-160410a

      1. IDE mám 1.8.5. Jak zjistím verzi jádra?
        Projekt jsem normálně rozbalil do \Documents\Arduino\kws. Když to nenašlo knihovnu WiFiConfig.h, dohrál jsem z wct-160410a.zip složku WifiConfig do \Documents\Arduino\libraries.
        To mě práve zarazilo, protože třídu WiFiConfig tam vidím.

          1. Tak už vím, v čem je problém – abych byl kompatibilní s názvoslovím ESP věcí v Arduinu, tak jsem musel přejmenovat WifiConfig na WiFiConfig (velké F ve WiFi). Pokud používáte poslední verze knihovny WiFiConfig se staršími projekty, překontrolujte prosím její instanci (správně je WiFiConfig wifi; // konfigurace ESP modulu).

          2. To je ale 3,14čovina! Taky mě to mohlo napadnout. Vždyť přece C je case sensitive.
            Mockrát děkuju!

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *