diff --git a/.gitignore b/.gitignore index a4938ce5..d656f83e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,10 @@ .git .pio data/* +src/user_setups/active/* src/user_config_override.h platformio_override.ini +user_setups/active/* ## Visual Studio Code specific ###### .vscode diff --git a/README.md b/README.md index e9c141ba..763e189d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ # HASP - Open Hardware edition + +[![GitHub release](https://img.shields.io/github/release/fvanroie/hasp-lvgl.svg)](https://github.com/fvanroie/hasp-lvgl/releases) +[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/fvanroie/hasp-lvgl/blob/master/LICENSE) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) +[![GitHub issues](https://img.shields.io/github/issues/fvanroie/hasp-lvgl.svg)](http://github.com/fvanroie/hasp-lvgl/issues) + This project is a re-implementation of the popular HASwitchPlate sketch created by aderusha. The [original HASwitchPlate][1] project uses a Wemos D1 mini and requires a Nextion/TJC HMI display. This rewrite removes the Nextion/TJC requirement by using the [Littlev Graphics Library][2] on the MCU to drive a cheap commodity display. @@ -19,14 +25,14 @@ This version also adds ESP32 and STM32 support to take advantage of the addition | SPI display | :white_check_mark: yes | :white_check_mark: yes | :white_check_mark: yes | Parallel display | :x: no | :white_check_mark: yes | :white_check_mark: yes | PWM Screen dimming | :white_check_mark: yes | :white_check_mark: yes | :white_check_mark: yes -| Maximum Page Count | 4 | 12 | +| Maximum Page Count | 4 | 12 | 12 | Object Types / Widgets | 14 | 15 | 15 | Dynamic Objects | :white_check_mark: yes | :white_check_mark: yes | :white_check_mark: yes | [Lvgl Theme Support][3] | basic only | all themes | tbd | [Custom .zi V5 font][4] | :white_check_mark: yes (latin1) | :white_check_mark: yes (latin1) | no | [FontAwesome Icons][5] | :white_check_mark: 1300+ | :white_check_mark: 1300+ | no | PNG images | :x: no | :grey_question: tbd | :grey_question: tbd -| Network | :white_check_mark: Wifi | :white_check_mark: Wifi | :grey_question: tbd +| Network | :white_check_mark: Wifi | :white_check_mark: Wifi | :white_check_mark: Ethernet ## Cloning diff --git a/include/hasp_conf.h b/include/hasp_conf.h index a14b936f..28260cbd 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -7,43 +7,88 @@ #define HASP_USE_APP 1 -/* Network */ -#define HASP_HAS_NETWORK (ARDUINO_ARCH_ESP32>0 || ARDUINO_ARCH_ESP8266>0) +/* Network Services */ +#define HASP_HAS_NETWORK (ARDUINO_ARCH_ESP32 > 0 || ARDUINO_ARCH_ESP8266 > 0) +#ifndef HASP_USE_OTA #define HASP_USE_OTA (HASP_HAS_NETWORK) -#define HASP_USE_WIFI (HASP_HAS_NETWORK) -#define HASP_USE_MQTT (HASP_HAS_NETWORK) -#define HASP_USE_HTTP (HASP_HAS_NETWORK) -#define HASP_USE_MDNS (HASP_HAS_NETWORK) -#define HASP_USE_SYSLOG (HASP_HAS_NETWORK) -#define HASP_USE_TELNET (HASP_HAS_NETWORK) - -/* Filesystem */ -#define HASP_HAS_FILESYSTEM (ARDUINO_ARCH_ESP32>0 || ARDUINO_ARCH_ESP8266>0) - -#define HASP_USE_SPIFFS (HASP_HAS_FILESYSTEM) -#define HASP_USE_EEPROM (HASP_HAS_FILESYSTEM) -#define HASP_USE_SDCARD 0 - -#define HASP_USE_BUTTON 1 - -#define HASP_USE_QRCODE 1 -#define HASP_USE_PNGDECODE 0 - -#define HASP_NUM_INPUTS 3 // Buttons -#define HASP_NUM_OUTPUTS 3 - -#if defined(ARDUINO_ARCH_ESP32) -#define HASP_NUM_PAGES 12 -#else -#define HASP_NUM_PAGES 4 #endif +#ifndef HASP_USE_WIFI +#define HASP_USE_WIFI (HASP_HAS_NETWORK) +#endif -#if HASP_USE_SPIFFS>0 +#ifndef HASP_USE_ETHERNET +#define HASP_USE_ETHERNET 0 +#endif + +#ifndef HASP_USE_MQTT +#define HASP_USE_MQTT 1 +#endif + +#ifndef HASP_USE_HTTP +#define HASP_USE_HTTP 1 +#endif + +#ifndef HASP_USE_MDNS +#define HASP_USE_MDNS (HASP_HAS_NETWORK) +#endif + +#ifndef HASP_USE_SYSLOG +#define HASP_USE_SYSLOG 0 +#endif + +#ifndef HASP_USE_TELNET +#define HASP_USE_TELNET 0 +#endif + +/* Filesystem */ +#define HASP_HAS_FILESYSTEM (ARDUINO_ARCH_ESP32 > 0 || ARDUINO_ARCH_ESP8266 > 0) + +#ifndef HASP_USE_SPIFFS +#define HASP_USE_SPIFFS (HASP_HAS_FILESYSTEM) +#endif + +#ifndef HASP_USE_EEPROM +#define HASP_USE_EEPROM 1 +#endif + +#ifndef HASP_USE_SDCARD +#define HASP_USE_SDCARD 0 +#endif + +#ifndef HASP_USE_GPIO +#define HASP_USE_GPIO 1 +#endif + +#ifndef HASP_USE_QRCODE +#define HASP_USE_QRCODE 1 +#endif + +#ifndef HASP_USE_PNGDECODE +#define HASP_USE_PNGDECODE 0 +#endif + +#ifndef HASP_NUM_INPUTS +#define HASP_NUM_INPUTS 3 // Buttons +#endif + +#ifndef HASP_NUM_OUTPUTS +#define HASP_NUM_OUTPUTS 3 +#endif + +#ifndef HASP_NUM_PAGES +#if defined(ARDUINO_ARCH_ESP8266) +#define HASP_NUM_PAGES 4 +#else +#define HASP_NUM_PAGES 12 +#endif +#endif + +/* Includes */ +#if HASP_USE_SPIFFS > 0 #if defined(ARDUINO_ARCH_ESP32) #include "SPIFFS.h" -#include "hasp_eeprom.h" #endif #include // Include the SPIFFS library #include "hasp_spiffs.h" @@ -51,42 +96,70 @@ #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) //#include "lv_zifont.h" #endif -#endif +#endif // SPIFFS -#if HASP_USE_EEPROM>0 +#if HASP_USE_EEPROM > 0 #include "hasp_eeprom.h" #endif -#if HASP_USE_WIFI>0 +#if HASP_USE_WIFI > 0 #include "hasp_wifi.h" #endif -#if HASP_USE_MQTT>0 +#if HASP_USE_ETHERNET > 0 +#if USE_BUILTIN_ETHERNET > 0 +#include +#include +#warning Use built-in STM32 Ethernet +#elif USE_UIP_ETHERNET +#include +#include +#warning Use ENC28J60 Ethernet shield +#else +#include "Ethernet.h" +#warning Use W5x00 Ethernet shield +#endif +#include "hasp_ethernet.h" +#endif + +#if HASP_USE_MQTT > 0 #include "hasp_mqtt.h" #endif -#if HASP_USE_HTTP>0 +#if HASP_USE_HTTP > 0 #include "hasp_http.h" #endif -#if HASP_USE_TELNET>0 +#if HASP_USE_TELNET > 0 #include "hasp_telnet.h" #endif -#if HASP_USE_MDNS>0 +#if HASP_USE_MDNS > 0 #include "hasp_mdns.h" #endif -#if HASP_USE_BUTTON>0 +#if HASP_USE_BUTTON > 0 #include "hasp_button.h" #endif -#if HASP_USE_OTA>0 +#if HASP_USE_OTA > 0 #include "hasp_ota.h" #endif +#if HASP_USE_TASMOTA_SLAVE > 0 +#include "hasp_slave.h" +#endif + +#if HASP_USE_ETHERNET > 0 +#include "hasp_ethernet.h" #endif #ifndef FPSTR #define FPSTR(pstr_pointer) (reinterpret_cast(pstr_pointer)) #endif + +#ifndef PGM_P +#define PGM_P const char * +#endif + +#endif // HASP_CONF_H \ No newline at end of file diff --git a/include/lv_conf.h b/include/lv_conf.h index 244aa61a..85829f49 100644 --- a/include/lv_conf.h +++ b/include/lv_conf.h @@ -80,7 +80,7 @@ typedef int16_t lv_coord_t; # define LV_MEM_SIZE (12 * 1024U) // 12KB #endif #ifndef LV_MEM_SIZE -# define LV_MEM_SIZE (64 * 1024U) // 48KB +# define LV_MEM_SIZE (20 * 1024U) // 48KB #endif /* Complier prefix for a big array declaration */ diff --git a/include/stm32f4/hal_conf_custom.h b/include/stm32f4/hal_conf_custom.h new file mode 100644 index 00000000..b0bc4acf --- /dev/null +++ b/include/stm32f4/hal_conf_custom.h @@ -0,0 +1,16 @@ +/* Include the normal default core configuration */ +#include "stm32f4xx_hal_conf_default.h" + +#if USE_BUILTIN_ETHERNET +/* Remove the default PHY address */ +#ifdef LAN8742A_PHY_ADDRESS +#undef LAN8742A_PHY_ADDRESS +#endif + +/* Section 2: PHY configuration section */ +/* Redefine LAN8742A PHY Address*/ +#ifndef LAN8742A_PHY_ADDRESS +#define LAN8742A_PHY_ADDRESS 0x01U //HASP_PHY_ADDRESS +#endif + +#endif \ No newline at end of file diff --git a/lcd_config.ini b/lcd_config.ini index 0e421971..dcbd3ebb 100644 --- a/lcd_config.ini +++ b/lcd_config.ini @@ -8,7 +8,7 @@ lolin24 = -D ILI9341_DRIVER=1 -D TFT_WIDTH=240 -D TFT_HEIGHT=320 - -D TFT_ROTATION=0 ; 0=0, 1=90, 2=180 or 3=270 degree + -D TFT_ROTATION=2 ; 0=0, 1=90, 2=180 or 3=270 degree -D SPI_FREQUENCY=40000000 -D SPI_TOUCH_FREQUENCY=2500000 -D SPI_READ_FREQUENCY=20000000 diff --git a/lib/ArduinoLog/ArduinoLog.cpp b/lib/ArduinoLog/ArduinoLog.cpp index d9ad7e06..c7265fd0 100644 --- a/lib/ArduinoLog/ArduinoLog.cpp +++ b/lib/ArduinoLog/ArduinoLog.cpp @@ -129,7 +129,6 @@ void Logging::print(Print * logOutput, const char * format, va_list args) ++format; printFormat(logOutput, *format, (va_list *)&args); } else { - //_logOutput->print(*format); logOutput->print(*format); } } diff --git a/lib/ArduinoLog/ArduinoLog.h b/lib/ArduinoLog/ArduinoLog.h index 645d4f74..d0f9f3d9 100644 --- a/lib/ArduinoLog/ArduinoLog.h +++ b/lib/ArduinoLog/ArduinoLog.h @@ -285,19 +285,15 @@ class Logging { if(_logOutput[i] == NULL || level>_level[i]) continue; if(_prefix != NULL) { - // _prefix(level, _logOutput[i]); + _prefix(level, _logOutput[i]); } va_list args; va_start(args, msg); -#ifdef STM32_CORE_VERSION_MAJOR - print(_logOutput[i], msg, args); - Serial.println(); -#else - print(_logOutput[i], msg, args); -#endif + print(_logOutput[i], msg, args); + if(_suffix != NULL) { - // _suffix(level, _logOutput[i]); + _suffix(level, _logOutput[i]); } } diff --git a/lib/lv_fs_if/lv_fs_spiffs.cpp b/lib/lv_fs_if/lv_fs_spiffs.cpp index 49acb1ce..aad335bd 100644 --- a/lib/lv_fs_if/lv_fs_spiffs.cpp +++ b/lib/lv_fs_if/lv_fs_spiffs.cpp @@ -150,7 +150,7 @@ static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, Log.verbose(F("LVFS: %d"), __LINE__); lv_spiffs_file_t * fp = (lv_spiffs_file_t *)file_p; /*Just avoid the confusing casings*/ // Log.verbose(F("LVFS: Copying %s"), f.name()); - Log.verbose(F("LVFS: %d"), __LINE__); + Log.verbose(F("LVFS: %d - %x - %d"), __LINE__, fp, sizeof(lv_spiffs_file_t)); if (fp != NULL) (*fp) = file; // memcpy(fp,&file,sizeof(lv_spiffs_file_t)); Log.verbose(F("LVFS: %d"), __LINE__); diff --git a/lib/lvgl b/lib/lvgl index 8b663bdc..ecd0d4fb 160000 --- a/lib/lvgl +++ b/lib/lvgl @@ -1 +1 @@ -Subproject commit 8b663bdc39b8a745cee39334b2f6c065babd5fd9 +Subproject commit ecd0d4fb0907d73e07788283c16e5a4ab1e829b6 diff --git a/platformio.ini b/platformio.ini index 81b7f8d9..8a971a18 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,6 +18,9 @@ extra_configs = pin_config.ini ; -- Add customizations to this file only: platformio_override.ini + ; -- Put active [env] files in this dir to be included in the build menu + user_setups/active/*.ini + user_setups/*/*.ini default_envs = ; Uncomment the needed environments in platformio_override.ini @@ -47,11 +50,13 @@ lib_deps = ;TFT_eSPI@^1.4.20 ; Tft SPI drivers PubSubClient@^2.7.0 ; MQTT client ArduinoJson@^6.15.1,>6.15.0 ; needs at least 6.15.0 + StreamUtils@^1.4.0 Syslog@^2.0.0 AceButton@^1.4.0 ;AsyncTCP ;https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip ;https://github.com/me-no-dev/ESPAsyncTCP/archive/master.zip + https://github.com/andrethomas/TasmotaSlave.git lib_ignore = https://github.com/littlevgl/lvgl.git @@ -67,6 +72,7 @@ build_flags = -D SPIFFS_TEMPORAL_FD_CACHE ; speedup opening recent files -D ARDUINOJSON_DECODE_UNICODE=1 ; for utf-8 symbols -D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments + -D STREAMUTILS_ENABLE_EEPROM=1 ; for STM32, it also supports EEPROM ;-D DISABLE_LOGGING -I include ; include lv_conf.h and hasp_conf.h ${override.build_flags} @@ -88,6 +94,9 @@ esp32_flags= stm32_flags= ${env.build_flags} -D IRAM_ATTR= ; No IRAM_ATTR available on STM32 + -D STM32 + -D STREAMUTILS_USE_EEPROM_UPDATE=1 ; update cell only when changed + -D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages ; -- By default there are no ${override.build_flags} set ; -- to use it, copy platformio_override.ini from the template @@ -120,210 +129,6 @@ hspi32 = ; 7 - mirror content, and rotate 90 deg anti-clockwise - -;*************************************************** -; STM32F4 build -;*************************************************** -[env:black_f407vg] -platform = ststm32 -board = diymore_f407vgt -board_build.mcu = stm32f407vgt6 -upload_protocol = dfu -monitor_port = COM7 ; To change the port, use platform_override.ini -build_flags = - ${env.build_flags} - ${flags.stm32_flags} - -I include/stm32f4 -; -- TFT_eSPI build options ------------------------ - ${lcd.lolin24} - ;-D TFT_MISO=PB4 ;Default - ;-D TFT_MOSI=PB5 ;Default - ;-D TFT_SCLK=PB3 ;Default - -D TFT_CS=PB11 ;D8 - -D TFT_DC=PC5 ;D3 - -D TFT_BCKL=-1 ;None, configurable via web UI (e.g. 2 for D4) - -D TOUCH_CS=PC4 ;NC - -D TFT_RST=-1 ;D4 - -D STM32 - -lib_deps = - ${env.lib_deps} - Ticker@^3.1.5 - STM32duino LwIP@^2.1.2 - STM32duino STM32Ethernet@^1.0.5 - -src_filter = +<*> -<.git/> -<.svn/> - - - - - + - - -;*************************************************** -; Generic ESP32 build -;*************************************************** -[env:esp32dev-mrb3511] -platform = espressif32 -board = esp32dev -upload_port = COM1 ; To change the port, use platform_override.ini -monitor_port = COM1 ; To change the port, use platform_override.ini -debug_tool = esp-prog -debug_init_break = tbreak setup - -build_flags = - ${flags.esp32_flags} -; -- TFT_eSPI build options ------------------------ - ${lcd.mrb3511} - -D TFT_BCKL=5 ;None, configurable via web UI (e.g. 2 for D4) - -D TFT_CS=33 ; Chip select control pin - -D TFT_DC=15 ; =RS; Data Command control pin - must use a pin in the range 0-31 - -D TFT_RST=32 ; Reset pin - -D TFT_WR=4 ; Write strobe control pin - must use a pin in the range 0-31 - -D TFT_RD=2 - -D TFT_D0=12 ; Must use pins in the range 0-31 for the data bus - -D TFT_D1=13 ; so a single register write sets/clears all bits - -D TFT_D2=26 - -D TFT_D3=25 - -D TFT_D4=17 - -D TFT_D5=16 - -D TFT_D6=27 - -D TFT_D7=14 - -D TOUCH_SDA=21 - -D TOUCH_SCL=22 - -D TOUCH_IRQ=34 ; use 34-39 as these are input only pins - -D TOUCH_RST=-1 ; not used, connected to 3.3V -; -- Debugging options ----------------------------- -; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG - -; -- Library options ------------------------------- -lib_deps = - ${env.lib_deps} - https://github.com/netwizeBE/arduino-goodix.git ; GT911 touch screen driver - -src_filter = +<*> +<../drivers/stm32f429_disco> - - -;*************************************************** -; Generic ESP32 build with ILI9488 SPI 4-WIRE -;*************************************************** -[env:esp32dev-ili9488] -platform = espressif32 -board = esp32dev -upload_port = COM2 ; To change the port, use platform_override.ini -monitor_port = COM2 ; To change the port, use platform_override.ini -; upload_protocol = espota ; Use ArduinoOTA after flashing over serial -; upload_port = 10.4.0.171 ; IP of the ESP -; upload_flags = -; --port=3232 -debug_tool = esp-prog -debug_init_break = tbreak setup - -build_flags = - ${flags.esp32_flags} -; -- TFT_eSPI build options ------------------------ - -D USER_SETUP_LOADED=1 - -D ILI9488_DRIVER=1 - -D TFT_ROTATION=0 ; 0=0, 1=90, 2=180 or 3=270 degree - -D TFT_WIDTH=320 - -D TFT_HEIGHT=480 - -D TFT_MISO=19 ;// (leave TFT SDO disconnected if other SPI devices share MISO) - -D TFT_MOSI=23 - -D TFT_SCLK=18 - -D TFT_CS=15 ;// Chip select control pin - -D TFT_DC=2 ;// Data Command control pin - -D TFT_RST=4 ;// Reset pin (could connect to RST pin) - -D TFT_BCKL=5 ;None, configurable via web UI (e.g. 2 for D4) - -D SUPPORT_TRANSACTIONS - -D TOUCH_CS=22 - -D TOUCH_DRIVER=0 ; XPT2606 Resistive touch panel driver - -D SPI_FREQUENCY=27000000 - -D SPI_TOUCH_FREQUENCY=2500000 - -D SPI_READ_FREQUENCY=16000000 - -; -- Debugging options ----------------------------- -; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG - -; -- Library options ------------------------------- -lib_deps = - ${env.lib_deps} - -src_filter = +<*> +<../drivers/stm32f429_disco> - - -;*************************************************** -; NodeMCU32S with MHS-4" RPI Display-B -;*************************************************** -[env:nodemcu32s-raspi] -platform = espressif32 -board = nodemcu-32s -upload_port = COM3 ; To change the port, use platform_override.ini -monitor_port = COM3 ; To change the port, use platform_override.ini -debug_tool = esp-prog -debug_init_break = tbreak setup - -build_flags = - ${flags.esp32_flags} -; -- TFT_eSPI build options ------------------------ - ${lcd.raspberrypi} - ${pins.vspi32} - -D TFT_CS=15 - -D TFT_DC=4 - -D TFT_RST=32 - -D TOUCH_CS=22 - -; -- Debugging options ----------------------------- -; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG - -; -- Library options ------------------------------- -lib_deps = - ${env.lib_deps} - - -;*************************************************** -; ESP32 build -;*************************************************** -[env:d132-unoshield] -platform = espressif32 -board = esp32dev -upload_port = COM4 ; To change the port, use platform_override.ini -monitor_port = COM4 ; To change the port, use platform_override.ini - -build_flags = - ${flags.esp32_flags} -; -- TFT_eSPI build options ------------------------ - -D USER_SETUP_LOADED=1 - ;-D ST7796_DRIVER=1 ;3.95inch Arduino Display-UNO - -D ILI9486_DRIVER=1 ;3.5inch Arduino Display-UNO - -D ESP32_PARALLEL=1 - -D TFT_ROTATION=${lcd.TFT_ROTATION} - -D TFT_WIDTH=320 - -D TFT_HEIGHT=480 - ${pins.vspi32} - -D TFT_BCKL=-1 ;None, configurable via web UI (e.g. 2 for D4) - -D TFT_CS=33 ; Chip select control pin - -D TFT_DC=15 ; Data Command control pin - must use a pin in the range 0-31 - -D TFT_RST=32 ; Reset pin - -D TFT_WR=4 ; Write strobe control pin - must use a pin in the range 0-31 - -D TFT_RD=2 - -D TFT_D0=12 ; Must use pins in the range 0-31 for the data bus - -D TFT_D1=13 ; so a single register write sets/clears all bits - -D TFT_D2=26 - -D TFT_D3=25 - -D TFT_D4=17 - -D TFT_D5=16 - -D TFT_D6=27 - -D TFT_D7=14 - -D SD_CS=5 - -D SPI_FREQUENCY=40000000 - ;-D SPI_TOUCH_FREQUENCY=2500000 ; Uses ADC instead - -D SPI_READ_FREQUENCY=20000000 -; -- Debugging options ----------------------------- -; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG - -; -- Library options ------------------------------- -lib_deps = - ${env.lib_deps} - -src_filter = +<*> +<../drivers/stm32f429_disco> - - - ;*************************************************** ; D1 Mini ESP32 with Lolin TFT 2.4" ;*************************************************** @@ -393,42 +198,6 @@ build_flags = -D TFT_RST=-1 ;RST -;*************************************************** -; ESP-12 build -;*************************************************** -[env:esp12e-st7735] -platform = espressif8266@^2.4.0 ;@2.3.2 -board = esp12e -upload_port = COM8 ; To change the port, use platform_override.ini -monitor_port = COM8 ; To change the port, use platform_override.ini -board_build.f_flash = 40000000L -board_build.flash_mode = dout -board_build.ldscript = eagle.flash.4m2m.ld ; 2Mb Spiffs -board_build.f_cpu = 160000000L ; set frequency to 160MHz -build_flags = - ${flags.esp8266_flags} -; -- TFT_eSPI build options ------------------------ - -D USER_SETUP_LOADED=1 - -D ST7735_DRIVER=1 - -D ST7735_BLACKTAB=1 - -D TFT_ROTATION=${lcd.TFT_ROTATION} - -D TFT_WIDTH=128 - -D TFT_HEIGHT=160 - -D TFT_MISO=-1 ;NC - -D TFT_MOSI=13 ;D7 - -D TFT_SCLK=14 ;D5 - -D TFT_CS=15 ;D8 - -D TFT_DC=0 ;D3 - -D TFT_BCKL=-1 ;None, configurable via web UI (e.g. 2 for D4) - -D TOUCH_CS=-1 ;NC - -D TFT_RST=2 ;D4 - -D SPI_FREQUENCY=27000000 - -; -- Library options ------------------------------- -lib_deps = - ${env.lib_deps} - ;Ethernet@<2.0.0 - ;*************************************************** ; Native build ;*************************************************** diff --git a/platformio_override-template.ini b/platformio_override-template.ini index 85445451..92f106ae 100644 --- a/platformio_override-template.ini +++ b/platformio_override-template.ini @@ -1,7 +1,7 @@ -; Copy this file and rename it to platform_override.ini -; ONLY edit platform_override.ini to make local changes to the parameters +; Copy this file and rename it to platformio_override.ini +; ONLY edit platformio_override.ini to make local changes to the parameters ; -; The platform_override.ini file is not overwritten or monitored by git +; The platformio_override.ini file is not overwritten or monitored by git [override] diff --git a/src/hasp.cpp b/src/hasp.cpp index cab2eaeb..fc983b0c 100644 --- a/src/hasp.cpp +++ b/src/hasp.cpp @@ -3,8 +3,9 @@ *********************/ #include "hasp_conf.h" #include -#include "ArduinoJson.h" #include "ArduinoLog.h" +#include "ArduinoJson.h" +#include "StreamUtils.h" #include "lvgl.h" #include "lv_conf.h" @@ -24,6 +25,8 @@ #include "hasp_attribute.h" #include "hasp.h" +#include "EEPROM.h" + //#if LV_USE_HASP /********************* @@ -665,7 +668,7 @@ void haspClearPage(uint16_t pageid) Log.warning(F("HASP: Cannot clear a layer")); } else { Log.notice(F("HASP: Clearing page %u"), pageid); - lv_page_clean(pages[pageid]); + lv_obj_clean(pages[pageid]); } } @@ -955,6 +958,15 @@ void haspLoadPage(const char * pages) file.close(); Log.notice(F("HASP: File %s loaded"), pages); +#else + +#if HASP_USE_EEPROM > 0 + Log.notice(F("HASP: Loading jsonl from EEPROM...")); + EepromStream eepromStream(4096, 1024); + dispatchJsonl(eepromStream); + Log.notice(F("HASP: Loaded jsonl from EEPROM")); +#endif + #endif } diff --git a/src/hasp.h b/src/hasp.h index c9dbbab9..74d7a40d 100644 --- a/src/hasp.h +++ b/src/hasp.h @@ -19,7 +19,7 @@ extern "C" { * INCLUDES *********************/ -#if HASP_USE_APP +#if HASP_USE_APP>0 /********************* * DEFINES @@ -81,8 +81,6 @@ void hasp_send_obj_attribute_int(lv_obj_t * obj, const char * attribute, int32_t void hasp_send_obj_attribute_color(lv_obj_t * obj, const char * attribute, lv_color_t color); void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char * attr, const char * payload); -void haspSendCmd(String nextionCmd); -void haspParseJson(String & strPayload); void haspNewObject(const JsonObject & config, uint8_t & saved_page_id); void haspReconnect(void); @@ -101,10 +99,10 @@ void IRAM_ATTR toggle_event_handler(lv_obj_t * obj, lv_event_t event); * MACROS **********************/ -#endif /*LV_USE_DEMO*/ +#endif /*HASP_USE_APP*/ #ifdef __cplusplus } /* extern "C" */ #endif -#endif /*DEMO_H*/ +#endif /*HASP_H*/ diff --git a/src/hasp_attribute.cpp b/src/hasp_attribute.cpp index 43a7aa6f..4a110d65 100644 --- a/src/hasp_attribute.cpp +++ b/src/hasp_attribute.cpp @@ -84,13 +84,6 @@ static lv_color_t haspPayloadToColor(const char * payload) case 7: if(!strcmp_P(payload, PSTR("magenta"))) return haspLogColor(LV_COLOR_MAGENTA); - /* HEX format #rrggbb or #rrggbbaa */ - int r, g, b, a; - if(*payload == '#' && sscanf(payload + 1, "%2x%2x%2x%2x", &r, &g, &b, &a) == 4) { - return haspLogColor(LV_COLOR_MAKE(r, g, b)); - } else if(*payload == '#' && sscanf(payload + 1, "%2x%2x%2x", &r, &g, &b) == 3) { - return haspLogColor(LV_COLOR_MAKE(r, g, b)); - } default: // if(!strcmp_P(payload, PSTR("darkblue"))) return haspLogColor(LV_COLOR_MAKE(0, 51, 102)); // if(!strcmp_P(payload, PSTR("lightblue"))) return haspLogColor(LV_COLOR_MAKE(46, 203, @@ -98,6 +91,14 @@ static lv_color_t haspPayloadToColor(const char * payload) break; } + /* HEX format #rrggbb or #rrggbbaa */ + int r, g, b, a; + if(*payload == '#' && sscanf(payload + 1, "%2x%2x%2x%2x", &r, &g, &b, &a) == 4) { + return haspLogColor(LV_COLOR_MAKE(r, g, b)); + } else if(*payload == '#' && sscanf(payload + 1, "%2x%2x%2x", &r, &g, &b) == 3) { + return haspLogColor(LV_COLOR_MAKE(r, g, b)); + } + /* 16-bit RGB565 Color Scheme*/ if(only_digits(payload)) { uint16_t c = atoi(payload); @@ -582,23 +583,19 @@ static void hasp_process_obj_attribute_val(lv_obj_t * obj, const char * attr, co lv_dropdown_set_selected(obj, val); return; } else if(check_obj_type(objtype, LV_HASP_LMETER)) { - lv_linemeter_set_value(obj, intval); - return; + return update ? lv_linemeter_set_value(obj, intval) : hasp_out_int(obj, attr, lv_linemeter_get_value(obj)); } else if(check_obj_type(objtype, LV_HASP_SLIDER)) { - lv_slider_set_value(obj, intval, LV_ANIM_ON); - return; + return update ? lv_slider_set_value(obj, intval, LV_ANIM_ON) + : hasp_out_int(obj, attr, lv_slider_get_value(obj)); } else if(check_obj_type(objtype, LV_HASP_LED)) { - lv_led_set_bright(obj, (uint8_t)val); - return; + return update ? lv_led_set_bright(obj, (uint8_t)val) : hasp_out_int(obj, attr, lv_led_get_bright(obj)); } else if(check_obj_type(objtype, LV_HASP_GAUGE)) { - lv_gauge_set_value(obj, 0, intval); - return; + return update ? lv_gauge_set_value(obj, 0, intval) : hasp_out_int(obj, attr, lv_gauge_get_value(obj, 0)); } else if(check_obj_type(objtype, LV_HASP_ROLLER)) { lv_roller_set_selected(obj, val, LV_ANIM_ON); return; } else if(check_obj_type(objtype, LV_HASP_BAR)) { - lv_bar_set_value(obj, intval, LV_ANIM_OFF); - return; + return update ? lv_bar_set_value(obj, intval, LV_ANIM_ON) : hasp_out_int(obj, attr, lv_bar_get_value(obj)); } else if(check_obj_type(objtype, LV_HASP_CPICKER)) { return update ? (void)lv_cpicker_set_color(obj, haspPayloadToColor(payload)) : hasp_out_color(obj, attr, lv_cpicker_get_color(obj)); @@ -794,9 +791,10 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char * **************************/ static inline bool is_true(const char * s) { - return (!strcmp_P(s, PSTR("true")) || !strcmp_P(s, PSTR("TRUE")) || !strcmp_P(s, PSTR("1")) || + return (!strcmp_P(s, PSTR("true")) || !strcmp_P(s, PSTR("TRUE")) || !strcmp_P(s, PSTR("True")) || !strcmp_P(s, PSTR("on")) || !strcmp_P(s, PSTR("ON")) || !strcmp_P(s, PSTR("On")) || - !strcmp_P(s, PSTR("yes")) || !strcmp_P(s, PSTR("YES")) || !strcmp_P(s, PSTR("Yes"))); + !strcmp_P(s, PSTR("yes")) || !strcmp_P(s, PSTR("YES")) || !strcmp_P(s, PSTR("Yes")) || + !strcmp_P(s, PSTR("1"))); } static inline bool only_digits(const char * s) @@ -808,17 +806,17 @@ static inline bool only_digits(const char * s) return strlen(s) == digits; } -void hasp_out_int(lv_obj_t * obj, const char * attr, uint32_t val) +void inline hasp_out_int(lv_obj_t * obj, const char * attr, uint32_t val) { hasp_send_obj_attribute_int(obj, attr, val); } -void hasp_out_str(lv_obj_t * obj, const char * attr, const char * data) +void inline hasp_out_str(lv_obj_t * obj, const char * attr, const char * data) { hasp_send_obj_attribute_str(obj, attr, data); } -void hasp_out_color(lv_obj_t * obj, const char * attr, lv_color_t color) +void inline hasp_out_color(lv_obj_t * obj, const char * attr, lv_color_t color) { hasp_send_obj_attribute_color(obj, attr, color); } diff --git a/src/hasp_button.cpp b/src/hasp_button.cpp deleted file mode 100644 index 400a0b84..00000000 --- a/src/hasp_button.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "Arduino.h" -#include "ArduinoLog.h" -#include "AceButton.h" - -#include "hasp_conf.h" -#include "lv_conf.h" - -#include "hasp_mqtt.h" // testing memory consumption -#include "hasp_button.h" -#include "hasp_dispatch.h" - -using namespace ace_button; -static AceButton * button[HASP_NUM_INPUTS]; // Connect your button between pin 2 and GND - -static void button_event_cb(AceButton * button, uint8_t eventType, uint8_t buttonState) -{ - char buffer[8]; - switch(eventType) { - case 0: // AceButton::kEventPressed: - memcpy_P(buffer, PSTR("DOWN"), sizeof(buffer)); - break; - case 2: // AceButton::kEventClicked: - memcpy_P(buffer, PSTR("SHORT"), sizeof(buffer)); - break; - // case AceButton::kEventDoubleClicked: - // memcpy_P(buffer, PSTR("DOUBLE"), sizeof(buffer)); - // break; - case 4: // AceButton::kEventLongPressed: - memcpy_P(buffer, PSTR("LONG"), sizeof(buffer)); - break; - case 5: // AceButton::kEventRepeatPressed: - return; // Fix needed for switches - memcpy_P(buffer, PSTR("HOLD"), sizeof(buffer)); - break; - case 1: // AceButton::kEventReleased: - memcpy_P(buffer, PSTR("UP"), sizeof(buffer)); - break; - } - dispatch_button(button->getId(), buffer); -} - -void buttonSetup(void) -{ - // button[0] = new Button(2); - button[1] = new AceButton(3, HIGH, 1); - button[2] = new AceButton(4, HIGH, 2); - - Log.verbose(F("BTNS: setup(): ready")); - - ButtonConfig * buttonConfig = ButtonConfig::getSystemButtonConfig(); - buttonConfig->setEventHandler(button_event_cb); - - // Features - buttonConfig->setFeature(ButtonConfig::kFeatureClick); - buttonConfig->setFeature(ButtonConfig::kFeatureLongPress); - buttonConfig->setFeature(ButtonConfig::kFeatureRepeatPress); - // buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick); - // buttonConfig->setFeature(ButtonConfig::kFeatureSuppressClickBeforeDoubleClick); - - // Delays - buttonConfig->setClickDelay(LV_INDEV_DEF_LONG_PRESS_TIME); - buttonConfig->setDoubleClickDelay(LV_INDEV_DEF_LONG_PRESS_TIME); - buttonConfig->setLongPressDelay(LV_INDEV_DEF_LONG_PRESS_TIME); - buttonConfig->setRepeatPressDelay(LV_INDEV_DEF_LONG_PRESS_TIME); - buttonConfig->setRepeatPressInterval(LV_INDEV_DEF_LONG_PRESS_REP_TIME); -} - -void IRAM_ATTR buttonLoop(void) -{ - // Should be called every 4-5ms or faster, for the default debouncing time - // of ~20ms. - for(uint8_t i = 0; i < HASP_NUM_INPUTS; i++) { - if(button[i]) button[i]->check(); - } -} diff --git a/src/hasp_button.h b/src/hasp_button.h deleted file mode 100644 index e19bb556..00000000 --- a/src/hasp_button.h +++ /dev/null @@ -1,10 +0,0 @@ -#if HASP_USE_BUTTON - -#ifndef HASP_BUTTON_H -#define HASP_BUTTON_H - -void buttonSetup(void); -void IRAM_ATTR buttonLoop(void); - -#endif -#endif diff --git a/src/hasp_config.cpp b/src/hasp_config.cpp index 86fec041..c2da806a 100644 --- a/src/hasp_config.cpp +++ b/src/hasp_config.cpp @@ -1,6 +1,7 @@ #include "Arduino.h" -#include "ArduinoJson.h" #include "ArduinoLog.h" +#include "ArduinoJson.h" +#include "StreamUtils.h" #include "hasp_config.h" #include "hasp_debug.h" @@ -13,21 +14,16 @@ #include "hasp_conf.h" -#if HASP_USE_SPIFFS>0 +#if HASP_USE_SPIFFS > 0 #include // Include the SPIFFS library #if defined(ARDUINO_ARCH_ESP32) #include "SPIFFS.h" #endif #endif -#if HASP_USE_EEPROM>0 +#if HASP_USE_EEPROM > 0 #include "EEPROM.h" #endif -#ifndef FPSTR -#define FPSTR(pstr_pointer) (reinterpret_cast(pstr_pointer)) -#endif - - void confDebugSet(const char * name) { /*char buffer[128]; @@ -77,13 +73,17 @@ void configStartDebug(bool setupdebug, String & configFile) { if(setupdebug) { debugStart(); // Debug started, now we can use it; HASP header sent +#if HASP_USE_SPIFFS > 0 Log.notice(F("FILE: [SUCCESS] SPI flash FS mounted")); -#if HASP_USE_SPIFFS>0 spiffsInfo(); spiffsList(); #endif } +#if HASP_USE_SPIFFS > 0 Log.notice(F("CONF: Loading %s"), configFile.c_str()); +#else + Log.notice(F("CONF: reading EEPROM")); +#endif } void configGetConfig(JsonDocument & settings, bool setupdebug = false) @@ -91,9 +91,10 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) String configFile((char *)0); configFile.reserve(128); configFile = String(FPSTR(HASP_CONFIG_FILE)); + DeserializationError error; -#if HASP_USE_SPIFFS>0 - File file = SPIFFS.open(configFile, "r"); +#if HASP_USE_SPIFFS > 0 + File file = SPIFFS.open(configFile, "r"); if(file) { size_t size = file.size(); @@ -102,7 +103,7 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) return; } - DeserializationError error = deserializeJson(settings, file); + error = deserializeJson(settings, file); if(!error) { file.close(); @@ -126,17 +127,26 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) return; } } +#else + +#if HASP_USE_EEPROM > 0 + EepromStream eepromStream(0, 1024); + error = deserializeJson(settings, eepromStream); +#endif + #endif // File does not exist or error reading file if(setupdebug) { debugPreSetup(settings[F("debug")]); } - configStartDebug(setupdebug, configFile); - Log.error(F("CONF: Failed to load %s"), configFile.c_str()); -} +#if HASP_USE_SPIFFS > 0 + Log.error(F("CONF: Failed to load %s"), configFile.c_str()); +#endif +} +/* void configBackupToEeprom() { #if HASP_USE_SPIFFS>0 @@ -165,10 +175,9 @@ void configBackupToEeprom() } #endif } - +*/ void configWriteConfig() { -#if HASP_USE_SPIFFS>0 String configFile((char *)0); configFile.reserve(128); configFile = String(FPSTR(HASP_CONFIG_FILE)); @@ -190,14 +199,15 @@ void configWriteConfig() bool writefile = false; bool changed = false; -#if HASP_USE_WIFI +#if HASP_USE_WIFI>0 if(settings[F("wifi")].as().isNull()) settings.createNestedObject(F("wifi")); changed = wifiGetConfig(settings[F("wifi")]); if(changed) { Log.verbose(F("WIFI: Settings changed")); writefile = true; } -#if HASP_USE_MQTT +#endif +#if HASP_USE_MQTT>0 if(settings[F("mqtt")].as().isNull()) settings.createNestedObject(F("mqtt")); changed = mqttGetConfig(settings[F("mqtt")]); if(changed) { @@ -206,7 +216,7 @@ void configWriteConfig() writefile = true; } #endif -#if HASP_USE_TELNET +#if HASP_USE_TELNET>0 if(settings[F("telnet")].as().isNull()) settings.createNestedObject(F("telnet")); changed = telnetGetConfig(settings[F("telnet")]); if(changed) { @@ -215,7 +225,7 @@ void configWriteConfig() writefile = true; } #endif -#if HASP_USE_MDNS +#if HASP_USE_MDNS>0 if(settings[F("mdns")].as().isNull()) settings.createNestedObject(F("mdns")); changed = mdnsGetConfig(settings[F("mdns")]); if(changed) { @@ -223,7 +233,7 @@ void configWriteConfig() writefile = true; } #endif -#if HASP_USE_HTTP +#if HASP_USE_HTTP>0 if(settings[F("http")].as().isNull()) settings.createNestedObject(F("http")); changed = httpGetConfig(settings[F("http")]); if(changed) { @@ -231,7 +241,6 @@ void configWriteConfig() configOutput(settings[F("http")]); writefile = true; } -#endif #endif if(settings[F("debug")].as().isNull()) settings.createNestedObject(F("debug")); @@ -258,6 +267,7 @@ void configWriteConfig() // changed |= otaGetConfig(settings[F("ota")].as()); if(writefile) { +#if HASP_USE_SPIFFS > 0 File file = SPIFFS.open(configFile, "w"); if(file) { Log.notice(F("CONF: Writing %s"), configFile.c_str()); @@ -265,36 +275,71 @@ void configWriteConfig() file.close(); if(size > 0) { Log.verbose(F("CONF: [SUCCESS] Saved %s"), configFile.c_str()); - configBackupToEeprom(); - return; + // configBackupToEeprom(); + } else { + Log.error(F("CONF: Failed to write %s"), configFile.c_str()); } + } else { + Log.error(F("CONF: Failed to write %s"), configFile.c_str()); } +#endif - Log.error(F("CONF: Failed to write %s"), configFile.c_str()); + // Method 1 + // Log.verbose(F("CONF: Writing to EEPROM")); + // EepromStream eepromStream(0, 1024); + // WriteBufferingStream bufferedWifiClient{eepromStream, 512}; + // serializeJson(doc, bufferedWifiClient); + // bufferedWifiClient.flush(); // <- OPTIONAL + // eepromStream.flush(); // (for ESP) + +#if defined(STM32F4xx) + // Method 2 + Log.verbose(F("CONF: Writing to EEPROM")); + char buffer[1024 + 128]; + size_t size = serializeJson(doc, buffer, sizeof(buffer)); + if(size > 0) { + uint16_t i; + for(i = 0; i < size; i++) eeprom_buffered_write_byte(i, buffer[i]); + eeprom_buffered_write_byte(i, 0); + eeprom_buffer_flush(); + Log.verbose(F("CONF: [SUCCESS] Saved EEPROM")); + } else { + Log.error(F("CONF: Failed to save config to EEPROM")); + } +#endif } else { - Log.notice(F("CONF: Configuration was not changed")); + Log.notice(F("CONF: Configuration did not change")); } -#endif + configOutput(settings); } void configSetup() { -#if HASP_USE_SPIFFS>0 - if(!SPIFFS.begin()) { -#endif - -#if HASP_USE_SPIFFS>0 - } else { -#endif - DynamicJsonDocument settings(1024 + 128); - Serial.print(__FILE__); - Serial.println(__LINE__); + DynamicJsonDocument settings(1024 + 128); - configGetConfig(settings, true); + for(uint8_t i = 0; i < 2; i++) { + Serial.print(__FILE__); + Serial.println(__LINE__); - Log.error(F("FILE: SPI flash init failed. Unable to mount FS: Using default settings...")); -#if HASP_USE_SPIFFS>0 + if(i == 0) { +#if HASP_USE_SPIFFS > 0 + EepromStream eepromStream(0, 2048); + DeserializationError error = deserializeJson(settings, eepromStream); +#else + continue; +#endif + } else { +#if HASP_USE_SPIFFS > 0 + if(!SPIFFS.begin()) { + Log.error(F("FILE: SPI flash init failed. Unable to mount FS: Using default settings...")); + return; + } +#endif + configGetConfig(settings, true); + } + + //#if HASP_USE_SPIFFS > 0 Log.verbose(F("Loading debug settings")); debugSetConfig(settings[F("debug")]); Log.verbose(F("Loading GUI settings")); @@ -303,29 +348,30 @@ void configSetup() haspSetConfig(settings[F("hasp")]); // otaGetConfig(settings[F("ota")]); -#if HASP_USE_WIFI +#if HASP_USE_WIFI>0 Log.verbose(F("Loading WiFi settings")); wifiSetConfig(settings[F("wifi")]); -#if HASP_USE_MQTT +#endif +#if HASP_USE_MQTT>0 Log.verbose(F("Loading MQTT settings")); mqttSetConfig(settings[F("mqtt")]); #endif -#if HASP_USE_TELNET +#if HASP_USE_TELNET>0 Log.verbose(F("Loading Telnet settings")); telnetSetConfig(settings[F("telnet")]); #endif -#if HASP_USE_MDNS +#if HASP_USE_MDNS>0 Log.verbose(F("Loading MDNS settings")); mdnsSetConfig(settings[F("mdns")]); #endif -#if HASP_USE_HTTP +#if HASP_USE_HTTP>0 Log.verbose(F("Loading HTTP settings")); httpSetConfig(settings[F("http")]); #endif -#endif + // } + Log.notice(F("User configuration loaded")); } - Log.notice(F("User configuration loaded")); -#endif + //#endif } void configOutput(const JsonObject & settings) diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp index 854b9db4..38033453 100644 --- a/src/hasp_debug.cpp +++ b/src/hasp_debug.cpp @@ -15,7 +15,7 @@ #endif #include "hasp_hal.h" -#if HASP_USE_MQTT>0 +#if HASP_USE_MQTT > 0 #include "hasp_mqtt.h" #endif @@ -31,11 +31,11 @@ #define SERIAL_SPEED 115200 #endif -#if HASP_USE_TELNET != 0 +#if HASP_USE_TELNET > 0 #include "hasp_telnet.h" #endif -#if HASP_USE_SYSLOG != 0 +#if HASP_USE_SYSLOG > 0 #include "Syslog.h" #ifndef SYSLOG_SERVER @@ -71,9 +71,11 @@ Syslog * syslog; #endif // USE_SYSLOG // Serial Settings +uint8_t serialInputIndex = 0; // Empty buffer +char serialInputBuffer[1024]; uint16_t debugSerialBaud = SERIAL_SPEED / 10; // Multiplied by 10 bool debugSerialStarted = false; -bool debugAnsiCodes = true; +bool debugAnsiCodes = true; //#define TERM_COLOR_Black "\u001b[30m" #define TERM_COLOR_GRAY "\e[37m" @@ -94,11 +96,12 @@ String debugHaspHeader() { String header((char *)0); header.reserve(256); - header = F(" _____ _____ _____ _____\r\n" - " | | | _ | __| _ |\r\n" - " | | |__ | __|\r\n" - " |__|__|__|__|_____|__|\r\n" - " Home Automation Switch Plate\r\n"); + if(debugAnsiCodes) header += TERM_COLOR_YELLOW; + header += F(" _____ _____ _____ _____\r\n" + " | | | _ | __| _ |\r\n" + " | | |__ | __|\r\n" + " |__|__|__|__|_____|__|\r\n" + " Home Automation Switch Plate\r\n"); char buffer[128]; snprintf(buffer, sizeof(buffer), PSTR(" Open Hardware edition v%u.%u.%u\r\n"), HASP_VERSION_MAJOR, HASP_VERSION_MINOR, HASP_VERSION_REVISION); @@ -119,7 +122,7 @@ void debugStart() // log/logf method) } -#if HASP_USE_SYSLOG != 0 +#if HASP_USE_SYSLOG > 0 void syslogSend(uint8_t priority, const char * debugText) { if(strlen(debugSyslogHost) != 0 && WiFi.isConnected()) { @@ -130,7 +133,7 @@ void syslogSend(uint8_t priority, const char * debugText) void debugSetup() { -#if HASP_USE_SYSLOG != 0 +#if HASP_USE_SYSLOG > 0 syslog = new Syslog(syslogClient, debugSyslogProtocol == 0 ? SYSLOG_PROTO_IETF : SYSLOG_PROTO_BSD); syslog->server(debugSyslogHost, debugSyslogPort); syslog->deviceHostname(mqttNodeName); @@ -155,7 +158,7 @@ bool debugGetConfig(const JsonObject & settings) if(debugTelePeriod != settings[FPSTR(F_DEBUG_TELEPERIOD)].as()) changed = true; settings[FPSTR(F_DEBUG_TELEPERIOD)] = debugTelePeriod; -#if HASP_USE_SYSLOG != 0 +#if HASP_USE_SYSLOG > 0 if(strcmp(debugSyslogHost, settings[FPSTR(F_CONFIG_HOST)].as().c_str()) != 0) changed = true; settings[FPSTR(F_CONFIG_HOST)] = debugSyslogHost; @@ -193,7 +196,7 @@ bool debugSetConfig(const JsonObject & settings) changed |= configSet(debugTelePeriod, settings[FPSTR(F_DEBUG_TELEPERIOD)], PSTR("debugTelePeriod")); /* Syslog Settings*/ -#if HASP_USE_SYSLOG != 0 +#if HASP_USE_SYSLOG > 0 if(!settings[FPSTR(F_CONFIG_HOST)].isNull()) { changed |= strcmp(debugSyslogHost, settings[FPSTR(F_CONFIG_HOST)]) != 0; strncpy(debugSyslogHost, settings[FPSTR(F_CONFIG_HOST)], sizeof(debugSyslogHost)); @@ -216,21 +219,23 @@ static void debugPrintTimestamp(int level, Print * _logOutput) time_t rawtime; struct tm * timeinfo; - //time(&rawtime); - //timeinfo = localtime(&rawtime); + // time(&rawtime); + // timeinfo = localtime(&rawtime); // strftime(buffer, sizeof(buffer), "%b %d %H:%M:%S.", timeinfo); // Serial.println(buffer); debugSendAnsiCode(F(TERM_COLOR_CYAN), _logOutput); - /* if(timeinfo->tm_year >= 120) { - char buffer[64]; - strftime(buffer, sizeof(buffer), "[%b %d %H:%M:%S.", timeinfo); // Literal String - _logOutput->print(buffer); - _logOutput->printf(PSTR("%03lu]"), millis() % 1000); - } else */ { - _logOutput->printf(PSTR("[%20.3f]"), (float)millis() / 1000); + /* if(timeinfo->tm_year >= 120) { + char buffer[64]; + strftime(buffer, sizeof(buffer), "[%b %d %H:%M:%S.", timeinfo); // Literal String + _logOutput->print(buffer); + _logOutput->printf(PSTR("%03lu]"), millis() % 1000); + } else */ + { + uint32_t msecs = millis(); + _logOutput->printf(PSTR("[%16d.%03d]"), msecs / 1000, msecs % 1000); } } @@ -328,15 +333,17 @@ void debugPreSetup(JsonObject settings) uint32_t baudrate = settings[FPSTR(F_CONFIG_BAUD)].as() * 10; if(baudrate == 0) baudrate = SERIAL_SPEED; - if(baudrate >= 9600u) { /* the baudrates are stored divided by 10 */ + if(baudrate >= 9600u) { /* the baudrates are stored divided by 10 */ -#ifdef STM32_CORE_VERSION_MAJOR - Serial.setRx(PA3); // User Serial2 - Serial.setTx(PA2); +#if defined(STM32F4xx) +#ifndef STM32_SERIAL1 // Define what Serial port to use for log output + Serial.setRx(PA3); // User Serial2 + Serial.setTx(PA2); +#endif #endif Serial.begin(baudrate); /* prepare for possible serial debug */ delay(10); - Log.registerOutput(0, &Serial, LOG_LEVEL_VERBOSE, true); + Log.registerOutput(0, &Serial, LOG_LEVEL_VERBOSE, true); debugSerialStarted = true; Serial.println(); Log.trace(("Serial started at %u baud"), baudrate); @@ -373,7 +380,26 @@ void debugLvgl(lv_log_level_t level, const char * file, uint32_t line, const cha #endif void debugLoop() -{} +{ + while(Serial.available()) { + char ch = Serial.read(); + Serial.print(ch); + if(ch == 13 || ch == 10) { + serialInputBuffer[serialInputIndex] = 0; + if(serialInputIndex > 0) dispatchCommand(serialInputBuffer); + serialInputIndex = 0; + } else { + if(serialInputIndex < sizeof(serialInputBuffer) - 1) { + serialInputBuffer[serialInputIndex++] = ch; + } + serialInputBuffer[serialInputIndex] = 0; + if(strcmp(serialInputBuffer, "jsonl=") == 0) { + dispatchJsonl(Serial); + serialInputIndex = 0; + } + } + } +} /*void printLocalTime() { diff --git a/src/hasp_dispatch.cpp b/src/hasp_dispatch.cpp index bed14991..ab227e64 100644 --- a/src/hasp_dispatch.cpp +++ b/src/hasp_dispatch.cpp @@ -38,7 +38,7 @@ void dispatchLoop() void dispatchStatusUpdate() { -#if HASP_USE_MQTT +#if HASP_USE_MQTT>0 mqtt_send_statusupdate(); #endif } @@ -48,11 +48,15 @@ void dispatchOutput(int output, bool state) int pin = 0; if(pin >= 0) { + Log.notice(F("PIN OUTPUT STATE %d"),state); #if defined(ARDUINO_ARCH_ESP32) ledcWrite(99, state ? 1023 : 0); // ledChannel and value +#elif defined(STM32F4xx) + digitalWrite(HASP_OUTPUT_PIN, state); #else - analogWrite(pin, state ? 1023 : 0); + digitalWrite(D1, state); + // analogWrite(pin, state ? 1023 : 0); #endif } } @@ -95,11 +99,6 @@ void dispatchAttribute(String strTopic, const char * payload) { if(strTopic.startsWith("p[")) { dispatchButtonAttribute(strTopic, payload); - } else if(strTopic.startsWith(F("output"))) { -#if defined(ARDUINO_ARCH_ESP8266) - uint8_t state = isON(payload) ? HIGH : LOW; - digitalWrite(D1, state); -#endif } else if(strTopic == F("page")) { dispatchPage(payload); @@ -138,9 +137,12 @@ void dispatchPage(String strPageid) String strPage((char *)0); strPage.reserve(128); strPage = haspGetPage(); -#if HASP_USE_MQTT +#if HASP_USE_MQTT > 0 mqtt_send_state(F("page"), strPage.c_str()); #endif +#if HASP_USE_TASMOTA_SLAVE > 0 + slave_send_state(F("page"), strPage.c_str()); +#endif } void dispatchClearPage(String strPageid) @@ -159,12 +161,16 @@ void dispatchDim(String strDimLevel) // Set the current state if(strDimLevel.length() != 0) guiSetDim(strDimLevel.toInt()); dispatchPrintln(F("DIM"), strDimLevel); - -#if HASP_USE_MQTT char buffer[8]; +#if defined(HASP_USE_MQTT) || defined(HASP_USE_TASMOTA_SLAVE) itoa(guiGetDim(), buffer, DEC); +#if HASP_USE_MQTT > 0 mqtt_send_state(F("dim"), buffer); #endif +#if HASP_USE_TASMOTA_SLAVE > 0 + slave_send_state(F("dim"), buffer); +#endif +#endif } void dispatchBacklight(String strPayload) @@ -177,14 +183,18 @@ void dispatchBacklight(String strPayload) // Return the current state strPayload = getOnOff(guiGetBacklight()); -#if HASP_USE_MQTT +#if HASP_USE_MQTT > 0 mqtt_send_state(F("light"), strPayload.c_str()); #endif +#if HASP_USE_TASMOTA_SLAVE > 0 + slave_send_state(F("light"), strPayload.c_str()); +#endif + } void dispatchCommand(String cmnd) { - // dispatchPrintln(F("CMND"), cmnd); + dispatchPrintln(F("CMND"), cmnd); if(cmnd.startsWith(F("page "))) { cmnd = cmnd.substring(5, cmnd.length()); @@ -266,34 +276,46 @@ void dispatchJsonl(char * payload) void dispatchIdle(const char * state) { -#if HASP_USE_MQTT>0 - mqtt_send_state(F("idle"), state); -#else +#if !defined(HASP_USE_MQTT) && !defined(HASP_USE_TASMOTA_SLAVE) Log.notice(F("OUT: idle = %s"), state); +#else +#if HASP_USE_MQTT > 0 + mqtt_send_state(F("idle"), state); +#endif +#if HASP_USE_TASMOTA_SLAVE > 0 + slave_send_state(F("idle"), state); +#endif #endif } void dispatchReboot(bool saveConfig) { if(saveConfig) configWriteConfig(); -#if HASP_USE_MQTT>0 +#if HASP_USE_MQTT > 0 mqttStop(); // Stop the MQTT Client first #endif debugStop(); -#if HASP_USE_WIFI>0 +#if HASP_USE_WIFI > 0 wifiStop(); #endif Log.verbose(F("-------------------------------------")); Log.notice(F("STOP: Properly Rebooting the MCU now!")); Serial.flush(); - //halRestart(); + halRestart(); } void dispatch_button(uint8_t id, const char * event) { +#if !defined(HASP_USE_MQTT) && !defined(HASP_USE_TASMOTA_SLAVE) + Log.notice(F("OUT: input%d = %s"), id, event); +#else #if HASP_USE_MQTT > 0 mqtt_send_input(id, event); #endif +#if HASP_USE_TASMOTA_SLAVE>0 + slave_send_input(id, event); +#endif +#endif } void dispatchWebUpdate(const char * espOtaUrl) @@ -306,10 +328,15 @@ void dispatchWebUpdate(const char * espOtaUrl) void IRAM_ATTR dispatch_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data) { +#if !defined(HASP_USE_MQTT) && !defined(HASP_USE_TASMOTA_SLAVE) + Log.notice(F("OUT: json = {\"p[%u].b[%u].%s\":\"%s\"}"), pageid, btnid, attribute, data); +#else #if HASP_USE_MQTT > 0 mqtt_send_obj_attribute_str(pageid, btnid, attribute, data); -#else - Log.notice(F("OUT: json = {\"p[%u].b[%u].%s\":\"%s\"}"), pageid, btnid, attribute, data); +#endif +#if HASP_USE_TASMOTA_SLAVE > 0 + slave_send_obj_attribute_str(pageid, btnid, attribute, data); +#endif #endif } @@ -356,14 +383,14 @@ void dispatchConfig(const char * topic, const char * payload) haspGetConfig(settings); } -#if HASP_USE_WIFI +#if HASP_USE_WIFI > 0 else if(strcmp_P(topic, PSTR("wifi")) == 0) { if(update) wifiSetConfig(settings); else wifiGetConfig(settings); } -#if HASP_USE_MQTT +#if HASP_USE_MQTT > 0 else if(strcmp_P(topic, PSTR("mqtt")) == 0) { if(update) mqttSetConfig(settings); @@ -371,11 +398,11 @@ void dispatchConfig(const char * topic, const char * payload) mqttGetConfig(settings); } #endif -#if HASP_USE_TELNET +#if HASP_USE_TELNET > 0 // else if(strcmp_P(topic, PSTR("telnet")) == 0) // telnetGetConfig(settings[F("telnet")]); #endif -#if HASP_USE_MDNS +#if HASP_USE_MDNS > 0 else if(strcmp_P(topic, PSTR("mdns")) == 0) { if(update) mdnsSetConfig(settings); @@ -383,7 +410,7 @@ void dispatchConfig(const char * topic, const char * payload) mdnsGetConfig(settings); } #endif -#if HASP_USE_HTTP +#if HASP_USE_HTTP > 0 else if(strcmp_P(topic, PSTR("http")) == 0) { if(update) httpSetConfig(settings); @@ -397,10 +424,15 @@ void dispatchConfig(const char * topic, const char * payload) if(!update) { settings.remove(F("pass")); // hide password in output size_t size = serializeJson(doc, buffer, sizeof(buffer)); -#if HASP_USE_MQTT - mqtt_send_state(F("config"), buffer); -#else +#if !defined(HASP_USE_MQTT) && !defined(HASP_USE_TASMOTA_SLAVE) Log.notice(F("OUT: config %s = %s"),topic,buffer); +#else +#if HASP_USE_MQTT > 0 + mqtt_send_state(F("config"), buffer); +#endif +#if HASP_USE_TASMOTA > 0 + slave_send_state(F("config"), buffer); +#endif #endif } } diff --git a/src/hasp_eeprom.cpp b/src/hasp_eeprom.cpp index 1aed0979..d53963fe 100644 --- a/src/hasp_eeprom.cpp +++ b/src/hasp_eeprom.cpp @@ -1,49 +1,23 @@ #include #include "EEPROM.h" -#include "hasp_debug.h" - -void eepromWrite(char addr, std::string & data); -std::string eepromRead(char addr); - void eepromSetup() { + +#if defined(STM32Fxx) + eeprom_buffer_fill(); + char buffer[] = "{\"objid\":10,\"id\":1,\"page\":0,\"x\":10,\"y\":45,\"w\":220,\"h\":55,\"toggle\":\"TRUE\",\"txt\":\"Toggle Me\"}"; + uint size = strlen(buffer); + uint16_t i; + for(i = 0; i < size; i++) eeprom_buffered_write_byte(i+4096, buffer[i]); + eeprom_buffered_write_byte(i+4096, 0); + // eeprom_buffer_flush(); +#endif + + // ESP8266 // Don't start at boot, only at write // EEPROM.begin(1024); // debugPrintln("EEPROM: Started Eeprom"); } void eepromLoop() -{} - -void eepromUpdate(uint16_t addr, char ch) -{ - if(EEPROM.read(addr) != ch) { - EEPROM.write(addr, ch); - } -} - -void eepromWrite(uint16_t addr, std::string & data) -{ - int count = data.length(); - for(int i = 0; i < count; i++) { - eepromUpdate(addr + i, data[i]); - } - eepromUpdate(addr + count, '\0'); - // EEPROM.commit(); -} - -std::string eepromRead(uint16_t addr) -{ - char data[1024]; // Max 1024 Bytes - int len = 0; - unsigned char k; - k = EEPROM.read(addr); - while(k != '\0' && len < 1023) // Read until null character - { - k = EEPROM.read(addr + len); - if((uint8_t(k) < 32) || (uint8_t(k) > 127)) break; // check for printable ascii, includes '\0' - data[len] = k; - len++; - } - return std::string(data); -} \ No newline at end of file +{} \ No newline at end of file diff --git a/src/hasp_ethernet.cpp b/src/hasp_ethernet.cpp new file mode 100644 index 00000000..d6f82bff --- /dev/null +++ b/src/hasp_ethernet.cpp @@ -0,0 +1,96 @@ +#include +#include "ArduinoJson.h" +#include "ArduinoLog.h" +#include "hasp_conf.h" +#include "hasp_hal.h" + +#if HASP_USE_ETHERNET > 0 + +EthernetClient EthClient; +IPAddress ip; + +void ethernetSetup() +{ +#if USE_BUILTIN_ETHERNET > 0 + // start Ethernet and UDP + Log.notice(F("ETH: Begin Ethernet LAN8720")); + if(Ethernet.begin() == 0) { + Log.notice(F("ETH: Failed to configure Ethernet using DHCP")); + } else { + ip = Ethernet.localIP(); + Log.notice(F("ETH: DHCP Success got IP %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + } + + Log.notice(F("ETH: MAC Address %s"), halGetMacAddress(0, ":")); + +#else + byte mac[6]; + uint32_t baseUID = (uint32_t)UID_BASE; + mac[0] = 0x00; + mac[1] = 0x80; + mac[2] = 0xE1; + mac[3] = (baseUID & 0x00FF0000) >> 16; + mac[4] = (baseUID & 0x0000FF00) >> 8; + mac[5] = (baseUID & 0x000000FF); + + char ethHostname[12]; + memset(ethHostname, 0 ,sizeof(ethHostname)); + snprintf(ethHostname, sizeof(ethHostname), PSTR("HASP-%02x%02x%02x"), mac[3], mac[4], mac[5]); + + Ethernet.setCsPin(W5500_CS); + Ethernet.setRstPin(W5500_RST); + Ethernet.setHostname(ethHostname); + Log.notice(F("ETH: Begin Ethernet W5500")); + if(Ethernet.begin(mac) == 0) { + Log.notice(F("ETH: Failed to configure Ethernet using DHCP")); + } else { + ip = Ethernet.localIP(); + Log.notice(F("ETH: DHCP Success got IP %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + } +#endif +} + +void ethernetLoop(void) +{ + switch(Ethernet.maintain()) { + case 1: + // renewed fail + Log.notice(F("ETH: Error: renewed fail")); + break; + + case 2: + // renewed success + ip = Ethernet.localIP(); + Log.notice(F("ETH: DHCP Renew Success got IP=%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + break; + + case 3: + // rebind fail + Log.notice(F("Error: rebind fail")); + break; + + case 4: + // rebind success + ip = Ethernet.localIP(); + Log.notice(F("ETH: DHCP Rebind Success got IP=%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + break; + + default: + // nothing happened + break; + } +} + +bool ethernetEvery5Seconds() +{ + bool state; +#if USE_BUILTIN_ETHERNET > 0 + state = Ethernet.linkStatus() == LinkON; +#else + state = Ethernet.link() == 1; +#endif + Log.warning(F("ETH: %s"), state ? F("ONLINE") : F("OFFLINE")); + return state; +} + +#endif \ No newline at end of file diff --git a/src/hasp_ethernet.h b/src/hasp_ethernet.h new file mode 100644 index 00000000..177f0908 --- /dev/null +++ b/src/hasp_ethernet.h @@ -0,0 +1,8 @@ +#ifndef HASP_ETHERNET_H +#define HASP_ETHERNET_H + +void ethernetSetup(); +void ethernetLoop(void); + +bool ethernetEvery5Seconds(); +#endif \ No newline at end of file diff --git a/src/hasp_gpio.cpp b/src/hasp_gpio.cpp index 1ab5cefb..885278db 100644 --- a/src/hasp_gpio.cpp +++ b/src/hasp_gpio.cpp @@ -1,10 +1,254 @@ -#include -#include "ArduinoJson.h" +#include "Arduino.h" +#include "ArduinoLog.h" + +#include "AceButton.h" +#include "lv_conf.h" // For timing defines + +#include "hasp_conf.h" +#include "hasp_gpio.h" +#include "hasp_dispatch.h" + +#define HASP_NUM_GPIO_CONFIG 5 + +uint8_t gpioUsedInputCount = 0; +uint16_t gpioConfig[HASP_NUM_GPIO_CONFIG]; + +using namespace ace_button; +static AceButton * button[HASP_NUM_INPUTS]; + +struct hasp_gpio_config_t { + const uint8_t pin; + const uint8_t group; + const uint8_t io_mode; + bool default_state; +}; + +// An array of button pins, led pins, and the led states. Cannot be const +// because ledState is mutable. + hasp_gpio_config_t gpioConfig2[HASP_NUM_GPIO_CONFIG] = { + {2, 8, INPUT, LOW}, + {3, 9, OUTPUT, LOW}, + {4, 10, INPUT, HIGH}, + {5, 11, OUTPUT, LOW}, + {6, 12, INPUT, LOW}, +}; + +#if defined(ARDUINO_ARCH_ESP32) +class TouchConfig : public ButtonConfig { + public: + TouchConfig(); + + protected: + // Number of iterations to sample the capacitive switch. Higher number + // provides better smoothing but increases the time taken for a single read. + static const uint8_t kSamples = 10; + + // The threshold value which is considered to be a "touch" on the switch. + static const long kTouchThreshold = 70; + + int readButton(uint8_t pin) override + { + // long total = mSensor.capacitiveSensor(kSamples); + return (touchRead(pin) > kTouchThreshold) ? LOW : HIGH; + } +}; + +TouchConfig touchConfig(); +#endif + +static void gpio_event_cb(AceButton * button, uint8_t eventType, uint8_t buttonState) +{ + char buffer[16]; + switch(eventType) { + case 0: // AceButton::kEventPressed: + memcpy_P(buffer, PSTR("DOWN"), sizeof(buffer)); + break; + case 2: // AceButton::kEventClicked: + memcpy_P(buffer, PSTR("SHORT"), sizeof(buffer)); + break; + case AceButton::kEventDoubleClicked: + memcpy_P(buffer, PSTR("DOUBLE"), sizeof(buffer)); + break; + case 4: // AceButton::kEventLongPressed: + memcpy_P(buffer, PSTR("LONG"), sizeof(buffer)); + break; + case 5: // AceButton::kEventRepeatPressed: + // return; // Fix needed for switches + memcpy_P(buffer, PSTR("HOLD"), sizeof(buffer)); + break; + case 1: // AceButton::kEventReleased: + memcpy_P(buffer, PSTR("UP"), sizeof(buffer)); + break; + default: + memcpy_P(buffer, PSTR("UNKNOWN"), sizeof(buffer)); + } + dispatch_button(button->getId(), buffer); +} + +void aceButtonSetup(void) +{ + ButtonConfig * buttonConfig = ButtonConfig::getSystemButtonConfig(); + buttonConfig->setEventHandler(gpio_event_cb); + + // Features + buttonConfig->setFeature(ButtonConfig::kFeatureClick); + buttonConfig->setFeature(ButtonConfig::kFeatureLongPress); + buttonConfig->setFeature(ButtonConfig::kFeatureRepeatPress); + // buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick); + // buttonConfig->setFeature(ButtonConfig::kFeatureSuppressClickBeforeDoubleClick); + + // Delays + buttonConfig->setClickDelay(LV_INDEV_DEF_LONG_PRESS_TIME); + buttonConfig->setDoubleClickDelay(LV_INDEV_DEF_LONG_PRESS_TIME); + buttonConfig->setLongPressDelay(LV_INDEV_DEF_LONG_PRESS_TIME); + buttonConfig->setRepeatPressDelay(LV_INDEV_DEF_LONG_PRESS_TIME); + buttonConfig->setRepeatPressInterval(LV_INDEV_DEF_LONG_PRESS_REP_TIME); +} + +void IRAM_ATTR gpioLoop(void) +{ + // Should be called every 4-5ms or faster, for the default debouncing time of ~20ms. + for(uint8_t i = 0; i < gpioUsedInputCount; i++) { + if(button[i]) button[i]->check(); + } +} + +void gpioAddButton( uint8_t pin, uint8_t input_mode, uint8_t default_state, uint8_t channel) +{ + + + uint8_t i; + for(i = 0; i < HASP_NUM_INPUTS; i++) { + + if(!button[i]) { + button[i] = new AceButton(pin, default_state, channel); + // button[i]->init(pin, default_state, channel); + + if(button[i]) { + pinMode(pin, input_mode); + + ButtonConfig * buttonConfig = button[i]->getButtonConfig(); + buttonConfig->setEventHandler(gpio_event_cb); + buttonConfig->setFeature(ButtonConfig::kFeatureClick); + buttonConfig->clearFeature(ButtonConfig::kFeatureDoubleClick); + buttonConfig->setFeature(ButtonConfig::kFeatureLongPress); + buttonConfig->clearFeature(ButtonConfig::kFeatureRepeatPress); + buttonConfig->clearFeature( + ButtonConfig::kFeatureSuppressClickBeforeDoubleClick); // Causes annoying pauses + + Log.verbose(F("GPIO: Button%d created on pin %d (channel %d) mode %d default %d"), i, pin, channel, + input_mode, default_state); + gpioUsedInputCount = i + 1; + return; + } + } + } + Log.error(F("GPIO: Failed to create Button%d pin %d (channel %d). All %d slots available are in use!"), i, pin, + channel, HASP_NUM_INPUTS); +} + +void gpioAddTouchButton( uint8_t pin, uint8_t input_mode, uint8_t default_state, uint8_t channel) +{ + uint8_t i; + for(i = 0; i < HASP_NUM_INPUTS; i++) { + + if(!button[i]) { + button[i] = new AceButton(); + + if(button[i]) { + pinMode(pin, input_mode); + + ButtonConfig * buttonConfig = button[i]->getButtonConfig(); + buttonConfig->setEventHandler(gpio_event_cb); + buttonConfig->setFeature(ButtonConfig::kFeatureClick); + buttonConfig->clearFeature(ButtonConfig::kFeatureDoubleClick); + buttonConfig->setFeature(ButtonConfig::kFeatureLongPress); + buttonConfig->clearFeature(ButtonConfig::kFeatureRepeatPress); + buttonConfig->clearFeature( + ButtonConfig::kFeatureSuppressClickBeforeDoubleClick); // Causes annoying pauses + + Log.verbose(F("GPIO: Button%d created on pin %d (channel %d) mode %d default %d"), i, pin, channel, + input_mode, default_state); + gpioUsedInputCount = i + 1; + return; + } + } + } + Log.error(F("GPIO: Failed to create Button%d pin %d (channel %d). All %d slots available are in use!"), i, pin, + channel, HASP_NUM_INPUTS); +} void gpioSetup() { + aceButtonSetup(); + + // gpioConfig[0] = PD15 * 256 + 5 + (INPUT << 3); #if defined(ARDUINO_ARCH_ESP8266) + gpioAddButton( D2, INPUT_PULLUP, HIGH, 1); pinMode(D1, OUTPUT); - pinMode(D2, INPUT_PULLUP); #endif + +#if defined(ARDUINO_ARCH_ESP32) + gpioAddButton( D2, INPUT, HIGH, 1); + pinMode(D1, OUTPUT); +#endif + + for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { + uint8_t pin = (gpioConfig[i] >> 8) & 0xFF; + uint8_t channel = gpioConfig[i] & 0b111; // 3bit + uint8_t input_mode = (gpioConfig[i] >> 3) & 0b11; // 2bit gpio mode + //uint8_t input_mode = gpioConfig[i].io_mode + uint8_t gpiotype = (gpioConfig[i] >> 5) & 0b111; // 3bit + uint8_t default_state = gpioConfig[i] & 0b1; // 1bit: 0=LOW, 1=HIGH + + switch(input_mode) { + case 1: + input_mode = OUTPUT; + break; + case 2: + input_mode = INPUT_PULLUP; + break; +#ifndef ARDUINO_ARCH_ESP8266 + case 3: + input_mode = INPUT_PULLDOWN; + break; +#endif + default: + input_mode = INPUT; + } + + switch(gpiotype) { + case HASP_GPIO_SWITCH: + case HASP_GPIO_BUTTON: + // gpioAddButton(gpioConfig[i].io_mode.pin, input_mode, gpioConfig[i].default_state, gpioConfig[i].group); + break; + + case HASP_GPIO_RELAY: + pinMode(pin, OUTPUT); + break; + + // case HASP_GPIO_LED: + case HASP_GPIO_PWM: + case HASP_GPIO_BACKLIGHT: + pinMode(pin, OUTPUT); +#if defined(ARDUINO_ARCH_ESP32) + // configure LED PWM functionalitites + ledcSetup(channel, 20000, 10); + // attach the channel to the GPIO to be controlled + ledcAttachPin(pin, channel); +#endif + break; + } + } + + /* + #if defined(ARDUINO_ARCH_ESP8266) + pinMode(D1, OUTPUT); + pinMode(D2, INPUT_PULLUP); + #endif + #if defined(STM32F4xx) + pinMode(HASP_OUTPUT_PIN, OUTPUT); + pinMode(HASP_INPUT_PIN, INPUT); + #endif + */ } \ No newline at end of file diff --git a/src/hasp_gpio.h b/src/hasp_gpio.h index 075f3a12..9a5c3b91 100644 --- a/src/hasp_gpio.h +++ b/src/hasp_gpio.h @@ -1,3 +1,25 @@ +#ifndef HASP_GPIO_H +#define HASP_GPIO_H + #include "ArduinoJson.h" -void gpioSetup(); +#ifdef __cplusplus +extern "C" { +#endif + +void gpioSetup(void); +void IRAM_ATTR gpioLoop(void); + +enum lv_hasp_gpio_type_t { + HASP_GPIO_SWITCH = 0, + HASP_GPIO_BUTTON = 1, + HASP_GPIO_RELAY = 2, + HASP_GPIO_PWM = 3, + HASP_GPIO_BACKLIGHT = 4, +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif \ No newline at end of file diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 021b890a..7c33af36 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -18,7 +18,7 @@ //#include "lv_ex_conf.h" //#include "tpcal.h" -#if HASP_USE_PNGDECODE +#if HASP_USE_PNGDECODE > 0 #include "png_decoder.h" #endif @@ -26,7 +26,7 @@ #define TOUCH_DRIVER 0 #endif -#if HASP_USE_SPIFFS +#if HASP_USE_SPIFFS > 0 #if defined(ARDUINO_ARCH_ESP32) #include "SPIFFS.h" #endif @@ -41,6 +41,11 @@ File pFileOut; #endif uint8_t guiSnapshot = 0; +#if defined(STM32F4xx) +//#include +// EthernetWebServer * webClient(0); +#endif + #if defined(ARDUINO_ARCH_ESP8266) #include ESP8266WebServer * webClient; // for snatshot @@ -75,10 +80,7 @@ static uint8_t guiRotation = TFT_ROTATION; #if ESP32 > 0 || ESP8266 > 0 static Ticker tick; /* timer for interrupt handler */ #else -static Ticker tick(lv_tick_handler,guiTickPeriod); -uint8_t serialInputIndex = 0; // Empty buffer -char serialInputBuffer[1024]; - +static Ticker tick(lv_tick_handler, guiTickPeriod); #endif static TFT_eSPI tft; // = TFT_eSPI(); /* TFT instance */ static uint16_t calData[5] = {0, 65535, 0, 65535, 0}; @@ -174,14 +176,15 @@ static bool guiCheckSleep() /* Flush VDB bytes to a stream */ static void gui_take_screenshot(uint8_t * data_p, size_t len) { -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) size_t res = 0; switch(guiSnapshot) { +#if HASP_USE_SPIFFS > 0 case 1: res = pFileOut.write(data_p, len); break; +#endif case 2: - res = webClient->client().write(data_p, len); + res = httpClientWrite(data_p, len); break; default: res = 0; // nothing to do @@ -189,7 +192,6 @@ static void gui_take_screenshot(uint8_t * data_p, size_t len) if(res != len) { Log.warning(F("GUI: Pixelbuffer not completely sent")); } -#endif } /* Experimetnal Display flushing */ @@ -200,7 +202,6 @@ static void IRAM_ATTR tft_espi_flush(lv_disp_drv_t * disp, const lv_area_t * are /* Update TFT */ tft.startWrite(); /* Start new TFT transaction */ tft.setWindow(area->x1, area->y1, area->x2, area->y2); /* set the working window */ - tft.setSwapBytes(true); /* set endianess */ tft.pushPixels((uint16_t *)color_p, len); /* Write words at once */ tft.endWrite(); /* terminate TFT transaction */ @@ -306,14 +307,6 @@ static void IRAM_ATTR lv_tick_handler(void) lv_tick_inc(guiTickPeriod); } -#ifdef STM32_CORE_VERSION -void Update_IT_callback(void) -{ - Serial.print("?"); - lv_tick_inc(guiTickPeriod); -} -#endif - /* Reading input device (simulated encoder here) */ /*bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data) { @@ -628,6 +621,14 @@ void guiSetup() { /* TFT init */ tft.begin(); + tft.setSwapBytes(true); /* set endianess */ + +#ifdef USE_DMA_TO_TFT + // DMA - should work with STM32F2xx/F4xx/F7xx processors + // NOTE: >>>>>> DMA IS FOR SPI DISPLAYS ONLY <<<<<< + tft.initDMA(); // Initialise the DMA engine (tested with STM32F446 and STM32F767) +#endif + tft.setRotation(guiRotation); /* 1/3=Landscape or 0/2=Portrait orientation */ #if TOUCH_DRIVER == 0 tft.setTouch(calData); @@ -656,14 +657,14 @@ void guiSetup() #else static lv_disp_buf_t disp_buf; static lv_color_t guiVdbBuffer1[16 * 512u]; // 16 KBytes - static lv_color_t guiVdbBuffer2[16 * 512u]; // 16 KBytes + // static lv_color_t guiVdbBuffer2[16 * 512u]; // 16 KBytes guiVDBsize = sizeof(guiVdbBuffer1) / sizeof(guiVdbBuffer1[0]); - lv_disp_buf_init(&disp_buf, guiVdbBuffer1, guiVdbBuffer2, guiVDBsize); - //lv_disp_buf_init(&disp_buf, guiVdbBuffer1, NULL, guiVDBsize); + // lv_disp_buf_init(&disp_buf, guiVdbBuffer1, guiVdbBuffer2, guiVDBsize); + lv_disp_buf_init(&disp_buf, guiVdbBuffer1, NULL, guiVDBsize); #endif /* Initialize PNG decoder */ -#if HASP_USE_PNGDECODE != 0 +#if HASP_USE_PNGDECODE > 0 png_decoder_init(); #endif @@ -673,8 +674,13 @@ void guiSetup() lv_fs_if_init(); // auxilary file system drivers #endif - /* Dump TFT Cofiguration */ + /* Dump TFT Configuration */ tftSetup(tft); +#ifdef USE_DMA_TO_TFT + Log.verbose(F("TFT: DMA : ENABELD")); +#else + Log.verbose(F("TFT: DMA : DISABELD")); +#endif /* Load User Settings */ // guiSetConfig(settings); @@ -780,27 +786,27 @@ void guiSetup() tick.attach_ms(guiTickPeriod, lv_tick_handler); #else -/* -#if defined(TIM1) - TIM_TypeDef * Instance = TIM1; -#else - TIM_TypeDef * Instance = TIM2; -#endif -*/ + /* + #if defined(TIM1) + TIM_TypeDef * Instance = TIM1; + #else + TIM_TypeDef * Instance = TIM2; + #endif + */ // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() // function is finished. - /* static HardwareTimer * MyTim = new HardwareTimer(Instance); - MyTim->pause(); - MyTim->setPrescaleFactor(1); - MyTim->setMode(0, TIMER_OUTPUT_COMPARE, NC); - MyTim->setOverflow(1000 * guiTickPeriod, MICROSEC_FORMAT); // MicroSec - MyTim->setCount(0,MICROSEC_FORMAT); - MyTim->refresh(); - MyTim->detachInterrupt(); - MyTim->attachInterrupt((void (*)(HardwareTimer *))lv_tick_handler); - MyTim->detachInterrupt(0); - MyTim->attachInterrupt(0,(void (*)(HardwareTimer *))lv_tick_handler); - MyTim->resume();*/ + /* static HardwareTimer * MyTim = new HardwareTimer(Instance); + MyTim->pause(); + MyTim->setPrescaleFactor(1); + MyTim->setMode(0, TIMER_OUTPUT_COMPARE, NC); + MyTim->setOverflow(1000 * guiTickPeriod, MICROSEC_FORMAT); // MicroSec + MyTim->setCount(0,MICROSEC_FORMAT); + MyTim->refresh(); + MyTim->detachInterrupt(); + MyTim->attachInterrupt((void (*)(HardwareTimer *))lv_tick_handler); + MyTim->detachInterrupt(0); + MyTim->attachInterrupt(0,(void (*)(HardwareTimer *))lv_tick_handler); + MyTim->resume();*/ tick.start(); #endif @@ -811,36 +817,17 @@ void guiSetup() void IRAM_ATTR guiLoop() { -#ifdef STM32_CORE_VERSION_MAJOR +#if defined(STM32F4xx) tick.update(); - - while(Serial.available()) { - char ch = Serial.read(); - Serial.print(ch); - if (ch == 13 ||ch == 10) { - serialInputBuffer[serialInputIndex] = 0; - if (serialInputIndex>0) dispatchCommand(serialInputBuffer); - serialInputIndex=0; - }else{ - if(serialInputIndex < sizeof(serialInputBuffer) - 1) { - serialInputBuffer[serialInputIndex++] = ch; - } - serialInputBuffer[serialInputIndex] = 0; - if (strcmp(serialInputBuffer,"jsonl=")==0){ - dispatchJsonl(Serial); - serialInputIndex=0; - } - } - } #endif - //lv_tick_handler(); + + // lv_tick_handler(); lv_task_handler(); /* let the GUI do its work */ guiCheckSleep(); #if TOUCH_DRIVER == 1 touch.loop(); #endif - } void guiStop() @@ -925,6 +912,7 @@ bool guiGetConfig(const JsonObject & settings) v.set(calData[i]); } else { changed = true; + tft.setTouch(calData); } i++; } @@ -935,6 +923,8 @@ bool guiGetConfig(const JsonObject & settings) for(uint8_t i = 0; i < 5; i++) { array.add(calData[i]); } + changed = true; + tft.setTouch(calData); } if(changed) configOutput(settings); @@ -991,6 +981,7 @@ bool guiSetConfig(const JsonObject & settings) oobeSetAutoCalibrate(true); } + if(status) tft.setTouch(calData); changed |= status; } @@ -1005,23 +996,15 @@ static void guiSetBmpHeader(uint8_t * buffer_p, int32_t data) *buffer_p++ = (data >> 24) & 0xFF; } -#if defined(ARDUINO_ARCH_ESP8266) static void guiSendBmpHeader(); -void guiTakeScreenshot(ESP8266WebServer & client) -#endif -#if defined(ARDUINO_ARCH_ESP32) - static void guiSendBmpHeader(); - -void guiTakeScreenshot(WebServer & client) -#endif // ESP32{ -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +void guiTakeScreenshot() { - webClient = &client; - lv_disp_t * disp = lv_disp_get_default(); + // webClient = &client; + // lv_disp_t * disp = lv_disp_get_default(); - webClient->setContentLength(122 + disp->driver.hor_res * disp->driver.ver_res * sizeof(lv_color_t)); - webClient->send(200, PSTR("image/bmp"), ""); + // webClient->setContentLength(122 + disp->driver.hor_res * disp->driver.ver_res * sizeof(lv_color_t)); + // webClient->send(200, PSTR("image/bmp"), ""); guiSnapshot = 2; guiSendBmpHeader(); @@ -1082,15 +1065,17 @@ static void guiSendBmpHeader() buffer[70 + 0] = 0x20; if(guiSnapshot == 1) { +#if HASP_USE_SPIFFS > 0 size_t len = pFileOut.write(buffer, 122); if(len != sizeof(buffer)) { Log.warning(F("GUI: Data written does not match header size")); } else { Log.verbose(F("GUI: Bitmap header written")); } +#endif } else if(guiSnapshot == 2) { - if(webClient->client().write(buffer, 122) != 122) { + if(httpClientWrite(buffer, 122) != 122) { Log.warning(F("GUI: Data sent does not match header size")); } else { Log.verbose(F("GUI: Bitmap header sent")); @@ -1107,6 +1092,7 @@ static void guiSendBmpHeader() * @param[in] pFileName Output binary file name. * **/ +#if HASP_USE_SPIFFS > 0 void guiTakeScreenshot(const char * pFileName) { pFileOut = SPIFFS.open(pFileName, "w"); diff --git a/src/hasp_gui.h b/src/hasp_gui.h index f6f0618f..76166eae 100644 --- a/src/hasp_gui.h +++ b/src/hasp_gui.h @@ -6,15 +6,17 @@ #include "lvgl.h" -#if defined(ARDUINO_ARCH_ESP8266) -#include -void guiTakeScreenshot(ESP8266WebServer & client); -#endif +// #if defined(ARDUINO_ARCH_ESP8266) +// #include +// void guiTakeScreenshot(ESP8266WebServer & client); +// #endif -#if defined(ARDUINO_ARCH_ESP32) -#include -void guiTakeScreenshot(WebServer & client); -#endif // ESP32 +// #if defined(ARDUINO_ARCH_ESP32) +// #include +// void guiTakeScreenshot(WebServer & client); +// #endif // ESP32 + +void guiTakeScreenshot(); void guiSetup(); void guiLoop(void); diff --git a/src/hasp_hal.cpp b/src/hasp_hal.cpp index 83eb07c7..0348fec9 100644 --- a/src/hasp_hal.cpp +++ b/src/hasp_hal.cpp @@ -1,25 +1,20 @@ -#if defined(ESP32) || defined(ESP8266) +#include "hasp_hal.h" +#include "hasp_conf.h" + +#if defined(ESP8266) #include +#include #endif -#include "hasp_hal.h" - -#if ESP32 +#if defined(ESP32) +#include +#include #include "esp_system.h" #endif #if defined(ARDUINO_ARCH_ESP32) #include // needed to get the ResetInfo -void halRestart(void) -{ -#if defined(ESP32) || defined(ESP8266) - ESP.restart(); -#else - NVIC_SystemReset(); -#endif -} - // Compatibility function for ESP8266 getRestInfo String esp32ResetReason(uint8_t cpuid) { @@ -90,6 +85,15 @@ String esp32ResetReason(uint8_t cpuid) } #endif +void halRestart(void) +{ +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) + ESP.restart(); +#else + NVIC_SystemReset(); +#endif +} + String halGetResetInfo() { #if defined(ARDUINO_ARCH_ESP32) @@ -105,57 +109,6 @@ String halGetResetInfo() #else return ""; #endif -} - - #ifdef __arm__ - // should use uinstd.h to define sbrk but Due causes a conflict - extern "C" char* sbrk(int incr); - #else // __ARM__ - extern char *__brkval; - #endif // __arm__ - - int freeMemory() { - char top; - #ifdef __arm__ - return &top - reinterpret_cast(sbrk(0)); - #elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) - return &top - __brkval; - #else // __arm__ - return __brkval ? &top - __brkval : &top - __malloc_heap_start; - #endif // __arm__ - } - -uint8_t halGetHeapFragmentation() -{ -#if defined(ARDUINO_ARCH_ESP32) - return (int8_t)(100.00f - (float)ESP.getMaxAllocHeap() * 100.00f / (float)ESP.getFreeHeap()); -#elif defined(ARDUINO_ARCH_ESP8266) - return ESP.getHeapFragmentation(); -#else - return 255; -#endif -} - -size_t halGetMaxFreeBlock() -{ -#if defined(ARDUINO_ARCH_ESP32) - return ESP.getMaxAllocHeap(); -#elif defined(ARDUINO_ARCH_ESP8266) - return ESP.getMaxFreeBlockSize(); -#else - return freeMemory(); -#endif -} - -size_t halGetFreeHeap(void) -{ -#if defined(ARDUINO_ARCH_ESP32) - return ESP.getFreeHeap(); -#elif defined(ARDUINO_ARCH_ESP8266) - return ESP.getFreeHeap(); -#else - return 1; -#endif } String halGetCoreVersion() @@ -193,8 +146,8 @@ String halGetChipModel() case CHIP_ESP32S2: model += F("ESP32-S2"); break; - #endif - default: +#endif + default: model = F("Unknown ESP"); } model += F(" rev"); @@ -202,4 +155,146 @@ String halGetChipModel() #endif // ESP32 return model; +} + +/*******************************/ +/* Memory Management Functions */ + +#if defined(STM32F4xx) +#include // for mallinfo() +#include // for sbrk() + +int freeHighMemory() +{ + char top; +#ifdef __arm__ + return &top - reinterpret_cast(sbrk(0)); +#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) + return &top - __brkval; +#else // __arm__ + return __brkval ? &top - __brkval : &top - __malloc_heap_start; +#endif // __arm__ +} +#endif + +/* +extern char *fake_heap_end; // current heap start +extern char *fake_heap_start; // current heap end + +char* getHeapStart() { + return fake_heap_start; +} + +char* getHeapEnd() { + return (char*)sbrk(0); +} + +char* getHeapLimit() { + return fake_heap_end; +} + +int getMemUsed() { // returns the amount of used memory in bytes + struct mallinfo mi = mallinfo(); + return mi.uordblks; +} + +int getMemFree() { // returns the amount of free memory in bytes + struct mallinfo mi = mallinfo(); + return mi.fordblks + freeHighMemory(); +} */ + +size_t halGetMaxFreeBlock() +{ +#if defined(ARDUINO_ARCH_ESP32) + return ESP.getMaxAllocHeap(); +#elif defined(ARDUINO_ARCH_ESP8266) + return ESP.getMaxFreeBlockSize(); +#else + return freeHighMemory(); +#endif +} + +size_t halGetFreeHeap(void) +{ +#if defined(ARDUINO_ARCH_ESP32) + return ESP.getFreeHeap(); +#elif defined(ARDUINO_ARCH_ESP8266) + return ESP.getFreeHeap(); +#else + struct mallinfo chuncks = mallinfo(); + + // fordblks + // This is the total size of memory occupied by free (not in use) chunks. + + return chuncks.fordblks + freeHighMemory(); +#endif +} + +uint8_t halGetHeapFragmentation() +{ +#if defined(ARDUINO_ARCH_ESP32) + return (int8_t)(100.00f - (float)ESP.getMaxAllocHeap() * 100.00f / (float)ESP.getFreeHeap()); +#elif defined(ARDUINO_ARCH_ESP8266) + return ESP.getHeapFragmentation(); +#else + return (int8_t)(100.00f - (float)freeHighMemory() * 100.00f / (float)halGetFreeHeap()); +#endif +} + +String halGetMacAddress(int start, const char * seperator) +{ + byte mac[6]; + +#if defined(STM32F4xx) + uint8_t * mac_p = nullptr; +#if USE_BUILTIN_ETHERNET > 0 + mac_p = Ethernet.MACAddress(); + for(uint8_t i = 0; i < 6; i++) mac[i] = *(mac_p + i); +#else + Ethernet.macAddress(mac); +#endif +#else + WiFi.macAddress(mac); +#endif + + String cMac((char *)0); + cMac.reserve(32); + + for(int i = start; i < 6; ++i) { + if(mac[i] < 0x10) cMac += "0"; + cMac += String(mac[i], HEX); + if(i < 5) cMac += seperator; + } + cMac.toUpperCase(); + return cMac; +} + +uint16_t halGetCpuFreqMHz() +{ +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_32) + return ESP.getCpuFreqMHz(); +#else + return (F_CPU / 1000 / 1000); +#endif +} + +String halFormatBytes(size_t bytes) +{ + String output((char *)0); + output.reserve(128); + + if(bytes < 1024) { + output += bytes; + } else if(bytes < (1024 * 1024)) { + output += bytes / 1024.0; + output += "K"; + } else if(bytes < (1024 * 1024 * 1024)) { + output += bytes / 1024.0 / 1024.0; + output += "M"; + } else { + output += bytes / 1024.0 / 1024.0 / 1024.0; + output += "G"; + } + output += "B"; + return output; } \ No newline at end of file diff --git a/src/hasp_hal.h b/src/hasp_hal.h index 23ac6501..9cdbef18 100644 --- a/src/hasp_hal.h +++ b/src/hasp_hal.h @@ -3,12 +3,15 @@ #include +void halRestart(void); uint8_t halGetHeapFragmentation(void); String halGetResetInfo(void); size_t halGetMaxFreeBlock(void); size_t halGetFreeHeap(void); String halGetCoreVersion(void); String halGetChipModel(); -void halRestart(void); +String halGetMacAddress(int start, const char * seperator); +uint16_t halGetCpuFreqMHz(void); +String halFormatBytes(size_t bytes); #endif \ No newline at end of file diff --git a/src/hasp_http.cpp b/src/hasp_http.cpp index 9bb9c5ab..3cb7e0fc 100644 --- a/src/hasp_http.cpp +++ b/src/hasp_http.cpp @@ -1,430 +1,3 @@ -#if 0 - -#include "Arduino.h" -#include "ArduinoJson.h" -#include "ArduinoLog.h" -//#include "Update.h" -#include "lvgl.h" - -#include "hasp_conf.h" - -#include "hasp_gui.h" -#include "hasp_hal.h" -#include "hasp_debug.h" -#include "hasp_mqtt.h" -#include "hasp_wifi.h" -#include "hasp_spiffs.h" -#include "hasp_config.h" -#include "hasp_dispatch.h" -#include "hasp.h" - -#ifdef ESP32 -#include -#include -#elif defined(ESP8266) -#include -#include -#endif -#include - -AsyncWebServer webServer(80); - -#if defined(ARDUINO_ARCH_ESP32) -#include "SPIFFS.h" -#endif -#include -#include - -bool httpEnable = true; -bool webServerStarted = false; -uint16_t httpPort = 80; -FS * filesystem = &SPIFFS; -File fsUploadFile; -char httpUser[32] = ""; -char httpPassword[32] = ""; -// HTTPUpload * upload; -#define HTTP_PAGE_SIZE (6 * 256) - -const char MAIN_MENU_BUTTON[] PROGMEM = - "

