Skocz do zawartości
matimoto87

ESP-IoT: uniwersalne podejście do IoT z ESP8266

Pomocna odpowiedź

Napisano (edytowany)

Cześć! Przedstawiam Wam mój projekt, oparty o ESP8266, którego robocza nazwa mojego projektu to ESP-IoT i jak pewnie się domyślacie związana jest z jakże popularnym dzisiaj tematem Internetu Rzeczy. Ogólnym założeniem projektu jest stworzenie taniego ekosystemu czujników IoT, dostępnego na każdą kieszeń oraz prezentacja danych w formie wykresów. Projekt można podzielić na dwie części, hardware oparte na ESP8266 oraz software, zbierający i prezentujący zapisane dane.

Hardware
Najpopularniejszym czujnikiem dzisiejszych czasów jest chyba czujnik temperatury, dlatego właśnie mój projekt urodził się z pomysłu stworzenia prostych czujników temperatury, które mógłbym umieścić w dowolnym miejscu w domu i cieszyć oko odczytami. Tak powstał prototyp czujnika opartego o cyfrowy termometr DS18B20. Począwszy od ESP-01 skończywszy na ESP-12F zaprojektowałem płytkę drukowaną, na której znajdują się wymagane do pracy z ESP i DS18B20 elementy. Płytka zasilana jest dwoma paluszkami AA, a ich żywotność po roku testów określam na ok 3 miesiące. Nie jest to idelany wynik, ale też nie jest źle. Pierwszy prototyp powstał w czeluściach mojego warsztatu metodą termotransferu i działa do dziś 🙂 Płytka jest na maksa utleniona, ale jeszcze zipie 🙂 Wykonanie kolejnych wersji płytek zlecałem już u Chińczyków, bo koszt ich wytworzenia jest na tyle tani, że uważam że nie warto bawić się w termotransfer. Poza tym, Chińczyki bez problemu robią płytki dwustronne, a w domu uzyskać takie PCB jest trudno. Najnowsza wersja płytki PCB składa się z procesora ESP-12F, dwóch przycisków (WIFI i RESET) oraz paru najważniejszych wyprowadzeń pinów CPU. Obecnie działająca u mnie w domu wersja płytki jest starsza, trochę już zaśniedziała, ale nadal wiernie śmiga.

Schemat ideowyPłytka PCBModuł ESP-IoT

Zasada działania programu, wgranego do ESP jest bardzo prosta. Na początku wyzwalany jest portal WIFI, który ma na celu dać użytkownikowi możliwość podłączenia się do własnej sieci WIFI bez ingerencji w kod źródłowy. Do tego celu została użyta biblioteka WiFiManager. Po podłączeniu do sieci WIFI czujnik łączy się z serwerem w celu sprawdzenia, czy jest dostępna dla niego aktualizacja programowania. Zdalną aktualizację oprogramowania ESP uzyskałem dzięki delikatnie zmodyfikowanej przeze mnie bibliotece ESP8266httpUpdate. Jej modyfikacja polega na dodaniu do nagłówka http wpisu z Chip-ID, ponieważ w drugiej części projektu prowadzę pełną ewidencję wyprodukowanych czujników, partą właśnie o Chip-ID. Następnie dokonywany jest odczyt temperatury z czujnika DS18B20, po czym wartość odczytu wysyłana jest w specjalnie przygotowaną bramkę, o czym za chwilę. Po wysłaniu odczytu w świat ESP usypiane jest w trybie deepSleep, by zaoszczędzić na zużyciu baterii.

#define SOFTWARE_VERSION "1.0.3"
#define API_KEY "172ffedf-aaeb-4f75-b41a-470e7ae3a87d"

#include <WiFiManager.h>  
#include <ESP8266WiFiMulti.h>
#include <ESP8266httpUpdateMK.h>

#include <OneWire.h>
#include <DallasTemperature.h>

#define WIFI_BUTTON 12  //* GPIO12 Button for Wifi Config Portal
#define PROG_BUTTON 0   //* GPIO0  Button for flashing mode
#define LED 2           //* GPIO2  Internal LED 

#define ONE_WIRE_BUS 13 //* GPIO13 OneWire Bus
#define SLEEP_TIME 30   //* Deep Sleep Time in minutes

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);

ADC_MODE(ADC_VCC);


//--------------------------------------------
#define UPDATE_SERVER "espiot.ga"
#define UPDATE_PORT 80

#define IOT_GATEWAY  "http://espiot.ga/gateway/savedata/"
#define IOT_REVERSE  "http://espiot.ga/gateway/request/"
//--------------------------------------------


