From c0bb7f6237209189d4ac986d878c27aae1a3d9b7 Mon Sep 17 00:00:00 2001 From: Thomas Ballmann Date: Sat, 29 Feb 2020 19:46:05 +0100 Subject: [PATCH] remove cloud stuff for standalone mode #16 --- .gitignore | 1 + .vscode/extensions.json | 12 ++--- .vscode/settings.json | 40 +++++++++++++- README.md | 13 ++++- app/vue.config.js | 2 +- include/download.h | 6 +++ include/faceWeather.h | 18 +++++++ platformio.ini | 10 +++- src/cloud.cpp | 7 ++- src/download.cpp | 93 ++++++++++++++++++++++++++++++++ src/faceCalendar.cpp | 44 ++++++++++----- src/faceWeather.cpp | 115 +++++++++++++++++++++++----------------- src/main.cpp | 26 +++++---- 13 files changed, 302 insertions(+), 85 deletions(-) create mode 100644 include/download.h create mode 100644 src/download.cpp diff --git a/.gitignore b/.gitignore index 95a60a9..74509fd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ .vscode/ipch .DS_Store /data/dist +/test \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 272828b..e80666b 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,7 @@ { - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ] -} \ No newline at end of file + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index a54caa7..b8cd1e2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,44 @@ "istream": "cpp", "ostream": "cpp", "sstream": "cpp", - "functional": "cpp" + "functional": "cpp", + "array": "cpp", + "bitset": "cpp", + "initializer_list": "cpp", + "regex": "cpp", + "utility": "cpp", + "deque": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "cstdint": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "limits": "cpp", + "memory": "cpp", + "new": "cpp", + "numeric": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp" } } \ No newline at end of file diff --git a/README.md b/README.md index 26e563d..9643d6e 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,15 @@ yarn --cwd app build # upload to device filesystem platformio run --target uploadfs -``` \ No newline at end of file + +# send a picture to display over json +curl -F 'myImage=@blackPNG.png' http://192.168.178.62/api/face + +# erase flash memory +pio run --target erase +``` + +## access fs over http + +> get photos from calendar face +http://192.168.178.65/fs/calendarPhoto.png \ No newline at end of file diff --git a/app/vue.config.js b/app/vue.config.js index 7638a8a..74801b4 100644 --- a/app/vue.config.js +++ b/app/vue.config.js @@ -8,7 +8,7 @@ module.exports = { devServer: { proxy: { '^/': { - target: 'http://192.168.178.62:80', + target: 'http://192.168.178.65:80', ws: true, changeOrigin: true }, diff --git a/include/download.h b/include/download.h new file mode 100644 index 0000000..093920a --- /dev/null +++ b/include/download.h @@ -0,0 +1,6 @@ +#ifndef DOWNLOAD_H +#define DOWNLOAD_H + +bool downloadFile(String url, const char *path); + +#endif \ No newline at end of file diff --git a/include/faceWeather.h b/include/faceWeather.h index 851b8fb..2dd5620 100644 --- a/include/faceWeather.h +++ b/include/faceWeather.h @@ -1,6 +1,24 @@ #ifndef FACE_WEATHER_H #define FACE_WEATHER_H +// TODO +struct faceWeatherData +{ + //char hostname[64]; + //int port; + + char current_icon[4]; + char current_description[20]; + + char location[20]; + + // current + int current_temp; + int today_min; + int today_max; + + // forecast +}; void setupFaceWeather(); void loopFaceWeather(); diff --git a/platformio.ini b/platformio.ini index 48607a4..c3d663d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -3,7 +3,13 @@ platform = espressif32 board = lolin32 framework = arduino monitor_speed = 115200 +; https://camo.githubusercontent.com/62eafe3a5c9bf3cdc31d6db740b7e58eaa1a3ab1/687474703a2f2f7777772e6275696c646c6f672e6e65742f626c6f672f77702d636f6e74656e742f75706c6f6164732f323032302f30322f6964655f73732e706e67 +; https://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables +; https://github.com/espressif/arduino-esp32/tree/master/tools/partitions +; https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/partition-tables.html +board_build.partitions = no_ota.csv +# OTA ;upload_port = 192.168.178.60 # lolin32 @@ -12,7 +18,9 @@ monitor_speed = 115200 # lolin32 lite upload_speed = 115200 -upload_port = /dev/cu.wchusbserial1460 +;upload_port = /dev/cu.wchusbserial1460 +upload_port = /dev/cu.wchusbserial1410 + lib_deps = GxEPD2@~1.2.4 diff --git a/src/cloud.cpp b/src/cloud.cpp index 2e3f686..1b7b1be 100644 --- a/src/cloud.cpp +++ b/src/cloud.cpp @@ -20,7 +20,6 @@ const char *setting_HeaderKeys[] = { // execute firmware update url "X-UpdateFirmware"}; -HTTPClient http; void requestCloud(); bool isCloudSetupComplete(); @@ -28,6 +27,8 @@ void updateInterval(unsigned long interval); void setupCloud() { +HTTPClient http; + Serial.println("setup cloud"); updateInterval(10); @@ -106,6 +107,9 @@ void updateInterval(unsigned long interval) */ void requestCloud() { + /* +HTTPClient http; + String config_Url = NVS.getString("cloud.url"); Serial.println(config_Url); @@ -260,4 +264,5 @@ void requestCloud() // clean up http.end(); + */ } \ No newline at end of file diff --git a/src/download.cpp b/src/download.cpp new file mode 100644 index 0000000..2419eee --- /dev/null +++ b/src/download.cpp @@ -0,0 +1,93 @@ +#include +#include +#include "download.h" + +HTTPClient http; + +bool downloadFile(String url, const char *path) +{ + // @note duration time: 200kb = 35sec write to flash + Serial.println("Download file: " + url); + + bool hasError = false; + String tmpFile = path; + tmpFile += ".tmp"; + + http.useHTTP10(true); // http1.1 chunked übertragung funktioniert irgendwie nicht + http.setTimeout(7000); + + http.begin(url); + int httpCode = http.GET(); + if (httpCode != HTTP_CODE_OK) + { + Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode != HTTP_CODE_OK && httpCode).c_str()); + hasError = true; + } + else + { + // track duration + long startMills = millis(); + + // get lenght of document (is -1 when Server sends no Content-Length header) + int len = http.getSize(); + + // create buffer for read + uint8_t buff[1024] = {0}; + + // get tcp stream + WiFiClient *stream = http.getStreamPtr(); + + // persist image + SPIFFS.begin(); + File file = SPIFFS.open(tmpFile, FILE_WRITE); + if (!file) + { + Serial.println("Failed to open file for writing"); + hasError = true; + } + + // read all data from server + while (http.connected() && (len > 0 || len == -1)) + { + // get available data size + size_t size = stream->available(); + + if (size) + { + // read up to xxx byte + int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); + + // write to storage + if (file) + { + file.write(buff, c); + } + + if (len > 0) + { + len -= c; + } + } + + delay(1); + } + + // done + if (file) + { + file.close(); + SPIFFS.remove(path); + SPIFFS.rename(tmpFile, path); + + SPIFFS.end(); + } + + Serial.print("download completed in: "); + Serial.println(millis() - startMills); + } + + // clean up + http.end(); + + return !hasError; +} \ No newline at end of file diff --git a/src/faceCalendar.cpp b/src/faceCalendar.cpp index c819047..98fc610 100644 --- a/src/faceCalendar.cpp +++ b/src/faceCalendar.cpp @@ -1,23 +1,27 @@ +#include +#include +#include #include "faceCalendar.h" #include "display.h" #include "datetime.h" -#include "SPIFFS.h" -#include "pngle.h" #include "tools.h" +#include "image.h" +#include "download.h" #include // weekday - month year #include // current day void downloadRandomePicture(); +void showFaceCalendar(); void display_calender(); void display_picture(); void display_time(); void on_draw2(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]); -using std::uint8_t; +const char faceCalendarPicture[] = "/calendarPhoto.png"; + // TODO use dynamic display width static constexpr int MAX_WIDTH = 640 - 250; -static constexpr int MAX_HEIGHT = 384; static int16_t curRowDelta[MAX_WIDTH + 1]; static int16_t nextRowDelta[MAX_WIDTH + 1]; @@ -27,22 +31,20 @@ void setupFaceCalendar() void loopFaceCalendar() { - EVERY_N_SECONDS(300) - { - Serial.println("TODO download new image"); - } - + // TODO update picture every x seconds + showFaceCalendar(); +} +void showFaceCalendar() +{ display.setRotation(0); display.setFullWindow(); display.firstPage(); display.fillScreen(GxEPD_WHITE); - // draw... display_picture(); display_calender(); - Serial.println("displayFlush"); display.nextPage(); } @@ -50,7 +52,21 @@ void downloadRandomePicture() { // https://images.unsplash.com/photo-1580886349729-1bd109928600?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjExMDM0OH0&w=640&h=200&fm=png&fit=crop // https://images.unsplash.com/photo-1580886349729-1bd109928600?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjExMDM0OH0&w=390&h=384&fm=png&fit=crop&colorquant=2 + // https://images.unsplash.com/photo-1581307385098-a0338263e357?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjExMDM0OH0&w=640&h=384&fm=png&fit=crop&duotone=000000,FFFFFF // final filter: &w=390&h=384&fm=png&fit=crop&duotone=000000,FFFFFF + Serial.println("TODO download new image"); + + // TODO download json file + + String pictureUrl = "https://images.unsplash.com/photo-1582910587039-b4f085805c86?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjExMDM0OH0"; + pictureUrl += "&w=390&h=384"; // size + pictureUrl += "&fm=png"; // format + pictureUrl += "&fit=crop"; // crop to needed size + pictureUrl += "&duotone=000000,FFFFFF"; // grayscale to save bytes + + downloadFile(pictureUrl, faceCalendarPicture); // /face/calendar/bg.png + + Serial.println("TODO download new image ---- done"); } void display_calender() @@ -129,7 +145,7 @@ void display_picture() pngle_t *pngle = pngle_new(); pngle_set_draw_callback(pngle, on_draw2); - File file = SPIFFS.open("/calendarPhoto.png", "r"); + File file = SPIFFS.open(faceCalendarPicture, "r"); if (!file) { Serial.println(" file not found"); @@ -143,12 +159,14 @@ void display_picture() } file.close(); + /* Serial.print(" width: "); Serial.print(pngle_get_width(pngle)); Serial.print(" height: "); Serial.println(pngle_get_height(pngle)); - Serial.println(" read png done"); + */ + pngle_destroy(pngle); } diff --git a/src/faceWeather.cpp b/src/faceWeather.cpp index d48871f..1070393 100644 --- a/src/faceWeather.cpp +++ b/src/faceWeather.cpp @@ -1,11 +1,16 @@ #include -#include +#include #include "faceWeather.h" #include "faceWeatherIcons.h" #include "display.h" +#include "download.h" #include // current day +const char faceWeatherCurrent[] = "/weatherCurrent.json"; +const char faceWeatherForecast[] = "/weatherForecast.json"; +faceWeatherData weatherData; + // TODO use theme color void display_current(); @@ -15,6 +20,27 @@ void setupFaceWeather() { } +void updateData() +{ + String url; + // http://api.openweathermap.org/data/2.5/weather?id=2766824&APPID=883b3c87223430d6f3a399645f8ba12b&lang=de&cnt=3&units=metric + // http://api.openweathermap.org/data/2.5/forecast?id=2766824&APPID=883b3c87223430d6f3a399645f8ba12b&lang=de + + // https://openweathermap.org/current + url = "http://api.openweathermap.org/data/2.5/weather?"; + url += "APPID=883b3c87223430d6f3a399645f8ba12b"; // api key + url += "&id=2766824"; // location + url += "&lang=de&units=metric"; // settings + downloadFile(url, faceWeatherCurrent); + + // https://openweathermap.org/forecast5 + url = "http://api.openweathermap.org/data/2.5/forecast?"; + url += "APPID=883b3c87223430d6f3a399645f8ba12b"; // api key + url += "&id=2766824"; // location + url += "&lang=de&cnt=3&units=metric"; // settings + downloadFile(url, faceWeatherForecast); +} + void loopFaceWeather() { display.setRotation(0); @@ -24,15 +50,12 @@ void loopFaceWeather() display.setTextColor(GxEPD_WHITE); display.setTextSize(1); - display_current(); display_forecast(); - display.nextPage(); } - void display_current() { // temperature @@ -42,19 +65,17 @@ void display_current() display.println("3°"); // icon - const uint *icon = getIconById("02n", 192); // 192 + const uint *icon = getIconById("02n", 192); // 192 if (icon) { display.drawBitmap(272, 30, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE); } - // text display.setTextSize(1); display.setCursor(400, 300); //display.println("Ein paar Wolken"); - // high display.setTextSize(1); display.setCursor(500, 30); @@ -63,10 +84,8 @@ void display_current() // low display.setCursor(500, 60); display.println("-3°"); - } - void display_forecast() { const uint *icon; @@ -79,70 +98,66 @@ void display_forecast() display.drawLine(420, 250, 420, 384, GxEPD_WHITE); // 210 per block - // day +1 icon = getIconById("03d", 96); if (icon) { - display.drawBitmap(0 +57, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE); + display.drawBitmap(0 + 57, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE); } - // day +2 icon = getIconById("09d", 96); if (icon) { - display.drawBitmap(210 +57, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE); + display.drawBitmap(210 + 57, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE); } - // day +3 icon = getIconById("13d", 96); if (icon) { - display.drawBitmap(410 +57, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE); + display.drawBitmap(410 + 57, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE); } - } - -/* -bool loadWeatherData(const char *type) +void loadConfiguration() { - HTTPClient http; - String url = "http://api.openweathermap.org/data/2.5/forecast?"; // weather | forecast - url += "id=2766824"; - url += "&lang=de"; - url += "&cnt=3"; - url += "&units=metric"; - url += "&APPID=883b3c87223430d6f3a399645f8ba12b"; - // "/data/2.5/" + RequestType + "?q=" + City + "," + Country + "&APPID=" + apikey + "&mode=json&units=" + units + "&lang=" + Language; - - //http.begin(client, server, 80, uri); - - http.begin(url); - int httpCode = http.GET(); - if (httpCode != HTTP_CODE_OK) + SPIFFS.begin(); + File file; + DeserializationError error; + + // current weather + file = SPIFFS.open(faceWeatherCurrent); + StaticJsonDocument<976> docCurrent; // Use arduinojson.org/v6/assistant to compute the capacity. + error = deserializeJson(docCurrent, file); + if (error) { - Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode != HTTP_CODE_OK && httpCode).c_str()); + Serial.println(F("Failed to read file, using default configuration")); } - else + + // TODO Copy values from the JsonDocument to the Config + weatherData.current_temp = 12; + + /* + config.port = doc["port"] | 2731; + strlcpy(config.hostname, // <- destination + doc["hostname"] | "example.com", // <- source + sizeof(config.hostname)); // <- destination's capacity + */ + file.close(); + + // forecast + file = SPIFFS.open(faceWeatherForecast); + StaticJsonDocument<2180> docForecast; // Use arduinojson.org/v6/assistant to compute the capacity. + error = deserializeJson(docForecast, file); + if (error) { - // TODO read... - - DynamicJsonDocument doc(1024 * 35); - DeserializationError error = deserializeJson(doc, http.getStream()); - if (error) - { - Serial.print(F("deserializeJson() failed with code ")); - Serial.println(error.c_str()); - return false; - } - - JsonObject root = doc.as(); + Serial.println(F("Failed to read file, using default configuration")); } - http.end(); -} + // TODO get values + + file.close(); -*/ \ No newline at end of file + SPIFFS.end(); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 8c9870d..73ad123 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,17 +4,17 @@ #include "wlan.h" #include "display.h" #include "settings.h" -#include "cloud.h" +//#include "cloud.h" +#include "datetime.h" +#include "playlist.h" #include "app.h" #include "imagePNG.h" #include "imageWBMP.h" - void gotoDeepSleep(); String getWakeupReason(); - void setup() { // put your setup code here, to run once: @@ -26,18 +26,21 @@ void setup() Serial.println(); setupDisplay(); - - //setupImagePNG(); - //setupImageWBMP(); - setupSettings(); setupDevice(); setupWlan(); - if (wlan_isConnected()) { - setupCloud(); + if (!setupDateTime()) + { + // re-try + setupDateTime(); + } + + setupPlaylist(); + + //setupCloud(); } setupApp(); @@ -52,8 +55,9 @@ void loop() if (wlan_isConnected()) { - loopCloud(); + loopPlaylist(); + //loopCloud(); } - loopDevice(); + //loopDevice(); } \ No newline at end of file