Zo, veel info en reacties. Bedankt allemaal !

Vooruit dan maar. Dan ga ik toch even wat dieper in op waar ik mee bezig ben. Ik heb een bordje ontworpen en inmiddels voorzien van een ESP12 en kan het besturen als een NodeMCU in Arduino IDE. Omdat ik nog wat M41T00's heb, zit die er ook op gesoldeerd. Dit is omdat ik deze RTC wil gebruiken om de tijd in de gaten te houden, wanneer ik een aangesloten LED aan/uit wil schakelen.
Een M41T00 is compatible met een DS1307, qua pins en registers.

Het is de bedoeling dat er instellingen opgeslagen kunnen worden. Daarvoor heb ik HTML-bestandjes (met <forms>). Elke pagina heeft eigen functie, en komen neer op het volgende :

1) tijd / weekdag instellen
2) In/uitschakeltijden instellen
3) Netwerkgegevens (softAP / station)
4) Algemene pagina om vlot ingestelde gegevens in te kunnen zien.

Deze instellingen wou ik in eerste instantie in de EEPROM zetten. Daarvoor is een EEPROM.h beschikbaar. Dat creeert een soort virtuele EEPROM. Handig, want als het boardje spanningsloos is, kunnen de instellingen er weer uit opgelepeld worden. Ik meende ergens gelezen te hebben dat indien je iets wijzigt in deze virtuele EEPROM, de hele bups wordt verhuisd naar een andere plek. Ik kreeg vaag het beeld van hoe dat met rewritable CD-ROMs gaat.

Voor mij een reden om dan over te stappen naar LittleFS. Dan een soort JSON-file met daarin de instellingen opslaan. Ook prima. Voordeel is, dat ik dan ook meteen een plek heb om die HTML-files op te slaan.

Het magische woord is : foto. Dat maakt het meestal een stuk interessanter. Goed, ik heb net een foto gemaakt van het printje. Dan krijg je een beter beeld bij waar ik mee zit te stoeien.

-=[ EDIT ]=-
Even nog een aanvulling. Ik had eerst de meest recente Arduino IDE geinstalleerd (2 punt nogwat). Het mooie is dat er best veel info op internet gevonden kan worden, voor de ESP8266. Sterker nog, Youtube is rijkelijk voorzien van instructie-videos. Het grote nadeel is : erg veel informatie is gebaseerd op de oudere Arduino-versie. Ik heb al diverse keren mn neus gestoten tegen bijv. het installeren met libraries. Dan zit je diverse keren te verbazen en vervolgens te tieren als iets niet werkt, zoals het wordt uitgelegd. Dat heeft me al veel tijd gekost. Dus, daarom maar uit nood een oudere versie geinstalleerd...

Ik gebruik nog steeds de 1.18 versie. In de 2.x versie zitten nog te veel bugs. Onderandere het verdwijnen van de ESP32 library was er 1 van. Voor 2.x is er ook nog geen lader voor LiitleFS, SPifFS of FatFS. Voor de 1.18 versie is die er wel. Dit is wel verschillend voor ESP32 en ESP8266.

HTML steek ik niet in LittleFS. Gewoon een .h bestand. Zoveel memory spaar je daar niet mee. Je mag het testen. Elke HTML pagina in een apparte .h file.

#include "htmlRoot.h"
#include "htmlLoginIndex.h"
#include "htmlServerIndex.h"

Waarna je de gegevens in deze .h file gewoon kan gebruiken.

void setupHTML() {
  server.on("/", []() {
    /*if (!server.authenticate(www_username, www_password)) {
      server.requestAuthentication();
      }*/
    htmlPage = FPSTR(rootHtmlHeader);
    htmlPage.concat(FPSTR(style));
    htmlPage.concat(FPSTR(rootBodyMain));
    server.send(200, "text/html", htmlPage);
  });
  htmlPage = FPSTR(loginIndex);
  htmlPage.concat(FPSTR(style));
  server.on("/update", HTTP_GET, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", htmlPage);
  });
  htmlPage = FPSTR(serverIndex);
  htmlPage.concat(FPSTR(style));
  server.on("/serverIndex", HTTP_GET, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", htmlPage);
  });
  /*handling uploading firmware file */

  server.on("/updater", HTTP_POST, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "ok");
    ESP.restart();
  }, []() {
    HTTPUpload& upload = server.upload();
    if (upload.status == UPLOAD_FILE_START) {
      Serial.printf("Update: %s\n", upload.filename.c_str());
      if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_WRITE) {
      /* flashing firmware to ESP*/
      if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_END) {
      if (Update.end(true)) { //true to set the size to the current progress
        Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
      } else {
        Update.printError(Serial);
      }
    }
  });
  server.begin();
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);
}

