Merge branch 'development' into pre-release

This commit is contained in:
Theo Arends 2020-04-20 18:31:20 +02:00
commit c977069df5
63 changed files with 1942 additions and 1424 deletions

3
.gitignore vendored
View File

@ -17,6 +17,7 @@ tasmota*.bin
tasmota*.bin.gz
tasmota*.map
platformio_override.ini
platformio_tasmota_cenv.ini
## Visual Studio Code specific ######
.vscode
@ -24,4 +25,4 @@ platformio_override.ini
.vscode/c_cpp_properties.json
.vscode/launch.json
*.bak
*.code-workspace
*.code-workspace

View File

@ -71,6 +71,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
- Add commands ``NrfPage``, ``NrfIgnore``, ``NrfScan`` and ``NrfBeacon`` to NRF24 Bluetooth driver (#8075)
- Add commands ``GlobalTemp`` and ``GlobalHum`` to init sensor data (#8152)
- Add command ``SetOption41 <x>`` to force sending gratuitous ARP every <x> seconds
- Add command ``SetOption73 1`` for button decoupling and send multi-press and hold MQTT messages by Federico Leoni (#8235)
- Add command ``SetOption90 1`` to disable non-json MQTT messages (#8044)
- Add command ``SetOption91 1`` to enable fading at startup / power on
- Add command ``Sensor10 0/1/2`` to control BH1750 resolution - 0 = High (default), 1 = High2, 2 = Low (#8016)

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x1F0000,
app1, app, ota_1, 0x200000, 0x1F0000,
spiffs, data, spiffs, 0x3F0000,0x10000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x1F0000
5 app1 app ota_1 0x200000 0x1F0000
6 spiffs data spiffs 0x3F0000 0x10000

View File

@ -1,6 +1,7 @@
# TasmotaSerial
Implementation of software serial with hardware serial fallback library for the ESP8266
Implementation of dual UART hardware serial for the ESP32
Allows for several instances to be active at the same time.

View File

@ -1,6 +1,6 @@
#######################################
# Syntax Coloring Map for TasmotaSerial
# (esp8266)
# (esp8266 and esp32)
#######################################
#######################################

View File

@ -1,15 +1,17 @@
{
"name": "TasmotaSerial",
"version": "2.4.1",
"version": "3.0.0",
"keywords": [
"serial", "io", "TasmotaSerial"
],
"description": "Implementation of software serial with hardware serial fallback for ESP8266.",
"description": "Implementation of software serial with hardware serial fallback for ESP8266 and ESP32.",
"repository":
{
"type": "git",
"url": "https://github.com/arendst/Tasmota/lib/TasmotaSerial"
},
"frameworks": "arduino",
"platforms": "espressif8266"
"platforms": [
"espressif8266", "espressif32"
]
}

View File

@ -1,9 +1,9 @@
name=TasmotaSerial
version=2.4.1
version=3.0.0
author=Theo Arends
maintainer=Theo Arends <theo@arends.com>
sentence=Implementation of software serial with hardware serial fallback for ESP8266.
sentence=Implementation of software serial with hardware serial fallback for ESP8266 and ESP32.
paragraph=
category=Signal Input/Output
url=
architectures=esp8266
architectures=esp8266,esp32

View File

@ -1,5 +1,5 @@
/*
TasmotaSerial.cpp - Minimal implementation of software serial for Tasmota
TasmotaSerial.cpp - Implementation of software serial with hardware serial fallback for Tasmota
Copyright (C) 2020 Theo Arends
@ -27,6 +27,8 @@ extern "C" {
#include <TasmotaSerial.h>
#ifdef ESP8266
// for STAGE and pre-2.6, we can have a single wrapper using attachInterruptArg()
void ICACHE_RAM_ATTR callRxRead(void *self) { ((TasmotaSerial*)self)->rxRead(); };
@ -79,6 +81,12 @@ static void (*ISRList[16])() = {
tms_isr_15
};
#else // ESP32
static int tasmota_serial_index = 2; // Allow UART2 and UART1 only
#endif // ESP8266
TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback, int nwmode, int buffer_size)
{
m_valid = false;
@ -87,12 +95,13 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
m_stop_bits = 1;
m_nwmode = nwmode;
serial_buffer_size = buffer_size;
if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
return;
}
m_rx_pin = receive_pin;
m_tx_pin = transmit_pin;
m_in_pos = m_out_pos = 0;
#ifdef ESP8266
if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
return;
}
if (hardware_fallback && (((3 == m_rx_pin) && (1 == m_tx_pin)) || ((3 == m_rx_pin) && (-1 == m_tx_pin)) || ((-1 == m_rx_pin) && (1 == m_tx_pin)))) {
m_hardserial = true;
}
@ -120,11 +129,16 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
digitalWrite(m_tx_pin, HIGH);
}
}
#else // ESP32
if (transmit_pin > 33) { return; } // GPIO34 - GPIO39 are Input only
m_hardserial = true;
#endif // ESP8266 - ESP32
m_valid = true;
}
TasmotaSerial::~TasmotaSerial()
{
#ifdef ESP8266
if (!m_hardserial) {
if (m_rx_pin > -1) {
detachInterrupt(m_rx_pin);
@ -134,6 +148,7 @@ TasmotaSerial::~TasmotaSerial()
}
}
}
#endif // ESP8266
}
bool TasmotaSerial::isValidGPIOpin(int pin)
@ -144,17 +159,31 @@ bool TasmotaSerial::isValidGPIOpin(int pin)
bool TasmotaSerial::begin(long speed, int stop_bits) {
m_stop_bits = ((stop_bits -1) &1) +1;
if (m_hardserial) {
#ifdef ESP8266
Serial.flush();
if (2 == m_stop_bits) {
Serial.begin(speed, SERIAL_8N2);
} else {
Serial.begin(speed, SERIAL_8N1);
}
#ifdef ESP8266
if (m_hardswap) {
Serial.swap();
}
#endif // ESP8266
#else // ESP32
if (tasmota_serial_index > 0) { // We only support UART1 and UART2 and keep UART0 for debugging
m_uart = tasmota_serial_index;
tasmota_serial_index--;
TSerial = new HardwareSerial(m_uart);
if (2 == m_stop_bits) {
TSerial->begin(speed, SERIAL_8N2, m_rx_pin, m_tx_pin);
} else {
TSerial->begin(speed, SERIAL_8N1, m_rx_pin, m_tx_pin);
}
} else {
m_valid = false;
}
// Serial.printf("TSR: Using UART%d\n", m_uart);
#endif // ESP8266 - ESP32
} else {
// Use getCycleCount() loop to get as exact timing as possible
m_bit_time = ESP.getCpuFreqMHz() * 1000000 / speed;
@ -170,12 +199,20 @@ bool TasmotaSerial::begin() {
}
bool TasmotaSerial::hardwareSerial() {
#ifdef ESP8266
return m_hardserial;
#else
return false; // On ESP32 do not mess with Serial0 buffers
#endif
}
void TasmotaSerial::flush() {
if (m_hardserial) {
#ifdef ESP8266
Serial.flush();
#else
TSerial->flush();
#endif
} else {
m_in_pos = m_out_pos = 0;
}
@ -183,7 +220,11 @@ void TasmotaSerial::flush() {
int TasmotaSerial::peek() {
if (m_hardserial) {
#ifdef ESP8266
return Serial.peek();
#else
return TSerial->peek();
#endif
} else {
if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1;
return m_buffer[m_out_pos];
@ -193,7 +234,11 @@ int TasmotaSerial::peek() {
int TasmotaSerial::read()
{
if (m_hardserial) {
#ifdef ESP8266
return Serial.read();
#else
return TSerial->read();
#endif
} else {
if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1;
uint32_t ch = m_buffer[m_out_pos];
@ -205,7 +250,11 @@ int TasmotaSerial::read()
int TasmotaSerial::available()
{
if (m_hardserial) {
#ifdef ESP8266
return Serial.available();
#else
return TSerial->available();
#endif
} else {
int avail = m_in_pos - m_out_pos;
if (avail < 0) avail += serial_buffer_size;
@ -250,7 +299,11 @@ void TasmotaSerial::_fast_write(uint8_t b) {
size_t TasmotaSerial::write(uint8_t b)
{
if (m_hardserial) {
#ifdef ESP8266
return Serial.write(b);
#else
return TSerial->write(b);
#endif
} else {
if (-1 == m_tx_pin) return 0;
if (m_high_speed) {

View File

@ -1,5 +1,5 @@
/*
TasmotaSerial.h - Minimal implementation of software serial for Tasmota
TasmotaSerial.h - Implementation of software serial with hardware serial fallback for Tasmota
Copyright (C) 2020 Theo Arends
@ -36,6 +36,10 @@
#include <inttypes.h>
#include <Stream.h>
#ifdef ESP32
#include <HardwareSerial.h>
#endif
class TasmotaSerial : public Stream {
public:
TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback = 0, int nwmode = 0, int buffer_size = TM_SERIAL_BUFFER_SIZE);
@ -55,6 +59,10 @@ class TasmotaSerial : public Stream {
uint32_t getLoopReadMetric(void) const { return m_bit_follow_metric; }
#ifdef ESP32
uint32_t getUart(void) const { return m_uart; }
#endif
using Print::write;
private:
@ -83,6 +91,12 @@ class TasmotaSerial : public Stream {
uint8_t *m_buffer;
void _fast_write(uint8_t b); // IRAM minimized version
#ifdef ESP32
HardwareSerial *TSerial;
int m_uart = 0;
#endif
};
#endif // TasmotaSerial_h

View File

@ -20,71 +20,5 @@
#include <rom/rtc.h>
#include <ESP8266WiFi.h>
#include "esp8266toEsp32.h"
// ESP Stuff
struct rst_info resetInfo;
String ESP_getResetReason(void)
{
// CPU 0
return String(rtc_get_reset_reason(0));
}
String ESP_getResetInfo(void)
{
return String(PSTR("0"));
}
uint32_t ESP_getBootVersion(void)
{
return 1;
}
bool ESP_rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t size)
{
return false;
}
bool ESP_rtcUserMemoryRead(uint32_t offset, uint32_t *data, size_t size)
{
return false;
}
void ESP_reset()
{
ESP.restart();
}
uint32_t ESP_getFlashChipId()
{
return 0;
}
uint32_t ESP_getChipId()
{
uint32_t id = 0;
for (uint32_t i = 0; i < 17; i = i +8) {
id |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}
return id;
}
String String_ESP_getChipId()
{
uint64_t mac = ESP.getEfuseMac();
return String(uint32_t(mac >> 32)) + String(uint32_t(mac));
}
uint32_t ESP_getFlashChipRealSize()
{
return ESP.getFlashChipSize();
}
uint32_t ESP_getSketchSize(void)
{
static uint32_t sketchsize = 0;
if (!sketchsize) {
sketchsize = ESP.getSketchSize(); // This takes almost 2 seconds on an ESP32
}
return sketchsize;
}

View File

@ -28,23 +28,6 @@
#include <Esp.h>
//
// ESP32
//
#define ESP_flashReadHeader(offset, data, size) ESP32_flashRead(offset, data, size)
#define ESP_flashRead(offset, data, size) ESP32_flashRead(offset, data, size)
String ESP_getResetReason(void);
uint32_t ESP_getBootVersion(void);
bool ESP_rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t size);
bool ESP_rtcUserMemoryRead(uint32_t offset, uint32_t *data, size_t size);
void ESP_reset();
String ESP_getResetInfo(void);
uint32_t ESP_getFlashChipId();
uint32_t ESP_getChipId();
String String_ESP_getChipId();
uint32_t ESP_getFlashChipRealSize();
uint32_t ESP_getSketchSize();
// Analog
inline void analogWrite(uint8_t pin, int val)
{
@ -67,7 +50,6 @@ typedef double real64_t;
#define ETS_UART_INTR_DISABLE()
#define ETS_UART_INTR_ENABLE()
#define getChipId() getEfuseMac()
#define ESPhttpUpdate httpUpdate
#define getFlashChipRealSize() getFlashChipSize()
@ -92,14 +74,13 @@ typedef int SerialConfig;
#undef LWIP_IPV6
struct rst_info
{
int reason;
};
#define REASON_DEFAULT_RST 1
#define REASON_EXT_SYS_RST 2
#define REASON_DEEP_SLEEP_AWAKE 3
#define REASON_DEFAULT_RST 0 // "Power on" normal startup by power on
#define REASON_WDT_RST 1 // "Hardware Watchdog" hardware watch dog reset
#define REASON_EXCEPTION_RST 2 // "Exception" exception reset, GPIO status wont change
#define REASON_SOFT_WDT_RST 3 // "Software Watchdog" software watch dog reset, GPIO status wont change
#define REASON_SOFT_RESTART 4 // "Software/System restart" software restart ,system_restart , GPIO status wont change
#define REASON_DEEP_SLEEP_AWAKE 5 // "Deep-Sleep Wake" wake up from deep-sleep
#define REASON_EXT_SYS_RST 6 // "External System" external system reset
// memmove ...
#define memcpy_P memcpy

View File

@ -28,6 +28,7 @@ def bin_map_copy(source, target, env):
shutil.copy(str(target[0]), bin_file)
# copy firmware.map to map/<variant>.map
shutil.copy("firmware.map", map_file)
if os.path.isfile("firmware.map"):
shutil.move("firmware.map", map_file)
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_map_copy])

View File

@ -87,17 +87,21 @@ extra_scripts = pio/strip-floats.py
pio/name-firmware.py
pio/gzip-firmware.py
[esp82xx_defaults]
build_flags = -D NDEBUG
-mtarget-align
-Wl,-Map,firmware.map
-DFP_IN_IROM
; new mechanism to set the IRremoteESP8266 supported protocols: none except HASH, NEC, RC5, RC6
-D_IR_ENABLE_DEFAULT_=false
[esp_defaults]
build_flags = -D_IR_ENABLE_DEFAULT_=false
-DDECODE_HASH=true -DDECODE_NEC=true -DSEND_NEC=true
-DDECODE_RC5=true -DSEND_RC5=true -DDECODE_RC6=true -DSEND_RC6=true
; new mechanism to set the IRremoteESP8266 supported protocols: none except HASH, NEC, RC5, RC6
[irremoteesp8266_full]
[esp82xx_defaults]
build_flags = ${esp_defaults.build_flags}
-Wl,-Map,firmware.map
-D NDEBUG
-mtarget-align
-DFP_IN_IROM
[irremoteesp_full]
build_flags = -DUSE_IR_REMOTE_FULL
-U_IR_ENABLE_DEFAULT_
-DDECODE_PRONTO=false -DSEND_PRONTO=false

View File

@ -12,6 +12,7 @@
[platformio]
extra_configs = platformio_tasmota_env32.ini
platformio_tasmota_cenv.ini
; *** Build/upload environment
default_envs =
@ -54,7 +55,7 @@ build_flags = ${core_active.build_flags}
upload_port = COM5
extra_scripts = ${scripts_defaults.extra_scripts}
pio/obj-dump.py
; pio/obj-dump.py
; *** Upload file to OTA server using SCP
;upload_port = user@host:/path
@ -227,9 +228,10 @@ build_type = debug
[common32]
platform = espressif32@1.12.0
platform_packages =
platform_packages = tool-esptoolpy@1.20800.0
board = wemos_d1_mini32
board_build.ldscript = esp32_out.ld
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
board_build.flash_mode = ${common.board_build.flash_mode}
board_build.f_cpu = ${common.board_build.f_cpu}
build_unflags = ${common.build_unflags}
@ -239,7 +241,7 @@ upload_resetmethod = ${common.upload_resetmethod}
upload_speed = 921600
extra_scripts = ${common.extra_scripts}
build_flags =
build_flags = ${esp_defaults.build_flags}
-D BUFFER_LENGTH=128
-D MQTT_MAX_PACKET_SIZE=1200
-D uint32=uint32_t

View File

@ -32,10 +32,10 @@ build_flags = ${common.build_flags} -DFIRMWARE_SENSORS
build_flags = ${common.build_flags} -DFIRMWARE_DISPLAYS
[env:tasmota-ir]
build_flags = ${common.build_flags} ${irremoteesp8266_full.build_flags} -DFIRMWARE_IR
build_flags = ${common.build_flags} ${irremoteesp_full.build_flags} -DFIRMWARE_IR
[env:tasmota-ircustom]
build_flags = ${common.build_flags} ${irremoteesp8266_full.build_flags}
build_flags = ${common.build_flags} ${irremoteesp_full.build_flags}
[env:tasmota-BG]
build_flags = ${common.build_flags} -DMY_LANGUAGE=bg-BG

View File

@ -4,6 +4,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -22,6 +23,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -40,6 +42,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -58,6 +61,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -76,6 +80,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -94,6 +99,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -112,6 +118,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -122,7 +129,7 @@ extra_scripts = ${common32.extra_scripts}
lib_extra_dirs = ${common32.lib_extra_dirs}
lib_ignore = ${common32.lib_ignore}
build_unflags = ${common32.build_unflags}
build_flags = ${common32.build_flags} ${irremoteesp8266_full.build_flags} -DFIRMWARE_IR
build_flags = ${common32.build_flags} ${irremoteesp_full.build_flags} -DFIRMWARE_IR
[env:tasmota32-ircustom]
framework = ${common.framework}
@ -130,6 +137,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -140,7 +148,7 @@ extra_scripts = ${common32.extra_scripts}
lib_extra_dirs = ${common32.lib_extra_dirs}
lib_ignore = ${common32.lib_ignore}
build_unflags = ${common32.build_unflags}
build_flags = ${common32.build_flags} ${irremoteesp8266_full.build_flags}
build_flags = ${common32.build_flags} ${irremoteesp_full.build_flags}
[env:tasmota32-BG]
framework = ${common.framework}
@ -148,6 +156,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -166,6 +175,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -184,6 +194,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -202,6 +213,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -220,6 +232,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -238,6 +251,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -256,6 +270,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -274,6 +289,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -292,6 +308,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -310,6 +327,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -328,6 +346,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -346,6 +365,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -364,6 +384,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -382,6 +403,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -400,6 +422,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -418,6 +441,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -436,6 +460,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -454,6 +479,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -472,6 +498,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -490,6 +517,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -508,6 +536,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}
@ -526,6 +555,7 @@ platform = ${common32.platform}
platform_packages = ${common32.platform_packages}
board = ${common32.board}
board_build.ldscript = ${common32.board_build.ldscript}
board_build.partitions = ${common32.board_build.partitions}
board_build.flash_mode = ${common32.board_build.flash_mode}
board_build.f_cpu = ${common32.board_build.f_cpu}
monitor_speed = ${common32.monitor_speed}

View File

@ -6,6 +6,12 @@
- Release Fred
### 8.2.0.4 20200417
- Fix Zigbee DimmerUp/DimmerDown malformed
- Add config version tag
- Add command ``SetOption73 1`` for button decoupling and send multi-press and hold MQTT messages by Federico Leoni (#8235)
### 8.2.0.3 20200329
- Change light scheme 2,3,4 cycle time speed from 24,48,72,... seconds to 4,6,12,24,36,48,... seconds (#8034)

View File

@ -19,6 +19,8 @@
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
#ifdef ESP8266
// Use patched Parsing.cpp to fix ALEXA parsing issue in v2.4.2
#include <core_version.h>
#if defined(ARDUINO_ESP8266_RELEASE_2_4_2)
@ -620,4 +622,6 @@ bool ESP8266WebServer::_parseFormUploadAborted(){
return false;
}
#endif // ARDUINO_ESP8266_RELEASE
#endif // ARDUINO_ESP8266_RELEASE
#endif // ESP8266

View File

@ -297,6 +297,7 @@
#define D_CMND_DEVGROUP_NAME "DevGroupName"
#define D_CMND_DEVGROUP_SEND "DevGroupSend"
#define D_CMND_DEVGROUP_SHARE "DevGroupShare"
#define D_CMND_DEVGROUPSTATUS "DevGroupStatus"
#define D_CMND_SERIALSEND "SerialSend"
#define D_CMND_SERIALDELIMITER "SerialDelimiter"
#define D_CMND_BAUDRATE "Baudrate"

View File

@ -567,8 +567,8 @@
#define D_SENSOR_SPI_MOSI "SPI - MOSI"
#define D_SENSOR_SPI_CLK "SPI - CLK"
#define D_SENSOR_BACKLIGHT "Retroilluminazione"
#define D_SENSOR_PMS5003_TX "PMS5003 Tx"
#define D_SENSOR_PMS5003_RX "PMS5003 Rx"
#define D_SENSOR_PMS5003_TX "PMS5003 - TX"
#define D_SENSOR_PMS5003_RX "PMS5003 - RX"
#define D_SENSOR_SDS0X1_RX "SDS0X1 - RX"
#define D_SENSOR_SDS0X1_TX "SDS0X1 - TX"
#define D_SENSOR_HPMA_RX "HPMA - RX"

View File

@ -391,7 +391,7 @@
#define SUNRISE_DAWN_ANGLE DAWN_NORMAL // Select desired Dawn Angle from (DAWN_NORMAL, DAWN_CIVIL, DAWN_NAUTIC, DAWN_ASTRONOMIC)
// -- Ping ----------------------------------------
// #define USE_PING // Enable Ping command (+3k code)
// #define USE_PING // Enable Ping command (+2k code)
// -- Rules or Script ----------------------------
// Select none or only one of the below defines

View File

@ -86,7 +86,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t energy_weekend : 1; // bit 20 (v6.6.0.8) - CMND_TARIFF
uint32_t dds2382_model : 1; // bit 21 (v6.6.0.14) - SetOption71 - Select different Modbus registers for Active Energy (#6531)
uint32_t hardware_energy_total : 1; // bit 22 (v6.6.0.15) - SetOption72 - Enable hardware energy total counter as reference (#6561)
uint32_t mqtt_buttons : 1; // bit 23 (v8.2.0.3) - SetOption73 - Detach buttons from relays and enable MQTT action state for multipress
uint32_t mqtt_buttons : 1; // bit 23 (v8.2.0.3) - SetOption73 - Detach buttons from relays and enable MQTT action state for multipress
uint32_t ds18x20_internal_pullup : 1; // bit 24 (v7.0.0.1) - SetOption74 - Enable internal pullup for single DS18x20 sensor
uint32_t grouptopic_mode : 1; // bit 25 (v7.0.0.1) - SetOption75 - GroupTopic replaces %topic% (0) or fixed topic cmnd/grouptopic (1)
uint32_t bootcount_update : 1; // bit 26 (v7.0.0.4) - SetOption76 - Enable incrementing bootcount when deepsleep is enabled
@ -245,7 +245,7 @@ typedef struct {
} EnergyUsage;
typedef struct PACKED {
typedef struct {
uint8_t fnid = 0;
uint8_t dpid = 0;
} TuyaFnidDpidMap;
@ -253,7 +253,7 @@ typedef struct PACKED {
const uint32_t settings_text_size = 699; // Settings.text_pool[size] = Settings.display_model (2D2) - Settings.text_pool (017)
const uint8_t MAX_TUYA_FUNCTIONS = 16;
struct PACKED SYSCFG {
struct {
uint16_t cfg_holder; // 000 v6 header
uint16_t cfg_size; // 002
unsigned long save_flag; // 004
@ -369,7 +369,13 @@ struct PACKED SYSCFG {
uint8_t module; // 474
uint8_t ws_color[4][3]; // 475
uint8_t ws_width[3]; // 481
myio my_gp; // 484
#ifdef ESP8266
myio my_gp; // 484 - 17 bytes (ESP8266)
#else // ESP32
uint8_t free_esp32_484[17]; // 484
#endif // ESP8266 - ESP32
uint8_t my_adc0; // 495
uint16_t light_pixels; // 496
uint8_t light_color[5]; // 498
@ -397,7 +403,14 @@ struct PACKED SYSCFG {
uint32_t ip_address[4]; // 544
unsigned long energy_kWhtotal; // 554
#ifdef ESP8266
char ex_mqtt_fulltopic[100]; // 558
#else // ESP32
myio my_gp; // 558 - 40 bytes (ESP32)
mytmplt user_template; // 580 - 37 bytes (ESP32)
uint8_t free_esp32_5a5[23]; // 5A5
#endif // ESP8266 - ESP32
SysBitfield2 flag2; // 5BC
unsigned long pulse_counter[MAX_COUNTERS]; // 5C0
@ -423,7 +436,12 @@ struct PACKED SYSCFG {
char user_template_name[15]; // 720 15 bytes - Backward compatibility since v8.2.0.3
mytmplt user_template; // 72F 14 bytes
#ifdef ESP8266
mytmplt user_template; // 72F 14 bytes (ESP8266)
#else // ESP32
uint8_t free_esp32_72f[14]; // 72F
#endif // ESP8266 - ESP32
uint8_t novasds_startingoffset; // 73D
uint8_t web_color[18][3]; // 73E
uint16_t display_width; // 774
@ -506,9 +524,11 @@ struct PACKED SYSCFG {
uint8_t zb_channel; // F32
uint8_t zb_free_byte; // F33
uint16_t pms_wake_interval; // F34
uint8_t config_version; // F36
uint8_t free_f36[130]; // F36
uint8_t free_f37[129]; // F37 - Decrement if adding new Setting variables just above and below
// Only 32 bit boundary variables below
uint16_t pulse_counter_debounce_low; // FB8
uint16_t pulse_counter_debounce_high; // FBA
uint32_t keeloq_master_msb; // FBC
@ -525,13 +545,17 @@ struct PACKED SYSCFG {
uint32_t cfg_crc32; // FFC
} Settings;
struct RTCRBT {
typedef struct {
uint16_t valid; // 280 (RTC memory offset 100 - sizeof(RTCRBT))
uint8_t fast_reboot_count; // 282
uint8_t free_003[1]; // 283
} RtcReboot;
} TRtcReboot;
TRtcReboot RtcReboot;
#ifdef ESP32
RTC_NOINIT_ATTR TRtcReboot RtcDataReboot;
#endif
struct RTCMEM {
typedef struct {
uint16_t valid; // 290 (RTC memory offset 100)
uint8_t oswatch_blocked_loop; // 292
uint8_t ota_loader; // 293
@ -547,7 +571,11 @@ struct RTCMEM {
uint8_t free_022[22]; // 2D6
// 2EC - 2FF free locations
} RtcSettings;
} TRtcSettings;
TRtcSettings RtcSettings;
#ifdef ESP32
RTC_NOINIT_ATTR TRtcSettings RtcDataSettings;
#endif
struct TIME_T {
uint8_t second;

View File

@ -30,7 +30,7 @@ uint32_t GetRtcSettingsCrc(void)
uint32_t crc = 0;
uint8_t *bytes = (uint8_t*)&RtcSettings;
for (uint32_t i = 0; i < sizeof(RTCMEM); i++) {
for (uint32_t i = 0; i < sizeof(RtcSettings); i++) {
crc += bytes[i]*(i+1);
}
return crc;
@ -40,16 +40,24 @@ void RtcSettingsSave(void)
{
if (GetRtcSettingsCrc() != rtc_settings_crc) {
RtcSettings.valid = RTC_MEM_VALID;
ESP_rtcUserMemoryWrite(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM));
#ifdef ESP8266
ESP.rtcUserMemoryWrite(100, (uint32_t*)&RtcSettings, sizeof(RtcSettings));
#else
RtcDataSettings = RtcSettings;
#endif
rtc_settings_crc = GetRtcSettingsCrc();
}
}
void RtcSettingsLoad(void)
{
ESP_rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM)); // 0x290
#ifdef ESP8266
ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RtcSettings)); // 0x290
#else
RtcSettings = RtcDataSettings;
#endif
if (RtcSettings.valid != RTC_MEM_VALID) {
memset(&RtcSettings, 0, sizeof(RTCMEM));
memset(&RtcSettings, 0, sizeof(RtcSettings));
RtcSettings.valid = RTC_MEM_VALID;
RtcSettings.energy_kWhtoday = Settings.energy_kWhtoday;
RtcSettings.energy_kWhtotal = Settings.energy_kWhtotal;
@ -77,7 +85,7 @@ uint32_t GetRtcRebootCrc(void)
uint32_t crc = 0;
uint8_t *bytes = (uint8_t*)&RtcReboot;
for (uint32_t i = 0; i < sizeof(RTCRBT); i++) {
for (uint32_t i = 0; i < sizeof(RtcReboot); i++) {
crc += bytes[i]*(i+1);
}
return crc;
@ -87,7 +95,11 @@ void RtcRebootSave(void)
{
if (GetRtcRebootCrc() != rtc_reboot_crc) {
RtcReboot.valid = RTC_MEM_VALID;
ESP_rtcUserMemoryWrite(100 - sizeof(RTCRBT), (uint32_t*)&RtcReboot, sizeof(RTCRBT));
#ifdef ESP8266
ESP.rtcUserMemoryWrite(100 - sizeof(RtcReboot), (uint32_t*)&RtcReboot, sizeof(RtcReboot));
#else
RtcDataReboot = RtcReboot;
#endif
rtc_reboot_crc = GetRtcRebootCrc();
}
}
@ -100,9 +112,13 @@ void RtcRebootReset(void)
void RtcRebootLoad(void)
{
ESP_rtcUserMemoryRead(100 - sizeof(RTCRBT), (uint32_t*)&RtcReboot, sizeof(RTCRBT)); // 0x280
#ifdef ESP8266
ESP.rtcUserMemoryRead(100 - sizeof(RtcReboot), (uint32_t*)&RtcReboot, sizeof(RtcReboot)); // 0x280
#else
RtcReboot = RtcDataReboot;
#endif
if (RtcReboot.valid != RTC_MEM_VALID) {
memset(&RtcReboot, 0, sizeof(RTCRBT));
memset(&RtcReboot, 0, sizeof(RtcReboot));
RtcReboot.valid = RTC_MEM_VALID;
// RtcReboot.fast_reboot_count = 0; // Explicit by memset
RtcRebootSave();
@ -289,7 +305,7 @@ uint16_t GetCfgCrc16(uint8_t *bytes, uint32_t size)
uint16_t GetSettingsCrc(void)
{
// Fix miscalculation if previous Settings was 3584 and current Settings is 4096 between 0x06060007 and 0x0606000A
uint32_t size = ((Settings.version < 0x06060007) || (Settings.version > 0x0606000A)) ? 3584 : sizeof(SYSCFG);
uint32_t size = ((Settings.version < 0x06060007) || (Settings.version > 0x0606000A)) ? 3584 : sizeof(Settings);
return GetCfgCrc16((uint8_t*)&Settings, size);
}
@ -309,7 +325,7 @@ uint32_t GetCfgCrc32(uint8_t *bytes, uint32_t size)
uint32_t GetSettingsCrc32(void)
{
return GetCfgCrc32((uint8_t*)&Settings, sizeof(SYSCFG) -4); // Skip crc32
return GetCfgCrc32((uint8_t*)&Settings, sizeof(Settings) -4); // Skip crc32
}
void SettingsSaveAll(void)
@ -335,7 +351,11 @@ void UpdateQuickPowerCycle(bool update)
uint32_t pc_register;
uint32_t pc_location = SETTINGS_LOCATION - CFG_ROTATES;
#ifdef ESP8266
ESP.flashRead(pc_location * SPI_FLASH_SEC_SIZE, (uint32*)&pc_register, sizeof(pc_register));
#else
QPCRead(&pc_register, sizeof(pc_register));
#endif
if (update && ((pc_register & 0xFFFFFFF0) == 0xFFA55AB0)) {
uint32_t counter = ((pc_register & 0xF) << 1) & 0xF;
if (0 == counter) { // 4 power cycles in a row
@ -343,16 +363,24 @@ void UpdateQuickPowerCycle(bool update)
EspRestart(); // And restart
} else {
pc_register = 0xFFA55AB0 | counter;
#ifdef ESP8266
ESP.flashWrite(pc_location * SPI_FLASH_SEC_SIZE, (uint32*)&pc_register, sizeof(pc_register));
#else
QPCWrite(&pc_register, sizeof(pc_register));
#endif
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("QPC: Flag %02X"), counter);
}
}
else if (pc_register != 0xFFA55ABF) {
pc_register = 0xFFA55ABF;
#ifdef ESP8266
// Assume flash is default all ones and setting a bit to zero does not need an erase
if (ESP.flashEraseSector(pc_location)) {
ESP.flashWrite(pc_location * SPI_FLASH_SEC_SIZE, (uint32*)&pc_register, sizeof(pc_register));
}
#else
QPCWrite(&pc_register, sizeof(pc_register));
#endif
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("QPC: Reset"));
}
}
@ -485,13 +513,13 @@ void SettingsSave(uint8_t rotate)
} else {
Settings.cfg_timestamp++;
}
Settings.cfg_size = sizeof(SYSCFG);
Settings.cfg_size = sizeof(Settings);
Settings.cfg_crc = GetSettingsCrc(); // Keep for backward compatibility in case of fall-back just after upgrade
Settings.cfg_crc32 = GetSettingsCrc32();
#ifdef ESP8266
if (ESP.flashEraseSector(settings_location)) {
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG));
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
}
if (!stop_flash_rotate && rotate) {
@ -500,12 +528,12 @@ void SettingsSave(uint8_t rotate)
delay(1);
}
}
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG D_SAVED_TO_FLASH_AT " %X, " D_COUNT " %d, " D_BYTES " %d"), settings_location, Settings.save_flag, sizeof(Settings));
#else // ESP32
SettingsSaveMain(&Settings, sizeof(SYSCFG));
SettingsWrite(&Settings, sizeof(Settings));
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG "Saved, " D_COUNT " %d, " D_BYTES " %d"), Settings.save_flag, sizeof(Settings));
#endif // ESP8266
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG D_SAVED_TO_FLASH_AT " %X, " D_COUNT " %d, " D_BYTES " %d"), settings_location, Settings.save_flag, sizeof(SYSCFG));
settings_crc32 = Settings.cfg_crc32;
}
#endif // FIRMWARE_MINIMAL
@ -514,8 +542,9 @@ void SettingsSave(uint8_t rotate)
void SettingsLoad(void)
{
#ifdef ESP8266
// Load configuration from eeprom or one of 7 slots below if first valid load does not stop_flash_rotate
struct SYSCFGH {
struct {
uint16_t cfg_holder; // 000
uint16_t cfg_size; // 002
unsigned long save_flag; // 004
@ -527,7 +556,7 @@ void SettingsLoad(void)
uint16_t cfg_holder = 0;
for (uint32_t i = 0; i < CFG_ROTATES; i++) {
flash_location--;
ESP_flashRead(flash_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG));
ESP.flashRead(flash_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
bool valid = false;
if (Settings.version > 0x06000000) {
bool almost_valid = (Settings.cfg_crc32 == GetSettingsCrc32());
@ -538,7 +567,7 @@ void SettingsLoad(void)
if (almost_valid && (0 == cfg_holder)) { cfg_holder = Settings.cfg_holder; } // At FB always active cfg_holder
valid = (cfg_holder == Settings.cfg_holder);
} else {
ESP_flashReadHeader((flash_location -1) * SPI_FLASH_SEC_SIZE, (uint32*)&_SettingsH, sizeof(SYSCFGH));
ESP.flashRead((flash_location -1) * SPI_FLASH_SEC_SIZE, (uint32*)&_SettingsH, sizeof(_SettingsH));
valid = (Settings.cfg_holder == _SettingsH.cfg_holder);
}
if (valid) {
@ -550,13 +579,16 @@ void SettingsLoad(void)
}
}
}
delay(1);
}
if (settings_location > 0) {
ESP_flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG));
ESP.flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
AddLog_P2(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG D_LOADED_FROM_FLASH_AT " %X, " D_COUNT " %lu"), settings_location, Settings.save_flag);
}
#else // ESP32
SettingsRead(&Settings, sizeof(Settings));
AddLog_P2(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG "Loaded, " D_COUNT " %lu"), Settings.save_flag);
#endif // ESP8266 - ESP32
#ifndef FIRMWARE_MINIMAL
if (!settings_location || (Settings.cfg_holder != (uint16_t)CFG_HOLDER)) { // Init defaults if cfg_holder differs from user settings in my_user_config.h
@ -667,10 +699,10 @@ void SettingsDefault(void)
void SettingsDefaultSet1(void)
{
memset(&Settings, 0x00, sizeof(SYSCFG));
memset(&Settings, 0x00, sizeof(Settings));
Settings.cfg_holder = (uint16_t)CFG_HOLDER;
Settings.cfg_size = sizeof(SYSCFG);
Settings.cfg_size = sizeof(Settings);
// Settings.save_flag = 0;
Settings.version = VERSION;
// Settings.bootcount = 0;
@ -679,7 +711,7 @@ void SettingsDefaultSet1(void)
void SettingsDefaultSet2(void)
{
memset((char*)&Settings +16, 0x00, sizeof(SYSCFG) -16);
memset((char*)&Settings +16, 0x00, sizeof(Settings) -16);
Settings.flag.stop_flash_rotate = APP_FLASH_CYCLE;
Settings.flag.global_state = APP_ENABLE_LEDLINK;
@ -1048,7 +1080,7 @@ void SettingsDelta(void)
#ifdef ESP8266
if (Settings.version < 0x06000000) {
Settings.cfg_size = sizeof(SYSCFG);
Settings.cfg_size = sizeof(Settings);
Settings.cfg_crc = GetSettingsCrc();
}
if (Settings.version < 0x06000002) {
@ -1132,7 +1164,7 @@ void SettingsDelta(void)
Settings.param[P_OVER_TEMP] = ENERGY_OVERTEMP;
}
if (Settings.version < 0x06060007) {
memset((char*)&Settings +0xE00, 0x00, sizeof(SYSCFG) -0xE00);
memset((char*)&Settings +0xE00, 0x00, sizeof(Settings) -0xE00);
}
if (Settings.version < 0x06060008) {
// Move current tuya dimmer range to the new param.
@ -1337,6 +1369,15 @@ void SettingsDelta(void)
}
#endif // ESP8266
if (Settings.version < 0x08020004) {
#ifdef ESP8266
Settings.config_version = 0; // ESP8266 (Has been 0 for long time)
#endif // ESP8266
#ifdef ESP32
Settings.config_version = 1; // ESP32
#endif // ESP32
}
Settings.version = VERSION;
SettingsSave(1);
}

View File

@ -99,7 +99,7 @@ uint32_t ResetReason(void)
REASON_DEEP_SLEEP_AWAKE = 5, // "Deep-Sleep Wake" wake up from deep-sleep
REASON_EXT_SYS_RST = 6 // "External System" external system reset
*/
return resetInfo.reason;
return ESP_ResetInfoReason();
}
String GetResetReason(void)
@ -1127,7 +1127,11 @@ void ModuleGpios(myio *gp)
if (USER_MODULE == Settings.module) {
memcpy(&src, &Settings.user_template.gp, sizeof(mycfgio));
} else {
#ifdef ESP8266
memcpy_P(&src, &kModules[Settings.module].gp, sizeof(mycfgio));
#else // ESP32
memcpy_P(&src, &kModules.gp, sizeof(mycfgio));
#endif // ESP8266 - ESP32
}
// 11 85 00 85 85 00 00 00 15 38 85 00 00 81
@ -1135,13 +1139,8 @@ void ModuleGpios(myio *gp)
uint32_t j = 0;
for (uint32_t i = 0; i < sizeof(mycfgio); i++) {
#ifdef ESP8266
if (6 == i) { j = 9; }
if (8 == i) { j = 12; }
#endif // ESP8266
#ifdef ESP32
if (6 == i) { j = 12; }
#endif // ESP32
dest[j] = src[i];
j++;
}
@ -1154,11 +1153,24 @@ gpio_flag ModuleFlag(void)
{
gpio_flag flag;
#ifdef ESP8266
if (USER_MODULE == Settings.module) {
flag = Settings.user_template.flag;
} else {
memcpy_P(&flag, &kModules[Settings.module].flag, sizeof(gpio_flag));
}
#else // ESP32
if (USER_MODULE == Settings.module) {
/*
gpio_flag gpio_adc0;
memcpy_P(&gpio_adc0, &Settings.user_template.gp + ADC0_PIN - MIN_FLASH_PINS, sizeof(gpio_flag));
flag = Settings.user_template.flag.data + gpio_adc0.data;
*/
memcpy_P(&flag, &Settings.user_template.gp + ADC0_PIN - MIN_FLASH_PINS, sizeof(gpio_flag));
} else {
memcpy_P(&flag, &kModules.gp + ADC0_PIN - MIN_FLASH_PINS, sizeof(gpio_flag));
}
#endif // ESP8266 - ESP32
return flag;
}
@ -1169,7 +1181,11 @@ void ModuleDefault(uint32_t module)
Settings.user_template_base = module;
char name[TOPSZ];
SettingsUpdateText(SET_TEMPLATE_NAME, GetTextIndexed(name, sizeof(name), module, kModuleNames));
#ifdef ESP8266
memcpy_P(&Settings.user_template, &kModules[module], sizeof(mytmplt));
#else // ESP32
memcpy_P(&Settings.user_template, &kModules, sizeof(mytmplt));
#endif // ESP8266 - ESP32
}
void SetModuleType(void)
@ -1179,12 +1195,7 @@ void SetModuleType(void)
bool FlashPin(uint32_t pin)
{
#ifdef ESP8266
return (((pin > 5) && (pin < 9)) || (11 == pin));
#endif // ESP8266
#ifdef ESP32
return ((pin > 5) && (pin < 12));
#endif // ESP32
}
uint8_t ValidPin(uint32_t pin, uint32_t gpio)
@ -1193,14 +1204,12 @@ uint8_t ValidPin(uint32_t pin, uint32_t gpio)
return GPIO_NONE; // Disable flash pins GPIO6, GPIO7, GPIO8 and GPIO11
}
#ifdef ESP8266
// if (!is_8285 && !Settings.flag3.user_esp8285_enable) { // SetOption51 - Enable ESP8285 user GPIO's
if ((WEMOS == Settings.module) && !Settings.flag3.user_esp8285_enable) { // SetOption51 - Enable ESP8285 user GPIO's
if ((pin == 9) || (pin == 10)) {
return GPIO_NONE; // Disable possible flash GPIO9 and GPIO10
}
}
#endif // ESP8266
return gpio;
}

View File

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define BUTTON_V1
//#define BUTTON_V1
#ifdef BUTTON_V1
/*********************************************************************************************\
* Button support

View File

@ -1,7 +1,7 @@
/*
support_button.ino - button support for Tasmota
support_button_v2.ino - button support for Tasmota
Copyright (C) 2020 Theo Arends
Copyright (C) 2020 Federico Leoni and Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -17,18 +17,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//#define BUTTON_V2
#define BUTTON_V2
#ifdef BUTTON_V2
/*********************************************************************************************\
* Button support
\*********************************************************************************************/
#define MAX_BUTTON_COMMANDS_V2 3 // Max number of button commands supported
#define MAX_RELAY_BUTTON1 4 // Max number of relay controlled by button1
#define MAX_RELAY_BUTTON1 5 // Max number of relay controlled by BUTTON1
const char kCommands[] PROGMEM =
D_CMND_WIFICONFIG " 2|" D_CMND_RESTART " 1|" D_CMND_UPGRADE " 1";
//D_CMND_WIFICONFIG " 2|" D_CMND_WIFICONFIG " 2|" D_CMND_WIFICONFIG " 2|" D_CMND_RESTART " 1|" D_CMND_UPGRADE " 1";
const char kMultiPress[] PROGMEM =
"|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|";
@ -103,11 +99,9 @@ uint8_t ButtonSerial(uint8_t serial_in_byte)
* Button handler with single press only or multi-press and hold on all buttons
*
* ButtonDebounce (50) - Debounce time in mSec
* SetOption1 (0) - If set do not execute config commands
* SetOption11 (0) - If set perform single press action on double press and reverse
* SetOption1 (0) - If set do not execute commands WifiConfig and Reset
* SetOption11 (0) - If set perform single press action on double press and reverse (on two relay devices only)
* SetOption13 (0) - If set act on single press only
* SetOption32 (40) - Max button hold time in Seconds
* SetOption40 (0) - Number of 0.1 seconds until hold is discarded if SetOption1 1 and SetOption13 0
* SetOption73 (0) - Decouple button from relay and send just mqtt topic
\*********************************************************************************************/
@ -118,11 +112,7 @@ void ButtonHandler(void)
uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command
uint16_t loops_per_second = 1000 / Settings.button_debounce; // ButtonDebounce (50)
char scmnd[20];
char scommand[CMDSZ];
char stopic[TOPSZ];
// uint8_t maxdev = (devices_present > MAX_KEYS) ? MAX_KEYS : devices_present;
// for (uint32_t button_index = 0; button_index < maxdev; button_index++) {
for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) {
uint8_t button = NOT_PRESSED;
uint8_t button_present = 0;
@ -179,23 +169,28 @@ void ButtonHandler(void)
if (!Button.hold_timer[button_index]) { button_pressed = true; } // Do not allow within 1 second
}
if (button_pressed) {
if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
if (!Settings.flag3.mqtt_buttons) {
if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
}
} else {
MqttButtonTopic(button_index +1, 1, 0); // SetOption73 (0) - Decouple button from relay and send just mqtt topic
}
}
}
#endif // ESP8266
else {
if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) {
if (Settings.flag.button_single && !Settings.flag3.mqtt_buttons) { // SetOption13 (0) - Allow only single button press for immediate action, SetOption73 (0) - Decouple button from relay and send just mqtt topic
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1);
if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
if (Settings.flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action, SetOption73 (0) - Decouple button from relay and send just mqtt topic
if (!Settings.flag3.mqtt_buttons) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1);
if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
}
} else {
MqttButtonTopic(button_index +1, 1, 0); // SetOption73 (0) - Decouple button from relay and send just mqtt topic
}
} else {
Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, Button.press_counter[button_index]);
@ -217,27 +212,28 @@ void ButtonHandler(void)
if (Button.hold_timer[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button hold
Button.press_counter[button_index] = 0;
if (Settings.flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic
snprintf_P(scommand, sizeof(scommand), PSTR("BUTTON%d"), button_index +1);
GetTopic_P(stopic, STAT, mqtt_topic, scommand);
Response_P(S_JSON_COMMAND_SVALUE, "ACTION", GetStateText(3));
MqttPublish(stopic);
MqttButtonTopic(button_index +1, 3, 1);
} else {
SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); // Execute Hold command via MQTT if ButtonTopic is set
}
SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); // Execute Hold command via MQTT if ButtonTopic is set
} else {
if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button held for factor times longer
Button.press_counter[button_index] = 0;
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1"));
ExecuteCommand(scmnd, SRC_BUTTON);
if (!Settings.flag.button_restrict) {
if ((Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10)) { // SetOption32 (40) - Button held for factor times longer
Button.press_counter[button_index] = 0;
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1"));
ExecuteCommand(scmnd, SRC_BUTTON);
}
}
}
}
}
if (!Settings.flag.button_single) { // SetOption13 (0) - Allow multi-press
if (!Settings.flag.button_single) { // SetOption13 (0) - Allow multi-press
if (Button.window_timer[button_index]) {
Button.window_timer[button_index]--;
} else {
if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < MAX_BUTTON_COMMANDS_V2 +6)) {
if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < 7)) {
bool single_press = false;
if (Button.press_counter[button_index] < 3) { // Single or Double press
#ifdef ESP8266
@ -251,10 +247,6 @@ void ButtonHandler(void)
if (Settings.flag.button_swap) { // SetOption11 (0)
Button.press_counter[button_index] = (single_press) ? 1 : 2;
}
// } else {
// if (!Settings.flag3.mqtt_buttons && button_index != 0) {
// Button.press_counter[button_index] = 1;
// }
}
}
}
@ -273,7 +265,7 @@ void ButtonHandler(void)
ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON);
} else {
SendKey(KEY_BUTTON, button_index +1, Button.press_counter[button_index] +9); // 2,3,4 and 5 press send just the key value (11,12,13 and 14) for rules
if (0 == button_index) { // First button can toggle up to 4 relays if present
if (0 == button_index) { // BUTTON1 can toggle up to 5 relays if present. If a relay is not present will send out the key value (2,11,12,13 and 14) for rules
if ((Button.press_counter[button_index] > 1 && pin[GPIO_REL1 + Button.press_counter[button_index]-1] < 99) && Button.press_counter[button_index] <= MAX_RELAY_BUTTON1) {
ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: Relay%d found on GPIO%d"), Button.press_counter[button_index], pin[GPIO_REL1 + Button.press_counter[button_index]-1]);
@ -281,21 +273,16 @@ void ButtonHandler(void)
}
}
}
} else { // 6 - 8 press are used to send commands
GetTextIndexed(scmnd, sizeof(scmnd), Button.press_counter[button_index] -6, kCommands);
} else { // 6 press start wificonfig 2
if (!Settings.flag.button_restrict) {
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2"));
ExecuteCommand(scmnd, SRC_BUTTON);
}
}
if (Settings.flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic
if (Button.press_counter[button_index] >= 1 && Button.press_counter[button_index] <= 5) {
char mqttstate[7];
GetTextIndexed(mqttstate, sizeof(mqttstate), Button.press_counter[button_index], kMultiPress);
SendKey(KEY_BUTTON, button_index +1, Button.press_counter[button_index] +9);
snprintf_P(scommand, sizeof(scommand), PSTR("BUTTON%d"), button_index +1);
GetTopic_P(stopic, STAT, mqtt_topic, scommand);
Response_P(S_JSON_COMMAND_SVALUE, "ACTION", mqttstate);
MqttPublish(stopic);
MqttButtonTopic(button_index +1, Button.press_counter[button_index], 0);
}
}
}
@ -306,12 +293,28 @@ void ButtonHandler(void)
}
}
}
}
}
Button.last_state[button_index] = button;
}
}
void MqttButtonTopic(uint8_t button_id, uint8_t action, uint8_t hold)
{
char scommand[CMDSZ];
char stopic[TOPSZ];
char mqttstate[7];
GetTextIndexed(mqttstate, sizeof(mqttstate), action, kMultiPress);
SendKey(KEY_BUTTON, button_id, (hold) ? 3 : action +9);
snprintf_P(scommand, sizeof(scommand), PSTR("BUTTON%d"), button_id);
GetTopic_P(stopic, STAT, mqtt_topic, scommand);
Response_P(S_JSON_COMMAND_SVALUE, "ACTION", (hold) ? SettingsText(SET_STATE_TXT4) : mqttstate);
MqttPublish(stopic);
}
void ButtonLoop(void)
{
if (Button.present) {

View File

@ -36,7 +36,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix
#ifdef USE_DEVICE_GROUPS_SEND
D_CMND_DEVGROUP_SEND "|"
#endif // USE_DEVICE_GROUPS_SEND
D_CMND_DEVGROUP_SHARE "|"
D_CMND_DEVGROUP_SHARE "|" D_CMND_DEVGROUPSTATUS "|"
#endif // USE_DEVICE_GROUPS
D_CMND_SENSOR "|" D_CMND_DRIVER;
@ -59,7 +59,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = {
#ifdef USE_DEVICE_GROUPS_SEND
&CmndDevGroupSend,
#endif // USE_DEVICE_GROUPS_SEND
&CmndDevGroupShare,
&CmndDevGroupShare, &CmndDevGroupStatus,
#endif // USE_DEVICE_GROUPS
&CmndSensor, &CmndDriver };
@ -413,20 +413,34 @@ void CmndStatus(void)
if ((0 == payload) || (1 == payload)) {
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_JSON_BAUDRATE "\":%d,\"" D_CMND_SERIALCONFIG "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\",\"" D_CMND_OTAURL "\":\"%s\",\""
D_JSON_RESTARTREASON "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\",\"" D_JSON_STARTUPUTC "\":\"%s\",\"" D_CMND_SLEEP "\":%d,\""
D_JSON_CONFIG_HOLDER "\":%d,\"" D_JSON_BOOTCOUNT "\":%d,\"BCResetTime\":\"%s\",\"" D_JSON_SAVECOUNT "\":%d,\"" D_JSON_SAVEADDRESS "\":\"%X\"}}"),
D_JSON_CONFIG_HOLDER "\":%d,\"" D_JSON_BOOTCOUNT "\":%d,\"BCResetTime\":\"%s\",\"" D_JSON_SAVECOUNT "\":%d"
#ifdef ESP8266
",\"" D_JSON_SAVEADDRESS "\":\"%X\""
#endif
"}}"),
Settings.baudrate * 300, GetSerialConfig().c_str(), SettingsText(SET_MQTT_GRP_TOPIC), SettingsText(SET_OTAURL),
GetResetReason().c_str(), GetUptime().c_str(), GetDateAndTime(DT_RESTART).c_str(), Settings.sleep,
Settings.cfg_holder, Settings.bootcount, GetDateAndTime(DT_BOOTCOUNT).c_str(), Settings.save_flag, GetSettingsAddress());
Settings.cfg_holder, Settings.bootcount, GetDateAndTime(DT_BOOTCOUNT).c_str(), Settings.save_flag
#ifdef ESP8266
, GetSettingsAddress()
#endif
);
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "1"));
}
if ((0 == payload) || (2 == payload)) {
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS2_FIRMWARE "\":{\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_BUILDDATETIME "\":\"%s\",\""
D_JSON_BOOTVERSION "\":%d,\"" D_JSON_COREVERSION "\":\"" ARDUINO_CORE_RELEASE "\",\"" D_JSON_SDKVERSION "\":\"%s\","
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS2_FIRMWARE "\":{\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_BUILDDATETIME "\":\"%s\""
#ifdef ESP8266
",\"" D_JSON_BOOTVERSION "\":%d"
#endif
",\"" D_JSON_COREVERSION "\":\"" ARDUINO_CORE_RELEASE "\",\"" D_JSON_SDKVERSION "\":\"%s\","
"\"Hardware\":\"%s\""
"%s}}"),
my_version, my_image, GetBuildDateAndTime().c_str(),
ESP_getBootVersion(), ESP.getSdkVersion(),
my_version, my_image, GetBuildDateAndTime().c_str()
#ifdef ESP8266
, ESP.getBootVersion()
#endif
, ESP.getSdkVersion(),
GetDeviceHardware().c_str(),
GetStatistics().c_str());
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "2"));
@ -445,10 +459,18 @@ void CmndStatus(void)
if ((0 == payload) || (4 == payload)) {
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_JSON_PROGRAMSIZE "\":%d,\"" D_JSON_FREEMEMORY "\":%d,\"" D_JSON_HEAPSIZE "\":%d,\""
D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d,\"" D_JSON_FLASHCHIPID "\":\"%06X\",\"" D_JSON_FLASHMODE "\":%d,\""
D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d"
#ifdef ESP8266
",\"" D_JSON_FLASHCHIPID "\":\"%06X\""
#endif
",\"" D_JSON_FLASHMODE "\":%d,\""
D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"]"),
ESP_getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024,
ESP.getFlashChipSize()/1024, ESP_getFlashChipRealSize()/1024, ESP_getFlashChipId(), ESP.getFlashChipMode(),
ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024
#ifdef ESP8266
, ESP.getFlashChipId()
#endif
, ESP.getFlashChipMode(),
LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5, feature6);
XsnsDriverState();
ResponseAppend_P(PSTR(",\"Sensors\":"));
@ -1114,13 +1136,8 @@ void CmndTemplate(void)
SettingsUpdateText(SET_TEMPLATE_NAME, "Merged");
uint32_t j = 0;
for (uint32_t i = 0; i < sizeof(mycfgio); i++) {
#ifdef ESP8266
if (6 == i) { j = 9; }
if (8 == i) { j = 12; }
#endif // ESP8266
#ifdef ESP32
if (6 == i) { j = 12; }
#endif // ESP32
if (my_module.io[j] > GPIO_NONE) {
Settings.user_template.gp.io[i] = my_module.io[j];
}
@ -1793,6 +1810,11 @@ void CmndDevGroupShare(void)
Settings.device_group_share_out = parm[1];
Response_P(PSTR("{\"" D_CMND_DEVGROUP_SHARE "\":{\"In\":\"%X\",\"Out\":\"%X\"}}"), Settings.device_group_share_in, Settings.device_group_share_out);
}
void CmndDevGroupStatus(void)
{
DeviceGroupStatus((XdrvMailbox.usridx ? XdrvMailbox.index - 1 : 0));
}
#endif // USE_DEVICE_GROUPS
void CmndSensor(void)