void blinkLed(int count = 1, int del = 0, int intdel = 10) {
  for (int i = 0; i < count; i++){
    digitalWrite(LED, LOW);
    delay(intdel);
    digitalWrite(LED, HIGH);
    if (del) delay(del);
  }
}

/**
 * RunWifiConfig
 * When the WIFI Button is pushed while ESP is rebooting, the WIFI Config Portal will turn on
 * 
 */
void RunWifiConfig() {
  Serial.println("[WIFI] Starting Configuration portal...");
  blinkLed(5, 500);
  WiFiManager wifiManager;
  wifiManager.resetSettings();
  String ssid = "ESP " + String(ESP.getChipId());
  if (wifiManager.startConfigPortal(ssid.c_str())) {
    ESP.restart();
  }
}

/**
 * SendHttp
 * Sending HTTP Post request to IoT Gateway 
 * 
 * @var String POST Data, bool debug (if true, UART will print HTTP payload)
 * @return null
 */
void SendHttp(String address, String _data, bool debug = false) {
  HTTPClient http;

  http.begin(address);
  http.setAuthorization(String(ESP.getChipId()).c_str(), String(API_KEY).c_str());
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");

  Serial.println("[HTTP] Sending data to IoT Gateway...");
  int httpCode = http.POST(_data);
  

  if (debug) {
    if (httpCode > 0) {
      Serial.printf("[HTTP] POST... code: %d\n", httpCode);

      if (httpCode == HTTP_CODE_OK) {
        String payload = http.getString();
        Serial.println(payload);
      }
    } else {
      Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }
  }

  http.end();
}

/**
 * CheckUpdate
 * Function that checks if there any software update to flash 
 * 
 * @var String server, Integer port, String software version
 * @return null
 */
void CheckUpdate(String server, int port, String _version) {

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("[UPDATE] Searching software update in [" + server + "]");
    ESPhttpUpdate.rebootOnUpdate(false);
    t_httpUpdate_return ret = ESPhttpUpdate.update(server, port, "/gateway/update", _version);
    switch (ret) {
      case HTTP_UPDATE_FAILED:
        Serial.print("[UPDATE] Update failed. ");
        Serial.println(ESPhttpUpdate.getLastErrorString());
        break;
      case HTTP_UPDATE_NO_UPDATES:
        Serial.println("[UPDATE] Software is up to date.");
        break;
      case HTTP_UPDATE_OK:
        blinkLed(3, 100, 500);
        Serial.println("[UPDATE] Update ok."); 
        SendHttp(IOT_REVERSE, "status=success");
        delay(1000);
        ESP.restart();
        break;
    }
  }
}

/**
 * GetVCC
 * Function return the Supply Voltage 
 * 
 * @return float
 */
float GetVCC() {
  float rawVcc = ESP.getVcc();  
  return rawVcc;
}

/**
 * GetTemp
 * Function return the Current Temperature using OneWire BUS 
 * 
 * @return float
 */
float GetTemp() {
  float temp;

  DS18B20.requestTemperatures();
  temp = DS18B20.getTempCByIndex(0);
    
  if (temp == 85) {
    GetTemp();
  } else {
    return temp;
  }
}

//-----------------------------------------------------------------------------------------------------------------------
void setup() {
  // put your setup code here, to run once:

  Serial.begin(115200);

  String _chipId  = String(ESP.getChipId()).c_str();

  Serial.println();
  Serial.println("****************************************");

  Serial.println("  ESP8266 ID:       [" + _chipId + "]");
  Serial.println("  Software version: [" + String(SOFTWARE_VERSION) + "]");
  Serial.println("  Supply Voltage:   [" + String(GetVCC()) + " mV]");
  Serial.println("  Update server:    [" + String(UPDATE_SERVER) + "]");

  Serial.println("****************************************");
  Serial.println();



  pinMode(WIFI_BUTTON, INPUT_PULLUP);
  pinMode(PROG_BUTTON, INPUT_PULLUP);
  pinMode(LED, OUTPUT);

  digitalWrite(LED, HIGH);

  if (GetVCC() < 2600.00) {
    digitalWrite(LED, LOW);
  }

  WiFi.begin();

  delay(500);

  if (digitalRead(WIFI_BUTTON) == LOW) {
    Serial.println("[WARNING] WIFI Button Pushed");
    RunWifiConfig();
  } else if (WiFi.SSID() == "") {
    Serial.println("[WARNING] WIFI Not Configured");
    RunWifiConfig();
  } else {


    Serial.print("[WIFI] Connecting to network");

    int i = 0;

    while (WiFi.status() != WL_CONNECTED && i < 10 ) {
      delay(1000);
      blinkLed();
      Serial.print(".");
      i = i + 1;
    }
    Serial.println();

    if (WiFi.status() == WL_CONNECTED) {
      Serial.print("[WIFI] Connected to " + WiFi.SSID() + ", IP Address: [");
      Serial.print(WiFi.localIP());
      Serial.println("]");
    } else {
      Serial.println("[WIFI] Not Connected... Restarting ESP...");
      ESP.restart();
    }
    Serial.println();
    CheckUpdate(UPDATE_SERVER, UPDATE_PORT, SOFTWARE_VERSION);
  }
  Serial.println();


  String temp = String(GetTemp());
  
  SendHttp(IOT_GATEWAY, "temp=" + temp + "&voltage=" + String(GetVCC()));

  Serial.println("[INFO] Temp: " + temp);
  Serial.println("[INFO] Going to sleep...");
  ESP.deepSleep(SLEEP_TIME * 60 * 1000000);
}