Wel zorgen dat het in je ROM blijft en niet in RAM wordt geladen.

static const char rootBodyMain[] PROGMEM = R"=====(

Dan je HTML tekst en afsluiten met

)=====";

In een EEPROM kan je ook een JSON stream opslaan. Je kan ook writeBlock of updateBlock gebruiken.

Hmm,. dat is best complex wat je schrijft (voor een beginner). Wat ik als alternatief had bedacht was een functie te maken van elke html-page, als een string en deze vervolgens met "replace" te bewerken.
Zoiets als :


String Func_Page() {
    String WebPage="<html>=head=<body>=Inhoud=</body></html>";
    return WebPage;
}

En in het hoofdprogramma de webpagina oproepen en delen aanpassen via :


 String HtmlPage = Func_Page();
 HtmlPage = HtmlPage.replace("=head=","<head><title>HoofdPagina</title></head>");

// en zo ook voor de =Inhoud=

Ik lees ook iets over ROM. Dat is bijzonder interessant dat je dit aanstipt. Ik had al mn vraagtekens bij : [] PROGMEM = R"=====(.
Ik begreep totaal niet wat dat betekende of zou doen. Nu is het me een beetje duidelijk geworden.

Verder is dat over het ontbreken van een lader precies de druppel die me overhaalde om naar een lagere versie te gaan.

Tot slot, is dat wat ik voorstel, mogelijk (tekst aanroepen via een functie) ? Of bestaat de kans dat dat niet goed gaat of teveel geheugen gaat vreten ?

-=[ edit ]=-
Even wat foutjes weggeschraapt in code.

Wil je een HTML pagina die zich ververst als er nieuwe gegevens zijn? Werk dan met websocket. Je kan dan zowel uit de ESP de pagina aanpassen als waardes versturen vanuit je client zonder dat er een refresh nodig is.

Het probleem bij PROGMEM, dat is zoveel als een constante String die niet kan gewijzigd worden. Om te wijzigen moet die in RAM.

EDIT: als de M41T00 quasi gelijk is aan de DS1307, dan kan je ook RTClib gebruiken. In de voorbeelden zit ook code voor de DS1307.

[Bericht gewijzigd door buckfast_beekeeper op (13%)]

PROGMEM is een term uit de AVR hoek. Die plaatst de string in flash geheugen en dan zijn er andere instructies nodig om die te benaderen.

Op een ESP heeft dat geheel geen effect. Daar is het een dummy die niks doet.

Zie pgmspace.h voor ESP:


#define PROGMEM
#define PGM_P         const char *
#define PGM_VOID_P    const void *
#define PSTR(s)       (s)
#define _SFR_BYTE(n)  (n)

Die is alleen gedefiniëerd om de code portable te houden zodat dezelfde code op verschillende processors kan draaien.

Bij deze plaats ik afbeeldingen van de webpages die ik heb gemaakt voor de ESP12. Ik denk dat daarmee best duidelijk wordt, waar ik mee bezig ben.
Ik heb dus html-pagina's waarin ik teksten met %xxx% heb staan. Deze zijn bedoeld om gegevens neer te zetten, die de ESP12 bij houdt of ingesteld worden.

  • Main
    Dit is de hoofdpagina waarin je de actuele instellingen kunt bekijken
  • Basic
    Basis-instellingen. Laat zien of de lamp is ingeschakeld, met welke PWM-waarde en verder de tijd en dag (DOW). Zoals je ziet, er is een Submit-knop. Je kunt de gegevens dus ook wijzigen.
  • Timer1
    De pagina waarop ingesteld kan worden op welke dagen (DOW) en tijden de lamp in/uitgeschakeld wordt. Net als bovenstaand puntje : de gegevens kunnen gewijzigd worden.

De werking van de overige tabs zal geen verrassing zijn. Deze werken hetzelfde als de "Basic-pagina" maar dan met andere gegevens.

P.S. Arco : Deze code is inderdaad mooi om te gebruiken. Trouwens, hoe komt een tijdstring binnen ? Testen met de HTML-pagina laat voor bijv. 10:00 zien dat er "10%3A00" verzonden wordt. Maar hoe komt het weer binnen via server.arg() binnen ? "10:00" of "10%A300" ?