"; -const char MIT_LICENSE[] PROGMEM = "
MIT License

"; - -const char HTTP_DOCTYPE[] PROGMEM = - ""; -const char HTTP_META_GO_BACK[] PROGMEM = ""; -const char HTTP_HEADER[] PROGMEM = "%s"; -const char HTTP_STYLE[] PROGMEM = - ""; -const char HTTP_SCRIPT[] PROGMEM = ""; -const char HTTP_HEADER_END[] PROGMEM = - "
"; - -// Additional CSS style to match Hass theme -const char HASP_STYLE[] PROGMEM = - ""; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -// URL for auto-update "version.json" -const char UPDATE_URL[] PROGMEM = "http://haswitchplate.com/update/version.json"; -// Default link to compiled Arduino firmware image -String espFirmwareUrl = "http://haswitchplate.com/update/HASwitchPlate.ino.d1_mini.bin"; -// Default link to compiled Nextion firmware images -String lcdFirmwareUrl = "http://haswitchplate.com/update/HASwitchPlate.tft"; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -String getOption(int value, String label, bool selected) -{ - char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR(""), value, - (selected ? PSTR(" selected") : ""), label.c_str()); - return buffer; -} -String getOption(String value, String label, bool selected) -{ - char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR(""), value.c_str(), - (selected ? PSTR(" selected") : ""), label.c_str()); - return buffer; -} - -bool httpIsAuthenticated(AsyncWebServerRequest * request, const String & page) -{ - if(httpPassword[0] != '\0') { // Request HTTP auth if httpPassword is set - if(!request->authenticate(httpUser, httpPassword)) { - request->requestAuthentication(); - return false; - } - } - - char buffer[128]; - snprintf(buffer, sizeof(buffer), PSTR("HTTP: Sending %s page to client connected from: %s"), page.c_str(), - request->client()->remoteIP().toString().c_str()); - debugPrintln(buffer); - return true; -} - -void webSendFooter(AsyncResponseStream * response) -{ - response->print(F("")); -} - -void webHandleRoot(AsyncWebServerRequest * request) -{ - if(!httpIsAuthenticated(request, F("root"))) return; - AsyncResponseStream * response = request->beginResponseStream("text/html"); - - String nodename((char *)0); - nodename.reserve(128); - nodename = httpGetNodename(); - - response->print(F("

