stats

ESPnow Mesh

ESPnow is een energie zuinige en snelle manier om korte berichten in de WiFi band uit te wisselen tussen esp's. Door een broadcast MAC adres te gebruiken kunnen meerdere esp's tegelijk worden bereikt, echter, alle unit's moeten zich dan wel binnen het bereik van de centrale unit bevinden. Door elke unit het bericht te laten herhalen kunnen we de berichten verder verspreiden. Met een slimme timing en toepassing van light sleep kunnen indrukwekkende afstanden worden overbrugt en een aanzienlijke energie besparing.

Een slimme timing wordt bereikt door de esp's een tijdbasis te geven die is afgeleid van de millis() tijd van de basis unit. Een bericht van 32 byte waarin ook het nummer van de verzender is opgenomen, duurt met ESPnow minder dan 2mS. Alle esp's wachten gelijktijdig op dit sync signaal. Na ontvangst wordt het bericht door de unit her-uitgezonden in zijn eigen tijdslot met zichzelf als afzender. Op deze wijze wordt een bericht verspreidt zonder dat de berichten elkaar verstoren.

Wanneer unit 3 en 5 het bericht direct van unit 0 ontvangen wachten deze resp. 6 en 10 mS alvorens het bericht in tijdslot 3 en 5 te herhalen. Krijgt unit 7 het bericht via unit 5 dan zal deze het bericht in tijdslot 7 (t.o.v unit 0) herhalen. Maar wanneer unit 4 het bericht (enkel) via unit 7 verneemt kan deze het niet herhalen omdat tijdslot 4 al verstreken is. Om dit te ondervangen verloopt de tijdslot volgorde afwisselend op en aftellend en golven daarmee de berichten ook weer terug naar de bron.

Bij 14 units en een sync herhaling van 1 Sec rest een theoretische sleep tijd van 9970mS. Trekken we daar de nodige software tijd vanaf dan komen we toch nog op een energie besparing van ruim 90% voor de inactieve periodes van de esp's. De onderdelen hieronder betreft een mesh netwerk voor een regie met veertien ESP-01's in het veld.

 
// ==== RX callback routine ====
void OnDataRecv(byte *mac, byte *data, byte len) {
  if (data[0] == SYNC) {
     memcpy(&Sync, data, sizeof(Sync));
     corr = Sync.Mils + 2 - millis();
     styd = Sync.Sync - corr - 10;
     cast = Sync.Afz & 127;
     sdir = (Sync.Afz & 128);
     rcvd = true;
  }
}

// ==== Synchro routine ====
  if (rcvd && millis() > ctyd) {
    ctyd = millis() + 2;
    if (cast == Conf.Unit) SendMessage(SYNC);
    if (sdir) cast--; else cast++;
    if (cast > Conf.Umax) cast = 0;
    if (!cast) rcvd = fals;
  }
  wait = (millis() > styd);
  if (!Bussy && !rcvd && !wait) {
    Sleep(styd - millis());
  }

// ==== TX info  routine ====
void SendMessage(byte type) {
  Sync.Afz = Conf.Unit + (sdir) ? 128 : 0;
  Sync.Mils = millis() + corr;
  esp_now_send(CAST, (byte*) &Sync, sizeof(Sync));
}

// ==== light sleep function ====
void Sleep(unsigned long sleep) {
  if (sleep > 999) sleep = 999; 
  wifi_set_opmode(NULL_MODE);
  wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);
  wifi_fpm_open();
  wifi_fpm_do_sleep(sleep * 1000);
  delay(sleep);
  WiFi.mode(WIFI_STA);
}

De sleep routine wordt enkel doorlopen wanneer de unit idle is en gewacht wordt tot het sync moment aanbreekt. Zodra de nieuwe sync info binnen komt wordt de syncro routine doorlopen. Wanneer de unit weer idle is zal de sleep routine weer worden doorlopen.

Noot:

  • Door een bug in de basis software van de ESP sleepmode dient de sleep tijd opgedeeld te worden in parten van max 1 Seconde.
  • Via de RX callback routine wordt ook de basis Configuratie van de units verzorgd. De eerste parameter van de data geeft aan welk bericht type het betreft.
  • CAST is het MAC broadcast adres.
  • Bussy is de actieve 'taak' flag van de unit.
  • De Synchro routine bevindt zich in de main loop.

    Heb je vragen of opmerkingen? Stuur me een berichtje en je krijgt alle gewenste informatie!

    HOME