Met websockets en json verzend je de gegevens op de manier dat je wil.

Op mijn ESP onder andere deze verzendfunctie


void postPompNode() {
  if (flgWebSocketOpen) {
    StaticJsonDocument<400> doc;
    doc["status"] = "Pomp";
    doc["pompAdres"] = pompNode.adres;
    doc["pompAlive"] = pompNode.alive;
    doc["pompOn"] = pompNode.pompOn;
    doc["pompKlepOn"] = pompNode.klepOn;
    doc["waterIn"] = pompNode.waterIn;
    doc["waterInFlow"] = pompNode.waterInFlow;
    doc["waterInJaar"] = pompNode.waterInJaar;
    doc["waterUit"] = pompNode.waterUit;
    doc["waterUitFlow"] = pompNode.waterUitFlow;
    doc["waterUitJaar"] = pompNode.waterUitJaar;
    doc["pompRTCTemperatuur"] = pompNode.rtcTemperatuur;
    doc["versie"] = pompNode.versie;
    doc["lastScan"] = dateTimeToString(pompNode.lastScan, false, false);
    //Serial.print("post node: ");
    //Serial.println(pompNode.versie);

    char json[400];
    serializeJson(doc, json);
    webSocket.broadcastTXT(json);
  }

In de html pagina heb je dan deze html code:


<table style="width: 80%" align="center">
      <tr>
        <th class="tdMid">Adres:</th>
        <th class="tdMid">Alive:</th>
        <th class="tdMid">Werking:</th>
        <th class="tdMid">Klep:</th>
        <th class="tdMid">Water in<br>in liter:</th>
        <th class="tdMid">Max water in flow<br>in liter/minuut:</th>
        <th class="tdMid">Water dit jaar in<br>in liter:</th>
        <th class="tdMid">Water uit<br>in liter:</th>
        <th class="tdMid">Max water uit flow<br>in liter/minuut:</th>
        <th class="tdMid">Water uit jaar in<br>in liter:</th>        
        <th class="tdMid">RTC temperatuur<br>°C:</th>
        <th class="tdMid">Laatste scan:</th>
        <th class="tdMid">Versie:</th>
      </tr>
      <tr>
        <td class="tdMid" id="pompAdres"></td>
        <td class="tdMid" id="pompAlive"></td>
        <td class="tdMid" id="pompAan"></td>
        <td class="tdMid" id="pompKlep"></td>
        <td class="tdMid" id="pompIn"></td>
        <td class="tdMid" id="pompInFlow"></td>
        <td class="tdMid" id="pompInJaar"></td>
        <td class="tdMid" id="pompUit"></td>
        <td class="tdMid" id="pompUitFlow"></td>
        <td class="tdMid" id="pompUitJaar"></td>
        <td class="tdMid" id="pompRTCTemperatuur"></td>
        <td class="tdMid" id="pompLastScan"></td>
        <td class="tdMid" id="pompVersie"></td>
      </tr>
    </table>    

En deze java script code


          else if(dataS["status"] == "Pomp"){
            document.getElementById("pompAdres").innerHTML = dataS["pompAdres"];
            if(dataS["pompAlive"]){
              document.getElementById("pompAlive").innerHTML = "Ja";
              // indien pomp online is verdere gegevens tonen
              if(dataS["pompOn"]){
                document.getElementById("pompAan").innerHTML = "Aan";
                document.getElementById("buttonPomp").className = "buttonOff";
                document.getElementById("buttonPomp").innerHTML = "Pomp uit";
              }     
              else{
                document.getElementById("pompAan").innerHTML = "Uit";
                document.getElementById("buttonPomp").className = "buttonOn";
                document.getElementById("buttonPomp").innerHTML = "Pomp aan";
              }      
              if(dataS["pompKlepOn"]){
                document.getElementById("pompKlep").innerHTML = "Open";
                document.getElementById("buttonPompKlep").className = "buttonOff";
                document.getElementById("buttonPompKlep").innerHTML = "Pomp klep dicht";
              }     
              else{
                document.getElementById("pompKlep").innerHTML = "Toe";
                document.getElementById("buttonPompKlep").className = "buttonOn";
                document.getElementById("buttonPompKlep").innerHTML = "Pomp klep open";
              }      
              document.getElementById("pompIn").innerHTML = dataS["waterIn"].toFixed(2);
              document.getElementById("pompInFlow").innerHTML = dataS["waterInFlow"].toFixed(2);
              document.getElementById("pompInJaar").innerHTML = dataS["waterInJaar"].toFixed(2);              
              document.getElementById("pompUit").innerHTML = dataS["waterUit"].toFixed(2);
              document.getElementById("pompUitFlow").innerHTML = dataS["waterUitFlow"].toFixed(2);
              document.getElementById("pompUitJaar").innerHTML = dataS["waterUitJaar"].toFixed(2);                            
              document.getElementById("pompRTCTemperatuur").innerHTML = dataS["pompRTCTemperatuur"].toFixed(2);
              document.getElementById("pompLastScan").innerHTML = dataS["lastScan"];
              document.getElementById("pompVersie").innerHTML = dataS["versie"];                                    
            }     

Er zit ook de code in die de respectievelijke buttons van de juiste tekst en kleur voorziet.

En dat ziet er dan zo uit;

edit: voor tijd kan je kiezen voor UTC of de npormale tijd. Maar in json kan je ook kiezen je datum en dergelijke in losse dagen, uren en minuten te verzenden. Je bent redelijk vrij als html pagina en esp de code maar op dezelfde manier begrijpen.

@buckfast_beekeeper :
OK,. interessant hoe je dat doet. Ik ga het bestuderen omdat ik er nog in thuis moet geraken (2 weken geleden pas echt begonnen met Arduino IDE). Ik heb wel voorzichtig een idee hoe het ongeveer werkt wat je laat zien.

@deKees :
Bedankt voor wat je schrijft over PROGMEM. Het heeft weinig zin om dat dan te gebruiken. Ik heb nog wel een vervolgvraag. Stel ik zet de html-code in een functie. En vervolgens met een andere functie vraag ik het op en voer daar wijzigingen op uit (zoals ik voorstelde). Hoe gaat dat met / in RAM ? Is het zo dat wanneer de complete html-string(webpage) verzonden is, RAM weer wordt vrijgegeven ? Ik vraag het uit voorzorg, omdat ik dingen lees over "heap" en nog wat dingen, waar ik de ballen van snap. Waar het mij om gaat, is dat de boel niet vast gaat lopen. Een andere optie die ik heb, is om de ESP om de 24 uur te resetten, terwijl de lamp / LED uit staat. Dan merkt een gebruiker er erg weinig van, maar netjes is het niet.
Daarnaast de websites vreten erg weinig geheugen, niets aan plaatjes en ik veronderstel dat je eenmalig wat gaat instellen en daarna de boel lekker op de achtergrond laat draaien. Het is een eenvoudige timer om de lamp in/uit te schakelen.

Oei, nu wordt het ingewikkeld... :)

Een variabele wordt aangemaakt op het moment van declaratie. En de levensduur hangt af van de 'scope'.

Een globale variabele -buiten een functie gedeclareerd- blijft altijd bestaan, zolang het programma draait.

Een lokale variabele (binnen een functie gedeclareerd) bestaat totdat het 'blok' is afgelopen. Zo een variabele wordt aangemaakt op de stack van het proces (thread) dat de variabele aanmaakt.

Bijv :



int GlobalVariable = 12;   // Blijft altijd bestaan

void PrintHtml()
{
   if( ... )
   {  int LocalVariable = 10;  // Alleen binnen het if-blok
      ...
   }
}

LocalVariable kun je alleen gebruiken binnen het if-blok waar hij is gedeclareerd, en daarna is die weg (gerecycled).

De ruimte op de stack is beperkt, zeker in een klein machientje als de ESP. Hooguit een paar kilobyte, al kun je dat wel aanpassen.

De heap is een blok werk-geheugen waar je stukken uit kunt gebruiken dmv malloc(). Die blijft dan bestaan totdat je dat geheugen weer teruggeeft aan de heap dmv free(). Doorgaans gebruik je een pointer om dat geheugen te kunnen benaderen:

Bijv


void PrintHtml()
{
   if( ... )
   {  char *pData = malloc(200);

      sprintf(PData, " .. " .. );
      .. 

      free(pData);
   }
}

Hier neem je een blok van 200 bytes van de heap die je via pData kunt gebruiken. De pointer pData is een lokale variable dus die is weg aan het eind van het if-blok. Voor die tijd moet je de free() aanroepen om het blok terug tegen aan de heap. Want anders wordt dat stuk nooit meer vrijgegeven, en heb je na een tijdje geen heap meer beschikbaar.

Meestal gebruik je die malloc() en free() niet direct. Maar die zitten wel vaak ingebouwd in library funkties. Bijv als je een String declareert dan wordt daar intern een pointer gebruikt en een stuk heap geheugen gereserveerd die je mbv de String funkties kunt gebruiken. De heap van een String wordt automatisch weer vrijgegeven zodra de String out-of-scope gaat, dwz aan het eind van de if-blok. Hiervoor is een 'destructor' funktie aan de String toegevoegd.

Je kunt zo een blok trouwens ook zonder if gebruiken. Dat doe ik soms wel eens om een locale scope te definiëren.

Bijv:


void PrintHtml()
{
   {  int LocalVariable = 10;
      ...
   }

   {  int LocalVariable = 10;
      ...
   }

   {  int LocalVariable = 10;
      ...
   }
}

Hier wordt 3 keer een lokale variabele aangemaakt die telkens aan het eind van het blok (sluithaakje) weer verdwijnt. In het volgende blok kun je dan weer een nieuwe aanmaken, eventueel met dezelfde naam.

@deKees :
Ha, precies de informatie die ik zocht en helder uitgelegd. Top en bedankt !
De pagina's die ik heb gemaakt, komen amper boven de 3 kb uit. Dan kan dat -in mijn geval- dus binnen een functie, omdat de geheugenruimte na afronden van de functie weer vrij komt.

Trouwens, waarom wordt een string als "char" gedefinieerd ? Ik definieer -tot nu toe- bijvoorbeeld :


void htmlPage () {
    String htmlContent;
 
    htmlContent = "bla die bla";
    htmlContent += "nog meer bla die bla";
    // wat bewerkingen
    // zoals htmlContent.replace("Zoek dit","Vervang door dat");
}

char is een basis-type van de taal. Die staat voor 1 byte.

Een string is dan in principe een array van die bytes. Dus


   char Name[] = "Jan";

Er zijn een flink aantal library funkties om zulke strings te manipuleren. Bijv strcpy(), strcat(), sprintf(). Maar dat is allemaal nogal primitief (stamt uit het stenen tijdperk, +/- 1972).

De String die jij gebruikt bestaat niet in de taal. Maar die wordt dan weer wel via een String library toegevoegd (uit de arduino IDE). Zo een String is feitelijk een object met een hele reeks member funkties die het gemakkelijk maken om zo een String te gebruiken. Zoals heap geheugen management, zoeken, replace etc. In jouw voorbeeld zijn de "=()", de "+=()" en de replace() van die member funkties, en er zijn er nog veel meer.

Op 4 september 2023 21:14:48 schreef deKees:
[...]

Een lokale variabele (binnen een functie gedeclareerd) bestaat totdat het 'blok' is afgelopen. Zo een variabele wordt aangemaakt op de stack van het proces (thread) dat de variabele aanmaakt.

[...]

Uitzondering is dan weer een variabele gedeclareerd binnen loop().

Op 4 september 2023 20:15:51 schreef oxurane:
@buckfast_beekeeper :
OK,. interessant hoe je dat doet. Ik ga het bestuderen omdat ik er nog in thuis moet geraken (2 weken geleden pas echt begonnen met Arduino IDE). Ik heb wel voorzichtig een idee hoe het ongeveer werkt wat je laat zien.

We zijn allemaal moeten beginnen. We hebben allemaal geworsteld met bepaalde zaken.

HTML in zijn oervorm is gewoon statisch. Er gebeuren pas wijzigingen als je de pagina een refresh geeft. Alles wordt dan opnieuw opgehaald. Zijn daar plaatjes bij, dan zorg je voor zeer veel webtrafiek. Bij een server zoals bij een krant kom je dan aan gigantische volumes extra.Daar is een oplossing voor gevonden in de vorm van websockets. Die gebruiken een andere poort(81 of 8081) in plaats van 80 of 8080 voor HTML. Deze websocket wordt ook gewoon open gehouden. Zodra de server nieuwe gegevens heeft voor een bepaald item, worden deze gegevens verzonden. Al de gebruikers, die dezelfde pagina geopend hebben, krijgen gelijktijdig dezelfde nieuwe info. De webpagina verwerkt deze in een fractie. Je kan dit testen door de websocket tutorial op een ESP te zetten en meerdere pc's deze laten openen. Drukt er nu 1 cliënt op de toets aa/uit dan wordt dit naar de server gezonden, deze verwerkt dit en zend de nieuwe info door. Dus alle clients hebben altijd de correcte info binnen enkele seconden.

Dit systeem wordt ook gebruikt voor news feeds en dergelijke.

Uitzondering is dan weer een variabele gedeclareerd binnen loop().

??? loop() (uit arduino) is een gewone functie net als alle andere functies. Daar zijn geen speciale regels voor. Dus ook daar zijn de locale variabelen weg aan het einde van de loop().

Je kunt er wel voor zorgen dat een lokale variabele blijft bestaan aan het eind van blok. Als je dat wilt moet je die 'static' declareren:



void loop()
{  
   int LocalVariable = 10;   // Deze is weg aan het eind van loop()
 
   static int BlijftBestaan = 20;  // Deze blijft wel bestaan

   LocalVariabele += 1;
   BlijftBestaan  += 1;

   Serial.println(LocalVariable);  // Geeft altijd 11
   Serial.println(BlijftBestaan);  // Wordt telkens opgehoogd
} 

De scoop van de loop blijft lopen tot je de loop stopt of de stekker er uit trekt. De loop is in principe eindeloos => dat alle variabelen binnen die loop eindeloos blijven bestaan.

fout. De loop() is een gewone functie. Die wordt alleen telkens opnieuw aangeroepen. Want in de arduino libraries zit een main() functie verstopt die er ongeveer zo uitziet:


int main()
{  setup();
   for ( ;; )
   {  loop();
   }
}

Maar je kunt wel binnen de loop() weer een oneindige loop aanmaken. Dan blijft de scope inderdaad wel bestaan.

Bijv


void loop()
{
   int LocalVariable;

   for ( ;; )   // Oneindige loop
   {  ...
   }
}        // <-- hier kom je nooit. Dus de scope blijft intact.   

[Bericht gewijzigd door deKees op (37%)]

Voor de lamp is het een overbodige luxe om met meerder personen tegelijk de instellingen van de lamp aan te passen. Dat gebeurt niet. Ik bedoel, eenmaal ingesteld, laat je het lekker rustig draaien.

Er zijn maar enkele instellingen nodig. Die kunnen in EEPROM of via JSon in een "config.json". Ik krijg dat laatste nog niet goed voor elkaar. Dat komt enerzijds doordat ik op de site van ArduinoJson, wel voorbeelden zie, maar die gaan over het ophalen van data via een website, via een SD kaartje, maar ik heb nog geen voorbeelden gevonden voor de LittleFS. Op het moment dat ik dit schrijf, ben ik het voorbeeld van een SD-kaartje aan het overzetten naar LittleFS.
Anderszijds misschien omdat ik het te simpel zie (en benader zoals ik een Atmega programmeer onder Bascom).

Wat ik eigenlijk probeer is dat ik sequentieel data kan lezen / schrijven naar de config.json. Dus dat ik opgeef welk "sleutelwoord" ik zoek en vervolgens de waarde ophalen. En eventueel een gewijzigde waarde terug schrijven naar de config.json.

Basic : is bedoeld om de RTC in te stellen en of de lamp AAN / UIT is / moet.
Timer1 : Instellen welke dagen / tijden de lamp in/uit geschakeld moet worden
Wifi : Nodig bij opstarten als AP en/of Station.

En het andere is, dat ik met LittleFS de html-paginas wil opslaan. Zijn statische pagina's, die met een "replace()" een beetje flexibel is geworden.

De reden dat ik deze keer een ESP12 heb gepakt is, omdat ik het te idioot vond om een Atmega het werk te laten doen en erachter een ESP12 voor een beetje internet-functionaliteit. Dat kan volgens mij heel goed zonder een Atmega en alleen in de ESP12.

-=[ edit ]=-
En als ik bovenstaande eindelijk voor elkaar heb, dan kan het zijn dat ik (veel) later overweeg of er nog andere handige functionaliteiten bij kunnen. Voor nu is het een lamp met ingebouwde timers en dat het eventueel aangestuurd kan worden via een mobieltje. Eerst een beetje ervaring opdoen met Arduino en een ESP12. Dus, maak het me alsjeblieft niet te moeilijk : er is geen noodzaak voor nieuws / weerberichten of het loggen van meetgegevens :)