")); - response->print(nodename); - response->print(F("


")); - - response->print(F("

")); - response->print( - F("

")); - response->print(F("

")); - - response->print( - F("

")); - - if(SPIFFS.exists(F("/edit.htm.gz"))) { - response->print(F("

")); - } - - response->print( - F("

")); - - webSendFooter(response); - request->send(response); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -void webHandleHaspConfig(AsyncWebServerRequest * request) -{ // http://plate01/config/http - if(!httpIsAuthenticated(request, F("config/hasp"))) return; - AsyncResponseStream * response = request->beginResponseStream("text/html"); - - DynamicJsonDocument settings(256); - haspGetConfig(settings.to()); - - String nodename((char *)0); - nodename.reserve(128); - nodename = httpGetNodename(); - - response->print(F("

")); - response->print(nodename); - response->print(F("


")); - - response->print(F("

")); - response->print(F("


")); - - response->print(F("
")); - response->print(F("

UI Theme (required)
")); - response->print( - F("Hue

")); - response->print(F("

Default Font

")); - - response->print(F("

Startup Layout (optional)
Startup Page (required)

Startup Brightness (required)

")); - - response->print(F("

")); - - response->print( - F("

")); - - webSendFooter(response); - request->send(response); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -void webHandleScreenshot(AsyncWebServerRequest * request) -{ // http://plate01/screenshot - if(!httpIsAuthenticated(request, F("screenshot"))) return; - - if(request->hasArg(F("q"))) { - guiTakeScreenshot(request); - } else { - AsyncResponseStream * response = request->beginResponseStream("text/html"); - - String nodename((char *)0); - nodename.reserve(128); - nodename = httpGetNodename(); - - response->print(F("