View File

@ -34,6 +34,7 @@ struct device_group_member {
IPAddress ip_address;
uint16_t received_sequence;
uint16_t acked_sequence;
uint32_t unicast_count;
};
struct device_group {
@ -48,7 +49,6 @@ struct device_group {
bool local;
char group_name[TOPSZ];
char message[128];
uint8_t group_member_count;
struct device_group_member * device_group_members;
#ifdef USE_DEVICE_GROUPS_SEND
uint8_t values_8bit[DGR_ITEM_LAST_8BIT];
@ -77,7 +77,7 @@ void DeviceGroupsInit(void)
// Initialize the device information for each device group.
device_groups = (struct device_group *)calloc(device_group_count, sizeof(struct device_group));
if (device_groups == nullptr) {
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: error allocating %u-element device group array"), device_group_count);
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Error allocating %u-element device group array"), device_group_count);
device_groups_initialization_failed = true;
return;
}
@ -155,6 +155,9 @@ bool DeviceGroupItemShared(bool incoming, uint8_t item)
case DGR_ITEM_BRI_PRESET_HIGH:
mask = DGR_SHARE_DIMMER_SETTINGS;
break;
case DGR_ITEM_EVENT:
mask = DGR_SHARE_EVENT;
break;
}
return (!mask || ((incoming ? Settings.device_group_share_in : Settings.device_group_share_out) & mask));
}
@ -169,7 +172,7 @@ void SendDeviceGroupPacket(IPAddress ip, char * packet, int len, const char * la
}
delay(10);
}
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: error sending %s packet"), label);
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Error sending %s packet"), label);
}
void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType message_type, ...)
@ -184,7 +187,7 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes
if (processing_remote_device_message && message_type != DGR_MSGTYPE_UPDATE_COMMAND) return;
// Get a pointer to the device information for this device.
device_group * device_group = &device_groups[device_group_index];
struct device_group * device_group = &device_groups[device_group_index];
// If we're still sending initial status requests, ignore this request.
if (device_group->initial_status_requests_remaining) return;
@ -225,24 +228,29 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes
else {
#ifdef USE_DEVICE_GROUPS_SEND
bool escaped;
bool use_command;
char chr;
char oper;
uint32_t old_value;
char * delim_ptr;
char * out_ptr;
#endif // USE_DEVICE_GROUPS_SEND
struct item {
uint8_t item;
uint32_t value;
void * value_ptr;
} item_array[32];
bool shared;
uint8_t item;
uint32_t value;
char * value_ptr;
struct item * item_ptr;
va_list ap;
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Building device group %s packet"), device_group->group_name);
#endif // DEVICE_GROUPS_DEBUG
#ifdef USE_DEVICE_GROUPS_SEND
use_command = (message_type == DGR_MSGTYPE_UPDATE_COMMAND);
#endif // USE_DEVICE_GROUPS_SEND
value = 0;
if (message_type == DGR_MSGTYP_UPDATE_MORE_TO_COME)
value |= DGR_FLAG_MORE_TO_COME;
@ -253,73 +261,96 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes
#endif // DEVICE_GROUPS_DEBUG
message_ptr = BeginDeviceGroupMessage(device_group, value, building_status_message || message_type == DGR_MSGTYP_PARTIAL_UPDATE);
// Build an array of all the items and values in this update.
memset(item_array, 0, sizeof(item_array));
item_ptr = item_array;
#ifdef USE_DEVICE_GROUPS_SEND
use_command = (message_type == DGR_MSGTYPE_UPDATE_COMMAND);
if (use_command) {
value_ptr = XdrvMailbox.data;
while ((item = strtoul(value_ptr, &value_ptr, 0))) {
item_ptr->item = item;
if (*value_ptr == '=') {
value_ptr++;
if (item <= DGR_ITEM_MAX_32BIT) {
oper = 0;
if (*value_ptr == '@') {
oper = value_ptr[1];
value_ptr += 2;
}
value = strtoul(value_ptr, &value_ptr, 0);
if (oper) {
old_value = (item <= DGR_ITEM_MAX_8BIT ? device_group->values_8bit[item] : (item <= DGR_ITEM_MAX_16BIT ? device_group->values_16bit[item - DGR_ITEM_MAX_8BIT - 1] : device_group->values_32bit[item - DGR_ITEM_MAX_16BIT - 1]));
value = (oper == '+' ? old_value + value : (oper == '-' ? old_value - value : (oper == '^' ? old_value ^ (value ? value : 0xffffffff) : old_value)));
}
item_ptr->value = value;
}
else if (item <= DGR_ITEM_MAX_STRING) {
item_ptr->value_ptr = out_ptr = value_ptr;
escaped = false;
while ((chr = *value_ptr++)) {
if (chr == ' ' && !escaped) break;
if (!(escaped = (chr == '\\' && !escaped))) *out_ptr++ = chr;
}
*out_ptr = 0;
}
else {
switch (item) {
case DGR_ITEM_LIGHT_CHANNELS:
item_ptr->value_ptr = out_ptr = value_ptr;
for (int i = 0; i < 5; i++) {
*out_ptr = strtoul(value_ptr, &value_ptr, 0);
if (*value_ptr == ',') value_ptr++;
}
break;
}
}
}
item_ptr++;
}
}
else {
#endif // USE_DEVICE_GROUPS_SEND
va_start(ap, message_type);
while ((item = va_arg(ap, int))) {
item_ptr->item = item;
if (item <= DGR_ITEM_MAX_32BIT)
item_ptr->value = va_arg(ap, int);
else if (item <= DGR_ITEM_MAX_STRING)
item_ptr->value_ptr = va_arg(ap, char *);
else {
switch (item) {
case DGR_ITEM_LIGHT_CHANNELS:
item_ptr->value_ptr = va_arg(ap, uint8_t *);
break;
}
}
item_ptr++;
}
va_end(ap);
#ifdef USE_DEVICE_GROUPS_SEND
}
#endif // USE_DEVICE_GROUPS_SEND
// If we're still building this update or all group members haven't acknowledged the previous
// update yet, update the message to include these new updates. First we need to rebuild the
// previous update message to remove any items and their values that are included in this new
// update.
if (device_group->message_length) {
uint8_t item_array[32];
int item_index = 0;
int kept_item_count = 0;
// Build an array of all the items in this new update.
#ifdef USE_DEVICE_GROUPS_SEND
if (use_command)
value_ptr = XdrvMailbox.data;
else
#endif // USE_DEVICE_GROUPS_SEND
va_start(ap, message_type);
#ifdef USE_DEVICE_GROUPS_SEND
while (use_command ? (item = strtoul(value_ptr, &delim_ptr, 0)) : (item = va_arg(ap, int))) {
#else // USE_DEVICE_GROUPS_SEND
while ((item = va_arg(ap, int))) {
#endif // !USE_DEVICE_GROUPS_SEND
item_array[item_index++] = item;
#ifdef USE_DEVICE_GROUPS_SEND
if (use_command) {
if (!*delim_ptr) break;
if (*delim_ptr == '=') {
delim_ptr = strchr(delim_ptr, ' ');
if (!delim_ptr) break;
}
value_ptr = delim_ptr + 1;
}
else {
#endif // USE_DEVICE_GROUPS_SEND
if (item <= DGR_ITEM_MAX_32BIT)
va_arg(ap, int);
else if (item <= DGR_ITEM_MAX_STRING)
va_arg(ap, char *);
else {
switch (item) {
case DGR_ITEM_LIGHT_CHANNELS:
va_arg(ap, uint8_t *);
break;
}
}
#ifdef USE_DEVICE_GROUPS_SEND
}
#endif // USE_DEVICE_GROUPS_SEND
}
#ifdef USE_DEVICE_GROUPS_SEND
if (!use_command) va_end(ap);
#else // USE_DEVICE_GROUPS_SEND
va_end(ap);
#endif // !USE_DEVICE_GROUPS_SEND
item_array[item_index] = 0;
// Rebuild the previous update message, removing any items whose values are included in this
// new update.
char * previous_message_ptr = message_ptr;
while (item = *previous_message_ptr++) {
// Search for this item in the new update.
for (item_index = 0; item_array[item_index]; item_index++) {
if (item_array[item_index] == item) break;
for (item_ptr = item_array; item_ptr->item; item_ptr++) {
if (item_ptr->item == item) break;
}
// If this item was found in the new update skip over it and it's value.
if (item_array[item_index]) {
if (item_ptr->item) {
if (item <= DGR_ITEM_MAX_32BIT) {
previous_message_ptr++;
if (item > DGR_ITEM_MAX_8BIT) {
@ -330,8 +361,9 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes
}
}
}
else if (item <= DGR_ITEM_MAX_STRING)
previous_message_ptr += *previous_message_ptr++;
else if (item <= DGR_ITEM_MAX_STRING) {
previous_message_ptr += strlen(previous_message_ptr) + 1;
}
else {
switch (item) {
case DGR_ITEM_LIGHT_CHANNELS:
@ -355,7 +387,7 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes
}
}
else if (item <= DGR_ITEM_MAX_STRING) {
*message_ptr++ = value = *previous_message_ptr++;
value = strlen(previous_message_ptr) + 1;
memmove(message_ptr, previous_message_ptr, value);
previous_message_ptr += value;
message_ptr += value;
@ -378,58 +410,20 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes
}
// Itertate through the passed items adding them and their values to the message.
#ifdef USE_DEVICE_GROUPS_SEND
if (use_command)
value_ptr = XdrvMailbox.data;
else
#endif // USE_DEVICE_GROUPS_SEND
va_start(ap, message_type);
#ifdef USE_DEVICE_GROUPS_SEND
while (use_command ? (item = strtoul(value_ptr, &delim_ptr, 0)) : (item = va_arg(ap, int))) {
#else // !USE_DEVICE_GROUPS_SEND
while ((item = va_arg(ap, int))) {
#endif // !USE_DEVICE_GROUPS_SEND
for (item_ptr = item_array; (item = item_ptr->item); item_ptr++) {
// Find out if this item is shared with the group and add the item code to the message if yes.
// If this item is shared with the group add it to the message.
shared = true;
if (!device_group_index) shared = DeviceGroupItemShared(false, item);
if (shared) *message_ptr++ = item;
if (shared) {
*message_ptr++ = item;
#ifdef USE_DEVICE_GROUPS_SEND
// If we're processing a command, get a pointer to the value if one was specified.
if (use_command) value_ptr = (*delim_ptr == '=' ? delim_ptr + 1 : nullptr);
#endif // USE_DEVICE_GROUPS_SEND
// For numeric items, get the specified value.
if (item <= DGR_ITEM_MAX_32BIT) {
#ifdef USE_DEVICE_GROUPS_SEND
// If we're processing a command, get the final value after processing any specified
// operators.
if (use_command) {
value = 0;
if (value_ptr) {
oper = 0;
if (*value_ptr == '@') {
oper = value_ptr[1];
value_ptr += 2;
}
value = strtoul(value_ptr, nullptr, 0);
if (oper) {
old_value = (item <= DGR_ITEM_MAX_8BIT ? device_group->values_8bit[item] : (item <= DGR_ITEM_MAX_16BIT ? device_group->values_16bit[item - DGR_ITEM_MAX_8BIT - 1] : device_group->values_32bit[item - DGR_ITEM_MAX_16BIT - 1]));
value = (oper == '+' ? old_value + value : (oper == '-' ? old_value - value : (oper == '^' ? old_value ^ (value ? value : 0xffffffff) : old_value)));
}
}
}
else
#endif // USE_DEVICE_GROUPS_SEND
value = va_arg(ap, int);
// If the item is shared, add it to the message.
if (shared) {
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">item=%u, value=%u"), item, value);
#endif // DEVICE_GROUPS_DEBUG
// For integer items, add the value to the message.
if (item <= DGR_ITEM_MAX_32BIT) {
value = item_ptr->value;
//#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(">%u=%u"), item, value);
//#endif // DEVICE_GROUPS_DEBUG
*message_ptr++ = value & 0xff;
if (item > DGR_ITEM_MAX_8BIT) {
#ifdef USE_DEVICE_GROUPS_SEND
@ -469,77 +463,36 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes
}
#endif // USE_DEVICE_GROUPS_SEND
}
}
// For string items, add the string to the message prefixed by the length.
else if (item <= DGR_ITEM_MAX_STRING) {
#ifdef USE_DEVICE_GROUPS_SEND
if (!use_command)
#endif // USE_DEVICE_GROUPS_SEND
value_ptr = va_arg(ap, char *);
if (shared) {
value = (value_ptr ? strlen((const char *)value_ptr) : 0);
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">item=%u, value=%s"), item, value_ptr);
#endif // DEVICE_GROUPS_DEBUG
*message_ptr++ = value;
memcpy(message_ptr, value_ptr, value);
message_ptr += value;
// For string items, add the null-terminated string to the message.
else if (item <= DGR_ITEM_MAX_STRING) {
if (item_ptr->value_ptr) {
value = strlen((const char *)item_ptr->value_ptr);
memcpy(message_ptr, item_ptr->value_ptr, value);
message_ptr += value;
}
*message_ptr++ = 0;
//#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(">%u='%s'"), item, item_ptr->value_ptr);
//#endif // DEVICE_GROUPS_DEBUG
}
}
// For special items, handle them individually.
else {
switch (item) {
case DGR_ITEM_LIGHT_CHANNELS:
#ifdef USE_DEVICE_GROUPS_SEND
if (use_command) {
if (shared) {
for (int i = 0; i < 5; i++) {
value = 0;
if (value_ptr) {
value = strtoul(value_ptr, &value_ptr, 0);
value_ptr = (*value_ptr == ',' ? value_ptr + 1 : nullptr);
}
*message_ptr++ = value;
}
// For special items, handle them individually.
else {
switch (item) {
case DGR_ITEM_LIGHT_CHANNELS:
value_ptr = (char *)item_ptr->value_ptr;
for (int i = 0; i < 5; i++) {
*message_ptr++ = (value_ptr ? *value_ptr++ : 0);
}
}
else {
#endif // USE_DEVICE_GROUPS_SEND
value_ptr = va_arg(ap, char *);
if (shared) {
memmove(message_ptr, value_ptr, 5);
message_ptr += 5;
}
#ifdef USE_DEVICE_GROUPS_SEND
}
#endif // USE_DEVICE_GROUPS_SEND
#ifdef DEVICE_GROUPS_DEBUG
if (shared) AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">item=%u, value=%u,%u,%u,%u,%u"), item, *(message_ptr - 5), *(message_ptr - 4), *(message_ptr - 3), *(message_ptr - 2), *(message_ptr - 1));
#endif // DEVICE_GROUPS_DEBUG
break;
//#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(">%u=%u,%u,%u,%u,%u"), item, *(message_ptr - 5), *(message_ptr - 4), *(message_ptr - 3), *(message_ptr - 2), *(message_ptr - 1));
//#endif // DEVICE_GROUPS_DEBUG
break;
}
}
}
#ifdef USE_DEVICE_GROUPS_SEND
// If we're processing a command, advance to the next item. If there are no more, break out of
// the loop.
if (use_command) {
if (!*delim_ptr) break;
if (*delim_ptr == '=') {
delim_ptr = strchr(delim_ptr, ' ');
if (!delim_ptr) break;
}
value_ptr = delim_ptr + 1;
}
#endif // USE_DEVICE_GROUPS_SEND
}
#ifdef USE_DEVICE_GROUPS_SEND
if (!use_command) va_end(ap);
#else // USE_DEVICE_GROUPS_SEND
va_end(ap);
#endif // !USE_DEVICE_GROUPS_SEND
// Add the EOL item code and calculate the message length.
*message_ptr++ = 0;
@ -551,7 +504,7 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes
// Multicast the packet.
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: sending %u-byte device group %s packet via multicast, sequence=%u"), device_group->message_length, device_group->group_name, device_group->message[device_group->message_header_length] | device_group->message[device_group->message_header_length + 1] << 8);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending %u-byte device group %s packet via multicast, sequence=%u"), device_group->message_length, device_group->group_name, device_group->message[device_group->message_header_length] | device_group->message[device_group->message_header_length + 1] << 8);
#endif // DEVICE_GROUPS_DEBUG
SendDeviceGroupPacket(IPAddress(0,0,0,0), device_group->message, device_group->message_length, PSTR("Multicast"));
@ -598,12 +551,10 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length)
if (!device_group_member) {
device_group_member = (struct device_group_member *)calloc(1, sizeof(struct device_group_member));
if (device_group_member == nullptr) {
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: error allocating device group member block"));
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Error allocating device group member block"));
return;
}
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: adding member %s (%p)"), IPAddressToString(remote_ip), device_group_member);
#endif // DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Adding member %s"), IPAddressToString(remote_ip));
device_group_member->ip_address = remote_ip;
*flink = device_group_member;
break;
@ -717,10 +668,11 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length)
case DGR_ITEM_BRI_PRESET_HIGH:
case DGR_ITEM_BRI_POWER_ON:
case DGR_ITEM_POWER:
case DGR_ITEM_EVENT:
case DGR_ITEM_LIGHT_CHANNELS:
break;
default:
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: ********** invalid item=%u received from device group %s member %s"), item, device_group->group_name, IPAddressToString(remote_ip));
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: ********** Invalid item=%u received from device group %s member %s"), item, device_group->group_name, IPAddressToString(remote_ip));
}
#endif // DEVICE_GROUPS_DEBUG
@ -748,27 +700,27 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length)
}
#endif // USE_DEVICE_GROUPS_SEND
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("<item=%u, value=%u"), item, value);
#endif // DEVICE_GROUPS_DEBUG
//#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("<%u=%u"), item, value);
//#endif // DEVICE_GROUPS_DEBUG
XdrvMailbox.payload = value;
}
else if (item <= DGR_ITEM_MAX_STRING) {
value = *message_ptr++;
value = strlen(message_ptr);
if (value >= packet_length - (message_ptr - packet)) goto badmsg; // Malformed message
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("<item=%u, value=%.*s"), item, value, message_ptr);
#endif // DEVICE_GROUPS_DEBUG
//#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("<%u='%s'"), item, message_ptr);
//#endif // DEVICE_GROUPS_DEBUG
XdrvMailbox.data_len = value;
XdrvMailbox.data = message_ptr;
message_ptr += value;
message_ptr += value + 1;
}
else {
switch (item) {
case DGR_ITEM_LIGHT_CHANNELS:
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("<item=%u, value=%u,%u,%u,%u,%u"), item, *message_ptr, *(message_ptr + 1), *(message_ptr + 2), *(message_ptr + 3), *(message_ptr + 4));
#endif // DEVICE_GROUPS_DEBUG
//#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("<%u=%u,%u,%u,%u,%u"), item, *message_ptr, *(message_ptr + 1), *(message_ptr + 2), *(message_ptr + 3), *(message_ptr + 4));
//#endif // DEVICE_GROUPS_DEBUG
XdrvMailbox.data = message_ptr;
message_ptr += 5;
break;
@ -787,6 +739,9 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length)
}
}
}
else if (item == DGR_ITEM_EVENT) {
CmndEvent();
}
XdrvCall(FUNC_DEVICE_GROUP_ITEM);
}
}
@ -802,13 +757,28 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length)
return;
badmsg:
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: malformed message received from %s"), IPAddressToString(remote_ip));
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Malformed message received from %s"), IPAddressToString(remote_ip));
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("packet_length=%u, offset=%u"), packet_length, message_ptr - packet);
#endif // DEVICE_GROUPS_DEBUG
processing_remote_device_message = false;
}
void DeviceGroupStatus(uint8_t device_group_index)
{
if (Settings.flag4.device_groups_enabled && device_group_index < device_group_count) {
char buffer[1024];
int member_count = 0;
struct device_group * device_group = &device_groups[device_group_index];
buffer[0] = buffer[1] = 0;
for (struct device_group_member * device_group_member = device_group->device_group_members; device_group_member; device_group_member = device_group_member->flink) {
snprintf(buffer, sizeof(buffer), PSTR("%s,{\"IPAddress\":\"%s\",\"ResendCount\":%u,\"LastRcvdSeq\":%u,\"LastAckedSeq\":%u}"), buffer, IPAddressToString(device_group_member->ip_address), device_group_member->unicast_count, device_group_member->received_sequence, device_group_member->acked_sequence);
member_count++;
}
Response_P(PSTR("{\"" D_CMND_DEVGROUPSTATUS "\":{\"Index\":%u,\"GroupName\":\"%s\",\"MessageSeq\":%u,\"MemberCount\":%d,\"Members\":[%s]}"), device_group_index, device_group->group_name, outgoing_sequence, member_count, &buffer[1]);
}
}
void DeviceGroupsLoop(void)
{
if (!Settings.flag4.device_groups_enabled) return;
@ -822,16 +792,16 @@ void DeviceGroupsLoop(void)
if (!device_groups_initialized) DeviceGroupsInit();
if (device_groups_initialization_failed) return;
// Load the status request message for all device groups. This message will be multicast 5
// times.
// Load the status request message for all device groups. This message will be multicast 10
// times at 200ms intervals.
next_check_time = now + 3000;
for (uint32_t device_group_index = 0; device_group_index < device_group_count; device_group_index++) {
device_group * device_group = &device_groups[device_group_index];
device_group->message_length = BeginDeviceGroupMessage(device_group, DGR_FLAG_RESET | DGR_FLAG_STATUS_REQUEST) - device_group->message;
device_group->initial_status_requests_remaining = 5;
device_group->initial_status_requests_remaining = 10;
device_group->next_ack_check_time = next_check_time;
}
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: (Re)discovering device groups"));
}
if (device_groups_initialization_failed) return;
@ -856,15 +826,15 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex
if (device_group->initial_status_requests_remaining) {
if (--device_group->initial_status_requests_remaining) {
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: sending initial status request for group %s"), device_group->group_name);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending initial status request for group %s"), device_group->group_name);
#endif // DEVICE_GROUPS_DEBUG
SendDeviceGroupPacket(IPAddress(0,0,0,0), device_group->message, device_group->message_length, PSTR("Initial"));
device_group->message[device_group->message_header_length + 2] = DGR_FLAG_STATUS_REQUEST; // The reset flag is on only for the first packet - turn it off now
device_group->next_ack_check_time = now + 200;
}
// If we've sent the initial status request message 5 times, send our status to all
// the members.
// If we've sent the initial status request message the set number of times, send our
// status to all the members.
else {
device_group->next_ack_check_time = 0;
_SendDeviceGroupMessage(device_group_index, DGR_MSGTYP_FULL_STATUS);
@ -874,7 +844,7 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex
// If we're done initializing, iterate through the group memebers, ...
else {
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: checking for ack's"));
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Checking for ack's"));
#endif // DEVICE_GROUPS_DEBUG
bool acked = true;
struct device_group_member ** flink = &device_group->device_group_members;
@ -887,9 +857,7 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex
// If we haven't receive an ack from this member in DGR_MEMBER_TIMEOUT ms, assume
// they're offline and remove them from the group.
if (device_group->member_timeout_time < now) {
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: removing member %s (%p)"), IPAddressToString(device_group_member->ip_address), device_group_member);
#endif // DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Removing member %s"), IPAddressToString(device_group_member->ip_address));
*flink = device_group_member->flink;
free(device_group_member);
}
@ -897,9 +865,10 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex
// Otherwise, unicast the last message directly to this member.
else {
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: sending %u-byte device group %s packet via unicast to %s, sequence %u, last message acked=%u"), device_group->message_length, device_group->group_name, IPAddressToString(device_group_member->ip_address), outgoing_sequence, device_group_member->acked_sequence);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending %u-byte device group %s packet via unicast to %s, sequence %u, last message acked=%u"), device_group->message_length, device_group->group_name, IPAddressToString(device_group_member->ip_address), outgoing_sequence, device_group_member->acked_sequence);
#endif // DEVICE_GROUPS_DEBUG
SendDeviceGroupPacket(device_group_member->ip_address, device_group->message, device_group->message_length, PSTR("Unicast"));
device_group_member->unicast_count++;
acked = false;
flink = &device_group_member->flink;
}
@ -940,7 +909,7 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex
#endif // DEVICE_GROUPS_DEBUG
if (device_group->next_announcement_time <= now) {
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: sending device group %s announcement"), device_group->group_name);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending device group %s announcement"), device_group->group_name);
#endif // DEVICE_GROUPS_DEBUG
SendDeviceGroupPacket(IPAddress(0,0,0,0), device_group->message, BeginDeviceGroupMessage(device_group, DGR_FLAG_ANNOUNCEMENT, true) - device_group->message, PSTR("Announcement"));
device_group->next_announcement_time = now + DGR_ANNOUNCEMENT_INTERVAL + random(10000);