Persoonlijk zou ik starten van het websocket voorbeeld van enkele antwoorden vroeger.

De HTML pagina's aanpassen naar wens en op dezelfde wijze verder werken.

Daarna de RTC en timer functies integreren. Er is ook een library beschikbaar die je toelaat om schakelmomenten te definiëren. De naam ontgaat me nu even.

Al wat je wil bestaat al. Het is alleen nog de puzzelstukken in elkaar passen.

Beetje een k-opmerking nu nog, maar is het niet veel handiger om gewoon NTP te doen ? NTP zit tegenwoordig standaard in het Espressif SDK voor zowel ESP8266 als ESP32.

Iets van:

#include <time.h> // time() ctime()

/* Configuration of NTP */
#define MY_NTP_SERVER "at.pool.ntp.org"
#define MY_TZ "CET-1CEST,M3.5.0/02,M10.5.0/03" // gmt+1 + dst

/* NTP Globals */
time_t now; // this is the epoch
struct tm tm; // the structure tm holds time information in a more convenient way

Setup:
configTime(MY_TZ, MY_NTP_SERVER); // --> Here is the IMPORTANT ONE LINER needed in your sketch!

bool NewSecond()
{
time(&now); // read the current time
if (now == before)
{
return false;
}

before = now;
localtime_r(&now, &tm); // update the structure tm with the current time

return true;
}