void loop() {
}

 

Software
W celu zbierania danych przygotowałem stronę internetową, a tak naprawdę tylko jej backend, by móc komunikować się z ESP. Roboczo nazwijmy ją bramką IoT. Czujnik komunikuje się z bramką dwa razy w trakcie jednego cyklu. Pierwszy raz sprawdza czy jest dostępna aktualizacja oprogramowania a drugi raz przekazuje odczyt temperatury. W celu zabezpieczenia się przed potencjalnymi hakierami, którzy by podszywali się pod ESP  za każdym razem sprawdzam nagłówki http, czy faktycznie rozmawiam z ESP oraz Chip-ID. Jeśli dany Chip-ID jest zarejestrowany w bazie danych, zezwalam na dalszą wymianę danych. Bramka napisana jest w PHP z użyciem mało znanego, starego, ale jakże fajnego frameworka Codeigniter. Kod źródłowy bramki dostępny jest pod tym adresem. Gdyby ktoś miał problem z odczytaniem i z rozumieniem kodu, pytajcie - wytłumaczę 🙂

 

Prezentacja danych
W związku z tym, że odczyty temperatury zapisuję w bazie danych MySQL, prezentacja danych jest dowolna. Ja obecnie używam systemu Grafana, którym łączę się do bazy MySQL i generuję wykres. Dodatkowo, mam na swoim domowym serwerze zainstalowany Homebridge, emulujący Apple’owy protokół Homekit, którym również łączę się do bazy danych, pobieram ostatni odczyt temperatury i wyświetlam w aplikacji Dom na iPhone. Dzięki temu na bieżąco znam odczyt z moich czujników J

1765049757_Screenshot_2019-07-2020_48.40_fCq1Aj.thumb.png.519a2ce2949b1638475e3f6786f4c2ad.pngIMG_0082.thumb.JPG.5aaa6f777288a55fb23b01fb0dbbc397.JPG1559239933_Screenshot_2019-07-2020_54.38_5TLGyz.thumb.png.bf1ca5f862068c83cfa87aaf37d0c464.png

Co dalej
Szerokie podejście do tematu ESP-IoT pozwoliło na stworzenie uniwersalnego narzędzia do obsługi wszelkiej maści czujników. Pierwszym pomysłem na kolejny moduł był czujnik tlenku węgla. Bramka mogłaby w przypadku występowania czadu wysłać SMS do właściciela z informacją o zagrożeniu, lecz to tylko na razie pomysł w mojej głowie. Na obecną chwilę powstało tylko parę czujników temperatury, opartych o DS18B12. Dlaczego DS a nie np DHT? Przez problem z zasilaniem. Chciałem użyć tylko dwóch paluszków i niestety ich napięcie nie wystarcza do zasilenia DHT. Czytelność oprogramowania i uniwersalność najnowszej wersji płytki pozwalana na szybkie modyfikacje, przez co każdy może we własnym zakresie, nawet na płytce prototypowej skorzystać z mojego systemu ESP-IoT. Kolejną drogą rozwoju jest uzbrojenie czujnika w akumulator litowo-jonowy i ogniwo fotowoltaiczne, w celu jak największego wydłużenia czasu pracy na baterii, ale to na razie tylko jeszcze nawet nie do końca przemyślany pomysł...

Zapraszam wszystkich do dyskusji na temat mojego rozwiązania. 

Schematic_ESP-IoT_ESP-IoT_20190720195243.png

Edytowano przez matimoto87
  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

Podoba Ci się ten projekt? Zostaw pozytywny komentarz i daj znać autorowi, że zbudował coś fajnego!

Masz uwagi? Napisz kulturalnie co warto zmienić. Doceń pracę autora nad konstrukcją oraz opisem.