")); - response->print(nodename); - response->print(F("


")); - - response->print(F("

")); - response->print(F("

print(F("el=document.getElementById('bmp');el.src='?q='+timestamp;return false;\">")); - response->print(F("

")); - // response->print( FPSTR(MAIN_MENU_BUTTON); - - webSendFooter(response); - request->send(response); - } -} -//////////////////////////////////////////////////////////////////////////////////////////////////// -void httpHandleNotFound(AsyncWebServerRequest * request) -{ // webServer 404 - // if(handleFileRead(webServer.uri())) return; - - debugPrintln(String(F("HTTP: Sending 404 to client connected from: ")) + request->client()->remoteIP().toString()); - - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - - httpMessage += F("File Not Found\n\nURI: "); - httpMessage += request->url(); - httpMessage += F("\nMethod: "); - httpMessage += (request->method() == HTTP_GET) ? F("GET") : F("POST"); - httpMessage += F("\nArguments: "); - httpMessage += request->args(); - httpMessage += "\n"; - for(uint8_t i = 0; i < request->args(); i++) { - httpMessage += " " + request->argName(i) + ": " + request->arg(i) + "\n"; - } - request->send(404, F("text/plain"), httpMessage); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -void webHandleSaveConfig() -{ - // if(!httpIsAuthenticated(F("saveConfig"))) return; - - configWriteConfig(); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -void webHandleFirmware() -{ - // if(!httpIsAuthenticated(F("firmware"))) return; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -void httpSetup() -{ - if(WiFi.getMode() != WIFI_STA) { - debugPrintln(F("HTTP: Wifi access point")); - // webServer.on(F("/"), webHandleWifiConfig); - } else { - - webServer.on(String(F("/")).c_str(), HTTP_GET, webHandleRoot); - webServer.on(String(F("/config/hasp")).c_str(), webHandleHaspConfig); - webServer.on(String(F("/screenshot")).c_str(), webHandleScreenshot); - - webServer.onNotFound(httpHandleNotFound); - - webServer.begin(); - - httpReconnect(); - debugPrintln(F("HTTP: Setup Complete")); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -void httpReconnect() -{ - if(!httpEnable) return; - - if(webServerStarted) { - webServer.end(); - webServerStarted = false; - debugPrintln(F("HTTP: Server stoped")); - } else if(WiFi.status() == WL_CONNECTED || WiFi.getMode() != WIFI_STA) { - - /* - if(WiFi.getMode() != WIFI_STA) { - webServer.on(F("/"), webHandleWifiConfig); - webServer.on(F("/config"), webHandleConfig); - webServer.onNotFound(httpHandleNotFound); - } else { - } - */ - webServer.begin(); - webServerStarted = true; - - debugPrintln(String(F("HTTP: Server started @ http://")) + - (WiFi.getMode() != WIFI_STA ? WiFi.softAPIP().toString() : WiFi.localIP().toString())); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -void httpLoop() -{ - // if(httpEnable) webServer.handleClient(); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -void httpEverySecond() -{ - if(httpEnable && !webServerStarted) httpReconnect(); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -bool httpGetConfig(const JsonObject & settings) -{ - settings[FPSTR(F_CONFIG_ENABLE)] = httpEnable; - settings[FPSTR(F_CONFIG_PORT)] = httpPort; - settings[FPSTR(F_CONFIG_USER)] = httpUser; - settings[FPSTR(F_CONFIG_PASS)] = httpPassword; - - configOutput(settings); - return true; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool httpSetConfig(const JsonObject & settings) -{ - configOutput(settings); - bool changed = false; - - changed |= configSet(httpPort, settings[FPSTR(F_CONFIG_PORT)], PSTR("httpPort")); - - if(!settings[FPSTR(F_CONFIG_USER)].isNull()) { - changed |= strcmp(httpUser, settings[FPSTR(F_CONFIG_USER)]) != 0; - strncpy(httpUser, settings[FPSTR(F_CONFIG_USER)], sizeof(httpUser)); - } - - if(!settings[FPSTR(F_CONFIG_PASS)].isNull()) { - changed |= strcmp(httpPassword, settings[FPSTR(F_CONFIG_PASS)]) != 0; - strncpy(httpPassword, settings[FPSTR(F_CONFIG_PASS)], sizeof(httpPassword)); - } - - return changed; -} - -#else - //#include "webServer.h" #include "Arduino.h" #include "ArduinoJson.h" @@ -432,7 +5,7 @@ bool httpSetConfig(const JsonObject & settings) #include "lvgl.h" #include "StringStream.h" -#ifdef ESP32 +#if defined(ARDUINO_ARCH_ESP32) #include "Update.h" #endif @@ -457,18 +30,26 @@ bool httpSetConfig(const JsonObject & settings) #include #endif -#if HASP_USE_HTTP>0 +#if HASP_USE_HTTP > 0 bool httpEnable = true; bool webServerStarted = false; uint16_t httpPort = 80; -FS * filesystem = &SPIFFS; + +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +FS * filesystem = &SPIFFS; File fsUploadFile; +#endif + char httpUser[32] = ""; char httpPassword[32] = ""; -HTTPUpload * upload; #define HTTP_PAGE_SIZE (6 * 256) +#if defined(STM32F4xx) +#include +EthernetWebServer webServer(80); +#endif + #if defined(ARDUINO_ARCH_ESP8266) #include ESP8266WebServer webServer(80); @@ -477,9 +58,10 @@ ESP8266WebServer webServer(80); #if defined(ARDUINO_ARCH_ESP32) #include WebServer webServer(80); - #endif // ESP32 +HTTPUpload * upload; + const char MAIN_MENU_BUTTON[] PROGMEM = "

"; const char MIT_LICENSE[] PROGMEM = "
MIT License

"; @@ -528,7 +110,6 @@ String lcdFirmwareUrl = "http://haswitchplate.com/update/HASwitchPlate.tft"; #if HASP_USE_MQTT > 0 extern char mqttNodeName[16]; -extern char mqttNodeName[16]; #else char mqttNodeName[3] = "na"; #endif @@ -551,10 +132,14 @@ bool httpIsAuthenticated(const __FlashStringHelper * page) } } - { - Log.verbose(F("HTTP: Sending %s page to client connected from: %s"), page, - webServer.client().remoteIP().toString().c_str()); - } +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) + Log.verbose(F("HTTP: Sending %s page to client connected from: %s"), page, + webServer.client().remoteIP().toString().c_str()); +#else + // Log.verbose(F("HTTP: Sending %s page to client connected from: %s"), page, + // String(webServer.client().remoteIP()).c_str()); +#endif + return true; } @@ -577,72 +162,100 @@ void webSendFooter() char buffer[128]; snprintf_P(buffer, sizeof(buffer), PSTR("%u.%u.%u"), HASP_VERSION_MAJOR, HASP_VERSION_MINOR, HASP_VERSION_REVISION); +#if defined(STM32F4xx) + webServer.sendContent(HTTP_END); + webServer.sendContent(buffer); + webServer.sendContent(HTTP_FOOTER); +#else webServer.sendContent_P(HTTP_END); webServer.sendContent(buffer); webServer.sendContent_P(HTTP_FOOTER); +#endif } void webSendPage(char * nodename, uint32_t httpdatalength, bool gohome = false) { - char buffer[64]; - snprintf_P(buffer, sizeof(buffer), PSTR("%u.%u.%u"), HASP_VERSION_MAJOR, HASP_VERSION_MINOR, HASP_VERSION_REVISION); + { + char buffer[64]; + snprintf_P(buffer, sizeof(buffer), PSTR("%u.%u.%u"), HASP_VERSION_MAJOR, HASP_VERSION_MINOR, + HASP_VERSION_REVISION); - /* Calculate Content Length upfront */ - uint16_t contentLength = strlen(buffer); // verion length - contentLength += sizeof(HTTP_DOCTYPE) - 1; - contentLength += sizeof(HTTP_HEADER) - 1 - 2 + strlen(nodename); - contentLength += sizeof(HTTP_SCRIPT) - 1; - contentLength += sizeof(HTTP_STYLE) - 1; - contentLength += sizeof(HASP_STYLE) - 1; - if(gohome) contentLength += sizeof(HTTP_META_GO_BACK) - 1; - contentLength += sizeof(HTTP_HEADER_END) - 1; - contentLength += sizeof(HTTP_END) - 1; - contentLength += sizeof(HTTP_FOOTER) - 1; + /* Calculate Content Length upfront */ + uint16_t contentLength = strlen(buffer); // verion length + contentLength += sizeof(HTTP_DOCTYPE) - 1; + contentLength += sizeof(HTTP_HEADER) - 1 - 2 + strlen(nodename); + contentLength += sizeof(HTTP_SCRIPT) - 1; + contentLength += sizeof(HTTP_STYLE) - 1; + contentLength += sizeof(HASP_STYLE) - 1; + if(gohome) contentLength += sizeof(HTTP_META_GO_BACK) - 1; + contentLength += sizeof(HTTP_HEADER_END) - 1; + contentLength += sizeof(HTTP_END) - 1; + contentLength += sizeof(HTTP_FOOTER) - 1; - if(httpdatalength > HTTP_PAGE_SIZE) { - Log.warning(F("HTTP: Sending page with %u static and %u dynamic bytes"), contentLength, httpdatalength); + if(httpdatalength > HTTP_PAGE_SIZE) { + Log.warning(F("HTTP: Sending page with %u static and %u dynamic bytes"), contentLength, httpdatalength); + } + + webServer.setContentLength(contentLength + httpdatalength); +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) + webServer.send_P(200, PSTR("text/html"), HTTP_DOCTYPE); // 122 +#else + webServer.send(200, ("text/html"), HTTP_DOCTYPE); // 122 +#endif + + sprintf_P(buffer, HTTP_HEADER, nodename); + webServer.sendContent(buffer); // 17-2+len } - webServer.setContentLength(contentLength + httpdatalength); - webServer.send_P(200, PSTR("text/html"), HTTP_DOCTYPE); // 122 - sprintf_P(buffer, HTTP_HEADER, nodename); - webServer.sendContent(buffer); // 17-2+len +#if defined(STM32F4xx) + webServer.sendContent(HTTP_SCRIPT); // 131 + webServer.sendContent(HTTP_STYLE); // 487 + webServer.sendContent(HASP_STYLE); // 145 + if(gohome) webServer.sendContent(HTTP_META_GO_BACK); // 47 + webServer.sendContent(HTTP_HEADER_END); // 80 +#else webServer.sendContent_P(HTTP_SCRIPT); // 131 webServer.sendContent_P(HTTP_STYLE); // 487 webServer.sendContent_P(HASP_STYLE); // 145 if(gohome) webServer.sendContent_P(HTTP_META_GO_BACK); // 47 webServer.sendContent_P(HTTP_HEADER_END); // 80 +#endif } void webHandleRoot() { if(!httpIsAuthenticated(F("root"))) return; - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - httpMessage += F("

"); - httpMessage += F("

"); - httpMessage += - PSTR("

"); + httpMessage += F("

"); + httpMessage += + F("

"); + httpMessage += + PSTR("

"); - httpMessage += - F("

"); + httpMessage += + F("

"); - if(SPIFFS.exists(F("/edit.htm.gz"))) { - httpMessage += F( - "

"); +#if HASP_USE_SPIFFS > 0 + if(SPIFFS.exists(F("/edit.htm.gz"))) { + httpMessage += F("

"); + } +#endif + + httpMessage += + F("

"); + + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); } - - httpMessage += - F("

"); - - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + // httpMessage.clear(); webSendFooter(); } @@ -651,16 +264,18 @@ void httpHandleReboot() { // http://plate01/reboot if(!httpIsAuthenticated(F("reboot"))) return; - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); - httpMessage = F("Rebooting Device"); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); + httpMessage = F("Rebooting Device"); - webSendPage(httpGetNodename(), httpMessage.length(), true); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), true); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); webSendFooter(); delay(200); @@ -692,30 +307,36 @@ void webHandleScreenshot() } if(webServer.hasArg(F("q"))) { - guiTakeScreenshot(webServer); + lv_disp_t * disp = lv_disp_get_default(); + webServer.setContentLength(122 + disp->driver.hor_res * disp->driver.ver_res * sizeof(lv_color_t)); + webServer.send(200, PSTR("image/bmp"), ""); + guiTakeScreenshot(); + webServer.client().stop(); + } else { + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + httpMessage += + F(""); + httpMessage += F("

"); + httpMessage += F( + "

"); + httpMessage += F("

"); + httpMessage += F("

"); + httpMessage += FPSTR(MAIN_MENU_BUTTON); - httpMessage += - F(""); - httpMessage += F("

"); - httpMessage += - F("

"); - httpMessage += F("

"); - httpMessage += F("

"); - httpMessage += FPSTR(MAIN_MENU_BUTTON); - - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); webSendFooter(); } } @@ -726,44 +347,47 @@ void webHandleAbout() { // http://plate01/about if(!httpIsAuthenticated(F("about"))) return; - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

HASP OpenHardware edition

Copyright© 2020 Francis Van Roie "); - httpMessage += FPSTR(MIT_LICENSE); - httpMessage += F("

Based on the previous work of the following open source developers.


"); - httpMessage += F("

HASwitchPlate

Copyright© 2019 Allen Derusha allen@derusha.org"); - httpMessage += FPSTR(MIT_LICENSE); - httpMessage += - F("

LittlevGL

Copyright© 2016 Gábor Kiss-Vámosi
Copyright© 2019 " - "LittlevGL"); - httpMessage += FPSTR(MIT_LICENSE); - httpMessage += F("

zi Font Engine

Copyright© 2020 Francis Van Roie"); - httpMessage += FPSTR(MIT_LICENSE); - httpMessage += F("

TFT_eSPI Library

Copyright© 2020 Bodmer (https://github.com/Bodmer) All " - "rights reserved.
FreeBSD License

"); - httpMessage += - F("

includes parts from the Adafruit_GFX library
Copyright© 2012 Adafruit Industries. " - "All rights reserved
BSD License

"); - httpMessage += F("

ArduinoJson

Copyright© 2014-2020 Benoit BLANCHON"); - httpMessage += FPSTR(MIT_LICENSE); - httpMessage += F("

PubSubClient

Copyright© 2008-2015 Nicholas O'Leary"); - httpMessage += FPSTR(MIT_LICENSE); - httpMessage += F("

ArduinoLog

Copyright© 2017,2018 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, " - "dhylands, Josha blemasle, mfalkvidd"); - httpMessage += FPSTR(MIT_LICENSE); - httpMessage += F("

Syslog

Copyright© 2016 Martin Sloup"); - httpMessage += FPSTR(MIT_LICENSE); - httpMessage += F("

QR Code generator

Copyright© Project Nayuki"); - httpMessage += FPSTR(MIT_LICENSE); - httpMessage += F("

AceButton

Copyright© 2018 Brian T. Park"); - httpMessage += FPSTR(MIT_LICENSE); + httpMessage += F("

HASP OpenHardware edition

Copyright© 2020 Francis Van Roie "); + httpMessage += FPSTR(MIT_LICENSE); + httpMessage += F("

Based on the previous work of the following open source developers.


"); + httpMessage += F("

HASwitchPlate

Copyright© 2019 Allen Derusha allen@derusha.org"); + httpMessage += FPSTR(MIT_LICENSE); + httpMessage += + F("

LittlevGL

Copyright© 2016 Gábor Kiss-Vámosi
Copyright© 2019 " + "LittlevGL"); + httpMessage += FPSTR(MIT_LICENSE); + httpMessage += F("

zi Font Engine

Copyright© 2020 Francis Van Roie"); + httpMessage += FPSTR(MIT_LICENSE); + httpMessage += F("

TFT_eSPI Library

Copyright© 2020 Bodmer (https://github.com/Bodmer) All " + "rights reserved.
FreeBSD License

"); + httpMessage += + F("

includes parts from the Adafruit_GFX library
Copyright© 2012 Adafruit Industries. " + "All rights reserved
BSD License

"); + httpMessage += F("

ArduinoJson

Copyright© 2014-2020 Benoit BLANCHON"); + httpMessage += FPSTR(MIT_LICENSE); + httpMessage += F("

PubSubClient

Copyright© 2008-2015 Nicholas O'Leary"); + httpMessage += FPSTR(MIT_LICENSE); + httpMessage += + F("

ArduinoLog

Copyright© 2017,2018 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, " + "dhylands, Josha blemasle, mfalkvidd"); + httpMessage += FPSTR(MIT_LICENSE); + httpMessage += F("

Syslog

Copyright© 2016 Martin Sloup"); + httpMessage += FPSTR(MIT_LICENSE); + httpMessage += F("

QR Code generator

Copyright© Project Nayuki"); + httpMessage += FPSTR(MIT_LICENSE); + httpMessage += F("

AceButton

Copyright© 2018 Brian T. Park"); + httpMessage += FPSTR(MIT_LICENSE); - httpMessage += FPSTR(MAIN_MENU_BUTTON); + httpMessage += FPSTR(MAIN_MENU_BUTTON); - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); webSendFooter(); } @@ -772,144 +396,151 @@ void webHandleInfo() { // http://plate01/ if(!httpIsAuthenticated(F("info"))) return; - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - /* HASP Stats */ - httpMessage += F("HASP Version: "); - httpMessage += String(haspGetVersion()); - httpMessage += F("
Build DateTime: "); - httpMessage += __DATE__; - httpMessage += F(" "); - httpMessage += __TIME__; - httpMessage += F(" CET
Uptime: "); + /* HASP Stats */ + httpMessage += F("HASP Version: "); + httpMessage += String(haspGetVersion()); + httpMessage += F("
Build DateTime: "); + httpMessage += __DATE__; + httpMessage += F(" "); + httpMessage += __TIME__; + httpMessage += F(" CET
Uptime: "); - unsigned long time = millis() / 1000; - uint16_t day = time / 86400; - time = time % 86400; - uint8_t hour = time / 3600; - time = time % 3600; - uint8_t min = time / 60; - time = time % 60; - uint8_t sec = time; + unsigned long time = millis() / 1000; + uint16_t day = time / 86400; + time = time % 86400; + uint8_t hour = time / 3600; + time = time % 3600; + uint8_t min = time / 60; + time = time % 60; + uint8_t sec = time; - if(day > 0) { - httpMessage += String(day); - httpMessage += F("d "); - } - if(day > 0 || hour > 0) { - httpMessage += String(hour); - httpMessage += F("h "); - } - if(day > 0 || hour > 0 || min > 0) { - httpMessage += String(min); - httpMessage += F("m "); - } - httpMessage += String(sec); - httpMessage += F("s"); + if(day > 0) { + httpMessage += String(day); + httpMessage += F("d "); + } + if(day > 0 || hour > 0) { + httpMessage += String(hour); + httpMessage += F("h "); + } + if(day > 0 || hour > 0 || min > 0) { + httpMessage += String(min); + httpMessage += F("m "); + } + httpMessage += String(sec); + httpMessage += F("s"); - httpMessage += F("
Free Memory: "); - httpMessage += spiffsFormatBytes(ESP.getFreeHeap()); - httpMessage += F("
Memory Fragmentation: "); - httpMessage += String(halGetHeapFragmentation()); + httpMessage += F("
Free Memory: "); + httpMessage += halFormatBytes(halGetFreeHeap()); + httpMessage += F("
Memory Fragmentation: "); + httpMessage += String(halGetHeapFragmentation()); - /* LVGL Stats */ - lv_mem_monitor_t mem_mon; - lv_mem_monitor(&mem_mon); - httpMessage += F("

LVGL Memory: "); - httpMessage += spiffsFormatBytes(mem_mon.total_size); - httpMessage += F("
LVGL Free: "); - httpMessage += spiffsFormatBytes(mem_mon.free_size); - httpMessage += F("
LVGL Fragmentation: "); - httpMessage += mem_mon.frag_pct; + /* LVGL Stats */ + lv_mem_monitor_t mem_mon; + lv_mem_monitor(&mem_mon); + httpMessage += F("

LVGL Memory: "); + httpMessage += halFormatBytes(mem_mon.total_size); + httpMessage += F("
LVGL Free: "); + httpMessage += halFormatBytes(mem_mon.free_size); + httpMessage += F("
LVGL Fragmentation: "); + httpMessage += mem_mon.frag_pct; - // httpMessage += F("
LCD Model: ")) + String(LV_HASP_HOR_RES_MAX) + " x " + - // String(LV_HASP_VER_RES_MAX); httpMessage += F("
LCD Version: ")) + - // String(lcdVersion); - httpMessage += F("

LCD Active Page: "); - httpMessage += String(haspGetPage()); + // httpMessage += F("
LCD Model: ")) + String(LV_HASP_HOR_RES_MAX) + " x " + + // String(LV_HASP_VER_RES_MAX); httpMessage += F("
LCD Version: ")) + + // String(lcdVersion); + httpMessage += F("

LCD Active Page: "); + httpMessage += String(haspGetPage()); - /* Wifi Stats */ - httpMessage += F("

SSID: "); - httpMessage += String(WiFi.SSID()); - httpMessage += F("
Signal Strength: "); + /* Wifi Stats */ +#if HASP_USE_WIFI > 0 + httpMessage += F("

SSID: "); + httpMessage += String(WiFi.SSID()); + httpMessage += F("
Signal Strength: "); - int8_t rssi = WiFi.RSSI(); - httpMessage += String(rssi); - httpMessage += F("dBm ("); + int8_t rssi = WiFi.RSSI(); + httpMessage += String(rssi); + httpMessage += F("dBm ("); - if(rssi >= -50) { - httpMessage += F("Excellent)"); - } else if(rssi >= -60) { - httpMessage += F("Good)"); - } else if(rssi >= -70) { - httpMessage += F("Fair)"); - } else if(rssi >= -80) { - httpMessage += F("Weak)"); - } else { - httpMessage += F("Very Bad)"); - } + if(rssi >= -50) { + httpMessage += F("Excellent)"); + } else if(rssi >= -60) { + httpMessage += F("Good)"); + } else if(rssi >= -70) { + httpMessage += F("Fair)"); + } else if(rssi >= -80) { + httpMessage += F("Weak)"); + } else { + httpMessage += F("Very Bad)"); + } - httpMessage += F("
IP Address: "); - httpMessage += String(WiFi.localIP().toString()); - httpMessage += F("
Gateway: "); - httpMessage += String(WiFi.gatewayIP().toString()); - httpMessage += F("
DNS Server: "); - httpMessage += String(WiFi.dnsIP().toString()); - httpMessage += F("
MAC Address: "); - httpMessage += String(WiFi.macAddress()); + httpMessage += F("
IP Address: "); + httpMessage += String(WiFi.localIP().toString()); + httpMessage += F("
Gateway: "); + httpMessage += String(WiFi.gatewayIP().toString()); + httpMessage += F("
DNS Server: "); + httpMessage += String(WiFi.dnsIP().toString()); + httpMessage += F("
MAC Address: "); + httpMessage += String(WiFi.macAddress()); +#endif /* Mqtt Stats */ #if HASP_USE_MQTT > 0 - httpMessage += F("