void loop()
{
if (NewSecond())
{
// this is a new second...

}

In de tm-struct zit dan alle info, maand, jaar dag, etc. maar ook wday.

Nooit meer bijzetten en zomertijd wordt voor je geregeld.

Overigens bak ik tegenwoordig html middels een python script in progmem en laat ik informatie via een api of websockets via javascript in de webpagina actualiseren.

Zie ook https://github.com/GerardZ/YetAnotherWeatherStation
Hier gebruik ik ook websockets...

@oxurane: is het een tijdschakelaar die 's avonds het licht aan doet als het donker wordt en uit als het licht wordt?

Dat kan gewoon door gebruik te maken van de gegevens die beschikbaar zijn. Er zijn minstens 2 plaatsen waar je sunrise en sunset kan opvragen voor je locatie. Hoef je geen uren bij te stellen. Bij mijn kerst verlichting pas ik dat ook toe.

https://api.sunrise-sunset.org/json?lat=52.047688&lng=5.685682&date=to…

of openweather maar daar heb je een key nodig. Uiteraard uren in UTC. Ook in je RTC kan je best UTC tijd gebruiken.

@Gradtje :
Ik heb helemaal geen bezwaar tegen het aandragen van andere opties. Ik vind het juist interessant en niet k*t. Wat mijn beperking is, is dat ik niet altijd gemakkelijk informatie kan vinden met uitleg. Of nog beter, makkelijk te begrijpen voorbeelden die ik kan uitproberen. Bedenk dat ik net nieuw ben in de wereld van Arduino. Ik heb de afgelopen 2 weken aardig wat zitten stoeien. Ik moet erkennen dat het bijzonder flexibel is. Aan de andere kant erger ik me dood als ik een foutmelding krijg vanwege het vergeten van een haakje, een ";" of een accolade, of case-sensitive variabelen. Het zal ongetwijfeld een beginners-ding zijn.
Dus ik sta aan de basis en heb nog veel te leren, al begrijp ik de kracht van de Arduino.

Verder is het internet-gedeelte van dit project, niets anders dan om eventueel met een mobieltje in de woonkamer de timers in te stellen. Maar omdat de ESP ook in Station-mode kan,. nou ja, ook vanaf een thuis-netwerk vanachter de computer. Het internet-gebeuren is puur om een LCD'tje te vervangen.

buckfast-beekeeper:
In dit ontwerp heb ik inderdaad ook rekening gehouden met een aansluiting van een LDR. Echter, ik was tijdens het ontwerp vergeten om rekening te houden met de max. spanning voor de ADC : 1 Volt. Balen, maar goed, niet erg. Misschien dat ik later iets ga bedenken om dat op te lossen ipv een nieuwe pcb maken.

Aan de andere kant erger ik me dood als ik een foutmelding krijg vanwege het vergeten van een haakje, een ";" of een accolade, of case-sensitive variabelen. Het zal ongetwijfeld een beginners-ding zijn.
Dus ik sta aan de basis en heb nog veel te leren, al begrijp ik de kracht van de Arduino.

Bekend verhaal...

Het is een tikkeltje intimiderend, maar misschien moest je eens naar PlatformIO in Visual Studio Code kijken (extension). Dit is een Arduino alternatief waardoor je meteen de beschikking krijgt over een hoop tools die voor VsCode beschikbaar zijn waaronder code-checking. Deze doet suggesties voor je, waarschuwt bij fouten en geeft extra info weer zoals types welke uit functies komen en de verwachte waardes die je moet meegeven. Ook library management is beter geregeld omdat dit op project-noveau wordt gedaan.

Studio Code heeft standaard Git-integratie en honderden extensions, waarvan enkele zeer handig kunnen zijn.

Aanvankelijk is het wat groot, maar eenmaal gewend maakt het het Arduino-leven een stuk gemakkelijker.

Zo, na ruim een maand, ben ik een stuk wijzer geworden met Arduino en over de ESP8266. HTML-files opgeslagen via LittleFS, die ik inlees en bewerk met actuele data. Verder sla ik bepaalde gegevens deels op in EEPROM, deels via de RTC. Het is allemaal benaderbaar / bestuurbaar met een mobieltje.

Kortom, ik nader het einde van dit projectje. Toch zie ik nog een paar probleempjes :

1) SoftAP + Paswoord
Wanneer ik in softAP-mode start met een paswoord, blijkt dat het stationsnaam onherkenbaar te zijn geworden.