View File

@ -17,11 +17,86 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*********************************************************************************************\
* ESP8266 Support
\*********************************************************************************************/
#ifdef ESP8266
extern "C" {
extern struct rst_info resetInfo;
}
uint32_t ESP_ResetInfoReason(void)
{
return resetInfo.reason;
}
String ESP_getResetReason(void)
{
return ESP.getResetReason();
}
uint32_t ESP_getChipId(void)
{
return ESP.getChipId();
}
uint32_t ESP_getSketchSize(void)
{
return ESP.getSketchSize();
}
void ESP_Restart(void)
{
// ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
ESP.reset();
}
#endif
/*********************************************************************************************\
* ESP32 Support
\*********************************************************************************************/
#ifdef ESP32
#include <nvs.h>
#include <rom/rtc.h>
void NvmLoad(const char *sNvsName, const char *sName, void *pSettings, unsigned nSettingsLen)
{
nvs_handle handle;
noInterrupts();
nvs_open(sNvsName, NVS_READONLY, &handle);
size_t size = nSettingsLen;
nvs_get_blob(handle, sName, pSettings, &size);
nvs_close(handle);
interrupts();
}
void NvmSave(const char *sNvsName, const char *sName, const void *pSettings, unsigned nSettingsLen)
{
nvs_handle handle;
noInterrupts();
nvs_open(sNvsName, NVS_READWRITE, &handle);
nvs_set_blob(handle, sName, pSettings, nSettingsLen);
nvs_commit(handle);
nvs_close(handle);
interrupts();
}
void NvmErase(const char *sNvsName)
{
nvs_handle handle;
noInterrupts();
nvs_open(sNvsName, NVS_READWRITE, &handle);
nvs_erase_all(handle);
nvs_commit(handle);
nvs_close(handle);
interrupts();
}
void SettingsErase(uint8_t type)
{
if (1 == type) // SDK parameter area
@ -34,75 +109,29 @@ void SettingsErase(uint8_t type)
{
}
noInterrupts();
nvs_handle handle;
nvs_open("main", NVS_READWRITE, &handle);
nvs_erase_all(handle);
nvs_commit(handle);
nvs_close(handle);
interrupts();
NvmErase("main");
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " t=%d"), type);
}
void SettingsLoad(const char *sNvsName, const char *sName, void *pSettings, unsigned nSettingsLen)
void SettingsRead(void *data, size_t size)
{
noInterrupts();
nvs_handle handle;
size_t size;
nvs_open(sNvsName, NVS_READONLY, &handle);
size = nSettingsLen;
nvs_get_blob(handle, sName, pSettings, &size);
nvs_close(handle);
interrupts();
NvmLoad("main", "Settings", data, size);
}
void SettingsSave(const char *sNvsName, const char *sName, const void *pSettings, unsigned nSettingsLen)
void SettingsWrite(const void *pSettings, unsigned nSettingsLen)
{
nvs_handle handle;
noInterrupts();
nvs_open(sNvsName, NVS_READWRITE, &handle);
nvs_set_blob(handle, sName, pSettings, nSettingsLen);
nvs_commit(handle);
nvs_close(handle);
interrupts();
NvmSave("main", "Settings", pSettings, nSettingsLen);
}
void ESP32_flashRead(uint32_t offset, uint32_t *data, size_t size)
void QPCRead(void *pSettings, unsigned nSettingsLen)
{
SettingsLoad("main", "Settings", data, size);
NvmLoad("qpc", "pcreg", pSettings, nSettingsLen);
}
void ESP32_flashReadHeader(uint32_t offset, uint32_t *data, size_t size)
void QPCWrite(const void *pSettings, unsigned nSettingsLen)
{
SettingsLoad("main", "SettingsH", data, size);
}
void SettingsSaveMain(const void *pSettings, unsigned nSettingsLen)
{
SettingsSave("main", "Settings", pSettings, nSettingsLen);
}
/*
void SettingsLoadMain(void *pSettings, unsigned nSettingsLen)
{
SettingsLoad("main", "Settings", pSettings, nSettingsLen);
}
void SettingsLoadMainH(void *pSettingsH, unsigned nSettingsLenH)
{
SettingsLoad("main", "SettingsH", pSettingsH, nSettingsLenH);
}
*/
void SettingsLoadUpg(void *pSettings, unsigned nSettingsLen)
{
SettingsLoad("upg", "Settings", pSettings, nSettingsLen);
}
void SettingsLoadUpgH(void *pSettings, unsigned nSettingsLen)
{
SettingsLoad("upg", "SettingsH", pSettings, nSettingsLen);
NvmSave("qpc", "pcreg", pSettings, nSettingsLen);
}
//
@ -174,4 +203,82 @@ void CmndBlockedLoop(void)
*/
}
//
// ESP32 specific
//
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
void DisableBrownout(void)
{
// https://github.com/espressif/arduino-esp32/issues/863#issuecomment-347179737
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // Disable brownout detector
}
//
// ESP32 Alternatives
//
String ESP32GetResetReason(uint32_t cpu_no)
{
// tools\sdk\include\esp32\rom\rtc.h
switch (rtc_get_reset_reason( (RESET_REASON) cpu_no)) {
case POWERON_RESET : return F("Vbat power on reset"); // 1
case SW_RESET : return F("Software reset digital core"); // 3
case OWDT_RESET : return F("Legacy watch dog reset digital core"); // 4
case DEEPSLEEP_RESET : return F("Deep Sleep reset digital core"); // 5
case SDIO_RESET : return F("Reset by SLC module, reset digital core"); // 6
case TG0WDT_SYS_RESET : return F("Timer Group0 Watch dog reset digital core"); // 7
case TG1WDT_SYS_RESET : return F("Timer Group1 Watch dog reset digital core"); // 8
case RTCWDT_SYS_RESET : return F("RTC Watch dog Reset digital core"); // 9
case INTRUSION_RESET : return F("Instrusion tested to reset CPU"); // 10
case TGWDT_CPU_RESET : return F("Time Group reset CPU"); // 11
case SW_CPU_RESET : return F("Software reset CPU"); // 12
case RTCWDT_CPU_RESET : return F("RTC Watch dog Reset CPU"); // 13
case EXT_CPU_RESET : return F("or APP CPU, reseted by PRO CPU"); // 14
case RTCWDT_BROWN_OUT_RESET : return F("Reset when the vdd voltage is not stable"); // 15
case RTCWDT_RTC_RESET : return F("RTC Watch dog reset digital core and rtc module"); // 16
default : return F("NO_MEAN"); // 0
}
}
String ESP_getResetReason(void)
{
return ESP32GetResetReason(0); // CPU 0
}
uint32_t ESP_ResetInfoReason(void)
{
RESET_REASON reason = rtc_get_reset_reason(0);
if (POWERON_RESET == reason) { return REASON_DEFAULT_RST; }
if (SW_CPU_RESET == reason) { return REASON_SOFT_RESTART; }
if (DEEPSLEEP_RESET == reason) { return REASON_DEEP_SLEEP_AWAKE; }
if (SW_RESET == reason) { return REASON_EXT_SYS_RST; }
}
uint32_t ESP_getChipId(void)
{
uint32_t id = 0;
for (uint32_t i = 0; i < 17; i = i +8) {
id |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}
return id;
}
uint32_t ESP_getSketchSize(void)
{
static uint32_t sketchsize = 0;
if (!sketchsize) {
sketchsize = ESP.getSketchSize(); // This takes almost 2 seconds on an ESP32
}
return sketchsize;
}
void ESP_Restart(void)
{
ESP.restart();
}
#endif // ESP32

