diff --git a/app/src/App.vue b/app/src/App.vue
index ae6eec1..eba3e4b 100644
--- a/app/src/App.vue
+++ b/app/src/App.vue
@@ -1,74 +1,83 @@
-
-
-
-
- update in 2min
-
-
-
-
+
+
+
+
+
-
-
-
- paperdash.io
-
-
- display
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+ paperdash.io
+
+
+ display
+
+
+
-
-
-
-
-
+
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/api/core.js b/app/src/api/core.js
deleted file mode 100644
index 7dd5a1c..0000000
--- a/app/src/api/core.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Mocking client-server processing
- */
-
-const _settings = {
- // connected wifi
- "wifi_ssid": "",
-
- // oparation mode
- "device_mode": "active",
-
- // Set rotation setting for display
- // 0 thru 3 corresponding to 4 cardinal rotations
- "device_rotation": 0,
-
- // deep sleep timer
- "cloud_refresh": 97
-}
-
-import axios from 'axios'
-
-export default {
-
- /**
- * @param cb
- * @returns {PromiseLike | Promise}
- */
- getSettings(cb) {
-
- return _settings
-
- return axios
- .get('/api/settings')
- .then(response => cb(response.data))
- }
-}
diff --git a/app/src/api/device.js b/app/src/api/device.js
new file mode 100644
index 0000000..60dcf56
--- /dev/null
+++ b/app/src/api/device.js
@@ -0,0 +1,80 @@
+/**
+ * Mocking client-server processing
+ */
+
+// eslint-disable-next-line
+const _settings = {
+ // connected wifi
+ "wifi_ssid": "",
+
+ // oparation mode
+ "device_mode": "active",
+
+ // Set rotation setting for display
+ // 0 thru 3 corresponding to 4 cardinal rotations
+ "device_rotation": 0,
+
+ // clound server endpoint
+ "cloud_server": ""
+}
+
+// eslint-disable-next-line
+const _wifiScan = [{ "rssi": -59, "ssid": "xd-design.info", "bssid": "38:10:D5:34:80:1B", "channel": 11, "secure": 3 }, { "rssi": -75, "ssid": "FRITZ!Box 7430 JI", "bssid": "38:10:D5:5D:FE:7C", "channel": 1, "secure": 3 }, { "rssi": -87, "ssid": "Vodafone Hotspot", "bssid": "AA:0E:14:BD:50:ED", "channel": 1, "secure": 0 }, { "rssi": -88, "ssid": "WLAN-548426", "bssid": "E0:60:66:55:7F:C5", "channel": 1, "secure": 3 }, { "rssi": -89, "ssid": "Familie Kalinowski", "bssid": "C8:0E:14:BD:50:ED", "channel": 1, "secure": 3 }, { "rssi": -91, "ssid": "WLAN-507287", "bssid": "E0:60:66:48:6C:6B", "channel": 1, "secure": 3 }, { "rssi": -94, "ssid": "TP-LINK_7238", "bssid": "A4:2B:B0:D8:72:38", "channel": 3, "secure": 3 }]
+
+import axios from 'axios'
+
+export default {
+
+ /**
+ * @param cb
+ * @returns {PromiseLike | Promise}
+ */
+ getSettings(cb) {
+ return axios
+ .get('/api/settings')
+ .then(response => cb(response.data))
+ },
+
+
+ /**
+ * @returns {IDBRequest | Promise}
+ */
+ putSettings(settings, cb) {
+ return axios
+ .put('/api/settings', settings, {
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(response => cb(response.data))
+ },
+
+
+ /**
+ * scan for wifi in range
+ * @param {*} cb
+ */
+ wifiScan(cb) {
+ return cb(_wifiScan)
+
+ // eslint-disable-next-line
+ return axios
+ .get('/api/wifi/scan')
+ .then(response => cb(response.data))
+ },
+
+
+
+ wifiConnect(ssid, password, cb) {
+ return axios
+ .put('/api/wifi/connect', {
+ ssid: ssid,
+ password: password
+ }, {
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(response => cb(response.data))
+ }
+}
diff --git a/app/src/main.js b/app/src/main.js
index 87edff9..e08ab80 100644
--- a/app/src/main.js
+++ b/app/src/main.js
@@ -8,5 +8,5 @@ Vue.config.productionTip = false
new Vue({
vuetify,
router,
- render: h => h(App)
+ render: h => h(App)
}).$mount('#app')
diff --git a/app/src/router/index.js b/app/src/router/index.js
index 39a10f9..14c29e5 100644
--- a/app/src/router/index.js
+++ b/app/src/router/index.js
@@ -3,6 +3,7 @@ import VueRouter from 'vue-router'
const Dashboard = () => import(/* webpackChunkName: "dashboard" */ '../views/Dashboard')
const Settings = () => import(/* webpackChunkName: "settings" */ '../views/Settings')
+const Wifi = () => import(/* webpackChunkName: "wifi" */ '../views/Wifi')
const Sandbox = () => import(/* webpackChunkName: "sandbox" */ '../views/Sandbox')
@@ -12,6 +13,7 @@ export default new VueRouter({
routes: [
{ path: '/', component: Dashboard },
{ path: '/settings', component: Settings },
+ { path: '/wifi', component: Wifi },
{ path: '/sandbox', component: Sandbox },
{ path: '*', redirect: '/' }
diff --git a/app/src/views/Dashboard.vue b/app/src/views/Dashboard.vue
index 62a68d4..b887505 100644
--- a/app/src/views/Dashboard.vue
+++ b/app/src/views/Dashboard.vue
@@ -18,4 +18,4 @@
+
\ No newline at end of file
diff --git a/app/src/views/Settings.vue b/app/src/views/Settings.vue
index ec7dabc..99e8210 100644
--- a/app/src/views/Settings.vue
+++ b/app/src/views/Settings.vue
@@ -1,18 +1,88 @@
-
- settings...
-
+
+
+
+
+
+
+
+
+
+
+
+ i8n:saved
+
+
+
+
+
+
+
+
+ i8n:save
+
+
+
+
+
+
+
diff --git a/app/src/views/Wifi.vue b/app/src/views/Wifi.vue
new file mode 100644
index 0000000..0680108
--- /dev/null
+++ b/app/src/views/Wifi.vue
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ i8n:saved
+
+
+
+
+
+ {{ wifiConnectSSID }}
+
+
+
+
+
+
+
+
+ i8n:Cancel
+ i8n:Connect
+
+
+
+
+
+
+ Wifi found
+
+
+
+
+
+
+
+
+
+
+
+ {{ wifi.channel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/vue.config.js b/app/vue.config.js
index 0500e4f..475a541 100644
--- a/app/vue.config.js
+++ b/app/vue.config.js
@@ -1,8 +1,17 @@
module.exports = {
- "outputDir": "../data/dist",
+ "outputDir": "../data/dist",
"filenameHashing": false,
"productionSourceMap": false,
- "transpileDependencies": [
- "vuetify"
- ]
+ "transpileDependencies": [
+ "vuetify"
+ ],
+ devServer: {
+ proxy: {
+ '^/api': {
+ target: 'http://192.168.178.65:80',
+ ws: true,
+ changeOrigin: true
+ },
+ }
+ }
}
\ No newline at end of file
diff --git a/src/app.cpp b/src/app.cpp
index 3381271..ab72c1a 100644
--- a/src/app.cpp
+++ b/src/app.cpp
@@ -4,9 +4,7 @@
#include "AsyncJson.h"
#include "ArduinoJson.h"
#include "settings.h"
-
-// https://techtutorialsx.com/2018/09/17/esp32-arduino-web-server-serving-external-css-file/
-// https://docs.platformio.org/en/latest/platforms/espressif8266.html#uploading-files-to-file-system-spiffs
+#include "device.h"
AsyncWebServer server(80);
@@ -14,17 +12,18 @@ void setupSettingsGet();
void setupSettingsPost();
void setupWifiScan();
void setupWifiConnect();
+void setupCurrentImage();
void setupApp()
{
Serial.println("setup configure");
- if (!SPIFFS.begin()) {
+ if (!SPIFFS.begin())
+ {
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
-
// @see https://github.com/me-no-dev/ESPAsyncWebServer
// @see https://arduinojson.org/v6/assistant/
@@ -32,27 +31,26 @@ void setupApp()
server
.serveStatic("/", SPIFFS, "/dist/")
.setDefaultFile("index.html")
- .setCacheControl("max-age=600")
- ;
+ .setCacheControl("max-age=600");
setupSettingsGet();
setupSettingsPost();
setupWifiScan();
setupWifiConnect();
-
+ setupCurrentImage();
// TODO response
- server.on("/test", HTTP_GET, [] (AsyncWebServerRequest *request) {
+ server.on("/stats", HTTP_GET, [](AsyncWebServerRequest *request) {
AsyncResponseStream *response = request->beginResponseStream("application/json");
-
DynamicJsonDocument root(1024);
+
root["heap"] = ESP.getFreeHeap();
- root["ssid"] = WiFi.SSID();
+ root["wifi"] = WiFi.SSID();
+ root["sleep"] = 97;
serializeJson(root, *response);
request->send(response);
- });
-
+ });
// CORS
//DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
@@ -61,120 +59,141 @@ void setupApp()
Serial.println("setup configure - done");
}
-
void setupSettingsGet()
{
- server.on("/api/settings", HTTP_GET, [] (AsyncWebServerRequest *request) {
+ server.on("/api/settings", HTTP_GET, [](AsyncWebServerRequest *request) {
AsyncResponseStream *response = request->beginResponseStream("application/json");
-
DynamicJsonDocument root(1024);
- //root["heap"] = ESP.getFreeHeap();
- // NVS.getString("wifi_ssid");
- root["wifi_ssid"] = NVS.getString("wifi_ssid"); // WiFi.SSID();
- root["device_mode"] = "active";
+
+ //root["wifi_ssid"] = NVS.getString("wifi_ssid");
+ root["device_mode"] = NVS.getString("device_mode");
root["device_rotation"] = 0;
- root["cloud_refresh"] = 97; // aktueller sleep timer
+ root["cloud_server"] = NVS.getString("cloud_server");
serializeJson(root, *response);
request->send(response);
- });
-
+ });
}
-
void setupSettingsPost()
{
- AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/api/settings", [](AsyncWebServerRequest *request, JsonVariant &json) {
- JsonObject jsonObj = json.to();
-
- Serial.println("/api/settings");
-
- NVS.setString("wifi_ssid", jsonObj["wifi_ssid"], true);
-
-
-/*
- char hostname[64];
-
- strlcpy(hostname, // <- destination
- jsonObj["wifi_ssid"] | "example.com", // <- source
- sizeof(hostname)); // <- destination's capacity
-*/
- Serial.println(NVS.getString("wifi_ssid"));
+ server.on("/api/settings", HTTP_PUT, [](AsyncWebServerRequest *request) { /* nothing and dont remove it */ }, NULL, [](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
+ DynamicJsonDocument doc(1024);
+ DeserializationError error = deserializeJson(doc, data);
+ if (error) {
+ Serial.print(F("deserializeJson() failed with code "));
+ Serial.println(error.c_str());
- // ...
- });
- server.addHandler(handler);
+ request->send(404, "text/plain", "");
+ }
+ else
+ {
+ if (doc.containsKey("device_mode")) {
+ NVS.setString("device_mode", doc["device_mode"]);
+ }
+ if (doc.containsKey("cloud_server")) {
+ NVS.setString("cloud_server", doc["cloud_server"]);
+ //Serial.println(doc["cloud_server"].as());
+ }
+ request->send(200, "application/ld+json; charset=utf-8", "{}");
+ } });
}
+/**
+ * @todo
+ */
void setupCurrentImage()
{
- server.on("/current-image", HTTP_GET, [] (AsyncWebServerRequest *request) {
-
+ server.on("/current-image", HTTP_GET, [](AsyncWebServerRequest *request) {
+ Serial.println("/current-image");
+ request->send(SPIFFS, "/currentImage.bin", "image/x-bmp");
+ });
- AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/currentImage.bin", "image/vnd.wap.wbmp");
+/*
+ server.on("/current-image2", HTTP_GET, [](AsyncWebServerRequest *request) {
+ AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/currentImage.bin", "image/x-bmp"); // image/x-bmp | image/vnd.wap.wbmp
//response->addHeader("Content-Encoding", "gzip");
-
+ //response->addHeader("Content-Disposition", "inline; filename=\"image.wbmp\"");
request->send(response);
- });
-
+ });
+*/
}
-
+/**
+ * @todo
+ */
void setupWifiScan()
{
//First request will return 0 results unless you start scan from somewhere else (loop/setup)
//Do not request more often than 3-5 seconds
- server.on("/api/wifi/scan", HTTP_GET, [](AsyncWebServerRequest *request){
+ server.on("/api/wifi/scan", HTTP_GET, [](AsyncWebServerRequest *request) {
String json = "[";
int n = WiFi.scanComplete();
- if(n == -2){
+ if (n == -2)
+ {
WiFi.scanNetworks(true);
- } else if(n){
- for (int i = 0; i < n; ++i){
- if(i) json += ",";
- json += "{";
- json += "\"rssi\":"+String(WiFi.RSSI(i));
- json += ",\"ssid\":\""+WiFi.SSID(i)+"\"";
- json += ",\"bssid\":\""+WiFi.BSSIDstr(i)+"\"";
- json += ",\"channel\":"+String(WiFi.channel(i));
- json += ",\"secure\":"+String(WiFi.encryptionType(i));
- json += "}";
+ }
+ else if (n)
+ {
+ for (int i = 0; i < n; ++i)
+ {
+ if (i)
+ {
+ json += ",";
+ }
+
+ json += "{";
+ json += "\"rssi\":" + String(WiFi.RSSI(i));
+ json += ",\"ssid\":\"" + WiFi.SSID(i) + "\"";
+ json += ",\"bssid\":\"" + WiFi.BSSIDstr(i) + "\"";
+ json += ",\"channel\":" + String(WiFi.channel(i));
+ json += ",\"secure\":" + String(WiFi.encryptionType(i));
+ json += "}";
}
+
WiFi.scanDelete();
- if(WiFi.scanComplete() == -2){
+ if (WiFi.scanComplete() == -2)
+ {
WiFi.scanNetworks(true);
}
}
+
json += "]";
request->send(200, "application/json", json);
json = String();
});
}
-
+/**
+ * @todo
+ */
void setupWifiConnect()
{
- AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/api/wifi/connect", [](AsyncWebServerRequest *request, JsonVariant &json) {
- //JsonObject jsonObj = json.to();
- // TODO save settings
+ server.on("/api/wifi/connect", HTTP_PUT, [](AsyncWebServerRequest *request) { /* nothing and dont remove it */ }, NULL, [](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
+ DynamicJsonDocument doc(1024);
+ Serial.println("/api/wifi/connect");
+ DeserializationError error = deserializeJson(doc, data);
+ if (error) {
+ Serial.print(F("deserializeJson() failed with code "));
+ Serial.println(error.c_str());
- AsyncResponseStream *response = request->beginResponseStream("application/json");
-
- DynamicJsonDocument root(1024);
- root["status"] = true;
- root["message"] = "";
-
- serializeJson(root, *response);
- request->send(response);
-
- // ist ein restart wichtig?
- //ESP.restart();
+ request->send(404, "text/plain", "");
+ }
+ else
+ {
+ if (doc.containsKey("user")) {
+ //NVS.setString("device_mode", doc["device_mode"]);
+ }
+ if (doc.containsKey("password")) {
+ //NVS.setString("cloud_server", doc["cloud_server"]);
+ //Serial.println(doc["cloud_server"].as());
+ }
- });
- server.addHandler(handler);
+ request->send(200, "application/ld+json; charset=utf-8", "{}");
+ } });
}
\ No newline at end of file
diff --git a/src/cloud.cpp b/src/cloud.cpp
index c519d7a..7e692e7 100644
--- a/src/cloud.cpp
+++ b/src/cloud.cpp
@@ -7,15 +7,17 @@
#include "display.h"
#include "device.h"
-
// TODO SMART SIGN CONFIG ========
-#define config_PullServer "http://paperdash.sonic.da-tom.com/gateway.php/" // pull server address
-String config_UUID = "22805938-2280-8022-3822-385980225980"; // TODO
+//#define config_PullServer "http://paperdash.sonic.da-tom.com/gateway.php/" // pull server address
+String config_UUID = "22805938-2280-8022-3822-385980225980"; // TODO
-//String config_PullServer;
-//String config_UUID;
+//#define config_PullServer = NVS.getString("cloud_server");
+//String config_UUID = NVS.getString("cloud_server");
// SMART SIGN CONFIG ========
+unsigned long requestInterval = 1000; // 1 sec
+unsigned long previousTime = 0;
+
// runtime data
const char *setting_HeaderKeys[] = {
// update deep sleep interval
@@ -23,21 +25,19 @@ const char *setting_HeaderKeys[] = {
// execute firmware update url
"UpdateFirmware"};
-//#include
-//#define FRAME_BUFFERBUFFE_SIZE GxEPD2_750::WIDTH *GxEPD2_750::HEIGHT / 8
-//PROGMEM unsigned char displayImageBuffer[FRAME_BUFFERBUFFE_SIZE];
-
HTTPClient http;
-void pullData();
+void requestCloud();
+bool isCloudSetupComplete();
+void updateInterval(unsigned long interval);
void setupCloud()
{
Serial.println("setup cloud");
- // load settings
- //config_PullServer = NVS.getString("cloud_gateway");
- config_UUID = NVS.getString("cloud_uuid");
+ updateInterval(10);
+
+ SPIFFS.begin();
http.useHTTP10(true); // http1.1 chunked übertragung funktioniert irgendwie nicht
http.setTimeout(7000);
@@ -48,7 +48,55 @@ void setupCloud()
void loopCloud()
{
- pullData();
+ if (isCloudSetupComplete())
+ {
+ if (NVS.getString("device_mode") == "passive")
+ {
+ Serial.println("requestCloud()");
+
+ Serial.println("passive, after this, we go to deep sleep and startover here again");
+ }
+ else
+ {
+ unsigned long currentTime = millis();
+
+ if (currentTime - previousTime >= requestInterval)
+ {
+ /* Update the timing for the next time around */
+ previousTime = currentTime;
+
+ Serial.println("requestCloud()");
+ requestCloud();
+ }
+ }
+
+ }
+}
+
+bool isCloudSetupComplete()
+{
+ return NVS.getString("cloud_server") != "" && config_UUID != "";
+}
+
+/**
+ * interval in seconds
+ */
+void updateInterval(unsigned long interval)
+{
+ //Serial.print("updateInterval: ");
+ //Serial.println(interval);
+
+ // update config
+ Serial.println("###### config update");
+ Serial.println(" set deep sleep interval from: " + String(deviceGetSleepInterval()) + " to " + interval);
+ Serial.println("###### config update");
+
+
+ // active wait state
+ requestInterval = interval * 1000;
+
+ // passive deep sleep state
+ deviceSetSleepInterval(interval);
}
/**
@@ -56,10 +104,11 @@ void loopCloud()
* 2. neues bild vom server laden und anzeigen sofern vorhanden
* @return bool true on new data to display
*/
-void pullData()
+void requestCloud()
{
- String pullUrl = String(config_PullServer) + "/" + config_UUID; // + "?deep-sleep=" + String(config_DeepSleepInterval) + "&wakeup=" + getWakeupReason();
+ //String pullUrl = String(config_PullServer) + "/" + config_UUID; // + "?deep-sleep=" + String(config_DeepSleepInterval) + "&wakeup=" + getWakeupReason();
+ String pullUrl = NVS.getString("cloud_server") + "/" + config_UUID; // + "?deep-sleep=" + String(config_DeepSleepInterval) + "&wakeup=" + getWakeupReason();
Serial.println(pullUrl);
http.begin(pullUrl);
@@ -75,17 +124,12 @@ void pullData()
if (false && DeepSleepInterval.toInt() == 0)
{
// disable deep sleep
- Serial.println("###### deep sleep disabled");
- deviceSetSleepInterval(0);
+ //Serial.println("###### deep sleep disabled");
+ //deviceSetSleepInterval(0);
}
else if (DeepSleepInterval.toInt() > 5 && DeepSleepInterval.toInt() != deviceGetSleepInterval())
{
- // update config
- Serial.println("###### config update");
- Serial.println(" set deep sleep interval from: " + String(deviceGetSleepInterval()) + " to " + DeepSleepInterval);
- Serial.println("###### config update");
-
- deviceSetSleepInterval(DeepSleepInterval.toInt());
+ updateInterval(DeepSleepInterval.toInt());
}
// update to new firmware
diff --git a/src/device.cpp b/src/device.cpp
index 64447fc..a35a8dd 100644
--- a/src/device.cpp
+++ b/src/device.cpp
@@ -1,81 +1,85 @@
#include "device.h"
+#include "settings.h"
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
RTC_DATA_ATTR int bootCount = 0;
-RTC_DATA_ATTR long config_DeepSleepInterval = 0;
+RTC_DATA_ATTR long config_DeepSleepInterval = 10; // sec
+unsigned long bootTime = 0;
// private methods
void sleepDevice();
-String getWakeupReason();
-
+bool isBootTimeOver();
/**
* setup deep sleep mode
*/
void setupDevice()
{
- // increment boot number and print it every reboot
- bootCount++;
-
- // TODO muss in der cloud passieren? config wakeup timer
- //deviceSetSleepInterval(300);
+ // increment boot number and print it every reboot
+ bootCount++;
+ bootTime = millis();
}
-
void loopDevice()
{
- if (config_DeepSleepInterval > 0)
- {
- sleepDevice();
- // device stop here
- }
+ if (NVS.getString("device_mode") == "passive")
+ {
+ // TODO give user a time window to switch the mode to active
+ if (true) // isBootTimeOver()
+ {
+ sleepDevice();
+ // device stop here
+ }
+ }
}
-
void sleepDevice()
{
- Serial.println("Going to sleep now");
- Serial.flush();
+ Serial.println("Going to sleep now");
+ Serial.flush();
esp_sleep_enable_timer_wakeup(config_DeepSleepInterval * uS_TO_S_FACTOR);
- esp_deep_sleep_start();
+ esp_deep_sleep_start();
}
-
void deviceSetSleepInterval(long interval)
{
config_DeepSleepInterval = interval;
}
-
long deviceGetSleepInterval()
{
return config_DeepSleepInterval;
}
-String getWakeupReason()
+bool isBootTimeOver()
{
- esp_sleep_wakeup_cause_t wakeup_reason;
- wakeup_reason = esp_sleep_get_wakeup_cause();
-
- //return String(wakeup_reason);
-
- switch (wakeup_reason)
- {
- case 1:
- return String("Wakeup caused by external signal using RTC_IO");
- case 2:
- return String("Wakeup caused by external signal using RTC_CNTL");
- case 3:
- return String("Wakeup caused by timer");
- case 4:
- return String("Wakeup caused by touchpad");
- case 5:
- return String("Wakeup caused by ULP program");
- default:
- return String("Wakeup was not caused by deep sleep: " + String(wakeup_reason));
- }
+ return millis() - bootTime >= 60000;
+}
- return String("unkown");
+String getWakeupReason()
+{
+ esp_sleep_wakeup_cause_t wakeup_reason;
+ wakeup_reason = esp_sleep_get_wakeup_cause();
+
+ //return String(wakeup_reason);
+
+ switch (wakeup_reason)
+ {
+ case 1:
+ return String("Wakeup caused by external signal using RTC_IO");
+ case 2:
+ return String("Wakeup caused by external signal using RTC_CNTL");
+ case 3:
+ return String("Wakeup caused by timer");
+ case 4:
+ return String("Wakeup caused by touchpad");
+ case 5:
+ return String("Wakeup caused by ULP program");
+ default:
+ return String("Wakeup was not caused by deep sleep: " + String(wakeup_reason));
+ }
+
+ return String("unkown");
}
\ No newline at end of file
diff --git a/src/display.cpp b/src/display.cpp
index d6e046a..38f112e 100644
--- a/src/display.cpp
+++ b/src/display.cpp
@@ -91,4 +91,4 @@ void printSplash()
display.setCursor(x, y);
display.print(Hello);
} while (display.nextPage());
-}
\ No newline at end of file
+}
diff --git a/src/image.cpp b/src/image.cpp
new file mode 100644
index 0000000..715faaf
--- /dev/null
+++ b/src/image.cpp
@@ -0,0 +1,298 @@
+#include
+#include
+
+typedef struct {
+ uint16_t x1;
+ uint16_t y1;
+ uint16_t x2;
+ uint16_t y2;
+} dispWin_t;
+
+dispWin_t dispWin = {
+ .x1 = 0,
+ .y1 = 0,
+ .x2 = 640, // DEFAULT_TFT_DISPLAY_WIDTH,
+ .y2 = 384, // DEFAULT_TFT_DISPLAY_HEIGHT,
+};
+uint8_t image_debug;
+
+// @see https://github.com/Bodmer/TJpg_Decoder/blob/master/examples/SPIFFS_Jpg/SPIFFS_Jpg.ino
+
+// @see https://github.com/loboris/ESP32_TFT_library/blob/aa21772f54a71887ec08b2e8bbaef9e304009891/components/tft/tft.c
+void TFT_bmp_image(int x, int y, uint8_t scale, char *fname, uint8_t *imgbuf, int size)
+{
+ FILE *fhndl = NULL;
+ struct stat sb;
+ int i, err=0;
+ int img_xsize, img_ysize, img_xstart, img_xlen, img_ystart, img_ylen;
+ int img_pos, img_pix_pos, scan_lines, rd_len;
+ uint8_t tmpc;
+ uint16_t wtemp;
+ uint32_t temp;
+ int disp_xstart, disp_xend, disp_ystart, disp_yend;
+ uint8_t buf[56];
+ char err_buf[64];
+ uint8_t *line_buf[2] = {NULL,NULL};
+ uint8_t lb_idx = 0;
+ uint8_t *scale_buf = NULL;
+ uint8_t scale_pix;
+ uint16_t co[3] = {0,0,0}; // RGB sum
+ uint8_t npix;
+
+ if (scale > 7) scale = 7;
+ scale_pix = scale+1; // scale factor ( 1~8 )
+
+ if (fname) {
+ // * File name is given, reading image from file
+ if (stat(fname, &sb) != 0) {
+ sprintf(err_buf, "opening file");
+ err = -1;
+ goto exit;
+ }
+ size = sb.st_size;
+ fhndl = fopen(fname, "r");
+ if (!fhndl) {
+ sprintf(err_buf, "opening file");
+ err = -2;
+ goto exit;
+ }
+
+ i = fread(buf, 1, 54, fhndl); // read header
+ }
+ else {
+ // * Reading image from buffer
+ if ((imgbuf) && (size > 54)) {
+ memcpy(buf, imgbuf, 54);
+ i = 54;
+ }
+ else i = 0;
+ }
+
+ sprintf(err_buf, "reading header");
+ if (i != 54) {err = -3; goto exit;}
+
+ // ** Check image header and get image properties
+ if ((buf[0] != 'B') || (buf[1] != 'M')) {err=-4; goto exit;} // accept only images with 'BM' id
+
+ memcpy(&temp, buf+2, 4); // file size
+ if (temp != size) {err=-5; goto exit;}
+
+ memcpy(&img_pos, buf+10, 4); // start of pixel data
+
+ memcpy(&temp, buf+14, 4); // BMP header size
+ if (temp != 40) {err=-6; goto exit;}
+
+ memcpy(&wtemp, buf+26, 2); // the number of color planes
+ if (wtemp != 1) {err=-7; goto exit;}
+
+ memcpy(&wtemp, buf+28, 2); // the number of bits per pixel
+ if (wtemp != 24) {err=-8; goto exit;}
+
+ memcpy(&temp, buf+30, 4); // the compression method being used
+ if (temp != 0) {err=-9; goto exit;}
+
+ memcpy(&img_xsize, buf+18, 4); // the bitmap width in pixels
+ memcpy(&img_ysize, buf+22, 4); // the bitmap height in pixels
+
+
+ // * scale image dimensions
+/*
+ img_xlen = img_xsize / scale_pix; // image display horizontal size
+ img_ylen = img_ysize / scale_pix; // image display vertical size
+
+ if (x == CENTER) x = ((dispWin.x2 - dispWin.x1 + 1 - img_xlen) / 2) + dispWin.x1;
+ else if (x == RIGHT) x = dispWin.x2 + 1 - img_xlen;
+
+ if (y == CENTER) y = ((dispWin.y2 - dispWin.y1 + 1 - img_ylen) / 2) + dispWin.y1;
+ else if (y == BOTTOM) y = dispWin.y2 + 1 - img_ylen;
+*/
+ if ((x < ((dispWin.x2 + 1) * -1)) || (x > (dispWin.x2 + 1)) || (y < ((dispWin.y2 + 1) * -1)) || (y > (dispWin.y2 + 1))) {
+ sprintf(err_buf, "out of display area (%d,%d", x, y);
+ err = -10;
+ goto exit;
+ }
+
+ // ** set display and image areas
+ if (x < dispWin.x1) {
+ disp_xstart = dispWin.x1;
+ img_xstart = -x; // image pixel line X offset
+ img_xlen += x;
+ }
+ else {
+ disp_xstart = x;
+ img_xstart = 0;
+ }
+ if (y < dispWin.y1) {
+ disp_ystart = dispWin.y1;
+ img_ystart = -y; // image pixel line Y offset
+ img_ylen += y;
+ }
+ else {
+ disp_ystart = y;
+ img_ystart = 0;
+ }
+ disp_xend = disp_xstart + img_xlen - 1;
+ disp_yend = disp_ystart + img_ylen - 1;
+ if (disp_xend > dispWin.x2) {
+ disp_xend = dispWin.x2;
+ img_xlen = disp_xend - disp_xstart + 1;
+ }
+ if (disp_yend > dispWin.y2) {
+ disp_yend = dispWin.y2;
+ img_ylen = disp_yend - disp_ystart + 1;
+ }
+
+ if ((img_xlen < 8) || (img_ylen < 8) || (img_xstart >= (img_xsize-2)) || ((img_ysize - img_ystart) < 2)) {
+ sprintf(err_buf, "image too small");
+ err = -11;
+ goto exit;
+ }
+
+ // ** Allocate memory for 2 lines of image pixels
+ line_buf[0] = static_cast(heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA));
+ if (line_buf[0] == NULL) {
+ sprintf(err_buf, "allocating line buffer #1");
+ err=-12;
+ goto exit;
+ }
+
+ line_buf[1] = static_cast(heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA));
+ if (line_buf[1] == NULL) {
+ sprintf(err_buf, "allocating line buffer #2");
+ err=-13;
+ goto exit;
+ }
+
+ if (scale) {
+ // Allocate memory for scale buffer
+ rd_len = img_xlen * 3 * scale_pix;
+ scale_buf = static_cast(malloc(rd_len*scale_pix));
+ if (scale_buf == NULL) {
+ sprintf(err_buf, "allocating scale buffer");
+ err=-14;
+ goto exit;
+ }
+ }
+ else rd_len = img_xlen * 3;
+
+ // ** ***************************************************** **
+ // ** BMP images are stored in file from LAST to FIRST line **
+ // ** ***************************************************** **
+
+ /* Used variables:
+ img_xsize horizontal image size in pixels
+ img_ysize number of image lines
+ img_xlen image display horizontal scaled size in pixels
+ img_ylen image display vertical scaled size in pixels
+ img_xstart first pixel in line to be displayed
+ img_ystart first image line to be displayed
+ img_xlen number of pixels in image line to be displayed, starting with 'img_xstart'
+ img_ylen number of lines in image to be displayed, starting with 'img_ystart'
+ rd_len length of color data which are read from image line in bytes
+ */
+
+ // Set position in image to the first color data (beginning of the LAST line)
+ img_pos += (img_ystart * (img_xsize*3));
+ if (fhndl) {
+ if (fseek(fhndl, img_pos, SEEK_SET) != 0) {
+ sprintf(err_buf, "file seek at %d", img_pos);
+ err = -15;
+ goto exit;
+ }
+ }
+
+ if (image_debug) printf("BMP: image size: (%d,%d) scale: %d disp size: (%d,%d) img xofs: %d img yofs: %d at: %d,%d; line buf: 2* %d scale buf: %d\r\n",
+ img_xsize, img_ysize, scale_pix, img_xlen, img_ylen, img_xstart, img_ystart, disp_xstart, disp_ystart, img_xsize*3, ((scale) ? (rd_len*scale_pix) : 0));
+
+ // * Select the display
+ //disp_select();
+
+ while ((disp_yend >= disp_ystart) && ((img_pos + (img_xsize*3)) <= size)) {
+ if (img_pos > size) {
+ sprintf(err_buf, "EOF reached: %d > %d", img_pos, size);
+ err = -16;
+ goto exit1;
+ }
+ if (scale == 0) {
+ // Read the line of color data into color buffer
+ if (fhndl) {
+ i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file
+ if (i != (img_xsize*3)) {
+ sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3);
+ err = -16;
+ goto exit1;
+ }
+ }
+ else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3);
+
+ if (img_xstart > 0) memmove(line_buf[lb_idx], line_buf[lb_idx]+(img_xstart*3), rd_len);
+ // Convert colors BGR-888 (BMP) -> RGB-888 (DISPLAY) ===
+ for (i=0; i < rd_len; i += 3) {
+ tmpc = line_buf[lb_idx][i+2] & 0xfc; // save R
+ line_buf[lb_idx][i+2] = line_buf[lb_idx][i] & 0xfc; // B -> R
+ line_buf[lb_idx][i] = tmpc; // R -> B
+ line_buf[lb_idx][i+1] &= 0xfc; // G
+ }
+ img_pos += (img_xsize*3);
+ }
+ else {
+ // scale image, read 'scale_pix' lines and find the average color
+ for (scan_lines=0; scan_lines size) break;
+ if (fhndl) {
+ i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file
+ if (i != (img_xsize*3)) {
+ sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3);
+ err = -17;
+ goto exit1;
+ }
+ }
+ else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3);
+ img_pos += (img_xsize*3);
+
+ // copy only data which are displayed to scale buffer
+ memcpy(scale_buf + (rd_len * scan_lines), line_buf[lb_idx]+img_xstart, rd_len);
+ }
+
+ // Populate display line buffer
+ for (int n=0;n<(img_xlen*3);n += 3) {
+ memset(co, 0, sizeof(co)); // initialize color sum
+ npix = 0; // initialize number of pixels in scale rectangle
+
+ // sum all pixels in scale rectangle
+ for (int sc_line=0; sc_line RGB-888 (DISPLAY)
+ line_buf[lb_idx][n+2] = (uint8_t)(co[0] / npix); // B
+ line_buf[lb_idx][n+1] = (uint8_t)(co[1] / npix); // G
+ line_buf[lb_idx][n] = (uint8_t)(co[2] / npix); // R
+ }
+ }
+
+ //wait_trans_finish(1);
+ //send_data(disp_xstart, disp_yend, disp_xend, disp_yend, img_xlen, (color_t *)line_buf[lb_idx]);
+ lb_idx = (lb_idx + 1) & 1; // change buffer
+
+ disp_yend--;
+ }
+ err = 0;
+exit1:
+ //disp_deselect();
+exit:
+ if (scale_buf) free(scale_buf);
+ if (line_buf[0]) free(line_buf[0]);
+ if (line_buf[1]) free(line_buf[1]);
+ if (fhndl) fclose(fhndl);
+ if ((err) && (image_debug)) printf("Error: %d [%s]\r\n", err, err_buf);
+
+ //return err;
+}
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index b077094..e25425c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -29,7 +29,7 @@ void setup()
if (wlan_isConnected())
{
- //setupCloud();
+ setupCloud();
}
setupApp();
@@ -44,7 +44,7 @@ void loop()
if (wlan_isConnected())
{
- //loopCloud();
+ loopCloud();
}
loopDevice();