MQTT Status: "); - if(mqttIsConnected()) { // Check MQTT connection - httpMessage += F("Connected"); - } else { - httpMessage += F("Disconnected, return code: "); - // +String(mqttClient.returnCode()); - } - httpMessage += F("
MQTT ClientID: "); + httpMessage += F("

MQTT Status: "); + if(mqttIsConnected()) { // Check MQTT connection + httpMessage += F("Connected"); + } else { + httpMessage += F("Disconnected, return code: "); + // +String(mqttClient.returnCode()); + } + httpMessage += F("
MQTT ClientID: "); - { - char mqttClientId[64]; - byte mac[6]; - WiFi.macAddress(mac); - snprintf_P(mqttClientId, sizeof(mqttClientId), PSTR("%s-%2x%2x%2x"), mqttNodeName, mac[3], mac[4], mac[5]); - httpMessage += mqttClientId; - } + { + char mqttClientId[64]; + String mac = halGetMacAddress(3, ""); + mac.toLowerCase(); + snprintf_P(mqttClientId, sizeof(mqttClientId), PSTR("%s-%s"), mqttNodeName, mac.c_str()); + httpMessage += mqttClientId; + } +#endif // MQTT + + /* ESP Stats */ + httpMessage += F("

MCU Model: "); + httpMessage += halGetChipModel(); + httpMessage += F("
CPU Frequency: "); + httpMessage += String(halGetCpuFreqMHz()); + +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) + httpMessage += F("MHz
Flash Chip Size: "); + httpMessage += halFormatBytes(ESP.getFlashChipSize()); + httpMessage += F("
Program Size: "); + httpMessage += halFormatBytes(ESP.getSketchSize()); + httpMessage += F("
Free Program Space: "); + httpMessage += halFormatBytes(ESP.getFreeSketchSpace()); #endif - /* ESP Stats */ - httpMessage += F("