View File

@ -371,13 +371,13 @@ void FLOG::stopRecording(void){
*
* @param size: size of the data entry/record in bytes, i.e. sizeof(myStruct)
* @param sendHeader: should implement at least something like:
* @example WebServer->setContentLength(CONTENT_LENGTH_UNKNOWN); // This is very likely unknown!!
* WebServer->sendHeader(F("Content-Disposition"), F("attachment; filename=myfile.txt"));
* @example Webserver->setContentLength(CONTENT_LENGTH_UNKNOWN); // This is very likely unknown!!
* Webserver->sendHeader(F("Content-Disposition"), F("attachment; filename=myfile.txt"));
* @param sendRecord: will receive the memory address as "uint8_t* addr" and should consume the current entry/record
* @example myStruct_t *entry = (myStruct_t*)addr;
* Then make useful Strings and send it, i.e.: WebServer->sendContent_P(myString);
* Then make useful Strings and send it, i.e.: Webserver->sendContent_P(myString);
* @param sendFooter: finish the download, should implement at least:
* @example WebServer->sendContent("");
* @example Webserver->sendContent("");
*/
void FLOG::startDownload(size_t size, CallbackNoArgs sendHeader, CallbackWithArgs sendRecord, CallbackNoArgs sendFooter){

View File

@ -708,8 +708,7 @@ void EspRestart(void)
ResetPwm();
WifiShutdown(true);
CrashDumpClear(); // Clear the stack dump in RTC
// ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
ESP_reset();
ESP_Restart();
}
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0

View File

@ -315,12 +315,13 @@ enum DevGroupItem { DGR_ITEM_EOL, DGR_ITEM_STATUS,
DGR_ITEM_POWER, DGR_ITEM_DIMMER_RANGE,
// Add new 32-bit items before this line
DGR_ITEM_LAST_32BIT, DGR_ITEM_MAX_32BIT = 191,
DGR_ITEM_EVENT,
// Add new string items before this line
DGR_ITEM_LAST_STRING, DGR_ITEM_MAX_STRING = 223,
DGR_ITEM_LIGHT_CHANNELS };
enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE_LIGHT_FADE = 4, DGR_SHARE_LIGHT_SCHEME = 8,
DGR_SHARE_LIGHT_COLOR = 16, DGR_SHARE_DIMMER_SETTINGS = 32 };
DGR_SHARE_LIGHT_COLOR = 16, DGR_SHARE_DIMMER_SETTINGS = 32, DGR_SHARE_EVENT = 64 };
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER,

View File