Als voorbeeld :

String AP_SSID = "DitStation";
String AP_PASS = "";           // Geen paswoord

WiFi.softAP(AP_SSID.c_str(), AP_PASS.c_str());

=> Resultaat : "DitStation" is zichtbaar.

Maar doe ik :

String AP_SSID = "DitStation";
String AP_PASS = "EenPaswoord";

WiFi.softAP(AP_SSID.c_str(), AP_PASS.c_str());

=> Resultaat : "ESPxxxxxx" is zichtbaar (xxx is een nummer).
Overigens, ik heb verder niet geprobeerd om in te loggen, omdat ik eerst wil begrijpen waar dit probleem vandaan komt.

2) https
Mijn mobieltje heeft soms de neiging om het ingevoerde IP-adres, vooraf aan te vullen met "https://".
Zoals ik heb begrepen, is https invoeren op de ESP8266 eigenlijk niet te doen. Te weinig rekenkracht. Hoe hebben jullie dat opgelost ? Of accepteer je dat het via "http://" verloopt ?

Fijn dat je er stilaan uit komt.

1) Daar loop ik ook soms tegenaan. Waarom? Zodra ze op de router zijn aangemeld krijgen ze een vast IP en concrete naam. Wat me verbaast is dat je een gedefinieerde string nog een keer moet invoeren als string