MCU Model: "); - httpMessage += halGetChipModel(); - httpMessage += F("
CPU Frequency: "); - httpMessage += String(ESP.getCpuFreqMHz()); - httpMessage += F("MHz
Flash Chip Size: "); - httpMessage += spiffsFormatBytes(ESP.getFlashChipSize()); - httpMessage += F("
Program Size: "); - httpMessage += spiffsFormatBytes(ESP.getSketchSize()); - httpMessage += F("
Free Program Space: "); - httpMessage += spiffsFormatBytes(ESP.getFreeSketchSpace()); + //#if defined(ARDUINO_ARCH_ESP32) + // httpMessage += F("
ESP SDK version: "); + // httpMessage += String(ESP.getSdkVersion()); + //#else + httpMessage += F("
Core version: "); + httpMessage += String(halGetCoreVersion()); + //#endif + httpMessage += F("
Last Reset: "); + httpMessage += halGetResetInfo(); -#if defined(ARDUINO_ARCH_ESP32) - httpMessage += F("
ESP SDK version: "); - httpMessage += String(ESP.getSdkVersion()); -#else - httpMessage += F("
ESP Core version: "); - httpMessage += String(ESP.getCoreVersion()); -#endif - httpMessage += F("
Last Reset: "); - httpMessage += halGetResetInfo(); + httpMessage += FPSTR(MAIN_MENU_BUTTON); - httpMessage += FPSTR(MAIN_MENU_BUTTON); - - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); webSendFooter(); } @@ -969,30 +600,6 @@ String getContentType(String filename) return encodedString; } */ -bool handleFileRead(String path) -{ - if(!httpIsAuthenticated(F("fileread"))) return false; - - path = webServer.urlDecode(path).substring(0, 31); - if(path.endsWith("/")) { - path += F("index.htm"); - } - String pathWithGz = path + F(".gz"); - if(filesystem->exists(pathWithGz) || filesystem->exists(path)) { - if(filesystem->exists(pathWithGz)) path += F(".gz"); - - File file = filesystem->open(path, "r"); - String contentType = getContentType(path); - if(path == F("/edit.htm.gz")) { - contentType = F("text/html"); - } - webServer.streamFile(file, contentType); - file.close(); - return true; - } - return false; -} - static unsigned long htppLastLoopTime = 0; void webUploadProgress() { @@ -1002,6 +609,7 @@ void webUploadProgress() } } +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) void webUpdatePrintError() { String output((char *)0); @@ -1015,16 +623,18 @@ void webUpdateReboot() { Log.notice(F("Update Success: %u bytes received. Rebooting..."), upload->totalSize); - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); - httpMessage += F("Upload complete. Rebooting device, please wait..."); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); + httpMessage += F("Upload complete. Rebooting device, please wait..."); - webSendPage(httpGetNodename(), httpMessage.length(), true); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), true); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); webSendFooter(); delay(250); @@ -1059,6 +669,32 @@ void webHandleFirmwareUpdate() } } } +#endif + +#if HASP_USE_SPIFFS > 0 +bool handleFileRead(String path) +{ + if(!httpIsAuthenticated(F("fileread"))) return false; + + path = webServer.urlDecode(path).substring(0, 31); + if(path.endsWith("/")) { + path += F("index.htm"); + } + String pathWithGz = path + F(".gz"); + if(filesystem->exists(pathWithGz) || filesystem->exists(path)) { + if(filesystem->exists(pathWithGz)) path += F(".gz"); + + File file = filesystem->open(path, "r"); + String contentType = getContentType(path); + if(path == F("/edit.htm.gz")) { + contentType = F("text/html"); + } + webServer.streamFile(file, contentType); + file.close(); + return true; + } + return false; +} void handleFileUpload() { @@ -1123,7 +759,7 @@ void handleFileDelete() } filesystem->remove(path); webServer.send_P(200, mimetype, PSTR("")); - path.clear(); + // path.clear(); } void handleFileCreate() @@ -1188,7 +824,8 @@ void handleFileList() file = root.openNextFile(); } output += "]"; -#else + webServer.send(200, PSTR("text/json"), output); +#elif defined(ARDUINO_ARCH_ESP8266) Dir dir = filesystem->openDir(path); String output = "["; while(dir.next()) { @@ -1209,9 +846,10 @@ void handleFileList() entry.close(); } output += "]"; -#endif webServer.send(200, PSTR("text/json"), output); +#endif } +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// void webHandleConfig() @@ -1245,51 +883,65 @@ void webHandleConfig() // Password might have changed if(!httpIsAuthenticated(F("config"))) return; +#if HASP_USE_WIFI > 0 } else if(save == String(PSTR("wifi"))) { wifiSetConfig(settings.as()); +#endif } } } +// Reboot after saving wifi config in AP mode +#if HASP_USE_WIFI > 0 if(WiFi.getMode() != WIFI_STA) { httpHandleReboot(); } - - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); - - httpMessage += - F("

"); - -#if HASP_USE_MQTT > 0 - httpMessage += - F("

"); #endif - httpMessage += - F("

"); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - httpMessage += - F("

"); +#if HASP_USE_WIFI > 0 + httpMessage += + F("

"); +#endif - httpMessage += - F("

"); +#if HASP_USE_MQTT > 0 + httpMessage += + F("

"); +#endif - httpMessage += - F("

"); + httpMessage += + F("

"); - httpMessage += F("

"); + httpMessage += + F("

"); - httpMessage += FPSTR(MAIN_MENU_BUTTON); - ; + httpMessage += + F("

"); - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); +#if HASP_USE_GPIO > 0 + httpMessage += + F("

"); +#endif + + httpMessage += + F("

"); + + httpMessage += F("

"); + + httpMessage += FPSTR(MAIN_MENU_BUTTON); + ; + + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); webSendFooter(); } @@ -1302,41 +954,43 @@ void webHandleMqttConfig() DynamicJsonDocument settings(256); mqttGetConfig(settings.to()); - // char buffer[128]; - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + { + // char buffer[128]; + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - httpMessage += F("
"); - httpMessage += F("HASP Node Name (required. lowercase letters, numbers, and _ only)" - "

Group Name (required)

MQTT Broker (required)
MQTT Port (required)
MQTT User (optional)
MQTT Password (optional)"); + httpMessage += F("HASP Node Name (required. lowercase letters, numbers, and _ only)" + "

Group Name (required)

MQTT Broker (required)
MQTT Port (required)
MQTT User (optional)
MQTT Password (optional)

"); - httpMessage += - PSTR("

"); + httpMessage += F("'>

"); + httpMessage += + PSTR("

"); - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); webSendFooter(); } #endif @@ -1346,70 +1000,71 @@ void webHandleGuiConfig() { // http://plate01/config/wifi if(!httpIsAuthenticated(F("config/gui"))) return; - DynamicJsonDocument settings(256); - guiGetConfig(settings.to()); + { + DynamicJsonDocument settings(256); + guiGetConfig(settings.to()); - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - httpMessage += F("
"); + httpMessage += F(""); - httpMessage += F("

Short Idle

"); + httpMessage += F("

Short Idle

"); - httpMessage += F("

Long Idle

"); + httpMessage += F("

Long Idle

"); - int8_t rotation = settings[FPSTR(F_GUI_ROTATION)].as(); - httpMessage += F("

Orientation

"); + int8_t rotation = settings[FPSTR(F_GUI_ROTATION)].as(); + httpMessage += F("

Orientation

"); - int8_t bcklpin = settings[FPSTR(F_GUI_BACKLIGHTPIN)].as(); - httpMessage += F("

Backlight Control "); + httpMessage += getOption(-1, F("None"), bcklpin == -1); #if defined(ARDUINO_ARCH_ESP32) - httpMessage += getOption(5, F("GPIO 5"), bcklpin == 5); - httpMessage += getOption(16, F("GPIO 16"), bcklpin == 16); // D4 on ESP32 for D1 mini 32 - httpMessage += getOption(17, F("GPIO 17"), bcklpin == 17); - httpMessage += getOption(18, F("GPIO 18"), bcklpin == 18); - httpMessage += getOption(19, F("GPIO 19"), bcklpin == 19); - httpMessage += getOption(21, F("GPIO 21"), bcklpin == 21); - httpMessage += getOption(22, F("GPIO 22"), bcklpin == 22); - httpMessage += getOption(23, F("GPIO 23"), bcklpin == 23); + httpMessage += getOption(5, F("GPIO 5"), bcklpin == 5); + httpMessage += getOption(16, F("GPIO 16"), bcklpin == 16); // D4 on ESP32 for D1 mini 32 + httpMessage += getOption(17, F("GPIO 17"), bcklpin == 17); + httpMessage += getOption(18, F("GPIO 18"), bcklpin == 18); + httpMessage += getOption(19, F("GPIO 19"), bcklpin == 19); + httpMessage += getOption(21, F("GPIO 21"), bcklpin == 21); + httpMessage += getOption(22, F("GPIO 22"), bcklpin == 22); + httpMessage += getOption(23, F("GPIO 23"), bcklpin == 23); #else - httpMessage += getOption(5, F("D1 - GPIO 5"), bcklpin == 5); - httpMessage += getOption(4, F("D2 - GPIO 4"), bcklpin == 4); - httpMessage += getOption(0, F("D3 - GPIO 0"), bcklpin == 0); - httpMessage += getOption(2, F("D4 - GPIO 2"), bcklpin == 2); + httpMessage += getOption(5, F("D1 - GPIO 5"), bcklpin == 5); + httpMessage += getOption(4, F("D2 - GPIO 4"), bcklpin == 4); + httpMessage += getOption(0, F("D3 - GPIO 0"), bcklpin == 0); + httpMessage += getOption(2, F("D4 - GPIO 2"), bcklpin == 2); #endif - httpMessage += F("

"); + httpMessage += F("

"); - httpMessage += F("

"); + httpMessage += F("

"); - httpMessage += PSTR("

"); + httpMessage += PSTR("

"); - httpMessage += - PSTR("

"); + httpMessage += + PSTR("

"); - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); + } webSendFooter(); if(webServer.hasArg(F("action"))) dispatchCommand(webServer.arg(F("action"))); @@ -1441,10 +1096,12 @@ void webHandleWifiConfig() } httpMessage += F("'>

"); +#if HASP_USE_WIFI > 0 if(WiFi.getMode() == WIFI_STA) { httpMessage += PSTR("

"); } +#endif webSendPage(httpGetNodename(), httpMessage.length(), false); webServer.sendContent(httpMessage); @@ -1459,93 +1116,138 @@ void webHandleHttpConfig() { // http://plate01/config/http if(!httpIsAuthenticated(F("config/http"))) return; - DynamicJsonDocument settings(256); - httpGetConfig(settings.to()); + { + DynamicJsonDocument settings(256); + httpGetConfig(settings.to()); - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - httpMessage += F("
"); - httpMessage += F("Web Username (optional)
Web Password (optional)"); + httpMessage += F("Web Username (optional)
Web Password (optional)

"); + + httpMessage += + PSTR("

"); + + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); } - httpMessage += F("'>

"); - - httpMessage += - PSTR("

"); - - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + // httpMessage.clear(); webSendFooter(); } #endif +//////////////////////////////////////////////////////////////////////////////////////////////////// +void webHandleGpioConfig() +{ // http://plate01/config/gpio + if(!httpIsAuthenticated(F("config/gpio"))) return; + + DynamicJsonDocument settings(256); + debugGetConfig(settings.to()); + + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); + + httpMessage += F("
"); + + httpMessage += F(""); + httpMessage += F(""); + httpMessage += F(""); + httpMessage += F(""); + + for(uint8_t i = 0; i < NUM_DIGITAL_PINS; i++) { + httpMessage += F(""); + } + + httpMessage += F("
PinTypeChannelNormalOptions
D1Button1HighOptions
D2Switch2HighOptions
D4Backligth15LowOptions
D4Backligth15LowOptions
"); + + // httpMessage += F("

"); + + httpMessage += + PSTR("

"); + + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); + webSendFooter(); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// void webHandleDebugConfig() -{ // http://plate01/config/http +{ // http://plate01/config/debug if(!httpIsAuthenticated(F("config/debug"))) return; DynamicJsonDocument settings(256); debugGetConfig(settings.to()); - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - httpMessage += F("
"); + httpMessage += F(""); - uint16_t baudrate = settings[FPSTR(F_CONFIG_BAUD)].as(); - httpMessage += F("

Serial Port

Telemetry Period (Seconds, 0=disable) " - "

"); + uint16_t baudrate = settings[FPSTR(F_CONFIG_BAUD)].as(); + httpMessage += F("

Serial Port

Telemetry Period (Seconds, 0=disable) " + "