@ -190,6 +190,12 @@ char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer
void setup(void)
{
#ifdef ESP32
#ifdef DISABLE_ESP32_BROWNOUT
DisableBrownout(); // Workaround possible weak LDO resulting in brownout detection during Wifi connection
#endif
#endif
global_state.data = 3; // Init global state (wifi_down, mqtt_down) to solve possible network issues
RtcRebootLoad();

View File

@ -2,7 +2,6 @@
#ifdef ESP32
#include <esp8266toEsp32.h>
#define PACKED __attribute((__packed__))
// Modul
#undef MODULE
#define MODULE WEMOS // [Module] Select default model
@ -10,21 +9,6 @@
#ifdef ESP8266
// ESP8266
#define PACKED
#define ESP_rtcUserMemoryWrite(offset, data, size) ESP.rtcUserMemoryWrite(offset, data, size)
#define ESP_rtcUserMemoryRead(offset, data, size) ESP.rtcUserMemoryRead(offset, data, size)
#define ESP_getResetReason() ESP.getResetReason()
#define ESP_reset() ESP.reset()
#define ESP_getBootVersion() ESP.getBootVersion()
#define ESP_getFlashChipId() ESP.getFlashChipId()
#define ESP_getFlashChipRealSize() ESP.getFlashChipRealSize()
#define ESP_getSketchSize() ESP.getSketchSize()
#define ESP_getChipId() ESP.getChipId()
//
// we need different ESP_flashRead for ESP32
//
#define ESP_flashReadHeader(offset, data, size) ESP.flashRead(offset, data, size)
#define ESP_flashRead(offset, data, size) ESP.flashRead(offset, data, size)
//
// UDP
#define PortUdp_write(p,n) PortUdp.write(p, n)

View File

@ -50,7 +50,7 @@
#define USE_DEEPSLEEP // Add support for deepsleep (+1k code)
#undef USE_EXS_DIMMER // Disable support for EX-Store WiFi Dimmer
//#define USE_HOTPLUG // Add support for sensor HotPlug
#undef USE_DEVICE_GROUPS // Disable support for device groups (+5k6 code)
//#undef USE_DEVICE_GROUPS // Disable support for device groups (+5k6 code)
#undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code)
#undef USE_KEELOQ // Disable support for Jarolift rollers by Keeloq algorithm (+4k5 code)
#undef USE_SONOFF_D1 // DIsable support for Sonoff D1 Dimmer (+0k7 code)

View File

@ -713,11 +713,12 @@ const char PINS_WEMOS[] PROGMEM = "D3TXD4RXD2D1flashcFLFLolD6D7D5D8D0A0";
// esp32 has more pins
#define USER_MODULE 255
#define MAX_GPIO_PIN 40 // Number of supported GPIO
#define MIN_FLASH_PINS 6 // Number of flash chip pins unusable for configuration (GPIO6, 7, 8, 9, 10 and 11)
#define ADC0_PIN 36 // Pin number of ADC0
#define MIN_FLASH_PINS 4 // Number of flash chip pins unusable for configuration (GPIO6, 7, 8 and 11)
#define ADC0_PIN 33 // Pin number of ADC0
#define WEMOS_MODULE 0 // Wemos module
const char PINS_WEMOS[] PROGMEM = "00TX02RX04050607080910111213141516171819202122232425262728293031A4A5A6A7A03738A3";
// 0 1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839
const char PINS_WEMOS[] PROGMEM = "IOTXIORXIOIOflashcFLFLolIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOA6A7A0IoIoA3";
#endif // ESP8266

View File

@ -45,106 +45,61 @@
/********************************************************************************************/
// Supported hardware modules
enum SupportedModules {
WEMOS,
ESP32_CAM,
MAXMODULE
};
WEMOS, ESP32_CAM_AITHINKER,
MAXMODULE};
const char kModuleNames[] PROGMEM =
"WeMos D1 ESP32|ESP32 CAM|"
;
"ESP32-DevKit|ESP32 Cam AiThinker";
// Default module settings
const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
WEMOS,
ESP32_CAM
ESP32_CAM_AITHINKER
};
const mytmplt kModules[MAXMODULE] PROGMEM = {
{ // "WeMos D1 ESP32", // Any ESP32 device like WeMos and NodeMCU hardware (ESP32)
GPIO_USER, //0 (I)O GPIO0, ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1, EMAC_TX_CLK
GPIO_USER, //1 IO TXD0 GPIO1, U0TXD, CLK_OUT3, EMAC_RXD2
GPIO_USER, //2 IO GPIO2, ADC2_CH2, TOUCH2, RTC_GPIO12, HSPIWP, HS2_DATA0, SD_DATA0
GPIO_USER, //3 IO RXD0 GPIO3, U0RXD, CLK_OUT2
GPIO_USER, //4 IO GPIO4, ADC2_CH0, TOUCH0, RTC_GPIO10, HSPIHD, HS2_DATA1, SD_DATA1, EMAC_TX_ER
GPIO_USER, //5 IO GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK
// 0, //6
// 0, //7
// 0, //8
// 0, //9
// 0, //10
// 0, //11
GPIO_USER, //12 (I)O GPIO12, ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI, HSPIQ, HS2_DATA2, SD_DATA2, EMAC_TXD3 (If driven High, flash voltage (VDD_SDIO) is 1.8V not default 3.3V. Has internal pull-down, so unconnected = Low = 3.3V. May prevent flashing and/or booting if 3.3V flash is connected and pulled high. See ESP32 datasheet for more details.)
GPIO_USER, //13 IO GPIO13, ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, HS2_DATA3, SD_DATA3, EMAC_RX_ER
GPIO_USER, //14 IO GPIO14, ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, HS2_CLK, SD_CLK, EMAC_TXD2
GPIO_USER, //15 (I)O GPIO15, ADC2_CH3, TOUCH3, MTDO, HSPICS0, RTC_GPIO13, HS2_CMD, SD_CMD, EMAC_RXD3 (If driven Low, silences boot messages from normal boot. Has internal pull-up, so unconnected = High = normal output.)
GPIO_USER, //16 IO GPIO16, HS1_DATA4, U2RXD, EMAC_CLK_OUT
GPIO_USER, //17 IO GPIO17, HS1_DATA5, U2TXD, EMAC_CLK_OUT_180
GPIO_USER, //18 IO GPIO18, VSPICLK, HS1_DATA7
GPIO_USER, //19 IO GPIO19, VSPIQ, U0CTS, EMAC_TXD0
0, //20
0, //21 IO GPIO21, VSPIHD, EMAC_TX_EN
GPIO_USER, //22 IO LED GPIO22, VSPIWP, U0RTS, EMAC_TXD1
GPIO_USER, //23 IO GPIO23, VSPID, HS1_STROBE
0, //24
GPIO_USER, //25 IO GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0
GPIO_USER, //26 IO GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1
GPIO_USER, //27 IO GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17, EMAC_RX_DV
0, //28
0, //29
0, //30
0, //31
GPIO_USER, //32 IO GPIO32, XTAL_32K_P (32.768 kHz crystal oscillator input), ADC1_CH4, TOUCH9, RTC_GPIO9
GPIO_USER, //33 IO GPIO33, XTAL_32K_N (32.768 kHz crystal oscillator output), ADC1_CH5, TOUCH8, RTC_GPIO8
GPIO_USER, //34 I NO PULLUP GPIO34, ADC1_CH6, RTC_GPIO4
GPIO_USER, //35 I NO PULLUP GPIO35, ADC1_CH7, RTC_GPIO5
GPIO_USER, //36 I NO PULLUP GPIO36, SENSOR_VP, ADC_H, ADC1_CH0, RTC_GPIO0
0, //37 NO PULLUP
0, //38 NO PULLUP
GPIO_USER //39 I NO PULLUP GPIO39, SENSOR_VN, ADC1_CH3, ADC_H, RTC_GPIO3
},
{ //"ESP32 CAM",
GPIO_USER, //0 (I)O GPIO0, ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1, EMAC_TX_CLK
GPIO_USER, //1 IO TXD0 GPIO1, U0TXD, CLK_OUT3, EMAC_RXD2
GPIO_USER, //2 IO GPIO2, ADC2_CH2, TOUCH2, RTC_GPIO12, HSPIWP, HS2_DATA0, SD_DATA0
GPIO_USER, //3 IO RXD0 GPIO3, U0RXD, CLK_OUT2
GPIO_USER, //4 IO GPIO4, ADC2_CH0, TOUCH0, RTC_GPIO10, HSPIHD, HS2_DATA1, SD_DATA1, EMAC_TX_ER
GPIO_USER, //5 IO GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK
// 0, //6
// 0, //7
// 0, //8
// 0, //9
// 0, //10
// 0, //11
GPIO_USER, //12 (I)O GPIO12, ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI, HSPIQ, HS2_DATA2, SD_DATA2, EMAC_TXD3 (If driven High, flash voltage (VDD_SDIO) is 1.8V not default 3.3V. Has internal pull-down, so unconnected = Low = 3.3V. May prevent flashing and/or booting if 3.3V flash is connected and pulled high. See ESP32 datasheet for more details.)
GPIO_USER, //13 IO GPIO13, ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, HS2_DATA3, SD_DATA3, EMAC_RX_ER
GPIO_USER, //14 IO GPIO14, ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, HS2_CLK, SD_CLK, EMAC_TXD2
GPIO_USER, //15 (I)O GPIO15, ADC2_CH3, TOUCH3, MTDO, HSPICS0, RTC_GPIO13, HS2_CMD, SD_CMD, EMAC_RXD3 (If driven Low, silences boot messages from normal boot. Has internal pull-up, so unconnected = High = normal output.)
GPIO_USER, //16 IO GPIO16, HS1_DATA4, U2RXD, EMAC_CLK_OUT
GPIO_USER, //17 IO GPIO17, HS1_DATA5, U2TXD, EMAC_CLK_OUT_180
GPIO_USER, //18 IO GPIO18, VSPICLK, HS1_DATA7
GPIO_USER, //19 IO GPIO19, VSPIQ, U0CTS, EMAC_TXD0
0, //20
0, //21 IO GPIO21, VSPIHD, EMAC_TX_EN
GPIO_USER, //22 IO LED GPIO22, VSPIWP, U0RTS, EMAC_TXD1
GPIO_USER, //23 IO GPIO23, VSPID, HS1_STROBE
0, //24
GPIO_USER, //25 IO GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0
GPIO_USER, //26 IO GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1
GPIO_USER, //27 IO GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17, EMAC_RX_DV
0, //28
0, //29
0, //30
0, //31
GPIO_USER, //32 IO GPIO32, XTAL_32K_P (32.768 kHz crystal oscillator input), ADC1_CH4, TOUCH9, RTC_GPIO9
GPIO_USER, //33 IO GPIO33, XTAL_32K_N (32.768 kHz crystal oscillator output), ADC1_CH5, TOUCH8, RTC_GPIO8
GPIO_USER, //34 I NO PULLUP GPIO34, ADC1_CH6, RTC_GPIO4
GPIO_USER, //35 I NO PULLUP GPIO35, ADC1_CH7, RTC_GPIO5
GPIO_USER, //36 I NO PULLUP GPIO36, SENSOR_VP, ADC_H, ADC1_CH0, RTC_GPIO0
0, //37 NO PULLUP
0, //38 NO PULLUP
GPIO_USER //39 I NO PULLUP GPIO39, SENSOR_VN, ADC1_CH3, ADC_H, RTC_GPIO3
}
const mytmplt kModules PROGMEM =
{ // WEMOS - Espressif ESP32-DevKitC - Any ESP32 device like WeMos and NodeMCU hardware (ESP32)
GPIO_USER, //0 (I)O GPIO0, ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1, EMAC_TX_CLK
GPIO_USER, //1 IO TXD0 GPIO1, U0TXD, CLK_OUT3, EMAC_RXD2
GPIO_USER, //2 IO GPIO2, ADC2_CH2, TOUCH2, RTC_GPIO12, HSPIWP, HS2_DATA0, SD_DATA0
GPIO_USER, //3 IO RXD0 GPIO3, U0RXD, CLK_OUT2
GPIO_USER, //4 IO GPIO4, ADC2_CH0, TOUCH0, RTC_GPIO10, HSPIHD, HS2_DATA1, SD_DATA1, EMAC_TX_ER
GPIO_USER, //5 IO GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK
//6 IO GPIO6, Flash CLK
//7 IO GPIO7, Flash D0
//8 IO GPIO8, Flash D1
GPIO_USER, //9 IO GPIO9, Flash D2, U1RXD
GPIO_USER, //10 IO GPIO10, Flash D3, U1TXD
//11 IO GPIO11, Flash CMD
GPIO_USER, //12 (I)O GPIO12, ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI, HSPIQ, HS2_DATA2, SD_DATA2, EMAC_TXD3 (If driven High, flash voltage (VDD_SDIO) is 1.8V not default 3.3V. Has internal pull-down, so unconnected = Low = 3.3V. May prevent flashing and/or booting if 3.3V flash is connected and pulled high. See ESP32 datasheet for more details.)
GPIO_USER, //13 IO GPIO13, ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, HS2_DATA3, SD_DATA3, EMAC_RX_ER
GPIO_USER, //14 IO GPIO14, ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, HS2_CLK, SD_CLK, EMAC_TXD2
GPIO_USER, //15 (I)O GPIO15, ADC2_CH3, TOUCH3, MTDO, HSPICS0, RTC_GPIO13, HS2_CMD, SD_CMD, EMAC_RXD3 (If driven Low, silences boot messages from normal boot. Has internal pull-up, so unconnected = High = normal output.)
GPIO_USER, //16 IO GPIO16, HS1_DATA4, U2RXD, EMAC_CLK_OUT
GPIO_USER, //17 IO GPIO17, HS1_DATA5, U2TXD, EMAC_CLK_OUT_180
GPIO_USER, //18 IO GPIO18, VSPICLK, HS1_DATA7
GPIO_USER, //19 IO GPIO19, VSPIQ, U0CTS, EMAC_TXD0
0, //20
GPIO_USER, //21 IO GPIO21, VSPIHD, EMAC_TX_EN
GPIO_USER, //22 IO LED GPIO22, VSPIWP, U0RTS, EMAC_TXD1
GPIO_USER, //23 IO GPIO23, VSPID, HS1_STROBE
0, //24
GPIO_USER, //25 IO GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0
GPIO_USER, //26 IO GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1
GPIO_USER, //27 IO GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17, EMAC_RX_DV
0, //28
0, //29
0, //30
0, //31
GPIO_USER, //32 IO GPIO32, XTAL_32K_P (32.768 kHz crystal oscillator input), ADC1_CH4, TOUCH9, RTC_GPIO9
GPIO_USER, //33 IO GPIO33, XTAL_32K_N (32.768 kHz crystal oscillator output), ADC1_CH5, TOUCH8, RTC_GPIO8
GPIO_USER, //34 I NO PULLUP GPIO34, ADC1_CH6, RTC_GPIO4
GPIO_USER, //35 I NO PULLUP GPIO35, ADC1_CH7, RTC_GPIO5
GPIO_USER, //36 I NO PULLUP GPIO36, SENSOR_VP, ADC_H, ADC1_CH0, RTC_GPIO0
0, //37 NO PULLUP
0, //38 NO PULLUP
GPIO_USER, //39 I NO PULLUP GPIO39, SENSOR_VN, ADC1_CH3, ADC_H, RTC_GPIO3
0 // Flag
};
#endif // ESP32

View File

@ -109,7 +109,7 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM =
"}"
"};"
"if (rfsh) {"
"x.open('GET','.?m=1'+a,true);" // ?m related to WebServer->hasArg("m")
"x.open('GET','.?m=1'+a,true);" // ?m related to Webserver->hasArg("m")
"x.send();"
"lt=setTimeout(la,%d);" // Settings.web_refresh
"}"
@ -146,7 +146,7 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM =
"eb('l1').innerHTML=s;"
"}"
"};"
"x.open('GET','.?m=1'+a,true);" // ?m related to WebServer->hasArg("m")
"x.open('GET','.?m=1'+a,true);" // ?m related to Webserver->hasArg("m")
"x.send();"
"lt=setTimeout(la,%d);" // Settings.web_refresh
"}";
@ -205,7 +205,7 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM =
"sn=t.scrollTop;"
"}"
"};"
"x.open('GET','cs?c2='+id+o,true);" // Related to WebServer->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp))
"x.open('GET','cs?c2='+id+o,true);" // Related to Webserver->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp))
"x.send();"
"}"
"lt=setTimeout(l,%d);"
@ -261,21 +261,14 @@ const char HTTP_SCRIPT_TEMPLATE[] PROGMEM =
"as=o.shift();" // Complete ADC0 list
"g=o.shift().split(',');" // Array separator
"j=0;"
// "for(i=0;i<13;i++){" // Supports 13 GPIOs
"for(i=0;i<" STR(MAX_USER_PINS) ";i++){" // Supports 13 GPIOs
#ifdef ESP8266
"if(6==i){j=9;}"
"if(8==i){j=12;}"
#endif
#ifdef ESP32
"if(6==i){j=12;}"
#endif
"sk(g[i],j);" // Set GPIO
"j++;"
"}"
"g=o.shift();" // FLAG
"os=as;"
// "sk(g&15,17);" // Set ADC0
"sk(g&15," STR(ADC0_PIN) ");" // Set ADC0
"g>>=4;"
"for(i=0;i<" STR(GPIO_FLAG_USED) ";i++){"
@ -295,16 +288,15 @@ const char HTTP_SCRIPT_TEMPLATE[] PROGMEM =
"function x2(a){"
"os=a.responseText;"
// "sk(17,99);" // 17 = WEMOS
"sk(" STR(WEMOS_MODULE) ",99);" // 17 = WEMOS
"st(" STR(USER_MODULE) ");"
"}"
#ifdef USE_JAVASCRIPT_ES6
"sl=()=>ld('tp?m=1',x2);" // ?m related to WebServer->hasArg("m")
"sl=()=>ld('tp?m=1',x2);" // ?m related to Webserver->hasArg("m")
#else
"function sl(){"
"ld('tp?m=1',x2);" // ?m related to WebServer->hasArg("m")
"ld('tp?m=1',x2);" // ?m related to Webserver->hasArg("m")
"}"
#endif
@ -321,15 +313,13 @@ const char HTTP_SCRIPT_MODULE2[] PROGMEM =
"}"
"function x3(a){" // ADC0
"os=a.responseText;"
// "sk(%d,17);"
"sk(%d," STR(ADC0_PIN) ");"
"}"
"function sl(){"
"ld('md?m=1',x1);" // ?m related to WebServer->hasArg("m")
"ld('md?g=1',x2);" // ?g related to WebServer->hasArg("g")
// "if(eb('g17')){"
"ld('md?m=1',x1);" // ?m related to Webserver->hasArg("m")
"ld('md?g=1',x2);" // ?g related to Webserver->hasArg("g")
"if(eb('g" STR(ADC0_PIN) "')){"
"ld('md?a=1',x3);" // ?a related to WebServer->hasArg("a")
"ld('md?a=1',x3);" // ?a related to Webserver->hasArg("a")
"}"
"}"
"wl(sl);";
@ -544,7 +534,7 @@ const uint16_t DNS_PORT = 53;
enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER, HTTP_MANAGER_RESET_ONLY};
DNSServer *DnsServer;
ESP8266WebServer *WebServer;
ESP8266WebServer *Webserver;
struct WEB {
String chunk_buffer = ""; // Could be max 2 * CHUNKED_BUFFER_SIZE
@ -561,7 +551,7 @@ struct WEB {
// Helper function to avoid code duplication (saves 4k Flash)
static void WebGetArg(const char* arg, char* out, size_t max)
{
String s = WebServer->arg(arg);
String s = Webserver->arg(arg);
strlcpy(out, s.c_str(), max);
// out[max-1] = '\0'; // Ensure terminating NUL
}
@ -574,7 +564,7 @@ void ShowWebSource(uint32_t source)
{
if ((source > 0) && (source < SRC_MAX)) {
char stemp1[20];
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SRC: %s from %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource), WebServer->client().remoteIP().toString().c_str());
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SRC: %s from %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource), Webserver->client().remoteIP().toString().c_str());
}
}
@ -589,28 +579,28 @@ void StartWebserver(int type, IPAddress ipweb)
{
if (!Settings.web_refresh) { Settings.web_refresh = HTTP_REFRESH_TIME; }
if (!Web.state) {
if (!WebServer) {
WebServer = new ESP8266WebServer((HTTP_MANAGER == type || HTTP_MANAGER_RESET_ONLY == type) ? 80 : WEB_PORT);
WebServer->on("/", HandleRoot);
WebServer->onNotFound(HandleNotFound);
WebServer->on("/up", HandleUpgradeFirmware);
WebServer->on("/u1", HandleUpgradeFirmwareStart); // OTA
WebServer->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop);
WebServer->on("/u2", HTTP_OPTIONS, HandlePreflightRequest);
WebServer->on("/cs", HTTP_GET, HandleConsole);
WebServer->on("/cs", HTTP_OPTIONS, HandlePreflightRequest);
WebServer->on("/cm", HandleHttpCommand);
if (!Webserver) {
Webserver = new ESP8266WebServer((HTTP_MANAGER == type || HTTP_MANAGER_RESET_ONLY == type) ? 80 : WEB_PORT);
Webserver->on("/", HandleRoot);
Webserver->onNotFound(HandleNotFound);
Webserver->on("/up", HandleUpgradeFirmware);
Webserver->on("/u1", HandleUpgradeFirmwareStart); // OTA
Webserver->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop);
Webserver->on("/u2", HTTP_OPTIONS, HandlePreflightRequest);
Webserver->on("/cs", HTTP_GET, HandleConsole);
Webserver->on("/cs", HTTP_OPTIONS, HandlePreflightRequest);
Webserver->on("/cm", HandleHttpCommand);
#ifndef FIRMWARE_MINIMAL
WebServer->on("/cn", HandleConfiguration);
WebServer->on("/md", HandleModuleConfiguration);
WebServer->on("/wi", HandleWifiConfiguration);
WebServer->on("/lg", HandleLoggingConfiguration);
WebServer->on("/tp", HandleTemplateConfiguration);
WebServer->on("/co", HandleOtherConfiguration);
WebServer->on("/dl", HandleBackupConfiguration);
WebServer->on("/rs", HandleRestoreConfiguration);
WebServer->on("/rt", HandleResetConfiguration);
WebServer->on("/in", HandleInformation);
Webserver->on("/cn", HandleConfiguration);
Webserver->on("/md", HandleModuleConfiguration);
Webserver->on("/wi", HandleWifiConfiguration);
Webserver->on("/lg", HandleLoggingConfiguration);
Webserver->on("/tp", HandleTemplateConfiguration);
Webserver->on("/co", HandleOtherConfiguration);
Webserver->on("/dl", HandleBackupConfiguration);
Webserver->on("/rs", HandleRestoreConfiguration);
Webserver->on("/rt", HandleResetConfiguration);
Webserver->on("/in", HandleInformation);
XdrvCall(FUNC_WEB_ADD_HANDLER);
XsnsCall(FUNC_WEB_ADD_HANDLER);
#endif // Not FIRMWARE_MINIMAL
@ -619,9 +609,9 @@ void StartWebserver(int type, IPAddress ipweb)
// Collect User-Agent for Alexa Hue Emulation
// This is used in xdrv_20_hue.ino in function findEchoGeneration()
WebServer->collectHeaders(HEADER_KEYS, sizeof(HEADER_KEYS)/sizeof(char*));
Webserver->collectHeaders(HEADER_KEYS, sizeof(HEADER_KEYS)/sizeof(char*));
WebServer->begin(); // Web server start
Webserver->begin(); // Web server start
}
if (Web.state != type) {
#if LWIP_IPV6
@ -639,7 +629,7 @@ void StartWebserver(int type, IPAddress ipweb)
void StopWebserver(void)
{
if (Web.state) {
WebServer->close();
Webserver->close();
Web.state = HTTP_OFF;
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_STOPPED));
}
@ -684,7 +674,7 @@ void WifiManagerBegin(bool reset_only)
void PollDnsWebserver(void)
{
if (DnsServer) { DnsServer->processNextRequest(); }
if (WebServer) { WebServer->handleClient(); }
if (Webserver) { Webserver->handleClient(); }
}
/*********************************************************************************************/
@ -692,7 +682,7 @@ void PollDnsWebserver(void)
bool WebAuthenticate(void)
{
if (strlen(SettingsText(SET_WEBPWD)) && (HTTP_MANAGER_RESET_ONLY != Web.state)) {
return WebServer->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD));
return Webserver->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD));
} else {
return true;
}
@ -705,7 +695,7 @@ bool HttpCheckPriviledgedAccess(bool autorequestauth = true)
return false;
}
if (autorequestauth && !WebAuthenticate()) {
WebServer->requestAuthentication();
Webserver->requestAuthentication();
return false;
}
return true;
@ -714,15 +704,15 @@ bool HttpCheckPriviledgedAccess(bool autorequestauth = true)
void HttpHeaderCors(void)
{
if (strlen(SettingsText(SET_CORS))) {
WebServer->sendHeader(F("Access-Control-Allow-Origin"), SettingsText(SET_CORS));
Webserver->sendHeader(F("Access-Control-Allow-Origin"), SettingsText(SET_CORS));
}
}
void WSHeaderSend(void)
{
WebServer->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate"));
WebServer->sendHeader(F("Pragma"), F("no-cache"));
WebServer->sendHeader(F("Expires"), F("-1"));
Webserver->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate"));
Webserver->sendHeader(F("Pragma"), F("no-cache"));
Webserver->sendHeader(F("Expires"), F("-1"));
HttpHeaderCors();
}
@ -733,7 +723,7 @@ void WSHeaderSend(void)
void WSSend(int code, int ctype, const String& content)
{
char ct[25]; // strlen("application/octet-stream") +1 = Longest Content type string
WebServer->send(code, GetTextIndexed(ct, sizeof(ct), ctype, kContentTypes), content);
Webserver->send(code, GetTextIndexed(ct, sizeof(ct), ctype, kContentTypes), content);
}
/**********************************************************************************************
@ -742,13 +732,13 @@ void WSSend(int code, int ctype, const String& content)
void WSContentBegin(int code, int ctype)
{
WebServer->client().flush();
Webserver->client().flush();
WSHeaderSend();
#ifdef ARDUINO_ESP8266_RELEASE_2_3_0
WebServer->sendHeader(F("Accept-Ranges"),F("none"));
WebServer->sendHeader(F("Transfer-Encoding"),F("chunked"));
Webserver->sendHeader(F("Accept-Ranges"),F("none"));
Webserver->sendHeader(F("Transfer-Encoding"),F("chunked"));
#endif
WebServer->setContentLength(CONTENT_LENGTH_UNKNOWN);
Webserver->setContentLength(CONTENT_LENGTH_UNKNOWN);
WSSend(code, ctype, ""); // Signal start of chunked content
Web.chunk_buffer = "";
}
@ -761,9 +751,9 @@ void _WSContentSend(const String& content) // Low level sendContent for a
const char * footer = "\r\n";
char chunk_size[11];
sprintf(chunk_size, "%x\r\n", len);
WebServer->sendContent(String() + chunk_size + content + footer);
Webserver->sendContent(String() + chunk_size + content + footer);
#else
WebServer->sendContent(content);
Webserver->sendContent(content);
#endif
#ifdef USE_DEBUG_DRIVER
@ -849,8 +839,8 @@ void WSContentSend_PD(const char* formatP, ...) // Content send snprintf_P ch
void WSContentStart_P(const char* title, bool auth)
{
if (auth && strlen(SettingsText(SET_WEBPWD)) && !WebServer->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD))) {
return WebServer->requestAuthentication();
if (auth && strlen(SettingsText(SET_WEBPWD)) && !Webserver->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD))) {
return Webserver->requestAuthentication();
}
WSContentBegin(200, CT_HTML);
@ -961,7 +951,7 @@ void WSContentEnd(void)
{
WSContentFlush(); // Flush chunk buffer
_WSContentSend(""); // Signal end of chunked content
WebServer->client().stop();
Webserver->client().stop();
}
void WSContentStop(void)
@ -1043,17 +1033,17 @@ void HandleRoot(void)
{
if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the page.
if (WebServer->hasArg("rst")) {
if (Webserver->hasArg("rst")) {
WebRestart(0);
return;
}
if (WifiIsInManagerMode()) {
#ifndef FIRMWARE_MINIMAL
if (strlen(SettingsText(SET_WEBPWD)) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1")) && HTTP_MANAGER_RESET_ONLY != Web.state) {
if (strlen(SettingsText(SET_WEBPWD)) && !(Webserver->hasArg("USER1")) && !(Webserver->hasArg("PASS1")) && HTTP_MANAGER_RESET_ONLY != Web.state) {
HandleWifiLogin();
} else {
if (!strlen(SettingsText(SET_WEBPWD)) || (((WebServer->arg("USER1") == WEB_USERNAME ) && (WebServer->arg("PASS1") == SettingsText(SET_WEBPWD) )) || HTTP_MANAGER_RESET_ONLY == Web.state)) {
if (!strlen(SettingsText(SET_WEBPWD)) || (((Webserver->arg("USER1") == WEB_USERNAME ) && (Webserver->arg("PASS1") == SettingsText(SET_WEBPWD) )) || HTTP_MANAGER_RESET_ONLY == Web.state)) {
HandleWifiConfiguration();
} else {
// wrong user and pass
@ -1243,11 +1233,11 @@ void HandleRoot(void)
bool HandleRootStatusRefresh(void)
{
if (!WebAuthenticate()) {
WebServer->requestAuthentication();
Webserver->requestAuthentication();
return true;
}
if (!WebServer->hasArg("m")) { // Status refresh requested
if (!Webserver->hasArg("m")) { // Status refresh requested
return false;
}
@ -1429,7 +1419,7 @@ void HandleTemplateConfiguration(void)
{
if (!HttpCheckPriviledgedAccess()) { return; }
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
TemplateSaveSettings();
WebRestart(1);
return;
@ -1437,7 +1427,7 @@ void HandleTemplateConfiguration(void)
char stemp[30]; // Template number and Sensor name
if (WebServer->hasArg("m")) {
if (Webserver->hasArg("m")) {
WSContentBegin(200, CT_PLAIN);
for (uint32_t i = 0; i < sizeof(kModuleNiceList); i++) { // "}2'%d'>%s (%d)}3" - "}2'0'>Sonoff Basic (1)}3"
uint32_t midx = pgm_read_byte(kModuleNiceList + i);
@ -1529,13 +1519,8 @@ void TemplateSaveSettings(void)
uint32_t j = 0;
for (uint32_t i = 0; i < sizeof(Settings.user_template.gp); i++) {
#ifdef ESP8266
if (6 == i) { j = 9; }
if (8 == i) { j = 12; }
#endif // ESP8266
#ifdef ESP32
if (6 == i) { j = 12; }
#endif // ESP32
snprintf_P(webindex, sizeof(webindex), PSTR("g%d"), j);
WebGetArg(webindex, tmp, sizeof(tmp)); // GPIO
uint8_t gpio = atoi(tmp);
@ -1543,12 +1528,11 @@ void TemplateSaveSettings(void)
j++;
}
// WebGetArg("g17", tmp, sizeof(tmp)); // FLAG - ADC0
WebGetArg("g" STR(ADC0_PIN), tmp, sizeof(tmp)); // FLAG - ADC0
uint32_t flag = atoi(tmp);
for (uint32_t i = 0; i < GPIO_FLAG_USED; i++) {
snprintf_P(webindex, sizeof(webindex), PSTR("c%d"), i);
uint32_t state = WebServer->hasArg(webindex) << i +4; // FLAG
uint32_t state = Webserver->hasArg(webindex) << i +4; // FLAG
flag += state;
}
WebGetArg("g99", tmp, sizeof(tmp)); // BASE
@ -1564,7 +1548,7 @@ void HandleModuleConfiguration(void)
{
if (!HttpCheckPriviledgedAccess()) { return; }
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
ModuleSaveSettings();
WebRestart(1);
return;
@ -1575,7 +1559,7 @@ void HandleModuleConfiguration(void)
myio cmodule;
ModuleGpios(&cmodule);
if (WebServer->hasArg("m")) {
if (Webserver->hasArg("m")) {
WSContentBegin(200, CT_PLAIN);
uint32_t vidx = 0;
for (uint32_t i = 0; i <= sizeof(kModuleNiceList); i++) { // "}2'%d'>%s (%d)}3" - "}2'255'>UserTemplate (0)}3" - "}2'0'>Sonoff Basic (1)}3"
@ -1592,7 +1576,7 @@ void HandleModuleConfiguration(void)
return;
}
if (WebServer->hasArg("g")) {
if (Webserver->hasArg("g")) {
WSContentBegin(200, CT_PLAIN);
for (uint32_t j = 0; j < sizeof(kGpioNiceList); j++) {
midx = pgm_read_byte(kGpioNiceList + j);
@ -1605,7 +1589,7 @@ void HandleModuleConfiguration(void)
}
#ifndef USE_ADC_VCC
if (WebServer->hasArg("a")) {
if (Webserver->hasArg("a")) {
WSContentBegin(200, CT_PLAIN);
for (uint32_t j = 0; j < ADC0_END; j++) {
WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, j, GetTextIndexed(stemp, sizeof(stemp), j, kAdc0Names), j);
@ -1675,17 +1659,28 @@ void ModuleSaveSettings(void)
if (ValidGPIO(i, cmodule.io[i])) {
snprintf_P(webindex, sizeof(webindex), PSTR("g%d"), i);
WebGetArg(webindex, tmp, sizeof(tmp));
Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]);
uint8_t value = (!strlen(tmp)) ? 0 : atoi(tmp);
#ifdef ESP8266
Settings.my_gp.io[i] = value;
#else // ESP32
if (i == ADC0_PIN) {
Settings.my_adc0 = value;
} else {
Settings.my_gp.io[i] = value;
}
#endif // ESP8266 - ESP32
gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(value);
}
}
}
#ifdef ESP8266
#ifndef USE_ADC_VCC
// WebGetArg("g17", tmp, sizeof(tmp));
WebGetArg("g" STR(ADC0_PIN), tmp, sizeof(tmp));
Settings.my_adc0 = (!strlen(tmp)) ? 0 : atoi(tmp);
gpios += F(", " D_ADC "0 "); gpios += String(Settings.my_adc0);
#endif // USE_ADC_VCC
#endif // ESP8266
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), ModuleName().c_str(), gpios.c_str());
}
@ -1720,7 +1715,7 @@ void HandleWifiConfiguration(void)
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI);
if (WebServer->hasArg("save") && HTTP_MANAGER_RESET_ONLY != Web.state) {
if (Webserver->hasArg("save") && HTTP_MANAGER_RESET_ONLY != Web.state) {
WifiSaveSettings();
WebRestart(2);
return;
@ -1731,7 +1726,7 @@ void HandleWifiConfiguration(void)
WSContentSendStyle();
if (HTTP_MANAGER_RESET_ONLY != Web.state) {
if (WebServer->hasArg("scan")) {
if (Webserver->hasArg("scan")) {
#ifdef USE_EMULATION
UdpDisconnect();
#endif // USE_EMULATION
@ -1844,7 +1839,7 @@ void HandleLoggingConfiguration(void)
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_LOGGING);
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
LoggingSaveSettings();
HandleConfiguration();
return;
@ -1909,7 +1904,7 @@ void HandleOtherConfiguration(void)
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_OTHER);
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
OtherSaveSettings();
WebRestart(1);
return;
@ -1973,7 +1968,7 @@ void OtherSaveSettings(void)
WebGetArg("wp", tmp, sizeof(tmp));
SettingsUpdateText(SET_WEBPWD, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? SettingsText(SET_WEBPWD) : tmp);
Settings.flag.mqtt_enabled = WebServer->hasArg("b1"); // SetOption3 - Enable MQTT
Settings.flag.mqtt_enabled = Webserver->hasArg("b1"); // SetOption3 - Enable MQTT
#ifdef USE_EMULATION
UdpDisconnect();
#if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE)
@ -1994,7 +1989,7 @@ void OtherSaveSettings(void)
/*
// This sometimes provides intermittent watchdog
bool template_activate = WebServer->hasArg("t2"); // Try this to tackle intermittent watchdog after execution of Template command
bool template_activate = Webserver->hasArg("t2"); // Try this to tackle intermittent watchdog after execution of Template command
WebGetArg("t1", tmp, sizeof(tmp));
if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255}
char svalue[128];
@ -2010,7 +2005,7 @@ void OtherSaveSettings(void)
*/
WebGetArg("t1", tmp, sizeof(tmp));
if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255}
snprintf_P(message, sizeof(message), PSTR(D_CMND_BACKLOG " " D_CMND_TEMPLATE " %s%s"), tmp, (WebServer->hasArg("t2")) ? "; " D_CMND_MODULE " 0" : "");
snprintf_P(message, sizeof(message), PSTR(D_CMND_BACKLOG " " D_CMND_TEMPLATE " %s%s"), tmp, (Webserver->hasArg("t2")) ? "; " D_CMND_MODULE " 0" : "");
ExecuteWebCommand(message, SRC_WEBGUI);
}
}
@ -2025,8 +2020,8 @@ void HandleBackupConfiguration(void)
if (!SettingsBufferAlloc()) { return; }
WiFiClient myClient = WebServer->client();
WebServer->setContentLength(sizeof(Settings));
WiFiClient myClient = Webserver->client();
Webserver->setContentLength(sizeof(Settings));
char attachment[TOPSZ];
@ -2036,7 +2031,7 @@ void HandleBackupConfiguration(void)
char hostname[sizeof(my_hostname)];
snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"), NoAlNumToUnderscore(hostname, my_hostname), my_version);
WebServer->sendHeader(F("Content-Disposition"), attachment);
Webserver->sendHeader(F("Content-Disposition"), attachment);
WSSend(200, CT_STREAM, "");
@ -2127,7 +2122,11 @@ void HandleInformation(void)
WSContentSend_P(PSTR("}1" D_BUILD_DATE_AND_TIME "}2%s"), GetBuildDateAndTime().c_str());
WSContentSend_P(PSTR("}1" D_CORE_AND_SDK_VERSION "}2" ARDUINO_CORE_RELEASE "/%s"), ESP.getSdkVersion());
WSContentSend_P(PSTR("}1" D_UPTIME "}2%s"), GetUptime().c_str());
#ifdef ESP8266
WSContentSend_P(PSTR("}1" D_FLASH_WRITE_COUNT "}2%d at 0x%X"), Settings.save_flag, GetSettingsAddress());
#else
WSContentSend_P(PSTR("}1" D_FLASH_WRITE_COUNT "}2%d"), Settings.save_flag);
#endif
WSContentSend_P(PSTR("}1" D_BOOT_COUNT "}2%d"), Settings.bootcount);
WSContentSend_P(PSTR("}1" D_RESTART_REASON "}2%s"), GetResetReason().c_str());
uint32_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present;
@ -2201,8 +2200,10 @@ void HandleInformation(void)
WSContentSend_P(PSTR("}1}2&nbsp;")); // Empty line
WSContentSend_P(PSTR("}1" D_ESP_CHIP_ID "}2%d"), ESP_getChipId());
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP_getFlashChipId());
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP_getFlashChipRealSize() / 1024);
#ifdef ESP8266
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP.getFlashChipId());
#endif
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP.getFlashChipRealSize() / 1024);
WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%dkB"), ESP.getFlashChipSize() / 1024);
WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%dkB"), ESP_getSketchSize() / 1024);
WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%dkB"), ESP.getFreeSketchSpace() / 1024);
@ -2336,7 +2337,7 @@ void HandleUploadLoop(void)
return;
}
HTTPUpload& upload = WebServer->upload();
HTTPUpload& upload = Webserver->upload();
if (UPLOAD_FILE_START == upload.status) {
restart_flag = 60;
@ -2498,6 +2499,16 @@ void HandleUploadLoop(void)
} else {
valid_settings = (settings_buffer[0] == CONFIG_FILE_SIGN);
}
if (valid_settings) {
#ifdef ESP8266
valid_settings = (0 == settings_buffer[0xF36]); // Settings.config_version
#endif // ESP8266
#ifdef ESP32
valid_settings = (1 == settings_buffer[0xF36]); // Settings.config_version
#endif // ESP32
}
if (valid_settings) {
SettingsDefaultSet2();
memcpy((char*)&Settings +16, settings_buffer +16, sizeof(Settings) -16);
@ -2549,8 +2560,8 @@ void HandleUploadLoop(void)
void HandlePreflightRequest(void)
{
HttpHeaderCors();
WebServer->sendHeader(F("Access-Control-Allow-Methods"), F("GET, POST"));
WebServer->sendHeader(F("Access-Control-Allow-Headers"), F("authorization"));
Webserver->sendHeader(F("Access-Control-Allow-Methods"), F("GET, POST"));
Webserver->sendHeader(F("Access-Control-Allow-Headers"), F("authorization"));
WSSend(200, CT_HTML, "");
}
@ -2562,54 +2573,54 @@ void HandleHttpCommand(void)
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_COMMAND));
bool valid = true;
if (strlen(SettingsText(SET_WEBPWD))) {
char tmp1[33];
WebGetArg("user", tmp1, sizeof(tmp1));
char tmp2[strlen(SettingsText(SET_WEBPWD)) +1];
WebGetArg("password", tmp2, sizeof(tmp2));
if (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, SettingsText(SET_WEBPWD)))) { valid = false; }
if (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, SettingsText(SET_WEBPWD)))) {
WSContentBegin(401, CT_JSON);
WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_NEED_USER_AND_PASSWORD "\"}"));
WSContentEnd();
return;
}
}
WSContentBegin(200, CT_JSON);
if (valid) {
uint32_t curridx = web_log_index;
String svalue = WebServer->arg("cmnd");
if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) {
ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCOMMAND);
if (web_log_index != curridx) {
uint32_t counter = curridx;
WSContentSend_P(PSTR("{"));
bool cflg = false;
do {
char* tmp;
size_t len;
GetLog(counter, &tmp, &len);
if (len) {
// [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char* JSON = (char*)memchr(tmp, '{', len);
if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
size_t JSONlen = len - (JSON - tmp);
if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); }
char stemp[JSONlen];
strlcpy(stemp, JSON +1, JSONlen -2);
WSContentSend_P(PSTR("%s%s"), (cflg) ? "," : "", stemp);
cflg = true;
}
uint32_t curridx = web_log_index;
String svalue = Webserver->arg("cmnd");
if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) {
ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCOMMAND);
if (web_log_index != curridx) {
uint32_t counter = curridx;
WSContentSend_P(PSTR("{"));
bool cflg = false;
do {
char* tmp;
size_t len;
GetLog(counter, &tmp, &len);
if (len) {
// [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char* JSON = (char*)memchr(tmp, '{', len);
if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
size_t JSONlen = len - (JSON - tmp);
if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); }
char stemp[JSONlen];
strlcpy(stemp, JSON +1, JSONlen -2);
WSContentSend_P(PSTR("%s%s"), (cflg) ? "," : "", stemp);
cflg = true;
}
counter++;
counter &= 0xFF;
if (!counter) counter++; // Skip 0 as it is not allowed
} while (counter != web_log_index);
WSContentSend_P(PSTR("}"));
} else {
WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}"));
}
}
counter++;
counter &= 0xFF;
if (!counter) counter++; // Skip 0 as it is not allowed
} while (counter != web_log_index);
WSContentSend_P(PSTR("}"));
} else {
WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENTER_COMMAND " cmnd=\"}"));
WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}"));
}
} else {
WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_NEED_USER_AND_PASSWORD "\"}"));
WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENTER_COMMAND " cmnd=\"}"));
}
WSContentEnd();
}
@ -2620,7 +2631,7 @@ void HandleConsole(void)
{
if (!HttpCheckPriviledgedAccess()) { return; }
if (WebServer->hasArg("c2")) { // Console refresh requested
if (Webserver->hasArg("c2")) { // Console refresh requested
HandleConsoleRefresh();
return;
}
@ -2640,7 +2651,7 @@ void HandleConsoleRefresh(void)
bool cflg = true;
uint32_t counter = 0; // Initial start, should never be 0 again
String svalue = WebServer->arg("c1");
String svalue = Webserver->arg("c1");
if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) {
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), svalue.c_str());
ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCONSOLE);
@ -2685,13 +2696,13 @@ void HandleConsoleRefresh(void)
void HandleNotFound(void)
{
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Not found (%s)"), WebServer->uri().c_str());
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Not found (%s)"), Webserver->uri().c_str());
if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the error page.
#ifdef USE_EMULATION
#ifdef USE_EMULATION_HUE
String path = WebServer->uri();
String path = Webserver->uri();
if ((EMUL_HUE == Settings.flag2.emulation) && (path.startsWith("/api"))) {
HandleHueApi(&path);
} else
@ -2699,9 +2710,9 @@ void HandleNotFound(void)
#endif // USE_EMULATION
{
WSContentBegin(404, CT_PLAIN);
WSContentSend_P(PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"), WebServer->uri().c_str(), (WebServer->method() == HTTP_GET) ? "GET" : "POST", WebServer->args());
for (uint32_t i = 0; i < WebServer->args(); i++) {
WSContentSend_P(PSTR(" %s: %s\n"), WebServer->argName(i).c_str(), WebServer->arg(i).c_str());
WSContentSend_P(PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"), Webserver->uri().c_str(), (Webserver->method() == HTTP_GET) ? "GET" : "POST", Webserver->args());
for (uint32_t i = 0; i < Webserver->args(); i++) {
WSContentSend_P(PSTR(" %s: %s\n"), Webserver->argName(i).c_str(), Webserver->arg(i).c_str());
}
WSContentEnd();
}
@ -2711,12 +2722,12 @@ void HandleNotFound(void)
bool CaptivePortal(void)
{
// Possible hostHeader: connectivitycheck.gstatic.com or 192.168.4.1
if ((WifiIsInManagerMode()) && !ValidIpAddress(WebServer->hostHeader().c_str())) {
if ((WifiIsInManagerMode()) && !ValidIpAddress(Webserver->hostHeader().c_str())) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED));
WebServer->sendHeader(F("Location"), String("http://") + WebServer->client().localIP().toString(), true);
Webserver->sendHeader(F("Location"), String("http://") + Webserver->client().localIP().toString(), true);
WSSend(302, CT_PLAIN, ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
WebServer->client().stop(); // Stop is needed because we sent no content length
Webserver->client().stop(); // Stop is needed because we sent no content length
return true;
}
return false;

View File

@ -1028,6 +1028,9 @@ void CmndPowerRetain(void)
}
}
Settings.flag.mqtt_power_retain = XdrvMailbox.payload; // CMND_POWERRETAIN
if (Settings.flag.mqtt_power_retain) {
Settings.flag4.only_json_message = 0; // SetOption90 - Disable non-json MQTT response
}
}
ResponseCmndStateText(Settings.flag.mqtt_power_retain); // CMND_POWERRETAIN
}
@ -1252,7 +1255,7 @@ void HandleMqttConfiguration(void)
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT);
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
MqttSaveSettings();
WebRestart(1);
return;
@ -1334,7 +1337,7 @@ bool Xdrv02(uint8_t function)
WSContentSend_P(HTTP_BTN_MENU_MQTT);
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration);
Webserver->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration);
break;
#endif // USE_WEBSERVER
case FUNC_COMMAND:

View File

@ -1985,6 +1985,17 @@ bool isChannelGammaCorrected(uint32_t channel) {
return true;
}
// is the channel a regular PWM or ColorTemp control
bool isChannelCT(uint32_t channel) {
#ifdef ESP8266
if (PHILIPS == my_module_type) {
if ((LST_COLDWARM == Light.subtype) && (1 == channel)) { return true; } // PMW reserved for CT
if ((LST_RGBCW == Light.subtype) && (4 == channel)) { return true; } // PMW reserved for CT
}
#endif // ESP8266
return false;
}
// Calculate the Gamma correction, if any, for fading, using the fast Gamma curve (10 bits in+out)
uint16_t fadeGamma(uint32_t channel, uint16_t v) {
if (isChannelGammaCorrected(channel)) {
@ -2106,7 +2117,9 @@ void LightSetOutputs(const uint16_t *cur_col_10) {
if (pin[GPIO_PWM1 +i] < 99) {
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d 10 bits %d"), i, cur_col_10[i]);
uint16_t cur_col = cur_col_10[i + Light.pwm_offset];
cur_col = cur_col > 0 ? changeUIntScale(cur_col, 0, Settings.pwm_range, Light.pwm_min, Light.pwm_max) : 0; // shrink to the range of pwm_min..pwm_max
if (!isChannelCT(i)) { // if CT don't use pwm_min and pwm_max
cur_col = cur_col > 0 ? changeUIntScale(cur_col, 0, Settings.pwm_range, Light.pwm_min, Light.pwm_max) : 0; // shrink to the range of pwm_min..pwm_max
}
analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - cur_col : cur_col);
}
}
@ -2371,9 +2384,6 @@ bool LightColorEntry(char *buffer, uint32_t buffer_length)
}
} else {
value = atoi(buffer);
#ifdef USE_LIGHT_PALETTE
value--;
#endif // USE_LIGHT_PALETTE
}
#ifdef USE_LIGHT_PALETTE
if (Light.palette_count) value = value % Light.palette_count;
@ -2404,6 +2414,7 @@ bool LightColorEntry(char *buffer, uint32_t buffer_length)
}
#ifdef USE_LIGHT_PALETTE
else if (Light.palette_count) {
value--;
Light.wheel = value;
memcpy_P(&Light.entry_color, &Light.palette[value * LST_MAX], LST_MAX);
entry_type = 1; // Hexadecimal

View File

@ -559,7 +559,7 @@ void HandleDomoticzConfiguration(void)
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ);
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
DomoticzSaveSettings();
WebRestart(1);
return;
@ -651,7 +651,7 @@ bool Xdrv07(uint8_t function)
WSContentSend_P(HTTP_BTN_MENU_DOMOTICZ);
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration);
Webserver->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration);
break;
#endif // USE_WEBSERVER
case FUNC_MQTT_SUBSCRIBE:

View File

@ -702,7 +702,7 @@ void HandleTimerConfiguration(void)
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TIMER);
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
TimerSaveSettings();
HandleConfiguration();
return;
@ -740,7 +740,7 @@ void TimerSaveSettings(void)
char message[LOGSZ];
Timer timer;
Settings.flag3.timers_enable = WebServer->hasArg("e0"); // CMND_TIMERS
Settings.flag3.timers_enable = Webserver->hasArg("e0"); // CMND_TIMERS
WebGetArg("t0", tmp, sizeof(tmp));
char *p = tmp;
snprintf_P(message, sizeof(message), PSTR(D_LOG_MQTT D_CMND_TIMERS " %d"), Settings.flag3.timers_enable); // CMND_TIMERS
@ -781,7 +781,7 @@ bool Xdrv09(uint8_t function)
#endif // USE_RULES
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/" WEB_HANDLE_TIMER, HandleTimerConfiguration);
Webserver->on("/" WEB_HANDLE_TIMER, HandleTimerConfiguration);
break;
#endif // USE_TIMERS_WEB
#endif // USE_WEBSERVER

View File

@ -1797,8 +1797,11 @@ void CmndEvent(void)
{
if (XdrvMailbox.data_len > 0) {
strlcpy(Rules.event_data, XdrvMailbox.data, sizeof(Rules.event_data));
#ifdef USE_DEVICE_GROUPS
SendLocalDeviceGroupMessage(DGR_MSGTYP_UPDATE, DGR_ITEM_EVENT, XdrvMailbox.data);
#endif // USE_DEVICE_GROUPS
}
ResponseCmndDone();
if (XdrvMailbox.command) ResponseCmndDone();
}
void CmndVariable(void)

View File