Właśnie zaakceptowałem Twój opis, możesz go teraz zgłosić do akcji rabatowej umieszczając link w temacie zbiorczym. Dziękuję za przedstawienie ciekawego projektu, zachęcam do prezentowania kolejnych DIY oraz aktywności na naszym forum 🙂

Udostępnij ten post


Link to post
Share on other sites
Dnia 20.07.2019 o 20:57, matimoto87 napisał:

W celu zabezpieczenia się przed potencjalnymi hakierami, którzy by podszywali się pod ESP  za każdym razem sprawdzam nagłówki http, czy faktycznie rozmawiam z ESP oraz Chip-ID.

Łączysz się po HTTP czy HTTPS?

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Http bez s... Wiem, zabezpieczenie jak ta lala 😐 Ale to jest w sumie dobry pomysł by się tak zabezpieczyć! Dzięki za sugestię.

Edytowano przez matimoto87
  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Lepsze to niż nic :)

Udostępnij ten post


Link to post
Share on other sites

@matimoto87 jak wrażenia na temat wykorzystywania systemu Grafana? Wygląda to bardzo fajnie, obyło się bez żadnych problemów?

Udostępnij ten post


Link to post
Share on other sites
7 minut temu, Treker napisał:

jak wrażenia na temat wykorzystywania systemu Grafana

Wiesz co, wrażenia w sumie bardzo dobre. Jest to fajny, intuicyjny i przede wszystkim darmowy system, z którego na prawdę można wiele wycisnąć. W związku z tym, że dane z czujników zbieram w bazie MySQL, Grafaną łączę się do bazy i generuję prostym SQL wykres. Grafanę znałem już w sumie wcześniej, bo na niej mam uruchomiony monitoring serwerów w pracy i u klientów, wykorzystując do tego również darmowy system Zabbix, ale to temat na inną historię 🙂

1780434649_Screenshot_2019-07-2220_39.17_T4PtQ7.thumb.png.6efc64c054fd38bbd4629c8e57fedae0.png

  • Pomogłeś! 1

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

To ja się pochwalę moją zabawką na esp8266: https://solar.gato-it.pl/

Pracuję jeszcze nad opisem projektu, ale myślę, że już jest się czym pochwalić. 

ESP8266 + WiFi + router GSM + MQTT + PERL + MySQL + PHP + JSON + Ajax + Yii 😉

Edytowano przez blazeyzem
  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

Bardzo fajnie to wygląda, muszę się bliżej tym zainteresować. Brakowało mi podobnego rozwiązania do generowania niektórych statystyk - przyda się 😉

Udostępnij ten post


Link to post
Share on other sites

@Treker jeśli na tym forum jest gdzieś miejsce, gdzie mógłbym opisać Grafanę, to mogę to zrobić 🙂

  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites
11 godzin temu, matimoto87 napisał:

Grafanę znałem już w sumie wcześniej, bo na niej mam uruchomiony monitoring serwerów w pracy

Możesz coś więcej na ten temat? Przydałoby mi się coś prostego do moich maszynek...

Udostępnij ten post


Link to post
Share on other sites
8 minut temu, ethanak napisał:

Przydałoby mi się coś prostego do moich maszynek

Ojjj, monitoring serwerów na Grafanie nie jest aż taki prosty 🙂 Grafana jest narzędziem do prezentacji zebranych danych, ale sama w sobie niczego nie zbiera, dlatego do monitoringu trzeba użyć jeszcze jednego narzędzia, jakim jest Zabbix. Konfiguracja Zabbixa i wyklikanie w Grafanie dashborda jest zwyczajnie czasochłonne... Ale efekty są niezłe 😄

grafana1.thumb.jpg.cce491663ef6493f7dd5cad887dc028b.jpggrafana2.thumb.jpg.a689befd6b15c04e8d501fc1bc8d39d1.jpg

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

E tam - chodzi mi o cos innego: takie coś ładne dla szefa żeby mógł sobie włączyć i pooglądać 🙂 Zabbix to w moim przypadku przerost formy nad treścią (potrzebuję praktycznie monitorowania zajętości dysku oraz loadu systemu, ew. alertów ze SMART-a) - a tu wystarczą proste skrypty na każdej maszynie.

Udostępnij ten post


Link to post
Share on other sites

@ethanak trochę się offtop zrobił, ale w takim razie szukałbym rozwiązań opartych o WMI 🙂 Grafana sama w sobie nie ma wtyczki WMI, ale jest narządź o nazwie Prometheus, który potrafi zbierać z WMI dane, a Grafana potrafi z nim gadać.

Udostępnij ten post


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!

Gość
Napisz odpowiedź...

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