====== Zadanie ====== Navrhněte zařízení sloužící k zobrazování informací na e-ink displeji Waveshare. Informace ke zobrazení se budou přenášet z PC pomocí zvoleného komunikačního rozhraní. Pokuste se dosáhnout co nejnižší spotřeby celého zařízení. ====== Úvod ====== Elektronický papier (ePaper) alebo e-ink displej je plochá zobrazovacia jednotka, ktorá odráža svetlo ako normálny papier a je schopná uchovať zobrazenie bez spotreby elektrickej energie. Pre svoju nízku energetickú náročnosť je vhodný pre použitie v batériovo napájaných vstavaných zariadeniach prepojených s internetom **IoT** (angl. //Internet of Things// - **internet vecí**). Cieľom tohto projektu je navrhnúť jednoduchý informačný panel s e-ink displejom pre zobrazovanie informácií, ako napr.: * Počasie, kalendár... * Emailové notifikácie, notifikácie sociálnych sietí... * Akýkoľvek užívateľom zvolený informačný text/obrázok. ---- ====== Vývojový hardware ====== ===== ESP32-DevKitC ===== [[http://espressif.com/en/products/hardware/esp32-devkitc/overview|ESP32-DevKitC]] je malá vývojová doska založená na obvode ESP32 firmy Espressif. Ide o cenovo dostupný SoC obvod, ktorý okrem iných obsahuje: dvojjadrový 32-bitový Xtensa LX6 mikroprocesor, Ultra-Low-Power koprocesor, 520k RAM, 34 GPIOs, 7 ADC, WiFi 802.11b/g/n/e/i, Bluetooth LE a. i. Vývojová doska ESP32-DevKitC navyše obsahuje prevodník USB/sériová linka CP2102 pre programovanie a komunikáciu s počítačom. {{:2017:e-ink:esp32_features.jpg?400 |}}{{:2017:e-ink:esp32-devkitc.jpg?400 |}} ===== Waveshare 4.2inch e-Paper Module ===== Ide o modul s 4,2" e-ink displejom a vstavaným COG kontrolérom. Jeho kľúčové vlastnosti sú: * Rozlíšenie: 400*300 pixelov. * Farebné rozlíšenie: čiernobiele (BW). * Komunikačné rozhranie: 3-wire SPI/4-wire SPI. * Bez možnosti čiastočnej obnovy zobrazenia (//partial refresh//). {{:2017:e-ink:4.2inch-e-paper-module-5.jpg?400 |}} ---- ====== Software ====== Softwareu pre obvod ESP32 bol realizovaný vo vývojovom prostredí Visual Studio Code s nainštalovaným cross-platformovým IDE [[http://platformio.org|PlatformIO]], ktorého súčasťou je framework [[https://github.com/espressif/esp-idf/releases|esp-idf]] dodávaný firmou Espressif. ==== Ovládanie e-ink displeja ==== Knižnica funkcií ''epd4in2.h'' pre ovládanie e-ink displeja bola vytvorená na základe knižnice v [[https://www.waveshare.com/wiki/File:4.2inch_e-paper_module_code.7z|demo aplikácii]], ktorú však bolo potrebné vo veľkej miere prispôsobiť obvodu ESP32. Jej hlavné funkcie sú: // Funkcia pre inicializáciu displeja void EPD_Init(); // Funkcia, kt. čaká, pokiaľ je v aktívnej úrovni BUSY signál displeja void EPD_WaitUntilIdle(); // Funkcia pre zaslanie frameu a jeho zobrazenie (aktualizácia displeja) void EPD_DisplayFrame(const uint8_t *frame); // Funkcia pre uvedenie displeja do režimu hlbokého spánku void EPD_Sleep(); Buffer ''frame_buffer''pre dáta k zobrazeniu na displeji je potrebné alokovať hneď na začiatku hlavnej funkcie ''app_main()''. Parameter ''MALLOC_CAP_DMA'' zabezpečuje, že alokovaný pamäťový priestor je dostupný cez DMA, ktorú využíva SPI driver obvodu ESP32. frame_buffer = pvPortMallocCaps((EPD_WIDTH * EPD_HEIGHT / 8), MALLOC_CAP_DMA); ---- ==== Počasie z OpenWeatherMap ==== Aktuálne počasie program sťahuje pomocou http GET requestu zo servera [[http://openweathermap.org]]. Využíva sa lwIP stack a sieľový socket. #define WEB_SERVER "api.openweathermap.org" #define WEB_PORT (80) #define WEB_URL "http://api.openweathermap.org/data/2.5/weather?q=Brno,cz&units=metric&appid=" static const char *REQUEST = "GET " WEB_URL " HTTP/1.0\r\n" "Host: "WEB_SERVER"\r\n" "User-Agent: esp-idf/1.0 esp32\r\n" "Connection: close\r\n" "\r\n"; Odpoveď zo servera sú dáta o aktuálnom počasí pre požadované mesto vo formáte JSON. Príklad: ''{"coord":{"lon":16.61,"lat":49.19},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"base":"stations","main":{"temp":-2.53,"pressure":1027,"humidity":86,"temp_min":-3,"temp_max":-2},"visibility":10000,"wind":{"speed":5.1,"deg":70},"clouds":{"all":90},"dt":1515949200,"sys":{"type":1,"id":5899,"message":0.0074,"country":"CZ","sunrise":1515912197,"sunset":1515943367},"id":3078610,"name":"Brno","cod":200}'' Pre ďalšie spracovanie je potrebné tieto dáta rozparsovať. Za týmto účelom bola s použitím knižnice ''cJSON.h'' vytvorená funkcia ''parseWeatherData'', ktorá zo vstupného JSON reťazca vyextrahuje údaje o teplote, atmosférickom tlaku, relatívnej vlhkosti, rýchlosti vetra a relatívnej oblačnosti.' /* Read HTTP response */ bzero(recv_buf, sizeof(recv_buf)); r = read(s, recv_buf, sizeof(recv_buf) - 1); recv_buf[r] = '\0'; ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d\r\n\r\n", r, errno); close(s); char *weather_json = (char *)strstr(recv_buf, "{"); if (parseWeatherData(weather_json, &weather)) { ESP_LOGE(TAG, "Failed to parse weather JSON...\r\n"); }; int parseWeatherData(const char * const weatherString, weather_data_t * const parsedWeather) { const cJSON *mainObj = NULL; const cJSON *temperature = NULL; const cJSON *pressure = NULL; const cJSON *humidity = NULL; const cJSON *wind = NULL; const cJSON *speed = NULL; const cJSON *clouds = NULL; const cJSON *all = NULL; cJSON *weather_json = cJSON_Parse(weatherString); if (weather_json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { printf("Error before: %s\r\n", error_ptr); return 1; }; }; mainObj = cJSON_GetObjectItem(weather_json, "main"); temperature = cJSON_GetObjectItem(mainObj, "temp"); pressure = cJSON_GetObjectItem(mainObj, "pressure"); humidity = cJSON_GetObjectItem(mainObj, "humidity"); wind = cJSON_GetObjectItem(weather_json, "wind"); speed = cJSON_GetObjectItem(wind, "speed"); clouds = cJSON_GetObjectItem(weather_json, "clouds"); all = cJSON_GetObjectItem(clouds, "all"); parsedWeather->temp = temperature->valuedouble; parsedWeather->pressure = (uint16_t)pressure->valueint; parsedWeather->humidity = (uint8_t)humidity->valueint; parsedWeather->windSpeed = speed->valuedouble; parsedWeather->clouds = all->valueint; cJSON_Delete(weather_json); return 0; ---- ===== Čas a dátum pomocou SNTP ===== Aktuálny čas a dátum, určený pre zobrazenie poslednej aktualizácie displeja, program nastavuje pomocou protokolu SNTP. static void initialize_sntp(void) { ESP_LOGI(TAG, "Initializing SNTP"); sntp_setoperatingmode(SNTP_OPMODE_POLL); sntp_setservername(0, "pool.ntp.org"); sntp_init(); } static int obtain_time(void) { int res = 1; xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); initialize_sntp(); // wait for time to be set int retry = 0; const int retry_count = 30; time(&time_now); tm_info = localtime(&time_now); while(tm_info->tm_year < (2016 - 1900) && ++retry < retry_count) { ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); vTaskDelay(500 / portTICK_RATE_MS); time(&time_now); tm_info = localtime(&time_now); } if (tm_info->tm_year < (2016 - 1900)) { ESP_LOGI(TAG, "System time NOT set."); res = 0; } else { ESP_LOGI(TAG, "System time is set."); } return res; } ---- ===== Formátovanie výstupu na displej ===== K formátovaniu výstupov na displej bola využitá knižnica ''epdpaind.h'' z [[https://www.waveshare.com/wiki/File:4.2inch_e-paper_module_code.7z|demo aplikácie]]. Táto knižnica poskytuje základné funkcie pre vykreslenie základných geometrických tvarov a textu s využitím jednoduchých fontov z knižnice ''fonts.h''. Väčšie možnosti poskytuje napr. v závere projektu objavená knižnica [[https://github.com/loboris/ESP32_ePaper_example|ESP32_ePaper_example]]. sprintf(tmp_buff, "Waiting for weather..."); Paint_DrawStringAt(&paint, 20, 60, tmp_buff, &Font16, UNCOLORED); sprintf(tmp_buff, "Current Weather in Brno:"); Paint_DrawStringAt(&paint, 20, 120, tmp_buff, &Font20, COLORED); sprintf(tmp_buff, "Temperature: %2.2f *C", weather.temp); Paint_DrawStringAt(&paint, 20, 140, tmp_buff, &Font16, COLORED); sprintf(tmp_buff, "Pressure: %4d hPa", weather.pressure); Paint_DrawStringAt(&paint, 20, 160, tmp_buff, &Font16, COLORED); sprintf(tmp_buff, "Humidity: %3d %%", weather.humidity); Paint_DrawStringAt(&paint, 20, 180, tmp_buff, &Font16, COLORED); sprintf(tmp_buff, "Wind speed: %2.2f m/s", weather.windSpeed); Paint_DrawStringAt(&paint, 20, 200, tmp_buff, &Font16, COLORED); sprintf(tmp_buff, "Cloudiness: %3d %%", weather.clouds); Paint_DrawStringAt(&paint, 20, 220, tmp_buff, &Font16, COLORED); time(&time_now); tm_info = localtime(&time_now); sprintf(tmp_buff, "Last update: Date: %02d.%02d.%04d at %02d:%02d:%02d ", tm_info->tm_mday, tm_info->tm_mon + 1, tm_info->tm_year + 1900, tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec ); Paint_DrawStringAt(&paint, 20, 281, tmp_buff, &Font12, COLORED); EPD_DisplayFrame(frame_buffer); EPD_WaitUntilIdle(); Po aktualizácii zobrazenia je možné displej aj obvod ESP32 uviesť do režimu hlbokého spánku. U displeja sa toho dosiahne odoslaním potrebných príkazov volaním funkcie ''EPD_Sleep''. U obvodu ESP32 bolo v pláne využiť funkciu ''esp_deep_sleep'', ktorá obvod uvedie do režimu hlbokého spánku na stanovenú dobu, po ktorej sa opäť automaticky preberie a vykoná svoju funkciu. ---- ====== Záver ====== Výsledkom riešenia projektu je informačný panel, ktorý zobrazuje informácie o aktuálnom počasí v užívateľom definovanom meste. Dáta vo formáte JSON sú získavané prostredníctvom http protokolu zo servera ''openweathermap.org''. Tie sú následne rozparsované a naformátované do výstupného frameu, ktorý je odoslaný do e-ink displeja prostredníctvom SPI rozhrania a zobrazený. Funkčnosť je možné overiť vo [[https://drive.google.com/open?id=1Qaca2lGZD5fkr57FlzeoJnUczxQI-132|videoukážke]]. Po úspešnom zobrazení aktuálneho počasia je displej uvedený do režimu hlbokého spánku, nie však obvod ESP32, nakoľko po prebudení z režimu hlbokého spánku (po volaní funkcie ''esp_deep_sleep'') došlo k nešpecifikovanej chybe vedúcej k zlyhaniu programu, ktorá pre časovú tieseň v závere projektu dosiaľ nebola odladená Definíciu mesta, pre ktoré sa má zobrazovať počasie, ako aj prístupových údajov do WiFi siete, do ktorej má byť obvod pripojený, API kľúča pre OpenWeatherMap a iných parametrov, je nutné vykonať priamo v zdrojovom kóde programu obvodu. Z dôvodu nutnosti zoznámiť sa s novým obvodom a jeho funkciami, vývojovým prostredím a preštudovať pomerne veľké množstvo dokumentácie, nezostal v rámci projektu čas na pôvodný zámer, ktorým bolo vykonávať všetku konfiguráciu prostredníctvom web stránky (bootstrap). Toto, spolu s ďalšími vecami, ako napr. rozšírenie zobrazenia o predpoveď počasia, jednoduché piktogramy, emailové notifikácie a pod., zostáva námetom pre ďalšiu prácu. [[https://drive.google.com/file/d/1Pg3luJ6izvvT_yll_Dd6A-uz28w3Sixp/view?usp=sharing|Zdrojové súbory]] ---- ====== Zdroje ====== KOLBAN, Niel. //Kolban's book on ESP32// [[https://leanpub.com/ESP8266_ESP32]]\\ [[https://github.com/loboris/ESP32_ePaper_example]]\\ [[https://openweathermap.org/current]]\\ [[https://www.waveshare.com/wiki/4.2inch_e-Paper_Module]]