"); - httpMessage += F("Syslog Hostame (optional)
Syslog Port (optional)
Syslog Port (optional) Syslog Facility "); + uint8_t logid = settings[FPSTR(F_CONFIG_LOG)].as(); + for(uint8_t i = 0; i < 8; i++) { + httpMessage += getOption(i, String(F("Local")) + i, i == logid); + } + + httpMessage += F("
Syslog Protocol () == 0) httpMessage += F(" checked"); + httpMessage += F(">IETF (RFC 5424)   () == 1) httpMessage += F(" checked"); + httpMessage += F(">BSD (RFC 3164)"); + + httpMessage += F("

"); + + httpMessage += + PSTR("

"); + + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); } - - httpMessage += F("
Syslog Protocol () == 0) httpMessage += F(" checked"); - httpMessage += F(">IETF (RFC 5424)   () == 1) httpMessage += F(" checked"); - httpMessage += F(">BSD (RFC 3164)"); - - httpMessage += F("

"); - - httpMessage += - PSTR("

"); - - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + // httpMessage.clear(); webSendFooter(); } @@ -1557,105 +1259,114 @@ void webHandleHaspConfig() DynamicJsonDocument settings(256); haspGetConfig(settings.to()); - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - httpMessage += F("

"); - httpMessage += F("


"); + httpMessage += F("

"); + httpMessage += F("


"); - httpMessage += F("
"); - httpMessage += F("

UI Theme (required)"); - uint8_t themeid = settings[FPSTR(F_CONFIG_THEME)].as(); - httpMessage += getOption(0, F("Built-in"), themeid == 0); - httpMessage += getOption(8, F("Hasp"), themeid == 8); + uint8_t themeid = settings[FPSTR(F_CONFIG_THEME)].as(); + httpMessage += getOption(0, F("Built-in"), themeid == 0); + httpMessage += getOption(8, F("Hasp"), themeid == 8); #if LV_USE_THEME_ALIEN == 1 - httpMessage += getOption(1, F("Alien"), themeid == 1); + httpMessage += getOption(1, F("Alien"), themeid == 1); #endif #if LV_USE_THEME_NIGHT == 1 - httpMessage += getOption(2, F("Night"), themeid == 2); + httpMessage += getOption(2, F("Night"), themeid == 2); #endif #if LV_USE_THEME_MONO == 1 - httpMessage += getOption(3, F("Mono"), themeid == 3); + httpMessage += getOption(3, F("Mono"), themeid == 3); #endif #if LV_USE_THEME_MATERIAL == 1 - httpMessage += getOption(4, F("Material"), themeid == 4); + httpMessage += getOption(4, F("Material"), themeid == 4); #endif #if LV_USE_THEME_ZEN == 1 - httpMessage += getOption(5, F("Zen"), themeid == 5); + httpMessage += getOption(5, F("Zen"), themeid == 5); #endif #if LV_USE_THEME_NEMO == 1 - httpMessage += getOption(6, F("Nemo"), themeid == 6); + httpMessage += getOption(6, F("Nemo"), themeid == 6); #endif #if LV_USE_THEME_TEMPL == 1 - httpMessage += getOption(7, F("Template"), themeid == 7); + httpMessage += getOption(7, F("Template"), themeid == 7); #endif - httpMessage += F("
"); - httpMessage += - F("Hue

"); - httpMessage += F("

Default Font
"); + httpMessage += + F("Hue

"); + httpMessage += F("

Default Font

"); + httpMessage += F("

"); - httpMessage += F("

Startup Layout (optional)
Startup Page (required)

Startup Brightness (required)

"); + httpMessage += settings[FPSTR(F_CONFIG_PAGES)].as(); + httpMessage += F("'>
Startup Page (required)

Startup Brightness (required)

"); - httpMessage += F("

"); + httpMessage += F("

"); - httpMessage += F("

"); + httpMessage += + F("

"); - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); webSendFooter(); } //////////////////////////////////////////////////////////////////////////////////////////////////// void httpHandleNotFound() { // webServer 404 +#if HASP_USE_SPIFFS > 0 if(handleFileRead(webServer.uri())) return; +#endif +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) Log.notice(F("HTTP: Sending 404 to client connected from: %s"), webServer.client().remoteIP().toString().c_str()); +#else + // Log.notice(F("HTTP: Sending 404 to client connected from: %s"), String(webServer.client().remoteIP()).c_str()); +#endif String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -1686,25 +1397,27 @@ void webHandleFirmware() { if(!httpIsAuthenticated(F("firmware"))) return; - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - httpMessage += F("

"); - httpMessage += F("

"); + httpMessage += F("

"); + httpMessage += F("

"); - httpMessage += F("

"); - httpMessage += F("

"); + httpMessage += F("

"); + httpMessage += F("

"); - httpMessage += FPSTR(MAIN_MENU_BUTTON); + httpMessage += FPSTR(MAIN_MENU_BUTTON); - webSendPage(httpGetNodename(), httpMessage.length(), false); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), false); + webServer.sendContent(httpMessage); + } + // httpMessage.clear(); webSendFooter(); } @@ -1713,18 +1426,20 @@ void httpHandleEspFirmware() { // http://plate01/espfirmware if(!httpIsAuthenticated(F("espfirmware"))) return; - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - httpMessage += F("

ESP update

Updating ESP firmware from: "); - httpMessage += webServer.arg("espFirmware"); + httpMessage += F("

ESP update

Updating ESP firmware from: "); + httpMessage += webServer.arg("espFirmware"); - webSendPage(httpGetNodename(), httpMessage.length(), true); - webServer.sendContent(httpMessage); - httpMessage.clear(); + webSendPage(httpGetNodename(), httpMessage.length(), true); + webServer.sendContent(httpMessage); + // httpMessage.clear(); + } webSendFooter(); Log.notice(F("HTTP: Attempting ESP firmware update from: %s"), webServer.arg("espFirmware").c_str()); @@ -1738,36 +1453,42 @@ void httpHandleResetConfig() bool resetConfirmed = webServer.arg(F("confirm")) == F("yes"); - String httpMessage((char *)0); - httpMessage.reserve(HTTP_PAGE_SIZE); - httpMessage += F("

"); - httpMessage += httpGetNodename(); - httpMessage += F("


"); + { + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += httpGetNodename(); + httpMessage += F("


"); - if(resetConfirmed) { // User has confirmed, so reset everything - bool formatted = SPIFFS.format(); - if(formatted) { - httpMessage += F("Resetting all saved settings and restarting device into WiFi AP mode"); + if(resetConfirmed) { // User has confirmed, so reset everything +#if HASP_USE_SPIFFS > 0 + bool formatted = SPIFFS.format(); + if(formatted) { + httpMessage += F("Resetting all saved settings and restarting device into WiFi AP mode"); + } else { + httpMessage += F("Failed to format the internal flash partition"); + resetConfirmed = false; + } +#endif } else { - httpMessage += F("Failed to format the internal flash partition"); - resetConfirmed = false; + httpMessage += + F("

Warning

This process will reset all settings to the default values. The internal flash " + "will " + "be erased and the device is restarted. You may need to connect to the WiFi AP displayed on the " + "panel to " + "re-configure the device before accessing it again. ALL FILES WILL BE LOST!" + "


" + "

" + "


"); + + httpMessage += + PSTR("

"); } - } else { - httpMessage += - F("

Warning

This process will reset all settings to the default values. The internal flash will " - "be erased and the device is restarted. You may need to connect to the WiFi AP displayed on the panel to " - "re-configure the device before accessing it again. ALL FILES WILL BE LOST!" - "


" - "

" - "


"); - httpMessage += - PSTR("

"); + webSendPage(httpGetNodename(), httpMessage.length(), resetConfirmed); + webServer.sendContent(httpMessage); } - - webSendPage(httpGetNodename(), httpMessage.length(), resetConfirmed); - webServer.sendContent(httpMessage); - httpMessage.clear(); + // httpMessage.clear(); webSendFooter(); if(resetConfirmed) { @@ -1781,8 +1502,14 @@ void webStart() { webServer.begin(); webServerStarted = true; +#if HASP_USE_WIFI > 0 Log.notice(F("HTTP: Server started @ http://%s"), (WiFi.getMode() != WIFI_STA ? WiFi.softAPIP().toString().c_str() : WiFi.localIP().toString().c_str())); +#else + IPAddress ip; + ip = Ethernet.localIP(); + Log.notice(F("HTTP: Server started @ http://%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); +#endif } void webStop() @@ -1797,10 +1524,12 @@ void httpSetup() { // httpSetConfig(settings); +#if HASP_USE_WIFI > 0 if(WiFi.getMode() != WIFI_STA) { Log.notice(F("HTTP: Wifi access point")); webServer.on(F("/"), webHandleWifiConfig); } else { +#endif webServer.on(F("/page/"), []() { String pageid = webServer.arg(F("page")); @@ -1808,6 +1537,7 @@ void httpSetup() haspSetPage(pageid.toInt()); }); +#if HASP_USE_SPIFFS > 0 webServer.on(F("/list"), HTTP_GET, handleFileList); // load editor webServer.on(F("/edit"), HTTP_GET, []() { @@ -1823,6 +1553,8 @@ void httpSetup() // second callback handles file uploads at that location webServer.on( F("/edit"), HTTP_POST, []() { webServer.send(200, "text/plain", ""); }, handleFileUpload); +#endif + // get heap status, analog input value and all GPIO statuses in one json call /*webServer.on(F("/all"), HTTP_GET, []() { String json; @@ -1851,17 +1583,24 @@ void httpSetup() #endif #if HASP_USE_WIFI > 0 webServer.on(F("/config/wifi"), webHandleWifiConfig); +#endif +#if HASP_USE_GPIO > 0 + webServer.on(F("/config/gpio"), webHandleGpioConfig); #endif webServer.on(F("/screenshot"), webHandleScreenshot); webServer.on(F("/saveConfig"), webHandleSaveConfig); webServer.on(F("/resetConfig"), httpHandleResetConfig); webServer.on(F("/firmware"), webHandleFirmware); +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) webServer.on( F("/update"), HTTP_POST, []() { webServer.send(200, "text/plain", ""); }, webHandleFirmwareUpdate); webServer.on(F("/espfirmware"), httpHandleEspFirmware); +#endif webServer.on(F("/reboot"), httpHandleReboot); webServer.onNotFound(httpHandleNotFound); +#if HASP_USE_WIFI > 0 } +#endif // Shared pages webServer.on(F("/about"), webHandleAbout); @@ -1879,7 +1618,11 @@ void httpReconnect() if(webServerStarted) { webStop(); - } else if(WiFi.status() == WL_CONNECTED || WiFi.getMode() != WIFI_STA) { + } else +#if HASP_USE_WIFI > 0 + if(WiFi.status() == WL_CONNECTED || WiFi.getMode() != WIFI_STA) +#endif + { webStart(); } } @@ -1944,5 +1687,24 @@ bool httpSetConfig(const JsonObject & settings) return changed; } -#endif +size_t httpClientWrite(const uint8_t * buf, size_t size) +{ + /***** Sending 16Kb at once freezes on STM32 EthernetClient *****/ + size_t bytes_sent = 0; + while(bytes_sent < size) { + if(!webServer.client()) return bytes_sent; + if(size - bytes_sent >= 2048) { + bytes_sent += webServer.client().write(buf + bytes_sent, 2048); + } else { + bytes_sent += webServer.client().write(buf + bytes_sent, size - bytes_sent); + } + // Serial.println(bytes_sent); + + // stm32_eth_scheduler(); // already in write + // webServer.client().flush(); + delay(1); // Fixes the freeze + } + return bytes_sent; +} + #endif \ No newline at end of file diff --git a/src/hasp_http.h b/src/hasp_http.h index d7a17db5..3caf1b7f 100644 --- a/src/hasp_http.h +++ b/src/hasp_http.h @@ -9,6 +9,8 @@ void httpLoop(void); void httpEvery5Seconds(void); void httpReconnect(void); +size_t httpClientWrite(const uint8_t *buf, size_t size); // Screenshot Write Data + bool httpGetConfig(const JsonObject & settings); bool httpSetConfig(const JsonObject & settings); diff --git a/src/hasp_mdns.cpp b/src/hasp_mdns.cpp index 7beb2941..c6613820 100644 --- a/src/hasp_mdns.cpp +++ b/src/hasp_mdns.cpp @@ -13,10 +13,10 @@ #include "hasp_config.h" #include "hasp_conf.h" -#if HASP_USE_MQTT +#if HASP_USE_MQTT>0 #include "hasp_mqtt.h" #endif -#if HASP_USE_MDNS +#if HASP_USE_MDNS>0 #include "hasp_mdns.h" #endif diff --git a/src/hasp_mqtt.cpp b/src/hasp_mqtt.cpp index eef09b2d..4bb7ef38 100644 --- a/src/hasp_mqtt.cpp +++ b/src/hasp_mqtt.cpp @@ -1,5 +1,5 @@ #include "hasp_conf.h" -#if HASP_USE_MQTT +#if HASP_USE_MQTT>0 #include #include "ArduinoJson.h" @@ -11,10 +11,22 @@ #if defined(ARDUINO_ARCH_ESP32) #include -#else +WiFiClient mqttNetworkClient; +#elif defined(ARDUINO_ARCH_ESP8266) #include #include #include +WiFiClient mqttNetworkClient; +#else + +#if defined(W5500_MOSI) && defined(W5500_MISO) && defined(W5500_SCLK) +#define W5500_LAN +#include +#else +#include +#endif + +EthernetClient mqttNetworkClient; #endif #include "hasp_hal.h" @@ -97,8 +109,7 @@ const String mqttLightSubscription = "hasp/" + String(haspGetNodename()) const String mqttLightBrightSubscription = "hasp/" + String(haspGetNodename()) + "/brightness/#"; */ -WiFiClient mqttWifiClient; -PubSubClient mqttClient(mqttWifiClient); +PubSubClient mqttClient(mqttNetworkClient); //////////////////////////////////////////////////////////////////////////////////////////////////// // Send changed values OUT @@ -179,11 +190,13 @@ void mqtt_send_statusupdate() snprintf_P(data, sizeof(data), PSTR("{\"status\":\"available\",\"version\":\"%s\",\"uptime\":%lu,"), haspGetVersion().c_str(), long(millis() / 1000)); strcat(buffer, data); +#if HASP_USE_WIFI>0 snprintf_P(buffer, sizeof(buffer), PSTR("\"ssid\":\"%s\",\"rssi\":%i,\"ip\":\"%s\","), WiFi.SSID().c_str(), WiFi.RSSI(), WiFi.localIP().toString().c_str()); strcat(data, buffer); +#endif snprintf_P(buffer, sizeof(buffer), PSTR("\"heapFree\":%u,\"heapFrag\":%u,\"espCore\":\"%s\","), - ESP.getFreeHeap(), halGetHeapFragmentation(), halGetCoreVersion().c_str()); + halGetFreeHeap(), halGetHeapFragmentation(), halGetCoreVersion().c_str()); strcat(data, buffer); snprintf_P(buffer, sizeof(buffer), PSTR("\"espCanUpdate\":\"false\",\"page\":%u,\"numPages\":%u,"), haspGetPage(), (HASP_NUM_PAGES)); @@ -339,9 +352,11 @@ void mqttReconnect() bool mqttFirstConnect = true; { - byte mac[6]; - WiFi.macAddress(mac); - snprintf_P(mqttClientId, sizeof(mqttClientId), PSTR("%s-%2x%2x%2x"), mqttNodeName, mac[3], mac[4], mac[5]); + String mac = halGetMacAddress(3, ""); + mac.toLowerCase(); + memset(mqttClientId, 0 ,sizeof(mqttClientId)); + snprintf_P(mqttClientId, sizeof(mqttClientId), PSTR("plate_%s"), mac.c_str()); + Log.verbose(mqttClientId); } // Attempt to connect and set LWT and Clean Session @@ -537,7 +552,7 @@ bool mqttSetConfig(const JsonObject & settings) } // Prefill node name if(strlen(mqttNodeName) == 0) { - String mac = wifiGetMacAddress(3, ""); + String mac = halGetMacAddress(3, ""); mac.toLowerCase(); snprintf_P(mqttNodeName, sizeof(mqttNodeName), PSTR("plate_%s"), mac.c_str()); changed = true; diff --git a/src/hasp_oobe.cpp b/src/hasp_oobe.cpp index 7f91127e..e63d27fe 100644 --- a/src/hasp_oobe.cpp +++ b/src/hasp_oobe.cpp @@ -14,7 +14,7 @@ #include "hasp_config.h" #include "hasp_dispatch.h" -#if HASP_USE_QRCODE != 0 +#if HASP_USE_QRCODE > 0 #include "lv_qrcode.h" #endif @@ -128,7 +128,7 @@ static void oobeSetupQR(const char * ssid, const char * pass) lv_obj_set_style_local_bg_opa(container, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0); lv_obj_set_style_local_border_opa(container, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0); -#if HASP_USE_QRCODE != 0 +#if HASP_USE_QRCODE > 0 snprintf_P(buffer, sizeof(buffer), PSTR("WIFI:S:%s;T:WPA;P:%s;;"), ssid, pass); lv_obj_t * qr = lv_qrcode_create(oobepage[0], 120, LV_COLOR_BLACK, LV_COLOR_WHITE); diff --git a/src/hasp_ota.cpp b/src/hasp_ota.cpp index 188fbcc0..cc7a3fca 100644 --- a/src/hasp_ota.cpp +++ b/src/hasp_ota.cpp @@ -10,11 +10,11 @@ #include "hasp_conf.h" -#if HASP_USE_MQTT +#if HASP_USE_MQTT>0 #include "hasp_mqtt.h" #endif -#if HASP_USE_MDNS +#if HASP_USE_MDNS>0 #include "hasp_mdns.h" #endif diff --git a/src/hasp_slave.cpp b/src/hasp_slave.cpp new file mode 100644 index 00000000..7ae71a3c --- /dev/null +++ b/src/hasp_slave.cpp @@ -0,0 +1,165 @@ +/********************* + * INCLUDES + *********************/ +#if HASP_USE_TASMOTA_SLAVE>0 + +#include "hasp_slave.h" +#include +#include "ArduinoJson.h" +#include "ArduinoLog.h" +#include "hasp_dispatch.h" +#include "hasp_gui.h" +#include "hasp_hal.h" +#include "hasp_tft.h" +#include "hasp_config.h" +#include "hasp.h" +#include "tasmotaSlave.h" + +// set RX and TX pins +HardwareSerial Serial2(PD6, PD5); +TasmotaSlave slave(&Serial2); + +#define slaveNodeTopic "hasp/" + +unsigned long updateLedTimer = 0; // timer in msec for tele mqtt send +unsigned long updatLedPeriod = 1000; // timer in msec for tele mqtt send + +bool ledstate = false; + + +void IRAM_ATTR slave_send_state(const __FlashStringHelper * subtopic, const char * payload) +{ + // page = 0 + // p[0].b[0].attr = abc + // dim = 100 + // idle = 0/1 + // light = 0/1 + // brightness = 100 + + char cBuffer[strlen(payload) + 64]; + memset(cBuffer, 0 ,sizeof(cBuffer)); + snprintf(cBuffer, sizeof(cBuffer), PSTR("publish %sstate/%s %s"), slaveNodeTopic ,subtopic, payload); + slave.ExecuteCommand((char*)cBuffer); + + // Log after char buffers are cleared + Log.notice(F("TAS PUB: %sstate/%S = %s"), slaveNodeTopic, subtopic, payload); +} + +void IRAM_ATTR slave_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data) +{ + char cBuffer[192]; + memset(cBuffer, 0 ,sizeof(cBuffer)); + snprintf_P(cBuffer, sizeof(cBuffer), PSTR("publish %sstate/json {\"p[%u].b[%u].%s\":\"%s\"}"), slaveNodeTopic, pageid, btnid, attribute, data); + slave.ExecuteCommand((char*)cBuffer); + // Log after char buffers are cleared + Log.notice(F("TAS PUB: %sstate/json = {\"p[%u].b[%u].%s\":\"%s\"}"), slaveNodeTopic, pageid, btnid, attribute, data); +} + +void slave_send_input(uint8_t id, const char * payload) +{ + // Log.trace(F("MQTT TST: %sstate/input%u = %s"), mqttNodeTopic, id, payload); // to be removed + + char cBuffer[strlen(payload) + 64]; + memset(cBuffer, 0 ,sizeof(cBuffer)); + snprintf_P(cBuffer, sizeof(cBuffer), PSTR("publish %sstate/input%u %s"), slaveNodeTopic, id, payload); + slave.ExecuteCommand((char*)cBuffer); + + // Log after char buffers are cleared + Log.notice(F("TAS PUB: %sstate/input%u = %s"), slaveNodeTopic, id, payload); +} + +void TASMO_TELE_JSON() +{ // Periodically publish a JSON string indicating system status + char data[3 * 128]; + { + char buffer[128]; + snprintf_P(data, sizeof(data), PSTR("{\"status\":\"available\",\"version\":\"%s\",\"uptime\":%lu,"), + haspGetVersion().c_str(), long(millis() / 1000)); + strcat(buffer, data); + snprintf_P(buffer, sizeof(buffer), PSTR("\"espCanUpdate\":\"false\",\"page\":%u,\"numPages\":%u,"), + haspGetPage(), (HASP_NUM_PAGES)); + strcat(data, buffer); + snprintf_P(buffer, sizeof(buffer), PSTR("\"tftDriver\":\"%s\",\"tftWidth\":%u,\"tftHeight\":%u}"), + tftDriverName().c_str(), (TFT_WIDTH), (TFT_HEIGHT)); + strcat(data, buffer); + } + slave.sendJSON((char*)data); + // slave_send_state(F("statusupdate"), data); + // debugLastMillis = millis(); +} + +void TASMO_DATA_RECEIVE(char *data) +{ + Log.verbose(F("TAS: Slave IN [%s]"), data); + + char dataType[3]; + memset(dataType, 0 ,sizeof(dataType)); + snprintf_P(dataType, sizeof(dataType), data); + Log.verbose(F("TAS: dataType [%s]"), dataType); + + if (!strcmp(dataType, "p[")){ // + dispatchCommand(data); + } else if (!strcmp(dataType, "[\"")) { + dispatchJson(data); + } else { + char slvCmd[20],slvVal[60]; + memset(slvCmd, 0 ,sizeof(slvCmd)); + memset(slvVal, 0 ,sizeof(slvVal)); + sscanf(data,"%[^=] =%s", slvCmd, slvVal); + + Log.verbose(F("TAS: Cmd[%s] Val[%s]"), slvCmd, slvVal); + + if (!strcmp(slvCmd, "calData")){ + if (strlen(slvVal) != 0) { + char cBuffer[strlen(slvVal) + 24]; + memset(cBuffer, 0 ,sizeof(cBuffer)); + snprintf_P(cBuffer, sizeof(cBuffer), PSTR("{'calibration':[%s]}"), slvVal); + dispatchConfig("gui",cBuffer); + } else { + dispatchConfig("gui",""); + } + } else if (!strcmp(slvCmd, "jsonl")) { + dispatchJsonl(slvVal); + } else if (!strcmp(slvCmd, "clearpage")) { + dispatchClearPage(slvVal); + } else { + dispatchCommand(data); + } + } +} + +void TASMO_EVERY_SECOND(void) +{ + if (ledstate) { + ledstate = false; + //digitalWrite(HASP_OUTPUT_PIN, 1); + // Log.verbose(F("LED OFF")); + } else { + ledstate = true; + //digitalWrite(HASP_OUTPUT_PIN, 0); + // Log.verbose(F("LED ON")); + } +} + +void slaveSetup() +{ + Serial2.begin(HASP_SLAVE_SPEED); + // slave.attach_FUNC_EVERY_SECOND(TASMO_EVERY_SECOND); + slave.attach_FUNC_JSON(TASMO_TELE_JSON); + slave.attach_FUNC_COMMAND_SEND(TASMO_DATA_RECEIVE); + + Log.notice(F("TAS: HASP SLAVE LOADED")); +} + +void slaveLoop(void) +{ + slave.loop(); + // demo code to run the led without tasmota + // if ((millis() - updateLedTimer) >= updatLedPeriod) { + // updateLedTimer = millis(); + // TASMO_EVERY_SECOND(); + // } + +} + +#endif \ No newline at end of file diff --git a/src/hasp_slave.h b/src/hasp_slave.h new file mode 100644 index 00000000..772a471c --- /dev/null +++ b/src/hasp_slave.h @@ -0,0 +1,20 @@ +#ifndef HASP_SLAVE_H +#define HASP_SLAVE_H + +#include "ArduinoJson.h" + +#define HASP_SLAVE_SPEED 57600 + +void TASMO_EVERY_SECOND(void); +void TASMO_DATA_RECEIVE(char *data); +void IRAM_ATTR slave_send_state(const __FlashStringHelper * subtopic, const char * payload); +void IRAM_ATTR slave_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data); +void slave_send_input(uint8_t id, const char * payload); +void slave_send_statusupdate(); + + +void slaveSetup(); +void slaveLoop(void); + + +#endif \ No newline at end of file diff --git a/src/hasp_spiffs.cpp b/src/hasp_spiffs.cpp index fdd64f8a..b916b07a 100644 --- a/src/hasp_spiffs.cpp +++ b/src/hasp_spiffs.cpp @@ -5,7 +5,7 @@ #include "hasp_conf.h" #include "hasp_spiffs.h" -#if HASP_USE_SPIFFS +#if HASP_USE_SPIFFS>0 #if defined(ARDUINO_ARCH_ESP32) #include "SPIFFS.h" #endif @@ -14,7 +14,7 @@ void spiffsInfo() { // Get all information of your SPIFFS -#if defined(ARDUINO_ARCH_ESP8266) +#if 0 FSInfo fs_info; SPIFFS.info(fs_info); @@ -91,7 +91,7 @@ void spiffsSetup() { // no SPIFFS settings, as settings depend on SPIFFS -#if HASP_USE_SPIFFS +#if HASP_USE_SPIFFS>0 #if defined(ARDUINO_ARCH_ESP8266) if(!SPIFFS.begin()) { #else @@ -102,25 +102,4 @@ void spiffsSetup() Log.verbose(F("FILE: SPI Flash FS mounted")); } #endif -} - -String spiffsFormatBytes(size_t bytes) -{ - String output((char *)0); - output.reserve(128); - - if(bytes < 1024) { - output += bytes; - } else if(bytes < (1024 * 1024)) { - output += bytes / 1024.0; - output += "K"; - } else if(bytes < (1024 * 1024 * 1024)) { - output += bytes / 1024.0 / 1024.0; - output += "M"; - } else { - output += bytes / 1024.0 / 1024.0 / 1024.0; - output += "G"; - } - output += "B"; - return output; } \ No newline at end of file diff --git a/src/hasp_spiffs.h b/src/hasp_spiffs.h index 39dbb956..c0dadaca 100644 --- a/src/hasp_spiffs.h +++ b/src/hasp_spiffs.h @@ -7,6 +7,5 @@ void spiffsSetup(void); void spiffsList(); void spiffsInfo(); -String spiffsFormatBytes(size_t bytes); #endif \ No newline at end of file diff --git a/src/hasp_telnet.cpp b/src/hasp_telnet.cpp index b59c2096..e6595dba 100644 --- a/src/hasp_telnet.cpp +++ b/src/hasp_telnet.cpp @@ -9,11 +9,20 @@ #include "hasp_config.h" #include "hasp_dispatch.h" #include "hasp_telnet.h" +#include "hasp_conf.h" #if defined(ARDUINO_ARCH_ESP32) #include -#else +WiFiClient telnetClient; +static WiFiServer * telnetServer; +#elif defined(ARDUINO_ARCH_ESP8266) #include +WiFiClient telnetClient; +static WiFiServer * telnetServer; +#else +//#include +EthernetClient telnetClient; +static EthernetServer telnetServer(23); #endif #define TELNET_UNAUTHENTICATED 0 @@ -21,12 +30,14 @@ #define TELNET_USERNAME_NOK 99 #define TELNET_AUTHENTICATED 255 +#if HASP_USE_HTTP > 0 extern char httpUser[32]; extern char httpPassword[32]; +#endif uint8_t telnetLoginState = TELNET_UNAUTHENTICATED; -WiFiClient telnetClient; -static WiFiServer * telnetServer; +// WiFiClient telnetClient; +// static WiFiServer * telnetServer; uint16_t telnetPort = 23; bool telnetInCommandMode = false; uint8_t telnetEnabled = true; // Enable telnet debug output @@ -36,7 +47,7 @@ char telnetInputBuffer[128]; void telnetClientDisconnect() { - Log.notice(F("Closing session from %s"), telnetClient.remoteIP().toString().c_str()); + // Log.notice(F("Closing session from %s"), telnetClient.remoteIP().toString().c_str()); telnetClient.stop(); Log.unregisterOutput(1); // telnetClient telnetLoginState = TELNET_UNAUTHENTICATED; @@ -51,7 +62,7 @@ void telnetClientLogon() telnetLoginState = TELNET_AUTHENTICATED; // User and Pass are correct telnetLoginAttempt = 0; // Reset attempt counter Log.registerOutput(1, &telnetClient, LOG_LEVEL_VERBOSE, true); - Log.notice(F("Client login from %s"), telnetClient.remoteIP().toString().c_str()); + // Log.notice(F("Client login from %s"), telnetClient.remoteIP().toString().c_str()); telnetClient.flush(); /* Echo locally as separate string */ // telnetClient.print(F("TELNET: Client login from ")); @@ -66,17 +77,25 @@ void telnetAcceptClient() telnetClient.stop(); // client disconnected Log.unregisterOutput(1); // telnetClient } - telnetClient = telnetServer->available(); // ready for new client - Log.notice(F("Client connected from %s"), telnetClient.remoteIP().toString().c_str()); + telnetClient = telnetServer.available(); // ready for new client + // Log.notice(F("Client connected from %s"), telnetClient.remoteIP().toString().c_str()); + if(!telnetClient) { + Log.notice(F("Client NOT connected")); + return; + } + Log.notice(F("Client connected")); /* Avoid a buffer here */ telnetClient.print(0xFF); // DO TERMINAL-TYPE telnetClient.print(0xFD); telnetClient.print(0x1B); +#if HASP_USE_HTTP > 0 if(strlen(httpUser) != 0 || strlen(httpPassword) != 0) { telnetClient.print(F("\r\nUsername: ")); telnetLoginState = TELNET_UNAUTHENTICATED; - } else { + } else +#endif + { telnetClientLogon(); } telnetInputIndex = 0; // reset input buffer index @@ -100,6 +119,7 @@ static void telnetProcessLine() switch(telnetLoginState) { case TELNET_UNAUTHENTICATED: { telnetClient.printf(PSTR("Password: %c%c%c"), 0xFF, 0xFB, 0x01); // Hide characters +#if HASP_USE_HTTP > 0 telnetLoginState = strcmp(telnetInputBuffer, httpUser) == 0 ? TELNET_USERNAME_OK : TELNET_USERNAME_NOK; break; } @@ -112,13 +132,16 @@ static void telnetProcessLine() telnetLoginState = TELNET_UNAUTHENTICATED; telnetLoginAttempt++; // Subsequent attempt telnetClient.println(F("Authorization failed!\r\n")); - Log.warning(F("Incorrect login attempt from %s"), telnetClient.remoteIP().toString().c_str()); + // Log.warning(F("Incorrect login attempt from %s"), telnetClient.remoteIP().toString().c_str()); if(telnetLoginAttempt >= 3) { telnetClientDisconnect(); } else { telnetClient.print(F("Username: ")); } } +#else + telnetClientLogon(); +#endif break; } default: @@ -173,6 +196,15 @@ void telnetSetup() // telnetSetConfig(settings); if(telnetEnabled) { // Setup telnet server for remote debug output +#if defined(STM32F4xx) + // if(!telnetServer) telnetServer = new EthernetServer(telnetPort); + // if(telnetServer) { + telnetServer.begin(); + Log.notice(F("Debug telnet console started")); + // } else { + // Log.error(F("Failed to start telnet server")); + //} +#else if(!telnetServer) telnetServer = new WiFiServer(telnetPort); if(telnetServer) { telnetServer->setNoDelay(true); @@ -189,12 +221,41 @@ void telnetSetup() } else { Log.error(F("Failed to start telnet server")); } +#endif } } void IRAM_ATTR telnetLoop() { // Basic telnet client handling code from: https://gist.github.com/tablatronix/4793677ca748f5f584c95ec4a2b10303 +#if defined(STM32F4xx) +Ethernet.schedule(); + // if(telnetServer) + { // client is connected + EthernetClient client = telnetServer.available(); + if(client) { + if(!telnetClient || !telnetClient.connected()) { + //telnetAcceptClient(client); + + telnetClient = client; // ready for new client + // Log.notice(F("Client connected from %s"), telnetClient.remoteIP().toString().c_str()); + if(!telnetClient) { + Log.notice(F("Client NOT connected")); + return; + } + Log.notice(F("Client connected")); + + /* Avoid a buffer here */ + // telnetClient.print(0xFF); // DO TERMINAL-TYPE + // telnetClient.print(0xFD); + // telnetClient.print(0x1B); + + } else { + //client.stop(); // have client, block new connections + } + } + } +#else if(telnetServer && telnetServer->hasClient()) { // client is connected if(!telnetClient || !telnetClient.connected()) { telnetAcceptClient(); @@ -209,6 +270,7 @@ void IRAM_ATTR telnetLoop() telnetProcessCharacter(telnetClient.read()); // client input processing } } +#endif } bool telnetGetConfig(const JsonObject & settings) diff --git a/src/hasp_tft.cpp b/src/hasp_tft.cpp index b8f07ed0..031b5f23 100644 --- a/src/hasp_tft.cpp +++ b/src/hasp_tft.cpp @@ -3,6 +3,7 @@ #include "TFT_eSPI.h" #include "hasp_tft.h" +#include "hasp_hal.h" #if defined(ARDUINO_ARCH_ESP8266) ADC_MODE(ADC_VCC); // tftShowConfig measures the voltage on the pin @@ -84,11 +85,10 @@ void tftShowConfig(TFT_eSPI & tft) Log.verbose(F("TFT: TFT_eSPI : v%s"), tftSetup.version.c_str()); #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_32) Log.verbose(F("TFT: Processor : ESP%x"), tftSetup.esp); - Log.verbose(F("TFT: CPU freq. : %i MHz"), ESP.getCpuFreqMHz()); #else Log.verbose(F("TFT: Processor : STM%x"), tftSetup.esp); - Log.verbose(F("TFT: CPU freq. : %i MHz"), F_CPU/1000/1000); #endif + Log.verbose(F("TFT: CPU freq. : %i MHz"), halGetCpuFreqMHz()); #if defined(ARDUINO_ARCH_ESP8266) Log.verbose(F("TFT: Voltage : %2.2f V"), ESP.getVcc() / 918.0); // 918 empirically determined @@ -98,6 +98,7 @@ void tftShowConfig(TFT_eSPI & tft) #if defined(ARDUINO_ARCH_ESP8266) Log.verbose(F("TFT: SPI overlap : %s"), (tftSetup.overlap == 1) ? PSTR("Yes") : PSTR("No")); #endif + if(tftSetup.tft_driver != 0xE9D) // For ePaper displays the size is defined in the sketch { Log.verbose(F("TFT: Driver : %s"), tftDriverName().c_str()); // tftSetup.tft_driver); @@ -155,14 +156,10 @@ void tftShowConfig(TFT_eSPI & tft) tftPinInfo(F("TFT_D7"), tftSetup.pin_tft_d7); if(tftSetup.serial == 1) { - char buffer[8]; - snprintf_P(buffer, sizeof(buffer), "%4.2f", (float)tftSetup.tft_spi_freq / 10.0f); - Log.verbose(F("TFT: Display SPI freq. : %s MHz"), buffer); + Log.verbose(F("TFT: Display SPI freq. : %d.%d MHz"), tftSetup.tft_spi_freq / 10, tftSetup.tft_spi_freq % 10); } if(tftSetup.pin_tch_cs != -1) { - char buffer[8]; - snprintf_P(buffer, sizeof(buffer), "%4.2f", (float)tftSetup.tch_spi_freq / 10.0f); - Log.verbose(F("TFT: Touch SPI freq. : %s MHz"), buffer); + Log.verbose(F("TFT: Touch SPI freq. : %d.%d MHz"), tftSetup.tch_spi_freq / 10, tftSetup.tch_spi_freq % 10); } } diff --git a/src/hasp_wifi.cpp b/src/hasp_wifi.cpp index ecde60b0..2921b027 100644 --- a/src/hasp_wifi.cpp +++ b/src/hasp_wifi.cpp @@ -41,22 +41,6 @@ uint8_t wifiReconnectCounter = 0; // const byte DNS_PORT = 53; // DNSServer dnsServer; -String wifiGetMacAddress(int start, const char * seperator) -{ - byte mac[6]; - WiFi.macAddress(mac); - String cMac((char *)0); - cMac.reserve(32); - - for(int i = start; i < 6; ++i) { - if(mac[i] < 0x10) cMac += "0"; - cMac += String(mac[i], HEX); - if(i < 5) cMac += seperator; - } - cMac.toUpperCase(); - return cMac; -} - void wifiConnected(IPAddress ipaddress) { Log.notice(F("WIFI: Received IP address %s"), ipaddress.toString().c_str()); diff --git a/src/hasp_wifi.h b/src/hasp_wifi.h index 3ee27d27..ea7b397c 100644 --- a/src/hasp_wifi.h +++ b/src/hasp_wifi.h @@ -13,6 +13,4 @@ bool wifiTestConnection(); bool wifiGetConfig(const JsonObject & settings); bool wifiSetConfig(const JsonObject & settings); -String wifiGetMacAddress(int start, const char * seperator); - #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 5bb44c72..e03e3c21 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,11 @@ #include "hasp_conf.h" // load first #include +#include "hasp_conf.h" #include "hasp_debug.h" -#include "hasp_spiffs.h" #include "hasp_config.h" #include "hasp_gui.h" #include "hasp.h" -#include "hasp_conf.h" #include "hasp_oobe.h" #include "hasp_gpio.h" @@ -22,15 +21,15 @@ void setup() ***************************/ /* Init Storage */ -#if HASP_USE_EEPROM -// eepromSetup(); // Don't start at boot, only at write +#if HASP_USE_EEPROM>0 + eepromSetup(); // Don't start at boot, only at write #endif -#if HASP_USE_SPIFFS +#if HASP_USE_SPIFFS>0 spiffsSetup(); #endif -#if HASP_USE_SDCARD +#if HASP_USE_SDCARD>0 sdcardSetup(); #endif @@ -43,41 +42,45 @@ void setup() * Apply User Configuration ***************************/ debugSetup(); - gpioSetup(); - guiSetup(); -#if HASP_USE_WIFI +#if HASP_USE_GPIO>0 + gpioSetup(); +#endif + +#if HASP_USE_WIFI>0 wifiSetup(); #endif + + guiSetup(); oobeSetup(); haspSetup(); -#if HASP_USE_WIFI - -#if HASP_USE_HTTP - httpSetup(); -#endif - -#if HASP_USE_MQTT - mqttSetup(); -#endif - -#if HASP_USE_TELNET - telnetSetup(); -#endif - -#if HASP_USE_MDNS +#if HASP_USE_MDNS>0 mdnsSetup(); #endif -#if HASP_USE_OTA +#if HASP_USE_OTA>0 otaSetup(); #endif -#endif // WIFI +#if HASP_USE_ETHERNET > 0 + ethernetSetup(); +#endif -#if HASP_USE_BUTTON - buttonSetup(); +#if HASP_USE_MQTT>0 + mqttSetup(); +#endif + +#if HASP_USE_HTTP>0 + httpSetup(); +#endif + +#if HASP_USE_TELNET > 0 + telnetSetup(); +#endif + +#if HASP_USE_TASMOTA_SLAVE>0 + slaveSetup(); #endif mainLastLoopTime = millis() - 1000; // reset loop counter @@ -86,82 +89,98 @@ void setup() void loop() { /* Storage Loops */ -#if HASP_USE_EEPROM - eepromLoop(); -#endif - // spiffsLoop(); -#if HASP_USE_SDCARD - // sdcardLoop(); -#endif + /* + #if HASP_USE_EEPROM>0 + // eepromLoop(); // Not used + #endif - // configLoop(); + #if HASP_USE_SPIFFS>0 + // spiffsLoop(); // Not used + #endif + + #if HASP_USE_SDCARD>0 + // sdcardLoop(); // Not used + #endif + + // configLoop(); // Not used + */ /* Graphics Loops */ // tftLoop(); guiLoop(); - /* Application Loops */ // haspLoop(); + debugLoop(); + +#if HASP_USE_GPIO>0 + gpioLoop(); +#endif /* Network Services Loops */ -#if HASP_USE_WIFI +#if HASP_USE_ETHERNET > 0 + ethernetLoop(); +#endif -#if HASP_USE_MQTT +#if HASP_USE_MQTT>0 mqttLoop(); #endif // MQTT -#if HASP_USE_HTTP +#if HASP_USE_HTTP>0 httpLoop(); #endif // HTTP -#if HASP_USE_TELNET - telnetLoop(); -#endif // TELNET - -#if HASP_USE_MDNS +#if HASP_USE_MDNS>0 mdnsLoop(); #endif // MDNS -#if HASP_USE_BUTTON - buttonLoop(); -#endif // BUTTON - -#if HASP_USE_OTA +#if HASP_USE_OTA>0 otaLoop(); #endif // OTA -#endif // WIFI +#if HASP_USE_TELNET > 0 + telnetLoop(); +#endif // TELNET - // Every Second Loop +#if HASP_USE_TASMOTA_SLAVE>0 + slaveLoop(); +#endif // TASMOTASLAVE + + // digitalWrite(HASP_OUTPUT_PIN, digitalRead(HASP_INPUT_PIN)); // sets the LED to the button's value + + /* Timer Loop */ if(millis() - mainLastLoopTime >= 1000) { /* Run Every Second */ -#if HASP_USE_OTA +#if HASP_USE_OTA>0 otaEverySecond(); #endif debugEverySecond(); /* Run Every 5 Seconds */ - if(mainLoopCounter == 0 || mainLoopCounter == 4) { -#if HASP_USE_HTTP + if(mainLoopCounter == 0 || mainLoopCounter == 5) { +#if HASP_USE_WIFI > 0 + isConnected = wifiEvery5Seconds(); +#endif + +#if HASP_USE_ETHERNET > 0 + isConnected = ethernetEvery5Seconds(); +#endif + +#if HASP_USE_HTTP > 0 httpEvery5Seconds(); #endif -#if HASP_USE_WIFI - isConnected = wifiEvery5Seconds(); - -#if HASP_USE_MQTT +#if HASP_USE_MQTT > 0 mqttEvery5Seconds(isConnected); -#endif - #endif } - /* Update counters */ + /* Reset loop counter every 10 seconds */ + if(mainLoopCounter >= 9) { + mainLoopCounter = 0; + } else { + mainLoopCounter++; + } mainLastLoopTime += 1000; - mainLoopCounter++; - if(mainLoopCounter >= 10) { - mainLoopCounter = 0; - } } delay(3); diff --git a/user_setups/esp32/d1-mini-esp32_ili9341.ini b/user_setups/esp32/d1-mini-esp32_ili9341.ini new file mode 100644 index 00000000..bae61bc9 --- /dev/null +++ b/user_setups/esp32/d1-mini-esp32_ili9341.ini @@ -0,0 +1,23 @@ +;***************************************************; +; D1 Mini ESP32 with Lolin TFT 2.4" ; +; - D1-mini-esp32 board ; +; - ili9341 TFT ; +; - xpt2606 touch controller ; +;***************************************************; + +[env:d1mini32-lolintft24] +platform = espressif32@^1.12.0 +board = wemos_d1_mini32 +upload_port = COM5 ; To change the port, use platform_override.ini +monitor_port = COM5 ; To change the port, use platform_override.ini +board_build.partitions = default.csv +build_flags = + ${flags.esp32_flags} +; -- TFT_eSPI build options ------------------------ + ${lcd.lolin24} + ${pins.vspi32} + -D TFT_DC=5 + -D TFT_CS=26 + -D TFT_RST=-1 ; RST + -D TFT_BCKL=-1 ; None, configurable via web UI (e.g. 21) + -D TOUCH_CS=17 ; (can also be 22 or 16) diff --git a/user_setups/esp32/d132-unoshield_ili9486_parallel.ini b/user_setups/esp32/d132-unoshield_ili9486_parallel.ini new file mode 100644 index 00000000..e3c45355 --- /dev/null +++ b/user_setups/esp32/d132-unoshield_ili9486_parallel.ini @@ -0,0 +1,49 @@ +;***************************************************; +; ESP32 build with ; +; - Wemos "TTGo" D1 R32 board ; +; - ili9486 TFT ; +;***************************************************; + +[env:d132-unoshield] +platform = espressif32 +board = esp32dev +upload_port = COM4 ; To change the port, use platform_override.ini +monitor_port = COM4 ; To change the port, use platform_override.ini + +build_flags = + ${flags.esp32_flags} +; -- TFT_eSPI build options ------------------------ + -D USER_SETUP_LOADED=1 + ;-D ST7796_DRIVER=1 ;3.95inch Arduino Display-UNO + -D ILI9486_DRIVER=1 ;3.5inch Arduino Display-UNO + -D ESP32_PARALLEL=1 + -D TFT_ROTATION=${lcd.TFT_ROTATION} + -D TFT_WIDTH=320 + -D TFT_HEIGHT=480 + ${pins.vspi32} + -D TFT_BCKL=-1 ;None, configurable via web UI (e.g. 2 for D4) + -D TFT_CS=33 ; Chip select control pin + -D TFT_DC=15 ; Data Command control pin - must use a pin in the range 0-31 + -D TFT_RST=32 ; Reset pin + -D TFT_WR=4 ; Write strobe control pin - must use a pin in the range 0-31 + -D TFT_RD=2 + -D TFT_D0=12 ; Must use pins in the range 0-31 for the data bus + -D TFT_D1=13 ; so a single register write sets/clears all bits + -D TFT_D2=26 + -D TFT_D3=25 + -D TFT_D4=17 + -D TFT_D5=16 + -D TFT_D6=27 + -D TFT_D7=14 + -D SD_CS=5 + -D SPI_FREQUENCY=40000000 + ;-D SPI_TOUCH_FREQUENCY=2500000 ; Uses ADC instead + -D SPI_READ_FREQUENCY=20000000 +; -- Debugging options ----------------------------- +; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + +; -- Library options ------------------------------- +lib_deps = + ${env.lib_deps} + +src_filter = +<*> +<../drivers/stm32f429_disco> diff --git a/user_setups/esp32/esp32-dev_ili9488.ini b/user_setups/esp32/esp32-dev_ili9488.ini new file mode 100644 index 00000000..b3fac875 --- /dev/null +++ b/user_setups/esp32/esp32-dev_ili9488.ini @@ -0,0 +1,48 @@ +;***************************************************; +; Generic ESP32 build with ; +; - ili9488 TFT SPI 4-WIRE ; +; - xpt2606 touch controller ; +;***************************************************; + +[env:esp32dev-ili9488] +platform = espressif32 +board = esp32dev +upload_port = COM2 ; To change the port, use platform_override.ini +monitor_port = COM2 ; To change the port, use platform_override.ini +; upload_protocol = espota ; Use ArduinoOTA after flashing over serial +; upload_port = 10.4.0.171 ; IP of the ESP +; upload_flags = +; --port=3232 +debug_tool = esp-prog +debug_init_break = tbreak setup + +build_flags = + ${flags.esp32_flags} +; -- TFT_eSPI build options ------------------------ + -D USER_SETUP_LOADED=1 + -D ILI9488_DRIVER=1 + -D TFT_ROTATION=0 ; 0=0, 1=90, 2=180 or 3=270 degree + -D TFT_WIDTH=320 + -D TFT_HEIGHT=480 + -D TFT_MISO=19 ;// (leave TFT SDO disconnected if other SPI devices share MISO) + -D TFT_MOSI=23 + -D TFT_SCLK=18 + -D TFT_CS=15 ;// Chip select control pin + -D TFT_DC=2 ;// Data Command control pin + -D TFT_RST=4 ;// Reset pin (could connect to RST pin) + -D TFT_BCKL=5 ;None, configurable via web UI (e.g. 2 for D4) + -D SUPPORT_TRANSACTIONS + -D TOUCH_CS=22 + -D TOUCH_DRIVER=0 ; XPT2606 Resistive touch panel driver + -D SPI_FREQUENCY=27000000 + -D SPI_TOUCH_FREQUENCY=2500000 + -D SPI_READ_FREQUENCY=16000000 + +; -- Debugging options ----------------------------- +; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + +; -- Library options ------------------------------- +lib_deps = + ${env.lib_deps} + +src_filter = +<*> +<../drivers/stm32f429_disco> diff --git a/user_setups/esp32/esp32-dev_ili9488_parallel.ini b/user_setups/esp32/esp32-dev_ili9488_parallel.ini new file mode 100644 index 00000000..52e79ade --- /dev/null +++ b/user_setups/esp32/esp32-dev_ili9488_parallel.ini @@ -0,0 +1,46 @@ +;***************************************************; +; Generic ESP32 build with ; +; - ESP32dev board ; +; - ili9488 TFT ; +; - GT911 touch controller ; +;***************************************************; + +[env:esp32dev-mrb3511] +platform = espressif32 +board = esp32dev +upload_port = COM1 ; To change the port, use platform_override.ini +monitor_port = COM1 ; To change the port, use platform_override.ini +debug_tool = esp-prog +debug_init_break = tbreak setup + +build_flags = + ${flags.esp32_flags} +; -- TFT_eSPI build options ------------------------ + ${lcd.mrb3511} + -D TFT_BCKL=5 ;None, configurable via web UI (e.g. 2 for D4) + -D TFT_CS=33 ; Chip select control pin + -D TFT_DC=15 ; =RS; Data Command control pin - must use a pin in the range 0-31 + -D TFT_RST=32 ; Reset pin + -D TFT_WR=4 ; Write strobe control pin - must use a pin in the range 0-31 + -D TFT_RD=2 + -D TFT_D0=12 ; Must use pins in the range 0-31 for the data bus + -D TFT_D1=13 ; so a single register write sets/clears all bits + -D TFT_D2=26 + -D TFT_D3=25 + -D TFT_D4=17 + -D TFT_D5=16 + -D TFT_D6=27 + -D TFT_D7=14 + -D TOUCH_SDA=21 + -D TOUCH_SCL=22 + -D TOUCH_IRQ=34 ; use 34-39 as these are input only pins + -D TOUCH_RST=-1 ; not used, connected to 3.3V +; -- Debugging options ----------------------------- +; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + +; -- Library options ------------------------------- +lib_deps = + ${env.lib_deps} + https://github.com/netwizeBE/arduino-goodix.git ; GT911 touch screen driver + +src_filter = +<*> +<../drivers/stm32f429_disco> diff --git a/user_setups/esp32/esp32cam_st7796.ini b/user_setups/esp32/esp32cam_st7796.ini new file mode 100644 index 00000000..cc111771 --- /dev/null +++ b/user_setups/esp32/esp32cam_st7796.ini @@ -0,0 +1,41 @@ +;***************************************************; +; ESP32 build with ; +; - ESP32Cam board ; +; - st7796 TFT ; +; - xpt2606 touch controller ; +;***************************************************; + +[env:esp32cam-st7796] +platform = espressif32 +board = esp32cam +; upload_port = COM18 ; To change the port, use platform_override.ini +; monitor_port = COM18 ; To change the port, use platform_override.ini +; upload_protocol = espota ; Use ArduinoOTA after flashing over serial +; upload_port = x.x.x.x; IP of the ESP +; upload_flags = +; --port=3232 + +debug_tool = esp-prog +debug_init_break = tbreak setup +;board_build.partitions = min_spiffs.csv +board_build.partitions = default.csv +;ESP32 CAM PINS +build_flags = + ${flags.esp32_flags} +; -- TFT_eSPI build options ------------------------ + ${lcd.raspberrypi} + -D USE_HSPI_PORT + ${pins.hspi32} + -D TFT_CS=15 + -D TFT_DC=2 + -D TFT_RST=-1 ; 3.3v + -D TOUCH_CS=0 ; 3 ; RX + -D TFT_BCKL=-1 + +; -- Debugging options ----------------------------- +; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + +; -- Library options ------------------------------- +lib_deps = + ${env.lib_deps} + diff --git a/user_setups/esp32/nodemcu-32s_st7796.ini b/user_setups/esp32/nodemcu-32s_st7796.ini new file mode 100644 index 00000000..9ccd8f96 --- /dev/null +++ b/user_setups/esp32/nodemcu-32s_st7796.ini @@ -0,0 +1,31 @@ +;***************************************************; +; NodeMCU32S with build with ; +; - st7796 TFT ; +; - MHS-4" RPI Display-B ; +; - xpt2606 touch controller ; +;***************************************************; + +[env:nodemcu32s-raspi] +platform = espressif32 +board = nodemcu-32s +upload_port = COM3 ; To change the port, use platform_override.ini +monitor_port = COM3 ; To change the port, use platform_override.ini +debug_tool = esp-prog +debug_init_break = tbreak setup + +build_flags = + ${flags.esp32_flags} +; -- TFT_eSPI build options ------------------------ + ${lcd.raspberrypi} + ${pins.vspi32} + -D TFT_CS=15 + -D TFT_DC=4 + -D TFT_RST=32 + -D TOUCH_CS=22 + +; -- Debugging options ----------------------------- +; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + +; -- Library options ------------------------------- +lib_deps = + ${env.lib_deps} diff --git a/user_setups/esp8266/D1-mini_ili9341.ini b/user_setups/esp8266/D1-mini_ili9341.ini new file mode 100644 index 00000000..bd669242 --- /dev/null +++ b/user_setups/esp8266/D1-mini_ili9341.ini @@ -0,0 +1,28 @@ +;***************************************************; +; D1 Mini ESP8266 with Lolin TFT 2.4" ; +; - D1-mini board ; +; - ili9341 TFT ; +; - xpt2606 touch controller ; +;***************************************************; + +[env:d1mini-lolintft24] +platform = espressif8266@^2.4.0 ;@2.3.2 +board = d1_mini +upload_port = COM7 ; To change the port, use platform_override.ini +monitor_port = COM7 ; To change the port, use platform_override.ini +board_build.f_flash = 40000000L +board_build.flash_mode = dout +board_build.ldscript = eagle.flash.4m2m.ld ; 2Mb Spiffs +board_build.f_cpu = 160000000L ; set frequency to 160MHz +build_flags = + ${flags.esp8266_flags} +; -- TFT_eSPI build options ------------------------ + ${lcd.lolin24} + ;-D TFT_MISO=12 ;D6 Use default HSPI + ;-D TFT_MOSI=13 ;D7 Use default HSPI + ;-D TFT_SCLK=14 ;D5 Use default HSPI + -D TFT_DC=15 ;D8 + -D TFT_CS=16 ;D0 + -D TFT_BCKL=-1 ;None, configurable via web UI (e.g. 2 for D4) + -D TOUCH_CS=0 ;D3 (can also be D1 or D2) + -D TFT_RST=-1 ;RST diff --git a/user_setups/esp8266/esp8266_st7735.ini b/user_setups/esp8266/esp8266_st7735.ini new file mode 100644 index 00000000..077eec02 --- /dev/null +++ b/user_setups/esp8266/esp8266_st7735.ini @@ -0,0 +1,38 @@ +;***************************************************; +; ESP8266 build with ; +; - ESP-12 board ; +; - st7735 TFT ; +;***************************************************; + +[env:esp12e-st7735] +platform = espressif8266@^2.4.0 ;@2.3.2 +board = esp12e +upload_port = COM8 ; To change the port, use platform_override.ini +monitor_port = COM8 ; To change the port, use platform_override.ini +board_build.f_flash = 40000000L +board_build.flash_mode = dout +board_build.ldscript = eagle.flash.4m2m.ld ; 2Mb Spiffs +board_build.f_cpu = 160000000L ; set frequency to 160MHz +build_flags = + ${flags.esp8266_flags} +; -- TFT_eSPI build options ------------------------ + -D USER_SETUP_LOADED=1 + -D ST7735_DRIVER=1 + -D ST7735_BLACKTAB=1 + -D TFT_ROTATION=${lcd.TFT_ROTATION} + -D TFT_WIDTH=128 + -D TFT_HEIGHT=160 + -D TFT_MISO=-1 ;NC + -D TFT_MOSI=13 ;D7 + -D TFT_SCLK=14 ;D5 + -D TFT_CS=15 ;D8 + -D TFT_DC=0 ;D3 + -D TFT_BCKL=-1 ;None, configurable via web UI (e.g. 2 for D4) + -D TOUCH_CS=-1 ;NC + -D TFT_RST=2 ;D4 + -D SPI_FREQUENCY=27000000 + +; -- Library options ------------------------------- +lib_deps = + ${env.lib_deps} + ;Ethernet@<2.0.0 diff --git a/user_setups/stm32f4xx/stm32f407-black_ili9341.ini b/user_setups/stm32f4xx/stm32f407-black_ili9341.ini new file mode 100644 index 00000000..8f96fa44 --- /dev/null +++ b/user_setups/stm32f4xx/stm32f407-black_ili9341.ini @@ -0,0 +1,53 @@ +;***************************************************; +; STM32F4 build with ; +; - DIY_more board ; +; - ili9341 TFT ; +; - xpt2046 touch controller ; +;***************************************************; + +[env:black_f407vg] +platform = ststm32 +board = diymore_f407vgt +board_build.mcu = stm32f407vgt6 +upload_protocol = dfu +monitor_port = COM7 ; To change the port, use platform_override.ini +build_flags = + ${env.build_flags} + ${flags.stm32_flags} + -I include/stm32f4 +; -- TFT_eSPI build options ------------------------ + ${lcd.lolin24} + ;-D TFT_MISO=PB4 ;Default + ;-D TFT_MOSI=PB5 ;Default + ;-D TFT_SCLK=PB3 ;Default + -D TFT_CS=PE13 ;D8 + -D TFT_DC=PE14 ;D3 + -D TFT_BCKL=-1 ;None, configurable via web UI (e.g. 2 for D4) + -D TOUCH_CS=PA6 ;NC + -D TFT_RST=-1 ;D4 + -D HASP_OUTPUT_PIN=PE0 ; User LED D2 on DevEBox board + -D HASP_INPUT_PIN=PD15 ; User Button K1 on DevEBox board + -D STM32_SERIAL1 ; Set this option to use Serial1 as default sersial port, leave out if using Serial2 + ;-D HAL_ETH_MODULE_ENABLED=1 ; enable ethernet support + ;-D LAN8742A_PHY_ADDRESS=0x01U ; set LAN8720 PHY address + -D HASP_USE_TASMOTA_SLAVE=1 + -D HASP_USE_ETHERNET=1 + -D W5500_MOSI=PB15 ;SPI2 MOSI + -D W5500_MISO=PB14 ;SPI2 MISO + -D W5500_SCLK=PB13 ;SPI2 SCLK + -D W5500_CS=PB6 ;SPI2 CS + -D W5500_RST=PD1 ;SPI2 CS + +lib_deps = + ${env.lib_deps} + Ticker@^3.1.5 + ;Ethernet + ; STM32duino LwIP@^2.1.2 + ; STM32duino STM32Ethernet@^1.0.5 + https://github.com/stm32duino/LwIP.git + https://github.com/netwizeBE/Ethernet3.git + https://github.com/khoih-prog/EthernetWebServer_STM32 + +src_filter = +<*> -<.git/> -<.svn/> - - - - - + + +;*************************************************** diff --git a/user_setups/stm32f4xx/stm32f407-devebox_ili9341.ini b/user_setups/stm32f4xx/stm32f407-devebox_ili9341.ini new file mode 100644 index 00000000..43b5d65c --- /dev/null +++ b/user_setups/stm32f4xx/stm32f407-devebox_ili9341.ini @@ -0,0 +1,52 @@ +;***************************************************; +; STM32F4xx build with ; +; - DevEBox board ; +; - ili9341 TFT ; +; - xpt2046 touch controller ; +;***************************************************; + +[env:DevEBox_STM32F4xx] +platform = ststm32 +board = black_f407zg +board_build.mcu = stm32f407vgt6 +; upload_protocol = dfu +upload_protocol = stlink +debug_tool = stlink +monitor_port = COM19 ; To change the port, use platform_override.ini +build_flags = + ${env.build_flags} + ${flags.stm32_flags} + -I include/stm32f4 +; -- TFT_eSPI build options ------------------------ + ${lcd.lolin24} + ;-D TFT_MISO=PB4 ;Default + ;-D TFT_MOSI=PB5 ;Default + ;-D TFT_SCLK=PB3 ;Default + -D TFT_CS=PE13 ;D8 + -D TFT_DC=PE14 ;D3 + -D TFT_BCKL=-1 ;None, configurable via web UI (e.g. 2 for D4) + -D TOUCH_CS=PA6 ;NC + -D TFT_RST=-1 ;D4 + -D STM32 + -D TFT_SPI3 + -D USE_DMA_TO_TFT + -D HASP_USE_TASMOTA_SLAVE=1 + -D HASP_OUTPUT_PIN=PA1 ; User LED D2 on DevEBox board + -D HASP_INPUT_PIN=PA0 ; User Button K1 on DevEBox board + -D STM32_SERIAL1 ; Set this option to use Serial1 as default sersial port, leave out if using Serial2 + -D HASP_USE_ETHERNET=1 + -D USE_BUILTIN_ETHERNET=1 + -D HAL_ETH_MODULE_ENABLED=1 + ; -D LAN8742A_PHY_ADDRESS=0x01U ; moved to include\stm32f4\hal_conf_custom.h + ; -D DP83848_PHY_ADDRESS=0x01U + +lib_deps = + ${env.lib_deps} + Ticker@^3.1.5 + ; STM32duino LwIP@^2.1.2 + ; STM32duino STM32Ethernet@^1.0.5 + https://github.com/stm32duino/LwIP.git + https://github.com/stm32duino/STM32Ethernet.git + https://github.com/khoih-prog/EthernetWebServer_STM32 + +src_filter = +<*> -<.git/> -<.svn/> - - - - - +