@ -65,6 +65,35 @@ keywords if then else endif, or, and are better readable for beginners (others m
uint32_t EncodeLightId(uint8_t relay_id);
uint32_t DecodeLightId(uint32_t hue_id);
#if defined(ESP32) && defined(ESP32_SCRIPT_SIZE) && !defined(USE_24C256) && !defined(USE_SCRIPT_FATFS)
#include "FS.h"
#include "SPIFFS.h"
void SaveFile(const char *name,const uint8_t *buf,uint32_t len) {
File file = SPIFFS.open(name, FILE_WRITE);
if (!file) return;
file.write(buf, len);
file.close();
}
#define FORMAT_SPIFFS_IF_FAILED true
uint8_t spiffs_mounted=0;
void LoadFile(const char *name,uint8_t *buf,uint32_t len) {
if (!spiffs_mounted) {
if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){
//Serial.println("SPIFFS Mount Failed");
return;
}
spiffs_mounted=1;
}
File file = SPIFFS.open(name);
if (!file) return;
file.read(buf, len);
file.close();
}
#endif
// offsets epoch readings by 1.1.2019 00:00:00 to fit into float with second resolution
#define EPOCH_OFFSET 1546300800
@ -3341,8 +3370,8 @@ void Script_FileUploadConfiguration(void)
if (!HttpCheckPriviledgedAccess()) { return; }
if (WebServer->hasArg("download")) {
String stmp = WebServer->arg("download");
if (Webserver->hasArg("download")) {
String stmp = Webserver->arg("download");
char *cp=(char*)stmp.c_str();
if (DownloadFile(cp)) {
// is directory
@ -3386,7 +3415,7 @@ void script_upload(void) {
//AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: file upload"));
HTTPUpload& upload = WebServer->upload();
HTTPUpload& upload = Webserver->upload();
if (upload.status == UPLOAD_FILE_START) {
char npath[48];
sprintf(npath,"%s/%s",path,upload.filename.c_str());
@ -3402,7 +3431,7 @@ void script_upload(void) {
}
} else {
Web.upload_error=1;
WebServer->send(500, "text/plain", "500: couldn't create file");
Webserver->send(500, "text/plain", "500: couldn't create file");
}
}
@ -3428,8 +3457,8 @@ uint8_t DownloadFile(char *file) {
uint32_t flen=download_file.size();
download_Client = WebServer->client();
WebServer->setContentLength(flen);
download_Client = Webserver->client();
Webserver->setContentLength(flen);
char attachment[100];
char *cp;
@ -3440,7 +3469,7 @@ uint8_t DownloadFile(char *file) {
}
}
snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"),cp);
WebServer->sendHeader(F("Content-Disposition"), attachment);
Webserver->sendHeader(F("Content-Disposition"), attachment);
WSSend(200, CT_STREAM, "");
uint8_t buff[512];
@ -3472,7 +3501,7 @@ uint8_t DownloadFile(char *file) {
void HandleScriptTextareaConfiguration(void) {
if (!HttpCheckPriviledgedAccess()) { return; }
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
ScriptSaveSettings();
HandleConfiguration();
return;
@ -3486,13 +3515,13 @@ void HandleScriptConfiguration(void) {
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_SCRIPT);
#ifdef USE_SCRIPT_FATFS
if (WebServer->hasArg("d1")) {
if (Webserver->hasArg("d1")) {
DownloadFile(glob_script_mem.flink[0]);
}
if (WebServer->hasArg("d2")) {
if (Webserver->hasArg("d2")) {
DownloadFile(glob_script_mem.flink[1]);
}
if (WebServer->hasArg("upl")) {
if (Webserver->hasArg("upl")) {
Script_FileUploadConfiguration();
}
#endif
@ -3532,14 +3561,14 @@ void HandleScriptConfiguration(void) {
void ScriptSaveSettings(void) {
if (WebServer->hasArg("c1")) {
if (Webserver->hasArg("c1")) {
bitWrite(Settings.rule_enabled,0,1);
} else {
bitWrite(Settings.rule_enabled,0,0);
}
String str = WebServer->arg("t1");
String str = Webserver->arg("t1");
if (*str.c_str()) {
@ -3597,6 +3626,11 @@ void ScriptSaveSettings(void) {
}
#endif
#if defined(ESP32) && defined(ESP32_SCRIPT_SIZE) && !defined(USE_24C256) && !defined(USE_SCRIPT_FATFS)
if (glob_script_mem.flags&1) {
SaveFile("/script.txt",(uint8_t*)glob_script_mem.script_ram,ESP32_SCRIPT_SIZE);
}
#endif
}
if (glob_script_mem.script_mem) {
@ -3990,11 +4024,11 @@ void Script_Handle_Hue(String *path) {
uint8_t device = DecodeLightId(atoi(path->c_str()));
uint8_t index = device-devices_present-1;
if (WebServer->args()) {
if (Webserver->args()) {
response = "[";
StaticJsonBuffer<400> jsonBuffer;
JsonObject &hue_json = jsonBuffer.parseObject(WebServer->arg((WebServer->args())-1));
JsonObject &hue_json = jsonBuffer.parseObject(Webserver->arg((Webserver->args())-1));
if (hue_json.containsKey("on")) {
response += FPSTR(sHUE_LIGHT_RESPONSE_JSON);
@ -4436,8 +4470,8 @@ void Script_Check_HTML_Setvars(void) {
if (!HttpCheckPriviledgedAccess()) { return; }
if (WebServer->hasArg("sv")) {
String stmp = WebServer->arg("sv");
if (Webserver->hasArg("sv")) {
String stmp = Webserver->arg("sv");
char cmdbuf[64];
memset(cmdbuf,0,sizeof(cmdbuf));
char *cp=cmdbuf;
@ -4820,6 +4854,13 @@ bool Xdrv10(uint8_t function)
switch (function) {
case FUNC_PRE_INIT:
/*
#ifdef USE_WEBCAM
if (Settings.module==ESP32_CAM_AITHINKER) {
webcam_setup();
}
#endif
*/
// set defaults to rules memory
glob_script_mem.script_ram=Settings.rules[0];
glob_script_mem.script_size=MAX_SCRIPT_SIZE;
@ -4889,6 +4930,21 @@ bool Xdrv10(uint8_t function)
}
#endif
#if defined(ESP32) && defined(ESP32_SCRIPT_SIZE) && !defined(USE_24C256) && !defined(USE_SCRIPT_FATFS)
char *script;
script=(char*)calloc(ESP32_SCRIPT_SIZE+4,1);
if (!script) break;
LoadFile("/script.txt",(uint8_t*)script,ESP32_SCRIPT_SIZE);
glob_script_mem.script_ram=script;
glob_script_mem.script_size=ESP32_SCRIPT_SIZE;
script[ESP32_SCRIPT_SIZE-1]=0;
// use rules storage for permanent vars
glob_script_mem.script_pram=(uint8_t*)Settings.rules[0];
glob_script_mem.script_pram_size=MAX_SCRIPT_SIZE;
glob_script_mem.flags=1;
#endif
// assure permanent memory is 4 byte aligned
{ uint32_t ptr=(uint32_t)glob_script_mem.script_pram;
ptr&=0xfffffffc;
@ -4932,13 +4988,13 @@ bool Xdrv10(uint8_t function)
WSContentSend_P(HTTP_BTN_MENU_RULES);
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/" WEB_HANDLE_SCRIPT, HandleScriptConfiguration);
WebServer->on("/ta",HTTP_POST, HandleScriptTextareaConfiguration);
Webserver->on("/" WEB_HANDLE_SCRIPT, HandleScriptConfiguration);
Webserver->on("/ta",HTTP_POST, HandleScriptTextareaConfiguration);
#ifdef USE_SCRIPT_FATFS
WebServer->on("/u3", HTTP_POST,[]() { WebServer->sendHeader("Location","/u3");WebServer->send(303);},script_upload);
WebServer->on("/u3", HTTP_GET,ScriptFileUploadSuccess);
WebServer->on("/upl", HTTP_GET,Script_FileUploadConfiguration);
Webserver->on("/u3", HTTP_POST,[]() { Webserver->sendHeader("Location","/u3");Webserver->send(303);},script_upload);
Webserver->on("/u3", HTTP_GET,ScriptFileUploadSuccess);
Webserver->on("/upl", HTTP_GET,Script_FileUploadConfiguration);
#endif
break;
#endif // USE_WEBSERVER

View File

@ -809,22 +809,22 @@ void HandleKNXConfiguration(void)
char tmp[100];
String stmp;
if ( WebServer->hasArg("save") ) {
if ( Webserver->hasArg("save") ) {
KNX_Save_Settings();
HandleConfiguration();
}
else
{
if ( WebServer->hasArg("btn_add") ) {
if ( WebServer->arg("btn_add") == "1" ) {
if ( Webserver->hasArg("btn_add") ) {
if ( Webserver->arg("btn_add") == "1" ) {
stmp = WebServer->arg("GAop"); //option selected
stmp = Webserver->arg("GAop"); //option selected
uint8_t GAop = stmp.toInt();
stmp = WebServer->arg("GA_FNUM");
stmp = Webserver->arg("GA_FNUM");
uint8_t GA_FNUM = stmp.toInt();
stmp = WebServer->arg("GA_AREA");
stmp = Webserver->arg("GA_AREA");
uint8_t GA_AREA = stmp.toInt();
stmp = WebServer->arg("GA_FDEF");
stmp = Webserver->arg("GA_FDEF");
uint8_t GA_FDEF = stmp.toInt();
if (GAop) {
@ -834,13 +834,13 @@ void HandleKNXConfiguration(void)
else
{
stmp = WebServer->arg("CBop"); //option selected
stmp = Webserver->arg("CBop"); //option selected
uint8_t CBop = stmp.toInt();
stmp = WebServer->arg("CB_FNUM");
stmp = Webserver->arg("CB_FNUM");
uint8_t CB_FNUM = stmp.toInt();
stmp = WebServer->arg("CB_AREA");
stmp = Webserver->arg("CB_AREA");
uint8_t CB_AREA = stmp.toInt();
stmp = WebServer->arg("CB_FDEF");
stmp = Webserver->arg("CB_FDEF");
uint8_t CB_FDEF = stmp.toInt();
if (CBop) {
@ -848,19 +848,19 @@ void HandleKNXConfiguration(void)
}
}
}
else if ( WebServer->hasArg("btn_del_ga") )
else if ( Webserver->hasArg("btn_del_ga") )
{
stmp = WebServer->arg("btn_del_ga");
stmp = Webserver->arg("btn_del_ga");
uint8_t GA_NUM = stmp.toInt();
KNX_DEL_GA(GA_NUM);
}
else if ( WebServer->hasArg("btn_del_cb") )
else if ( Webserver->hasArg("btn_del_cb") )
{
stmp = WebServer->arg("btn_del_cb");
stmp = Webserver->arg("btn_del_cb");
uint8_t CB_NUM = stmp.toInt();
KNX_DEL_CB(CB_NUM);
@ -954,16 +954,16 @@ void KNX_Save_Settings(void)
String stmp;
address_t KNX_addr;
Settings.flag.knx_enabled = WebServer->hasArg("b1");
Settings.flag.knx_enable_enhancement = WebServer->hasArg("b2");
Settings.flag.knx_enabled = Webserver->hasArg("b1");
Settings.flag.knx_enable_enhancement = Webserver->hasArg("b2");
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_ENABLED ": %d, " D_KNX_ENHANCEMENT ": %d"),
Settings.flag.knx_enabled, Settings.flag.knx_enable_enhancement );
stmp = WebServer->arg("area");
stmp = Webserver->arg("area");
KNX_addr.pa.area = stmp.toInt();
stmp = WebServer->arg("line");
stmp = Webserver->arg("line");
KNX_addr.pa.line = stmp.toInt();
stmp = WebServer->arg("member");
stmp = Webserver->arg("member");
KNX_addr.pa.member = stmp.toInt();
Settings.knx_physsical_addr = KNX_addr.value;
knx.physical_address_set( KNX_addr ); // Set Physical KNX Address of the device
@ -1224,7 +1224,7 @@ bool Xdrv11(uint8_t function)
WSContentSend_P(HTTP_BTN_MENU_KNX);
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/kn", HandleKNXConfiguration);
Webserver->on("/kn", HandleKNXConfiguration);
break;
#endif // USE_KNX_WEB_MENU
#endif // USE_WEBSERVER

View File

@ -448,7 +448,7 @@ static const char * FIRST_GEN_UA[] = { // list of User-Agents signature
// Check if the Echo device is of 1st generation, which triggers different results
uint32_t findEchoGeneration(void) {
// result is 1 for 1st gen, 2 for 2nd gen and further
String user_agent = WebServer->header("User-Agent");
String user_agent = Webserver->header("User-Agent");
uint32_t gen = 2;
for (uint32_t i = 0; i < sizeof(FIRST_GEN_UA)/sizeof(char*); i++) {
@ -521,11 +521,11 @@ void HueLightsCommand(uint8_t device, uint32_t device_id, String &response) {
const size_t buf_size = 100;
char * buf = (char*) malloc(buf_size);
if (WebServer->args()) {
if (Webserver->args()) {
response = "[";
StaticJsonBuffer<300> jsonBuffer;
JsonObject &hue_json = jsonBuffer.parseObject(WebServer->arg((WebServer->args())-1));
JsonObject &hue_json = jsonBuffer.parseObject(Webserver->arg((Webserver->args())-1));
if (hue_json.containsKey("on")) {
on = hue_json["on"];
snprintf_P(buf, buf_size,
@ -542,6 +542,7 @@ void HueLightsCommand(uint8_t device, uint32_t device_id, String &response) {
}
} else {
#endif
/*
switch(on)
{
case false : ExecuteCommandPower(device, POWER_OFF, SRC_HUE);
@ -549,6 +550,8 @@ void HueLightsCommand(uint8_t device, uint32_t device_id, String &response) {
case true : ExecuteCommandPower(device, POWER_ON, SRC_HUE);
break;
}
*/
ExecuteCommandPower(device, (on) ? POWER_ON : POWER_OFF, SRC_HUE);
response += buf;
resp = true;
#ifdef USE_SHUTTER
@ -827,8 +830,8 @@ void HandleHueApi(String *path)
path->remove(0, 4); // remove /api
uint16_t apilen = path->length();
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_API " (%s)"), path->c_str()); // HTP: Hue API (//lights/1/state
for (args = 0; args < WebServer->args(); args++) {
String json = WebServer->arg(args);
for (args = 0; args < Webserver->args(); args++) {
String json = Webserver->arg(args);
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_POST_ARGS " (%s)"), json.c_str()); // HTP: Hue POST args ({"on":false})
}
@ -861,7 +864,7 @@ bool Xdrv20(uint8_t function)
#endif
switch (function) {
case FUNC_WEB_ADD_HANDLER:
WebServer->on(F("/description.xml"), HandleUpnpSetupHue);
Webserver->on(F("/description.xml"), HandleUpnpSetupHue);
break;
}
}

View File

@ -198,7 +198,7 @@ void HandleUpnpEvent(void)
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_BASIC_EVENT));
char event[500];
strlcpy(event, WebServer->arg(0).c_str(), sizeof(event));
strlcpy(event, Webserver->arg(0).c_str(), sizeof(event));
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), event);
@ -259,10 +259,10 @@ bool Xdrv21(uint8_t function)
if (devices_present && (EMUL_WEMO == Settings.flag2.emulation)) {
switch (function) {
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
WebServer->on("/eventservice.xml", HandleUpnpService);
WebServer->on("/metainfoservice.xml", HandleUpnpMetaService);
WebServer->on("/setup.xml", HandleUpnpSetupWemo);
Webserver->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
Webserver->on("/eventservice.xml", HandleUpnpService);
Webserver->on("/metainfoservice.xml", HandleUpnpMetaService);
Webserver->on("/setup.xml", HandleUpnpSetupWemo);
break;
}
}

View File

@ -25,15 +25,15 @@ void ZigbeeZCLSend_Raw(uint16_t dtsAddr, uint16_t groupaddr, uint16_t clusterId,
// Get an JSON attribute, with case insensitive key search
JsonVariant &getCaseInsensitive(const JsonObject &json, const char *needle) {
const JsonVariant &getCaseInsensitive(const JsonObject &json, const char *needle) {
// key can be in PROGMEM
if ((nullptr == &json) || (nullptr == needle) || (0 == pgm_read_byte(needle))) {
return *(JsonVariant*)nullptr;
}
for (auto kv : json) {
const char *key = kv.key;
JsonVariant &value = kv.value;
for (JsonObject::const_iterator it=json.begin(); it!=json.end(); ++it) {
const char *key = it->key;
const JsonVariant &value = it->value;
if (0 == strcasecmp_P(key, needle)) {
return value;

View File

@ -65,7 +65,7 @@ typedef int32_t (*Z_DeviceTimer)(uint16_t shortaddr, uint16_t groupaddr, uint16_
typedef enum Z_Def_Category {
Z_CAT_NONE = 0, // no category, it will happen anyways
Z_CAT_READ_ATTR, // Attribute reporting, either READ_ATTRIBUTE or REPORT_ATTRIBUTE, we coalesce all attributes reported if we can
Z_CAT_VIRTUAL_ATTR, // Creation of a virtual attribute, typically after a time-out. Ex: Aqara presence sensor
Z_CAT_VIRTUAL_OCCUPANCY, // Creation of a virtual attribute, typically after a time-out. Ex: Aqara presence sensor
Z_CAT_REACHABILITY, // timer set to measure reachability of device, i.e. if we don't get an answer after 1s, it is marked as unreachable (for Alexa)
Z_CAT_READ_0006, // Read 0x0006 cluster
Z_CAT_READ_0008, // Read 0x0008 cluster

View File

@ -190,23 +190,21 @@ void ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, String &response) {
const size_t buf_size = 100;
char * buf = (char*) malloc(buf_size);
if (WebServer->args()) {
if (Webserver->args()) {
response = "[";
StaticJsonBuffer<300> jsonBuffer;
JsonObject &hue_json = jsonBuffer.parseObject(WebServer->arg((WebServer->args())-1));
JsonObject &hue_json = jsonBuffer.parseObject(Webserver->arg((Webserver->args())-1));
if (hue_json.containsKey("on")) {
on = hue_json["on"];
snprintf_P(buf, buf_size,
PSTR("{\"success\":{\"/lights/%d/state/on\":%s}}"),
device_id, on ? "true" : "false");
switch(on)
{
case false : ZigbeeHuePower(shortaddr, 0x00);
break;
case true : ZigbeeHuePower(shortaddr, 0x01);
break;
if (on) {
ZigbeeHuePower(shortaddr, 0x01);
} else {
ZigbeeHuePower(shortaddr, 0x00);
}
response += buf;
resp = true;

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,7 @@ ZF(DimmerMove) ZF(DimmerStep)
ZF(HueMove) ZF(HueStep) ZF(SatMove) ZF(SatStep) ZF(ColorMove) ZF(ColorStep)
ZF(ArrowClick) ZF(ArrowHold) ZF(ArrowRelease) ZF(ZoneStatusChange)
ZF(xxxx00) ZF(xxxx) ZF(01xxxx) ZF(00) ZF(01) ZF() ZF(xxxxyy) ZF(001902) ZF(011902) ZF(xxyyyy) ZF(xx)
ZF(xxxx00) ZF(xxxx) ZF(01xxxx) ZF(00) ZF(01) ZF() ZF(xxxxyy) ZF(00190200) ZF(01190200) ZF(xxyyyy) ZF(xx)
ZF(xx000A00) ZF(xx0A00) ZF(xxyy0A00) ZF(xxxxyyyy0A00) ZF(xxxx0A00) ZF(xx0A)
ZF(xx190A00) ZF(xx19) ZF(xx190A) ZF(xxxxyyyy) ZF(xxxxyyzz) ZF(xxyyzzzz) ZF(xxyyyyzz)
@ -82,8 +82,8 @@ const Z_CommandConverter Z_Commands[] PROGMEM = {
// Light & Shutter commands
{ Z(Power), 0x0006, 0xFF, 0x01, Z() }, // 0=Off, 1=On, 2=Toggle
{ Z(Dimmer), 0x0008, 0x04, 0x01, Z(xx0A00) }, // Move to Level with On/Off, xx=0..254 (255 is invalid)
{ Z(DimmerUp), 0x0008, 0x06, 0x01, Z(001902) }, // Step up by 10%, 0.2 secs
{ Z(DimmerDown), 0x0008, 0x06, 0x01, Z(011902) }, // Step down by 10%, 0.2 secs
{ Z(DimmerUp), 0x0008, 0x06, 0x01, Z(00190200) }, // Step up by 10%, 0.2 secs
{ Z(DimmerDown), 0x0008, 0x06, 0x01, Z(01190200) }, // Step down by 10%, 0.2 secs
{ Z(DimmerStop), 0x0008, 0x03, 0x01, Z() }, // Stop any Dimmer animation
{ Z(ResetAlarm), 0x0009, 0x00, 0x01, Z(xxyyyy) }, // Reset alarm (alarm code + cluster identifier)
{ Z(ResetAllAlarms), 0x0009, 0x01, 0x01, Z() }, // Reset all alarms

View File

@ -534,7 +534,9 @@ void Z_AqaraOccupancy(uint16_t shortaddr, uint16_t cluster, uint8_t endpoint, co
uint32_t occupancy = strToUInt(val_endpoint);
if (occupancy) {
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, OCCUPANCY_TIMEOUT, cluster, endpoint, Z_CAT_VIRTUAL_ATTR, 0, &Z_OccupancyCallback);
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, OCCUPANCY_TIMEOUT, cluster, endpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback);
} else {
zigbee_devices.resetTimersForDevice(shortaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY);
}
}
}

View File

@ -160,7 +160,7 @@ void HandlePcf8574(void)
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_PCF8574));
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
Pcf8574SaveSettings();
WebRestart(1);
return;
@ -193,9 +193,9 @@ void Pcf8574SaveSettings(void)
char stemp[7];
char tmp[100];
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("PCF: Start working on Save arguements: inverted:%d")), WebServer->hasArg("b1");
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("PCF: Start working on Save arguements: inverted:%d")), Webserver->hasArg("b1");
Settings.flag3.pcf8574_ports_inverted = WebServer->hasArg("b1"); // SetOption81 - Invert all ports on PCF8574 devices
Settings.flag3.pcf8574_ports_inverted = Webserver->hasArg("b1"); // SetOption81 - Invert all ports on PCF8574 devices
for (byte idx = 0; idx < Pcf8574.max_devices; idx++) {
byte count=0;
byte n = Settings.pcf8574_config[idx];
@ -248,7 +248,7 @@ bool Xdrv28(uint8_t function)
WSContentSend_P(HTTP_BTN_MENU_PCF8574);
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/" WEB_HANDLE_PCF8574, HandlePcf8574);
Webserver->on("/" WEB_HANDLE_PCF8574, HandlePcf8574);
break;
#endif // USE_WEBSERVER
}

View File

@ -40,7 +40,7 @@ void (* const PWMDimmerCommand[])(void) PROGMEM = {
#ifdef USE_PWM_DIMMER_REMOTE
struct remote_pwm_dimmer {
power_t power;
bool power_on;
uint8_t bri_power_on;
uint8_t bri_preset_low;
uint8_t bri_preset_high;
@ -178,7 +178,7 @@ void PWMDimmerHandleDevGroupItem(void)
uint8_t device_group_index = *(uint8_t *)XdrvMailbox.topic;
if (device_group_index > remote_pwm_dimmer_count) return;
bool device_is_local = device_groups[device_group_index].local;
struct remote_pwm_dimmer * remote_pwm_dimmer = &remote_pwm_dimmers[device_group_index];
struct remote_pwm_dimmer * remote_pwm_dimmer = &remote_pwm_dimmers[device_group_index - 1];
#else // USE_PWM_DIMMER_REMOTE
if (*(uint8_t *)XdrvMailbox.topic) return;
#endif // !USE_PWM_DIMMER_REMOTE
@ -190,7 +190,7 @@ void PWMDimmerHandleDevGroupItem(void)
break;
case DGR_ITEM_POWER:
if (!device_is_local) {
remote_pwm_dimmer->power = value;
remote_pwm_dimmer->power_on = value & 1;
remote_pwm_dimmer->power_button_increases_bri = (remote_pwm_dimmer->bri < 128);
}
break;
@ -286,7 +286,7 @@ void PWMDimmerHandleButton(void)
// Initialize some variables.
#ifdef USE_PWM_DIMMER_REMOTE
bool power_is_on = (!active_device_is_local ? active_remote_pwm_dimmer->power : power);
bool power_is_on = (!active_device_is_local ? active_remote_pwm_dimmer->power_on : power);
bool is_power_button = (button_index == power_button_index);
#else // USE_PWM_DIMMER_REMOTE
bool power_is_on = power;
@ -344,8 +344,9 @@ void PWMDimmerHandleButton(void)
// If this is about the power button, ...
if (is_power_button) {
// If no other buttons are pressed, ...
if (buttons_pressed == 1) {
// If no other buttons are pressed and the up or down button was tapped while holding the
// power button before this, ...
if (buttons_pressed == 1 && !tap_count) {
// If the power is on, adjust the brightness. Set the direction based on the current
// direction for the device and then invert the direction when the power button is
@ -628,8 +629,8 @@ void PWMDimmerHandleButton(void)
#ifdef USE_DEVICE_GROUPS
#ifdef USE_PWM_DIMMER_REMOTE
if (!active_device_is_local) {
active_remote_pwm_dimmer->power ^= 1;
new_power = active_remote_pwm_dimmer->power;
active_remote_pwm_dimmer->power_on ^= 1;
new_power = active_remote_pwm_dimmer->power_on;
}
else {
#endif // USE_PWM_DIMMER_REMOTE

View File

@ -21,7 +21,10 @@
#define XDRV_38 38
#include <ping.h>
#include "lwip/icmp.h"
#include "lwip/inet_chksum.h"
#include "lwip/raw.h"
#include "lwip/timeouts.h"
const char kPingCommands[] PROGMEM = "|" // no prefix
D_CMND_PING
@ -31,119 +34,291 @@ void (* const PingCommand[])(void) PROGMEM = {
&CmndPing,
};
// inspired by https://github.com/dancol90/ESP8266Ping
typedef struct Ping_t {
uint16_t total_count; // total count if packets sent
uint16_t timeout_count; // time-outs (no responses)
uint32_t min_time; // minimum time in ms for a successful response
uint32_t max_time; // maximum time in ms for a successful response
uint32_t sum_time; // cumulated time in ms for all successful responses (used to compute the average)
bool busy; // is ping on-going
bool done; // indicates the ping campaign is finished
} Ping_t;
ping_option ping_opt;
Ping_t ping;
extern "C" {
// callbacks for ping
extern uint32 system_relative_time(uint32 time);
extern void ets_bzero(void *s, size_t n);
// called after a ping response is received or time-out
void ICACHE_RAM_ATTR ping_recv_cb(ping_option *popt, struct ping_resp *p_resp) {
// If successful
if (p_resp->ping_err >= 0) {
uint32_t resp_time = p_resp->resp_time;
ping.sum_time += resp_time;
if (resp_time < ping.min_time) { ping.min_time = resp_time; }
if (resp_time > ping.max_time) { ping.max_time = resp_time; }
const uint16_t Ping_ID = 0xAFAF; // PING packet ID
const size_t Ping_data_size = 32; // default packet size
const uint32_t Ping_timeout_ms = 1000; // default time-out of 1 second, which is enough for LAN/WIFI
const uint32_t Ping_coarse = 1000; // interval between sending packets, 1 packet every second
typedef struct Ping_t {
uint32 ip; // target IPv4 address
Ping_t *next; // next object in linked list
uint16_t seq_num; // next sequence number
uint16_t seqno; // reject a packet already received
uint8_t success_count; // sucessful responses received
uint8_t timeout_count; // time-outs (no responses)
uint8_t to_send_count; // number of packets remaining to send
uint32_t ping_time_sent; // timestamp when the packet was sent
uint32_t min_time; // minimum time in ms for a successful response
uint32_t max_time; // maximum time in ms for a successful response
uint32_t sum_time; // cumulated time in ms for all successful responses (used to compute the average)
bool done; // indicates the ping campaign is finished
bool fast; // fast mode, i.e. stop pings when first successful response
} Ping_t;
// globals
Ping_t *ping_head = nullptr; // head of the Linked List for ping objects
struct raw_pcb *t_ping_pcb = nullptr; // registered with first ping, deregistered after last ping, the same pcb is used for all packets
// ================================================================================
// Find the Ping object indexed by IP address
// ================================================================================
//
// find the ping structure corresponding to the specified IP, or nullptr if not found
//
Ping_t ICACHE_FLASH_ATTR * t_ping_find(uint32_t ip) {
Ping_t *ping = ping_head;
while (ping != nullptr) {
if (ping->ip == ip) {
return ping;
}
ping = ping->next;
}
return nullptr;
}
// ================================================================================
// Timer called a packet response is in time-out
// ================================================================================
//
// called after the ICMP timeout occured
// we never received the packet, increase the timeout count
//
void ICACHE_FLASH_ATTR t_ping_timeout(void* arg) {
Ping_t *ping = (Ping_t*) arg;
ping->timeout_count++;
}
// ================================================================================
// Send ICMP packet
// ================================================================================
// Prepare a echo ICMP request
//
void ICACHE_FLASH_ATTR t_ping_prepare_echo(struct icmp_echo_hdr *iecho, uint16_t len, Ping_t *ping) {
size_t data_len = len - sizeof(struct icmp_echo_hdr);
ICMPH_TYPE_SET(iecho, ICMP_ECHO);
ICMPH_CODE_SET(iecho, 0);
iecho->chksum = 0;
iecho->id = Ping_ID;
ping->seq_num++;
if (ping->seq_num == 0x7fff) { ping->seq_num = 0; }
iecho->seqno = htons(ping->seq_num); // TODO
/* fill the additional data buffer with some data */
for (uint32_t i = 0; i < data_len; i++) {
((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
}
iecho->chksum = inet_chksum(iecho, len);
}
//
// send the ICMP packet
//
void ICACHE_FLASH_ATTR t_ping_send(struct raw_pcb *raw, Ping_t *ping) {
struct pbuf *p;
uint16_t ping_size = sizeof(struct icmp_echo_hdr) + Ping_data_size;
ping->ping_time_sent = system_get_time();
p = pbuf_alloc(PBUF_IP, ping_size, PBUF_RAM);
if (!p) { return; }
if ((p->len == p->tot_len) && (p->next == nullptr)) {
ip_addr_t ping_target;
struct icmp_echo_hdr *iecho;
ping_target.addr = ping->ip;
iecho = (struct icmp_echo_hdr *) p->payload;
t_ping_prepare_echo(iecho, ping_size, ping);
raw_sendto(raw, p, &ping_target);
}
pbuf_free(p);
}
// ================================================================================
// Timer called when it's time to send next packet, of when finished
// ================================================================================
// this timer is called every x seconds to send a new packet, whatever happened to the previous packet
static void ICACHE_FLASH_ATTR t_ping_coarse_tmr(void *arg) {
Ping_t *ping = (Ping_t*) arg;
if (ping->to_send_count > 0) {
ping->to_send_count--;
// have we sent all packets?
t_ping_send(t_ping_pcb, ping);
sys_timeout(Ping_timeout_ms, t_ping_timeout, ping);
sys_timeout(Ping_coarse, t_ping_coarse_tmr, ping);
} else {
sys_untimeout(t_ping_coarse_tmr, ping);
ping->done = true;
}
}
// called after the ping campaign is finished
void ICACHE_RAM_ATTR ping_sent_cb(ping_option *popt, struct ping_resp *p_resp) {
// copy counters to build the MQTT response
ping.total_count = p_resp->total_count;
ping.timeout_count = p_resp->timeout_count;
ping.done = true;
// ================================================================================
// Callback: a packet response was received
// ================================================================================
//
// Reveived packet
//
static uint8_t ICACHE_FLASH_ATTR t_ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) {
Ping_t *ping = t_ping_find(addr->addr);
if (nullptr == ping) { // unknown source address
return 0; // don't eat the packet and ignore it
}
if (pbuf_header( p, -PBUF_IP_HLEN)==0) {
struct icmp_echo_hdr *iecho;
iecho = (struct icmp_echo_hdr *)p->payload;
if ((iecho->id == Ping_ID) && (iecho->seqno == htons(ping->seq_num)) && iecho->type == ICMP_ER) {
if (iecho->seqno != ping->seqno){ // debounce already received packet
/* do some ping result processing */
sys_untimeout(t_ping_timeout, ping); // remove time-out handler
uint32_t delay = system_relative_time(ping->ping_time_sent);
delay /= 1000;
ping->sum_time += delay;
if (delay < ping->min_time) { ping->min_time = delay; }
if (delay > ping->max_time) { ping->max_time = delay; }
ping->success_count++;
ping->seqno = iecho->seqno;
if (ping->fast) { // if fast mode, abort further pings when first successful response is received
sys_untimeout(t_ping_coarse_tmr, ping);
ping->done = true;
ping->to_send_count = 0;
}
}
pbuf_free(p);
return 1; /* eat the packet */
}
}
return 0; /* don't eat the packet */
}
// ================================================================================
// Internal structure PCB management
// ================================================================================
// we are going to send a packet, make sure pcb is initialized
void t_ping_register_pcb(void) {
if (nullptr == t_ping_pcb) {
t_ping_pcb = raw_new(IP_PROTO_ICMP);
raw_recv(t_ping_pcb, t_ping_recv, nullptr); // we cannot register data structure here as we can only register one
raw_bind(t_ping_pcb, IP_ADDR_ANY);
}
}
// we have finsihed a ping series, deallocated if no more ongoing
void t_ping_deregister_pcb(void) {
if (nullptr == ping_head) { // deregister only if no ping is flying
raw_remove(t_ping_pcb);
t_ping_pcb = nullptr;
}
}
// ================================================================================
// Start pings
// ================================================================================
bool t_ping_start(uint32_t ip, uint32_t count) {
// check if pings are already ongoing for this IP
if (t_ping_find(ip)) {
return false;
}
Ping_t *ping = new Ping_t();
if (0 == count) {
count = 4;
ping->fast = true;
}
ping->min_time = UINT32_MAX;
ping->ip = ip;
ping->to_send_count = count - 1;
// add to Linked List from head
ping->next = ping_head;
ping_head = ping; // insert at head
t_ping_register_pcb();
t_ping_send(t_ping_pcb, ping);
// set timers for time-out and cadence
sys_timeout(Ping_timeout_ms, t_ping_timeout, ping);
sys_timeout(Ping_coarse, t_ping_coarse_tmr, ping);
}
}
// Check if any ping requests is completed, and publish the results
void PingResponsePoll(void) {
if (ping.done) {
uint32_t success = ping.total_count - ping.timeout_count;
uint32_t ip = ping_opt.ip;
Ping_t *ping = ping_head;
Ping_t **prev_link = &ping_head; // previous link pointer (used to remove en entry)
// Serial.printf(
// "DEBUG ping_sent_cb: ping reply\n"
// "\tsuccess_count = %d \n"
// "\ttimeout_count = %d \n"
// "\tmin_time = %d \n"
// "\tmax_time = %d \n"
// "\tavg_time = %d \n",
// success, ping.timeout_count,
// ping.min_time, ping.max_time,
// success ? ping.sum_time / success : 0
// );
while (ping != nullptr) {
if (ping->done) {
uint32_t success = ping->success_count;
uint32_t ip = ping->ip;
Response_P(PSTR("{\"" D_JSON_PING "\":{\"%d.%d.%d.%d\":{"
"\"Reachable\":%s"
",\"Success\":%d"
",\"Timeout\":%d"
",\"MinTime\":%d"
",\"MaxTime\":%d"
",\"AvgTime\":%d"
"}}}"),
ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, ip >> 24,
success ? "true" : "false",
success, ping.timeout_count,
ping.min_time, ping.max_time,
success ? ping.sum_time / success : 0
);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_PING));
XdrvRulesProcess();
ping.done = false;
ping.busy = false;
Response_P(PSTR("{\"" D_JSON_PING "\":{\"%d.%d.%d.%d\":{"
"\"Reachable\":%s"
",\"Success\":%d"
",\"Timeout\":%d"
",\"MinTime\":%d"
",\"MaxTime\":%d"
",\"AvgTime\":%d"
"}}}"),
ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, ip >> 24,
success ? "true" : "false",
success, ping->timeout_count,
success ? ping->min_time : 0, ping->max_time,
success ? ping->sum_time / success : 0
);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_PING));
XdrvRulesProcess();
// remove from linked list
*prev_link = ping->next;
// don't increment prev_link
Ping_t *ping_to_delete = ping;
ping = ping->next; // move to next before deleting the object
delete ping_to_delete; // free memory allocated
} else {
prev_link = &ping->next;
ping = ping->next;
}
}
}
/*********************************************************************************************\
* Ping Command
\*********************************************************************************************/
void CmndPing(void) {
uint32_t count = XdrvMailbox.index;
IPAddress ip;
RemoveSpace(XdrvMailbox.data);
if (count > 8) { count = 8; }
if (ping.busy) {
ResponseCmndChar_P(PSTR("Ping busy"));
return;
}
if (count > 10) { count = 8; } // max 8 seconds
if (WiFi.hostByName(XdrvMailbox.data, ip)) {
memset(&ping_opt, 0, sizeof(ping_opt));
memset(&ping, 0, sizeof(ping));
ping.min_time = UINT32_MAX;
ping_opt.count = count;
ping_opt.coarse_time = 1; // wait 1 second between messages
ping_opt.ip = ip;
// callbacks
ping_opt.recv_function = (ping_recv_function) ping_recv_cb; // at each response or time-out
ping_opt.sent_function = (ping_sent_function) ping_sent_cb; // when all packets have been sent and reveived
ping.busy = true;
if (ping_start(&ping_opt)) {
bool ok = t_ping_start(ip, count);
if (ok) {
ResponseCmndDone();
} else {
ResponseCmndChar_P(PSTR("Unable to send Ping"));
ping.busy = false;
ResponseCmndChar_P(PSTR("Ping already ongoing for this IP"));
}
} else {
ResponseCmndChar_P(PSTR("Unable to resolve IP address"));
}
}
@ -157,7 +332,7 @@ bool Xdrv38(uint8_t function)
switch (function) {
case FUNC_EVERY_250_MSECOND:
PingResponsePoll();
PingResponsePoll(); // TODO
break;
case FUNC_COMMAND:
result = DecodeCommand(kPingCommands, PingCommand);
@ -166,4 +341,4 @@ bool Xdrv38(uint8_t function)
return result;
}
#endif // USE_PING
#endif // USE_PING

View File

@ -172,11 +172,11 @@ void CpuLoadLoop(void)
CPU_loops ++;
if ((CPU_last_millis + (CPU_load_check *1000)) <= CPU_last_loop_time) {
#if defined(F_CPU) && (F_CPU == 160000000L)
int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *800) );
int CPU_load = 100 - ( (CPU_loops*(1 + 30*ssleep)) / (CPU_load_check *800) );
CPU_loops = CPU_loops / CPU_load_check;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(160MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops);
#else
int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *400) );
int CPU_load = 100 - ( (CPU_loops*(1 + 30*ssleep)) / (CPU_load_check *400) );
CPU_loops = CPU_loops / CPU_load_check;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(80MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops);
#endif
@ -188,6 +188,7 @@ void CpuLoadLoop(void)
/*******************************************************************************************/
#ifdef ESP8266
#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1)
// All version before core 2.4.2
// https://github.com/esp8266/Arduino/issues/2557
@ -224,10 +225,22 @@ void DebugFreeMem(void)
#endif // ARDUINO_ESP8266_RELEASE_2_x_x
#else // ESP32
void DebugFreeMem(void)
{
register uint8_t *sp asm("a1");
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), sp - pxTaskGetStackStart(NULL), XdrvMailbox.data);
}
#endif // ESP8266 - ESP32
/*******************************************************************************************/
void DebugRtcDump(char* parms)
{
#ifdef ESP8266
#define CFG_COLS 16
uint16_t idx;
@ -283,6 +296,7 @@ void DebugRtcDump(char* parms)
snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data);
AddLog(LOG_LEVEL_INFO);
}
#endif // ESP8266
}
/*******************************************************************************************/
@ -298,7 +312,7 @@ void DebugCfgDump(char* parms)
char *p;
uint8_t *buffer = (uint8_t *) &Settings;
maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS);
maxrow = ((sizeof(Settings)+CFG_COLS)/CFG_COLS);
uint16_t srow = strtol(parms, &p, 16) / CFG_COLS;
uint16_t mrow = strtol(p, &p, 10);
@ -342,7 +356,7 @@ void DebugCfgPeek(char* parms)
char *p;
uint16_t address = strtol(parms, &p, 16);
if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4;
if (address > sizeof(Settings)) address = sizeof(Settings) -4;
address = (address >> 2) << 2;
uint8_t *buffer = (uint8_t *) &Settings;
@ -367,7 +381,7 @@ void DebugCfgPoke(char* parms)
char *p;
uint16_t address = strtol(parms, &p, 16);
if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4;
if (address > sizeof(Settings)) address = sizeof(Settings) -4;
address = (address >> 2) << 2;
uint32_t data = strtol(p, &p, 16);
@ -385,6 +399,7 @@ void DebugCfgPoke(char* parms)
void SetFlashMode(uint8_t mode)
{
#ifdef ESP8266
uint8_t *_buffer;
uint32_t address;
@ -400,6 +415,7 @@ void SetFlashMode(uint8_t mode)
}
}
delete[] _buffer;
#endif // ESP8266
}
/*********************************************************************************************\
@ -503,6 +519,7 @@ uint32_t DebugSwap32(uint32_t x) {
void CmndFlashDump(void)
{
#ifdef ESP8266
// FlashDump
// FlashDump 0xFF000
// FlashDump 0xFC000 10
@ -533,6 +550,7 @@ void CmndFlashDump(void)
DebugSwap32(values[4]), DebugSwap32(values[5]), DebugSwap32(values[6]), DebugSwap32(values[7]));
}
ResponseCmndDone();
#endif // ESP8266
}
#ifdef USE_I2C
@ -600,10 +618,12 @@ void CmndI2cRead(void)
void CmndI2cStretch(void)
{
#ifdef ESP8266
if (i2c_flg && (XdrvMailbox.payload > 0)) {
Wire.setClockStretchLimit(XdrvMailbox.payload);
}
ResponseCmndDone();
#endif // ESP8266
}
void CmndI2cClock(void)

View File

@ -59,14 +59,18 @@
const char kHtuTypes[] PROGMEM = "HTU21|SI7013|SI7020|SI7021|T/RH?";
uint8_t htu_address;
uint8_t htu_type = 0;
uint8_t htu_delay_temp;
uint8_t htu_delay_humidity = 50;
uint8_t htu_valid = 0;
float htu_temperature = 0;
float htu_humidity = 0;
char htu_types[7];
struct {
float temperature = 0;
float humidity = 0;
uint8_t address;
uint8_t type = 0;
uint8_t delay_temp;
uint8_t delay_humidity = 50;
uint8_t valid = 0;
char types[7];
} Htu;
/*********************************************************************************************/
uint8_t HtuCheckCrc8(uint16_t data)
{
@ -82,6 +86,8 @@ uint8_t HtuCheckCrc8(uint16_t data)
uint8_t HtuReadDeviceId(void)
{
HtuReset(); // Fixes ESP32 sensor loss at restart
uint16_t deviceID = 0;
uint8_t checksum = 0;
@ -146,12 +152,12 @@ bool HtuRead(void)
uint8_t checksum = 0;
uint16_t sensorval = 0;
if (htu_valid) { htu_valid--; }
if (Htu.valid) { Htu.valid--; }
Wire.beginTransmission(HTU21_ADDR);
Wire.write(HTU21_READTEMP);
if (Wire.endTransmission() != 0) { return false; } // In case of error
delay(htu_delay_temp); // Sensor time at max resolution
delay(Htu.delay_temp); // Sensor time at max resolution
Wire.requestFrom(HTU21_ADDR, 3);
if (3 == Wire.available()) {
@ -161,12 +167,12 @@ bool HtuRead(void)
}
if (HtuCheckCrc8(sensorval) != checksum) { return false; } // Checksum mismatch
htu_temperature = ConvertTemp(0.002681 * (float)sensorval - 46.85);
Htu.temperature = ConvertTemp(0.002681 * (float)sensorval - 46.85);
Wire.beginTransmission(HTU21_ADDR);
Wire.write(HTU21_READHUM);
if (Wire.endTransmission() != 0) { return false; } // In case of error
delay(htu_delay_humidity); // Sensor time at max resolution
delay(Htu.delay_humidity); // Sensor time at max resolution
Wire.requestFrom(HTU21_ADDR, 3);
if (3 <= Wire.available()) {
@ -177,19 +183,19 @@ bool HtuRead(void)
if (HtuCheckCrc8(sensorval) != checksum) { return false; } // Checksum mismatch
sensorval ^= 0x02; // clear status bits
htu_humidity = 0.001907 * (float)sensorval - 6;
if (htu_humidity > 100) { htu_humidity = 100.0; }
if (htu_humidity < 0) { htu_humidity = 0.01; }
Htu.humidity = 0.001907 * (float)sensorval - 6;
if (Htu.humidity > 100) { Htu.humidity = 100.0; }
if (Htu.humidity < 0) { Htu.humidity = 0.01; }
if ((0.00 == htu_humidity) && (0.00 == htu_temperature)) {
htu_humidity = 0.0;
if ((0.00 == Htu.humidity) && (0.00 == Htu.temperature)) {
Htu.humidity = 0.0;
}
if ((htu_temperature > 0.00) && (htu_temperature < 80.00)) {
htu_humidity = (-0.15) * (25 - htu_temperature) + htu_humidity;
if ((Htu.temperature > 0.00) && (Htu.temperature < 80.00)) {
Htu.humidity = (-0.15) * (25 - Htu.temperature) + Htu.humidity;
}
htu_humidity = ConvertHumidity(htu_humidity);
Htu.humidity = ConvertHumidity(Htu.humidity);
htu_valid = SENSOR_MAX_MISS;
Htu.valid = SENSOR_MAX_MISS;
return true;
}
@ -197,17 +203,17 @@ bool HtuRead(void)
void HtuDetect(void)
{
htu_address = HTU21_ADDR;
if (I2cActive(htu_address)) { return; }
Htu.address = HTU21_ADDR;
if (I2cActive(Htu.address)) { return; }
htu_type = HtuReadDeviceId();
if (htu_type) {
Htu.type = HtuReadDeviceId();
if (Htu.type) {
uint8_t index = 0;
HtuInit();
switch (htu_type) {
switch (Htu.type) {
case HTU21_CHIPID:
htu_delay_temp = 50;
htu_delay_humidity = 16;
Htu.delay_temp = 50;
Htu.delay_humidity = 16;
break;
case SI7021_CHIPID:
index++; // 3
@ -215,16 +221,16 @@ void HtuDetect(void)
index++; // 2
case SI7013_CHIPID:
index++; // 1
htu_delay_temp = 12;
htu_delay_humidity = 23;
Htu.delay_temp = 12;
Htu.delay_humidity = 23;
break;
default:
index = 4;
htu_delay_temp = 50;
htu_delay_humidity = 23;
Htu.delay_temp = 50;
Htu.delay_humidity = 23;
}
GetTextIndexed(htu_types, sizeof(htu_types), index, kHtuTypes);
I2cSetActiveFound(htu_address, htu_types);
GetTextIndexed(Htu.types, sizeof(Htu.types), index, kHtuTypes);
I2cSetActiveFound(Htu.address, Htu.types);
}
}
@ -233,15 +239,15 @@ void HtuEverySecond(void)
if (uptime &1) { // Every 2 seconds
// HTU21: 68mS, SI70xx: 37mS
if (!HtuRead()) {
AddLogMissed(htu_types, htu_valid);
AddLogMissed(Htu.types, Htu.valid);
}
}
}
void HtuShow(bool json)
{
if (htu_valid) {
TempHumDewShow(json, (0 == tele_period), htu_types, htu_temperature, htu_humidity);
if (Htu.valid) {
TempHumDewShow(json, (0 == tele_period), Htu.types, Htu.temperature, Htu.humidity);
}
}
@ -258,7 +264,7 @@ bool Xsns08(uint8_t function)
if (FUNC_INIT == function) {
HtuDetect();
}
else if (htu_type) {
else if (Htu.type) {
switch (function) {
case FUNC_EVERY_SECOND:
HtuEverySecond();

View File

@ -32,40 +32,39 @@
#define XSNS_22 22
uint8_t sr04_type = 1;
int sr04_echo_pin = 0;
int sr04_trig_pin = 0;
real64_t distance;
NewPing* sonar = nullptr;
TasmotaSerial* sonar_serial = nullptr;
uint8_t Sr04TModeDetect(void)
{
sr04_type = 0;
if (pin[GPIO_SR04_ECHO]>=99) return sr04_type;
if (99 == pin[GPIO_SR04_ECHO]) { return sr04_type; }
sr04_echo_pin = pin[GPIO_SR04_ECHO];
sr04_trig_pin = (pin[GPIO_SR04_TRIG] < 99) ? pin[GPIO_SR04_TRIG] : -1;
int sr04_echo_pin = pin[GPIO_SR04_ECHO];
int sr04_trig_pin = (pin[GPIO_SR04_TRIG] < 99) ? pin[GPIO_SR04_TRIG] : pin[GPIO_SR04_ECHO]; // if GPIO_SR04_TRIG is not configured use single PIN mode with GPIO_SR04_ECHO only
sonar_serial = new TasmotaSerial(sr04_echo_pin, sr04_trig_pin, 1);
if (sonar_serial->begin(9600,1)) {
DEBUG_SENSOR_LOG(PSTR("SR04: Detect mode"));
if (sr04_trig_pin!=-1) {
sr04_type = (Sr04TMiddleValue(Sr04TMode3Distance(),Sr04TMode3Distance(),Sr04TMode3Distance())!=NO_ECHO)?3:1;
if (sr04_trig_pin != -1) {
sr04_type = (Sr04TMiddleValue(Sr04TMode3Distance(), Sr04TMode3Distance(), Sr04TMode3Distance()) != NO_ECHO) ? 3 : 1;
} else {
sr04_type = 2;
sr04_type = 2;
}
} else {
sr04_type = 1;
}
if (sr04_type < 2) {
delete sonar_serial;
sonar_serial = nullptr;
sonar = new NewPing(sr04_trig_pin, sr04_echo_pin, 300);
delete sonar_serial;
sonar_serial = nullptr;
if (-1 == sr04_trig_pin) {
sr04_trig_pin = pin[GPIO_SR04_ECHO]; // if GPIO_SR04_TRIG is not configured use single PIN mode with GPIO_SR04_ECHO only
}
sonar = new NewPing(sr04_trig_pin, sr04_echo_pin, 300);
} else {
if (sonar_serial->hardwareSerial()) {
ClaimSerial();

View File

@ -494,7 +494,7 @@ void HandleHxAction(void)
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_HX711);
if (WebServer->hasArg("save")) {
if (Webserver->hasArg("save")) {
HxSaveSettings();
HandleConfiguration();
return;
@ -502,7 +502,7 @@ void HandleHxAction(void)
char stemp1[20];
if (WebServer->hasArg("reset")) {
if (Webserver->hasArg("reset")) {
snprintf_P(stemp1, sizeof(stemp1), PSTR("Sensor34 1")); // Reset
ExecuteWebCommand(stemp1, SRC_WEBGUI);
@ -510,7 +510,7 @@ void HandleHxAction(void)
return;
}
if (WebServer->hasArg("calibrate")) {
if (Webserver->hasArg("calibrate")) {
WebGetArg("p1", stemp1, sizeof(stemp1));
Settings.weight_reference = (!strlen(stemp1)) ? 0 : (unsigned long)(CharToFloat(stemp1) * 1000);
@ -593,7 +593,7 @@ bool Xsns34(uint8_t function)
WSContentSend_P(HTTP_BTN_MENU_HX711);
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/" WEB_HANDLE_HX711, HandleHxAction);
Webserver->on("/" WEB_HANDLE_HX711, HandleHxAction);
break;
#endif // USE_HX711_GUI
#endif // USE_WEBSERVER

View File

@ -98,7 +98,7 @@ The serial pins are GPS_RX and GPS_TX, no further installation steps needed. To
set latitude and longitude in settings
+ sensor60 14
open virtual serial port over TCP, usable for u-center
open virtual serial port over TCP, usable for u-center
+ sensor60 15
pause virtual serial port over TCP
@ -119,10 +119,6 @@ rule3 on tele-FLOG#sec do DisplayText [f0c1l4]SAV:%value% endon on tele-FLOG#r
#include "NTPServer.h"
#include "NTPPacket.h"
#ifdef ESP32
#include <HardwareSerial.h>
#endif
/*********************************************************************************************\
* constants
\*********************************************************************************************/
@ -137,7 +133,7 @@ const char kUBXTypes[] PROGMEM = "UBX";
#define UBX_SERIAL_BUFFER_SIZE 256
#define UBX_TCP_PORT 1234
#define NTP_MILLIS_OFFSET 50 // estimated latency in milliseconds
#define NTP_MILLIS_OFFSET 50 // estimated latency in milliseconds
/********************************************************************************************\
| *globals
@ -299,11 +295,7 @@ enum UBXMsgType {
#ifdef USE_FLOG
FLOG *Flog = nullptr;
#endif //USE_FLOG
#ifdef ESP8266
TasmotaSerial *UBXSerial;
#else
HardwareSerial *UBXSerial;
#endif
NtpServer timeServer(PortUdp);
@ -363,21 +355,13 @@ void UBXDetect(void)
{
UBX.mode.init = 0;
if ((pin[GPIO_GPS_RX] < 99) && (pin[GPIO_GPS_TX] < 99)) {
#ifdef ESP8266
UBXSerial = new TasmotaSerial(pin[GPIO_GPS_RX], pin[GPIO_GPS_TX], 1, 0, UBX_SERIAL_BUFFER_SIZE); // 64 byte buffer is NOT enough
if (UBXSerial->begin(9600)) {
#else
UBXSerial = new HardwareSerial(2);
UBXSerial->begin(9600,SERIAL_8N1,pin[GPIO_GPS_RX], pin[GPIO_GPS_TX]);
{
#endif
DEBUG_SENSOR_LOG(PSTR("UBX: started serial"));
#ifdef ESP8266
if (UBXSerial->hardwareSerial()) {
ClaimSerial();
DEBUG_SENSOR_LOG(PSTR("UBX: claim HW"));
}
#endif
}
}
else {
@ -504,8 +488,8 @@ uint32_t UBXprocessGPS()
#ifdef USE_FLOG
void UBXsendHeader(void)
{
WebServer->setContentLength(CONTENT_LENGTH_UNKNOWN);
WebServer->sendHeader(F("Content-Disposition"), F("attachment; filename=TASMOTA.gpx"));
Webserver->setContentLength(CONTENT_LENGTH_UNKNOWN);
Webserver->sendHeader(F("Content-Disposition"), F("attachment; filename=TASMOTA.gpx"));
WSSend(200, CT_STREAM, F(
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\r\n"
"<GPX version=\"1.1\" creator=\"TASMOTA\" xmlns=\"http://www.topografix.com/GPX/1/1\" \r\n"
@ -526,13 +510,13 @@ void UBXsendRecord(uint8_t *buf)
dtostrfd((double)entry->lon/10000000.0f,7,lon);
snprintf_P(record, sizeof(record),PSTR("<trkpt\n\t lat=\"%s\" lon=\"%s\">\n\t<time>%s</time>\n</trkpt>\n"),lat ,lon, stime);
// DEBUG_SENSOR_LOG(PSTR("FLOG: DL %u %u"), Flog->sector.dword_buffer[k+j],Flog->sector.dword_buffer[k+j+1]);
WebServer->sendContent_P(record);
Webserver->sendContent_P(record);
}
void UBXsendFooter(void)
{
WebServer->sendContent(F("</trkseg>\n</trk>\n</gpx>"));
WebServer->sendContent("");
Webserver->sendContent(F("</trkseg>\n</trk>\n</gpx>"));
Webserver->sendContent("");
Rtc.user_time_entry = false; // we have blocked the main loop and want a new valid time
}
@ -707,7 +691,7 @@ void UBXHandleTIME()
if (UBX.mode.forceUTCupdate || Rtc.user_time_entry == false){
AddLog_P(LOG_LEVEL_INFO, PSTR("UBX: UTC-Time is valid, set system time"));
Rtc.utc_time = UBX.rec_buffer.values.time;
}
}
Rtc.user_time_entry = true;
}
}
@ -928,7 +912,7 @@ bool Xsns60(uint8_t function)
break;
#ifdef USE_FLOG
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/UBX", UBXsendFile);
Webserver->on("/UBX", UBXsendFile);
break;
#endif //USE_FLOG
case FUNC_JSON_APPEND:

View File

@ -90,7 +90,7 @@ bool Xsns91(uint8_t function)
switch (function) {
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/metrics", HandleMetrics);
Webserver->on("/metrics", HandleMetrics);
break;
}
return result;