String AP_SSID = "DitStation";

WiFi.softAP(AP_SSID.c_str(), 

2) Stel eerder de vraag is het nodig dat het via https verloopt? Wat verstuur ik dat absoluut niet mag gekend zijn? Al mijn ESP zitten binnen het thuis netwerk. Iemand moet dan al op dat netwerk geraken. Er is maar 1 ESP bereikbaar van buiten het netwerk. En dan moet je de correcte poort ook nog kennen. Dat is alleszins geen 80 of 8080.

1. Wat BuckFast zegt, kan, maar ik zou dan niet verwachten dat hij dit ook als draadloos netwerk adverteert. Wellicht iets in de SDK.

2. Dit komt doordat browsers stilaan alles wat geen https als onveilig gaan bestempelen. Het zou met niet verbazen wanneer er over paar jaar alleen nog https verbindingen worden toegestaan tenzij expliciet anders aangegeven. Wel zie ik hier en daar wel uitzonderingen voor lokale netwerken.

Je schijnt wel SSL op de 8266 te kunnen doen, maar wat je al zegt, denk dat het niet erg vlot is, ik heb het nog niet geprobeerd.
Wat ik zelf doe is er HaProxy voor zetten, en die SSL te laten doen. Dus het certificaat op de HaProxy-server. Nadeel is natuurlijk dat je daar een server voor moet laten draaien. (kan gewoon op een pc of raspberry)

OK, bedankt voor de antwoorden.

Wat betreft probleem 1) : dit gebeurde terwijl er niet eens ingelogd was op een router via Station-mode. Dit gebeurde terwijl het als AccesPoint ingesteld was (en stand-alone).

Gezien de antwoorden op puntje 2) heb ik een idee hoe ik het nu ga oplossen.

Wat betreft die c_str(), dat is waarschijnlijk niet nodig. Ik had het voorheen zonder die optie gebruikt. Alleen, omdat ik het "hidden SSID"-probleem tegen kwam, ging ik dit proberen. Ik postte daarom de meest recente en gebruikte code.