Merge remote-tracking branch 'upstream/development' into development

Merge all recent changes into my branch
This commit is contained in:
Jörg R. Weimar 2019-02-22 15:29:36 +01:00
commit f0dde50f39
60 changed files with 2477 additions and 7075 deletions

86
TEMPLATE.md Normal file
View File

@ -0,0 +1,86 @@
## Sonoff-Tasmota template information
Sonoff-Tasmota uses Device or Module information to control peripherals connected to GPIOs. This information is stored in the ``sonoff_template.h`` file as a device specific template. The template contains information about what GPIO should be connected to what peripheral and what GPIO may be configured online using the ``GPIO`` command or GUI Configure Module menu. In addition a device may need specific coding to process the data from these peripherals. The module number as provided by the ``Modules`` command is used to select this coding.
Starting with version 6.4.1.16 Sonoff-Tasmota Modules can be extended by users online using a template. To provide easy processing by Sonoff-Tasmota a user template is written as JSON text and could look like this:
{"NAME":"UserModule1","GPIO":[17,148,29,149,7,255,255,255,138,255,139,255,255],"FLAG":0,"BASE":18}
The four properties with UPPERCASE property names have the following functionality:
Property name | Property value description
--------------|-------------------------------------------------------------------------------------------------------------------
NAME | Up to 14 characters for the Module name
GPIO | Up to 13 decimal numbers from 0 to 255 representing GPIO0 to GPIO5, GPIO09, GPIO10 and GPIO12 to GPIO16
FLAG | 8 bit mask flag register
BASE | Module number of a hard-coded device to be used when device specific functionality is needed
The above example, based on the Generic Module does not allow ADC0 input.
## GPIO functionality
The GPIO functionality numbers are the same is shown by command ``GPIOs``. In addition code 255 is added to select a GPIO as user configurable via the GUI Configure Module menu.
## FLAG functionality
The FLAG value is an 8-bit mask where each bit controls a features. Add FLAG values to set multiple bits.
FLAG | Mask | Feature description
-----|----------|------------------------------
1 | xxxxxxx1 | Allowing to use Analog0 (ADC0) as input if define USE_ADC_VCC in ``my_user_config.h`` is disabled
2 | xxxxxx1x | Enable GUI pull-up control message
4 | xxxxx1xx | Not used
8 | xxxx1xxx | Not used
16 | xxx1xxxx | Not used
32 | xx1xxxxx | Not used
64 | x1xxxxxx | Not used
128 | 1xxxxxxx | Not used
## BASE functionality
The following table lists hard-coded device specific functionality. Notice that not all device modules need special handling.
BASE | Module | Description
-----|----------------|----------------------------------------------
4 | Sonoff Dual | Process relay and button via hardware serial interface using GPIO01 and GPIO03. Change baudrate to 19200 bps. Process buttons as single press only
9 | Sonoff Touch | Invert ledstate 1 functionality
10 | Sonoff LED | Set light type to 2 PWM channels disregarding SetOption15. Fix device specific LED instabilities by disabling GPIO04, GPIO5 and GPIO14
12 | 4 Channel | See 4
13 | Motor C/AC | Force all relays ON at Power On and disable command ``PowerOnState``
15 | EXS Relay(s) | Enable pulse latching using even/odd numbered relay pairs
18 | Generic | Show Wemos specific pin information in GUI
19 | H801 | Change hardware UART Tx from GPIO01 to GPIO02
20 | Sonoff SC | Enable and Process data via hardware serial interface using GPIO01 and GPIO03. Change baudrate to 19200 bps
21 | Sonoff BN-SZ | Set light type to 1 PWM channel disregarding SetOption15
22 | Sonoff 4CH Pro | Button handling disregarding SetOption13 only allowing single press to enable RF learning while holding the button
24 | Sonoff Bridge | Enable and Process data via hardware serial interface using GPIO01 and GPIO03. Change baudrate to 19200 bps. Process 16 buttons in web GUI. Enable EFM8BB1 firmware upload
25 | Sonoff B1 | Set light type to RGBWC using MY92x1
26 | AiLight | Set light type to RGBW using MY92x1
27 | Sonoff T1 1CH | See 9
28 | Sonoff T1 2CH | See 9
29 | Sonoff T1 3CH | See 9
38 | Sonoff Dual R2 | Process buttons as single press only
43 | Sonoff iFan02 | Enable command ``Fanspeed``. Disable Interlock and PulseTime. Tune status information, MQTT data and GUI. Sync with microcontroller. Process Domoticz Fan state
47 | Xiaomi Philips | Process Color Temperature using PWM2 and Intensity using PWM1
53 | Tuya Dimmer | Enable and Process data via software or hardware serial interface using GPIO 148 and 149 or forced GPIO01 and GPIO03. Change baudrate to 9600 bps. Process all Buttons
55 | ARMTR Dimmer | Enable and Process data via software or hardware serial interface using GPIO 148 and 149. Change baudrate to 115200 bps.
57 | PS-16-DZ | Enable and Process data via software or hardware serial interface using GPIO 148 and 149. Change baudrate to 19200 bps.
61 | YTF IR Bridge | Disable serial interface to stop loopback
65 | Mi Desk Lamp | Process rotary and Button1 data specific to this device
## Usage
A user provided template can be stored in Sonoff-Tasmota using the ``Template`` command. It has the following options.
Command | Payload | Description
---------|----------|---------------------------------------
Template | | Show current user template
Template | 0 | Copy active module template to user template
Template | 1 .. 69 | Copy hard-coded module template to user template
The following command will store a complete template based on the Generic module
``Template {"NAME":"UserModule1","GPIO":[17,148,29,149,7,255,255,255,138,255,139,255,255],"FLAG":0,"BASE":18}``
The following command will update the name of a stored template
``Template {"NAME":"UserModule2"}``
The following command will update the flag of a stored template
``Template {"FLAG":1}``
The following command will update the base of a stored template to Generic
``Template {"BASE":0}``

File diff suppressed because it is too large Load Diff

View File

@ -1,156 +0,0 @@
# ESP8266 platform
# ------------------------------
# For more info:
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
name=ESP8266 Boards (2.5.0-beta2)
version=2.5.0-beta2
runtime.tools.signing={runtime.platform.path}/tools/signing.py
compiler.warning_flags=-w
compiler.warning_flags.none=-w
compiler.warning_flags.default=
compiler.warning_flags.more=-Wall
compiler.warning_flags.all=-Wall -Wextra
build.lwip_lib=-llwip_gcc
build.lwip_include=lwip/include
build.lwip_flags=-DLWIP_OPEN_SRC
build.vtable_flags=-DVTABLES_IN_FLASH
#build.exception_flags=-fexceptions
build.exception_flags=-fno-exceptions
#build.stdcpp_lib=-lstdc++
build.stdcpp_lib=-lstdc++-nox
#build.float=-u _printf_float -u _scanf_float
build.float=
build.led=
compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/
compiler.sdk.path={runtime.platform.path}/tools/sdk
compiler.libc.path={runtime.platform.path}/tools/sdk/libc/xtensa-lx106-elf
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include" "-I{compiler.sdk.path}/{build.lwip_include}" "-I{compiler.libc.path}/include" "-I{build.path}/core"
compiler.c.cmd=xtensa-lx106-elf-gcc
compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 {build.exception_flags} -ffunction-sections -fdata-sections {build.exception_flags}
compiler.S.cmd=xtensa-lx106-elf-gcc
compiler.S.flags=-c -g -x assembler-with-cpp -MMD -mlongcalls
compiler.c.elf.flags=-g {compiler.warning_flags} -Os -nostdlib -Wl,--no-check-sections -u app_entry {build.float} -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-L{compiler.libc.path}/lib" "-T{build.flash_ld}" -Wl,--gc-sections -Wl,-wrap,system_restart_local -Wl,-wrap,spi_flash_read
compiler.c.elf.cmd=xtensa-lx106-elf-gcc
compiler.c.elf.libs=-lhal -lphy -lpp -lnet80211 {build.lwip_lib} -lwpa -lcrypto -lmain -lwps -lbearssl -laxtls -lespnow -lsmartconfig -lairkiss -lwpa2 {build.stdcpp_lib} -lm -lc -lgcc
compiler.cpp.cmd=xtensa-lx106-elf-g++
compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections {build.exception_flags}
compiler.as.cmd=xtensa-lx106-elf-as
compiler.ar.cmd=xtensa-lx106-elf-ar
compiler.ar.flags=cru
compiler.elf2hex.cmd=esptool
compiler.elf2hex.flags=
compiler.size.cmd=xtensa-lx106-elf-size
compiler.esptool.cmd=esptool
compiler.esptool.cmd.windows=esptool.exe
# This can be overriden in boards.txt
build.extra_flags=-DESP8266
# These can be overridden in platform.local.txt
compiler.c.extra_flags=
compiler.c.elf.extra_flags=
compiler.S.extra_flags=
compiler.cpp.extra_flags=
compiler.ar.extra_flags=
compiler.objcopy.eep.extra_flags=
compiler.elf2hex.extra_flags=
## generate file with git version number
## needs bash, git, and echo
recipe.hooks.core.prebuild.1.pattern=python "{runtime.tools.signing}" --mode header --publickey "{build.source.path}/public.key" --out "{build.path}/core/Updater_Signing.h"
## windows-compatible version without git
recipe.hooks.core.prebuild.1.pattern.windows=cmd.exe /c rem cannot sign on windows
## Build the app.ld linker file
recipe.hooks.linking.prelink.1.pattern="{compiler.path}{compiler.c.cmd}" -CC -E -P {build.vtable_flags} "{runtime.platform.path}/tools/sdk/ld/eagle.app.v6.common.ld.h" -o "{build.path}/local.eagle.app.v6.common.ld"
## Compile c files
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
## Compile c++ files
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
## Compile S files
recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
## Create archives
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}"
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" -Wl,-Map "-Wl,{build.path}/{build.project_name}.map" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{archive_file_path}" {compiler.c.elf.libs} -Wl,--end-group "-L{build.path}"
## Create eeprom
recipe.objcopy.eep.pattern=
## Create hex
#recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex"
recipe.objcopy.hex.1.pattern="{runtime.tools.esptool.path}/{compiler.esptool.cmd}" -eo "{runtime.platform.path}/bootloaders/eboot/eboot.elf" -bo "{build.path}/{build.project_name}.bin" -bm {build.flash_mode} -bf {build.flash_freq} -bz {build.flash_size} -bs .text -bp 4096 -ec -eo "{build.path}/{build.project_name}.elf" -bs .irom0.text -bs .text -bs .data -bs .rodata -bc -ec
recipe.objcopy.hex.2.pattern=python "{runtime.tools.signing}" --mode sign --privatekey "{build.source.path}/private.key" --bin "{build.path}/{build.project_name}.bin" --out "{build.path}/{build.project_name}.bin.signed"
# No signing on Windows
recipe.objcopy.hex.1.pattern.windows="{runtime.tools.esptool.path}/{compiler.esptool.cmd}" -eo "{runtime.platform.path}/bootloaders/eboot/eboot.elf" -bo "{build.path}/{build.project_name}.bin" -bm {build.flash_mode} -bf {build.flash_freq} -bz {build.flash_size} -bs .text -bp 4096 -ec -eo "{build.path}/{build.project_name}.elf" -bs .irom0.text -bs .text -bs .data -bs .rodata -bc -ec
recipe.objcopy.hex.2.pattern.windows=
## Save hex
recipe.output.tmp_file={build.project_name}.bin
recipe.output.save_file={build.project_name}.{build.variant}.bin
## Compute size
recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf"
recipe.size.regex=^(?:\.irom0\.text|\.text|\.data|\.rodata|)\s+([0-9]+).*
recipe.size.regex.data=^(?:\.data|\.rodata|\.bss)\s+([0-9]+).*
#recipe.size.regex.eeprom=^(?:\.eeprom)\s+([0-9]+).*
# ------------------------------
tools.esptool.cmd=esptool
tools.esptool.cmd.windows=esptool.exe
tools.esptool.path={runtime.tools.esptool.path}
tools.esptool.network_cmd=python
tools.esptool.network_cmd.windows=python.exe
tools.esptool.upload.protocol=esp
tools.esptool.upload.params.verbose=-vv
tools.esptool.upload.params.quiet=
tools.esptool.upload.pattern="{path}/{cmd}" {upload.verbose} -cd {upload.resetmethod} -cb {upload.speed} -cp "{serial.port}" {upload.erase_cmd} -ca 0x00000 -cf "{build.path}/{build.project_name}.bin"
tools.esptool.upload.network_pattern="{network_cmd}" "{runtime.platform.path}/tools/espota.py" -i "{serial.port}" -p "{network.port}" "--auth={network.password}" -f "{build.path}/{build.project_name}.bin"
tools.mkspiffs.cmd=mkspiffs
tools.mkspiffs.cmd.windows=mkspiffs.exe
tools.mkspiffs.path={runtime.tools.mkspiffs.path}
tools.espupload.cmd=python
tools.espupload.cmd.windows=python.exe
tools.espupload.path={runtime.platform.path}/tools
tools.espupload.upload.protocol=espupload
tools.espupload.upload.params.verbose=
tools.espupload.upload.params.quiet=
tools.espupload.upload.pattern="{cmd}" "{path}/espupload.py" -f "{build.path}/{build.project_name}.bin"

View File

@ -1330,8 +1330,8 @@ cw01.upload.resetmethod=nodemcu
cw01.menu.CrystalFreq.26=26 MHz cw01.menu.CrystalFreq.26=26 MHz
cw01.menu.CrystalFreq.40=40 MHz cw01.menu.CrystalFreq.40=40 MHz
cw01.menu.CrystalFreq.40.build.extra_flags=-DF_CRYSTAL=40000000 -DESP8266 cw01.menu.CrystalFreq.40.build.extra_flags=-DF_CRYSTAL=40000000 -DESP8266
cw01.build.flash_mode=qio cw01.build.flash_mode=dio
cw01.build.flash_flags=-DFLASHMODE_QIO cw01.build.flash_flags=-DFLASHMODE_DIO
cw01.build.flash_freq=40 cw01.build.flash_freq=40
cw01.menu.eesz.4M=4M (no SPIFFS) cw01.menu.eesz.4M=4M (no SPIFFS)
cw01.menu.eesz.4M.build.flash_size=4M cw01.menu.eesz.4M.build.flash_size=4M
@ -6119,4 +6119,3 @@ espectro.menu.baud.512000.windows=512000
espectro.menu.baud.512000.upload.speed=512000 espectro.menu.baud.512000.upload.speed=512000
espectro.menu.baud.921600=921600 espectro.menu.baud.921600=921600
espectro.menu.baud.921600.upload.speed=921600 espectro.menu.baud.921600.upload.speed=921600

View File

@ -5,11 +5,11 @@
# For more info: # For more info:
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
name=ESP8266 Boards (2.5.0-beta3) name=ESP8266 Boards (2.5.0)
version=2.5.0-beta3 version=2.5.0
runtime.tools.xtensa-lx106-elf-gcc.path={runtime.platform.path}/tools/xtensa-lx106-elf
runtime.tools.esptool.path={runtime.platform.path}/tools/esptool
runtime.tools.signing={runtime.platform.path}/tools/signing.py runtime.tools.signing={runtime.platform.path}/tools/signing.py
compiler.warning_flags=-w compiler.warning_flags=-w
@ -78,13 +78,13 @@ compiler.elf2hex.extra_flags=
## generate file with git version number ## generate file with git version number
## needs bash, git, and echo ## needs bash, git, and echo
recipe.hooks.core.prebuild.1.pattern=python "{runtime.tools.signing}" --mode header --publickey "{build.source.path}/public.key" --out "{build.path}/core/Updater_Signing.h" recipe.hooks.core.prebuild.1.pattern=python "{runtime.tools.signing}" --mode header --publickey "{build.source.path}/public.key" --out "{build.path}/core/Updater_Signing.h"
recipe.hooks.core.prebuild.2.pattern=bash -c "mkdir -p {build.path}/core && echo \#define ARDUINO_ESP8266_GIT_VER 0x`git --git-dir {runtime.platform.path}/.git rev-parse --short=8 HEAD 2>/dev/null || echo ffffffff` >{build.path}/core/core_version.h"
recipe.hooks.core.prebuild.3.pattern=bash -c "mkdir -p {build.path}/core && echo \#define ARDUINO_ESP8266_GIT_DESC `cd "{runtime.platform.path}"; git describe --tags 2>/dev/null || echo unix-{version}` >>{build.path}/core/core_version.h"
## windows-compatible version without git ## windows-compatible version without git
recipe.hooks.core.prebuild.1.pattern.windows=cmd.exe /c rem cannot sign on windows recipe.hooks.core.prebuild.1.pattern.windows=cmd.exe /c rem cannot sign on windows
recipe.hooks.core.prebuild.2.pattern.windows=cmd.exe /c mkdir {build.path}\core & (echo #define ARDUINO_ESP8266_GIT_VER 0x00000000 & echo #define ARDUINO_ESP8266_GIT_DESC win-{version} ) > {build.path}\core\core_version.h
recipe.hooks.core.prebuild.3.pattern.windows=cmd.exe /c if exist {build.source.path}\public.key echo #error Cannot automatically build signed binaries on Windows > {build.path}\core\Updater_Signing.h
## Build the app.ld linker file ## Build the app.ld linker file
recipe.hooks.linking.prelink.1.pattern="{compiler.path}{compiler.c.cmd}" -CC -E -P {build.vtable_flags} "{runtime.platform.path}/tools/sdk/ld/eagle.app.v6.common.ld.h" -o "{build.path}/local.eagle.app.v6.common.ld" recipe.hooks.linking.prelink.1.pattern="{compiler.path}{compiler.c.cmd}" -CC -E -P {build.vtable_flags} "{runtime.platform.path}/tools/sdk/ld/eagle.app.v6.common.ld.h" -o "{build.path}/local.eagle.app.v6.common.ld"
@ -152,3 +152,4 @@ tools.espupload.upload.protocol=espupload
tools.espupload.upload.params.verbose= tools.espupload.upload.params.verbose=
tools.espupload.upload.params.quiet= tools.espupload.upload.params.quiet=
tools.espupload.upload.pattern="{cmd}" "{path}/espupload.py" -f "{build.path}/{build.project_name}.bin" tools.espupload.upload.pattern="{cmd}" "{path}/espupload.py" -f "{build.path}/{build.project_name}.bin"

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Ivan Seidel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,325 @@
/*
LinkedList.h - V1.1 - Generic LinkedList implementation
Works better with FIFO, because LIFO will need to
search the entire List to find the last one;
For instructions, go to https://github.com/ivanseidel/LinkedList
Created by Ivan Seidel Gomes, March, 2013.
Released into the public domain.
*/
#ifndef LinkedList_h
#define LinkedList_h
#include <stddef.h>
template<class T>
struct ListNode
{
T data;
ListNode<T> *next;
};
template <typename T>
class LinkedList{
protected:
int _size;
ListNode<T> *root;
ListNode<T> *last;
// Helps "get" method, by saving last position
ListNode<T> *lastNodeGot;
int lastIndexGot;
// isCached should be set to FALSE
// everytime the list suffer changes
bool isCached;
ListNode<T>* getNode(int index);
public:
LinkedList();
~LinkedList();
/*
Returns current size of LinkedList
*/
virtual int size();
/*
Adds a T object in the specified index;
Unlink and link the LinkedList correcly;
Increment _size
*/
virtual bool add(int index, T);
/*
Adds a T object in the end of the LinkedList;
Increment _size;
*/
virtual bool add(T);
/*
Adds a T object in the start of the LinkedList;
Increment _size;
*/
virtual bool unshift(T);
/*
Set the object at index, with T;
Increment _size;
*/
virtual bool set(int index, T);
/*
Remove object at index;
If index is not reachable, returns false;
else, decrement _size
*/
virtual T remove(int index);
/*
Remove last object;
*/
virtual T pop();
/*
Remove first object;
*/
virtual T shift();
/*
Get the index'th element on the list;
Return Element if accessible,
else, return false;
*/
virtual T get(int index);
/*
Clear the entire array
*/
virtual void clear();
};
// Initialize LinkedList with false values
template<typename T>
LinkedList<T>::LinkedList()
{
root=NULL;
last=NULL;
_size=0;
lastNodeGot = root;
lastIndexGot = 0;
isCached = false;
}
// Clear Nodes and free Memory
template<typename T>
LinkedList<T>::~LinkedList()
{
ListNode<T>* tmp;
while(root!=NULL)
{
tmp=root;
root=root->next;
delete tmp;
}
last = NULL;
_size=0;
isCached = false;
}
/*
Actualy "logic" coding
*/
template<typename T>
ListNode<T>* LinkedList<T>::getNode(int index){
int _pos = 0;
ListNode<T>* current = root;
// Check if the node trying to get is
// immediatly AFTER the previous got one
if(isCached && lastIndexGot <= index){
_pos = lastIndexGot;
current = lastNodeGot;
}
while(_pos < index && current){
current = current->next;
_pos++;
}
// Check if the object index got is the same as the required
if(_pos == index){
isCached = true;
lastIndexGot = index;
lastNodeGot = current;
return current;
}
return false;
}
template<typename T>
int LinkedList<T>::size(){
return _size;
}
template<typename T>
bool LinkedList<T>::add(int index, T _t){
if(index >= _size)
return add(_t);
if(index == 0)
return unshift(_t);
ListNode<T> *tmp = new ListNode<T>(),
*_prev = getNode(index-1);
tmp->data = _t;
tmp->next = _prev->next;
_prev->next = tmp;
_size++;
isCached = false;
return true;
}
template<typename T>
bool LinkedList<T>::add(T _t){
ListNode<T> *tmp = new ListNode<T>();
tmp->data = _t;
tmp->next = NULL;
if(root){
// Already have elements inserted
last->next = tmp;
last = tmp;
}else{
// First element being inserted
root = tmp;
last = tmp;
}
_size++;
isCached = false;
return true;
}
template<typename T>
bool LinkedList<T>::unshift(T _t){
if(_size == 0)
return add(_t);
ListNode<T> *tmp = new ListNode<T>();
tmp->next = root;
tmp->data = _t;
root = tmp;
_size++;
isCached = false;
return true;
}
template<typename T>
bool LinkedList<T>::set(int index, T _t){
// Check if index position is in bounds
if(index < 0 || index >= _size)
return false;
getNode(index)->data = _t;
return true;
}
template<typename T>
T LinkedList<T>::pop(){
if(_size <= 0)
return T();
isCached = false;
if(_size >= 2){
ListNode<T> *tmp = getNode(_size - 2);
T ret = tmp->next->data;
delete(tmp->next);
tmp->next = NULL;
last = tmp;
_size--;
return ret;
}else{
// Only one element left on the list
T ret = root->data;
delete(root);
root = NULL;
last = NULL;
_size = 0;
return ret;
}
}
template<typename T>
T LinkedList<T>::shift(){
if(_size <= 0)
return T();
if(_size > 1){
ListNode<T> *_next = root->next;
T ret = root->data;
delete(root);
root = _next;
_size --;
isCached = false;
return ret;
}else{
// Only one left, then pop()
return pop();
}
}
template<typename T>
T LinkedList<T>::remove(int index){
if (index < 0 || index >= _size)
{
return T();
}
if(index == 0)
return shift();
if (index == _size-1)
{
return pop();
}
ListNode<T> *tmp = getNode(index - 1);
ListNode<T> *toDelete = tmp->next;
T ret = toDelete->data;
tmp->next = tmp->next->next;
delete(toDelete);
_size--;
isCached = false;
return ret;
}
template<typename T>
T LinkedList<T>::get(int index){
ListNode<T> *tmp = getNode(index);
return (tmp ? tmp->data : T());
}
template<typename T>
void LinkedList<T>::clear(){
while(size() > 0)
shift();
}
#endif

View File

@ -0,0 +1,171 @@
# LinkedList
This library was developed targeting **`Arduino`** applications. However, works just great with any C++.
Implementing a buffer for objects takes time. If we are not in the mood, we just create an `array[1000]` with enough size.
The objective of this library is to create a pattern for projects.
If you need to use a List of: `int`, `float`, `objects`, `Lists` or `Wales`. **This is what you are looking for.**
With a simple but powerful caching algorithm, you can get subsequent objects much faster than usual. Tested without any problems with Lists bigger than 2000 members.
## Installation
1. [Download](https://github.com/ivanseidel/LinkedList/archive/master.zip) the Latest release from gitHub.
2. Unzip and modify the Folder name to "LinkedList" (Remove the '-version')
3. Paste the modified folder on your Library folder (On your `Libraries` folder inside Sketchbooks or Arduino software).
4. Reopen the Arduino software.
**If you are here, because another Library requires this class, just don't waste time reading bellow. Install and ready.**
-------------------------
## Getting started
### The `LinkedList` class
In case you don't know what a LinkedList is and what it's used for, take a quick look at [Wikipedia::LinkedList](https://en.wikipedia.org/wiki/Linked_list) before continuing.
#### To declare a LinkedList object
```c++
// Instantiate a LinkedList that will hold 'integer'
LinkedList<int> myLinkedList = LinkedList<int>();
// Or just this
LinkedList<int> myLinkedList;
// But if you are instantiating a pointer LinkedList...
LinkedList<int> *myLinkedList = new LinkedList<int>();
// If you want a LinkedList with any other type such as 'MyClass'
// Make sure you call delete(MyClass) when you remove!
LinkedList<MyClass> *myLinkedList = new LinkedList<MyClass>();
```
#### Getting the size of the linked list
```c++
// To get the size of a linked list, make use of the size() method
int theSize = myList.size();
// Notice that if it's pointer to the linked list, you should use -> instead
int theSize = myList->size();
```
#### Adding elements
```c++
// add(obj) method will insert at the END of the list
myList.add(myObject);
// add(index, obj) method will try to insert the object at the specified index
myList.add(0, myObject); // Add at the beginning
myList.add(3, myObject); // Add at index 3
// unshift(obj) method will insert the object at the beginning
myList.unshift(myObject);
```
#### Getting elements
```c++
// get(index) will return the element at index
// (notice that the start element is 0, not 1)
// Get the FIRST element
myObject = myList.get(0);
// Get the third element
myObject = myList.get(2);
// Get the LAST element
myObject = myList.get(myList.size() - 1);
```
#### Changing elements
```c++
// set(index, obj) method will change the object at index to obj
// Change the first element to myObject
myList.set(0, myObject);
// Change the third element to myObject
myList.set(2, myObject);
// Change the LAST element of the list
myList.set(myList.size() - 1, myObject);
```
#### Removing elements
```c++
// remove(index) will remove and return the element at index
// Remove the first object
myList.remove(0);
// Get and Delete the third element
myDeletedObject = myList.remove(2);
// pop() will remove and return the LAST element
myDeletedObject = myList.pop();
// shift() will remove and return the FIRST element
myDeletedObject = myList.shift();
// clear() will erase the entire list, leaving it with 0 elements
// NOTE: Clear wont DELETE/FREE memory from Pointers, if you
// are using Classes/Poiners, manualy delete and free those.
myList.clear();
```
------------------------
## Library Reference
### `ListNode` struct
- `T` `ListNode::data` - The object data
- `ListNode<T>` `*next` - Pointer to the next Node
### `LinkedList` class
**`boolean` methods returns if succeeded**
- `LinkedList<T>::LinkedList()` - Constructor.
- `LinkedList<T>::~LinkedList()` - Destructor. Clear Nodes to minimize memory. Does not free pointer memory.
- `int` `LinkedList<T>::size()` - Returns the current size of the list.
- `bool` `LinkedList<T>::add(T)` - Add element T at the END of the list.
- `bool` `LinkedList<T>::add(int index, T)` - Add element T at `index` of the list.
- `bool` `LinkedList<T>::unshift(T)` - Add element T at the BEGINNING of the list.
- `bool` `LinkedList<T>::set(int index, T)` - Set the element at `index` to T.
- `T` `LinkedList<T>::remove(int index)` - Remove element at `index`. Return the removed element. Does not free pointer memory
- `T` `LinkedList<T>::pop()` - Remove the LAST element. Return the removed element.
- `T` `LinkedList<T>::shift()` - Remove the FIRST element. Return the removed element.
- `T` `LinkedList<T>::get(int index)` - Return the element at `index`.
- `void` `LinkedList<T>::clear()` - Removes all elements. Does not free pointer memory.
- **protected** `int` `LinkedList<T>::_size` - Holds the cached size of the list.
- **protected** `ListNode<T>` `LinkedList<T>::*root` - Holds the root node of the list.
- **protected** `ListNode<T>` `LinkedList<T>::*last` - Holds the last node of the list.
- **protected** `ListNode<T>*` `LinkedList<T>::getNode(int index)` - Returns the `index` node of the list.
### Version History
* `1.1 (2013-07-20)`: Cache implemented. Getting subsequent objects is now O(N). Before, O(N^2).
* `1.0 (2013-07-20)`: Original release
![LinkedList](https://d2weczhvl823v0.cloudfront.net/ivanseidel/LinkedList/trend.png)

View File

@ -0,0 +1,81 @@
/*
LinkedList Example
Link: http://github.com/ivanseidel/LinkedList
Example Created by
Tom Stewart, github.com/tastewar
Edited by:
Ivan Seidel, github.com/ivanseidel
*/
#include <LinkedList.h>
// Let's define a new class
class Animal {
public:
char *name;
bool isMammal;
};
char catname[]="kitty";
char dogname[]="doggie";
char emuname[]="emu";
LinkedList<Animal*> myAnimalList = LinkedList<Animal*>();
void setup()
{
Serial.begin(9600);
Serial.println("Hello!" );
// Create a Cat
Animal *cat = new Animal();
cat->name = catname;
cat->isMammal = true;
// Create a dog
Animal *dog = new Animal();
dog->name = dogname;
dog->isMammal = true;
// Create a emu
Animal *emu = new Animal();
emu->name = emuname;
emu->isMammal = false; // just an example; no offense to pig lovers
// Add animals to list
myAnimalList.add(cat);
myAnimalList.add(emu);
myAnimalList.add(dog);
}
void loop() {
Serial.print("There are ");
Serial.print(myAnimalList.size());
Serial.print(" animals in the list. The mammals are: ");
int current = 0;
Animal *animal;
for(int i = 0; i < myAnimalList.size(); i++){
// Get animal from list
animal = myAnimalList.get(i);
// If its a mammal, then print it's name
if(animal->isMammal){
// Avoid printing spacer on the first element
if(current++)
Serial.print(", ");
// Print animal name
Serial.print(animal->name);
}
}
Serial.println(".");
while (true); // nothing else to do, loop forever
}

View File

@ -0,0 +1,58 @@
/*
LinkedList Example
Link: http://github.com/ivanseidel/LinkedList
Example Created by
Tom Stewart, github.com/tastewar
Edited by:
Ivan Seidel, github.com/ivanseidel
*/
#include <LinkedList.h>
LinkedList<int> myList = LinkedList<int>();
void setup()
{
Serial.begin(9600);
Serial.println("Hello!");
// Add some stuff to the list
int k = -240,
l = 123,
m = -2,
n = 222;
myList.add(n);
myList.add(0);
myList.add(l);
myList.add(17);
myList.add(k);
myList.add(m);
}
void loop() {
int listSize = myList.size();
Serial.print("There are ");
Serial.print(listSize);
Serial.print(" integers in the list. The negative ones are: ");
// Print Negative numbers
for (int h = 0; h < listSize; h++) {
// Get value from list
int val = myList.get(h);
// If the value is negative, print it
if (val < 0) {
Serial.print(" ");
Serial.print(val);
}
}
while (true); // nothing else to do, loop forever
}

View File

@ -0,0 +1,28 @@
#######################################
# Syntax Coloring
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
LinkedList KEYWORD1
ListNode KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
size KEYWORD2
add KEYWORD2
unshift KEYWORD2
set KEYWORD2
remove KEYWORD2
pop KEYWORD2
shift KEYWORD2
get KEYWORD2
clear KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,12 @@
{
"name": "LinkedList",
"keywords": "pattern",
"description": "A fully implemented LinkedList (int, float, objects, Lists or Wales) made to work with Arduino projects",
"repository":
{
"type": "git",
"url": "https://github.com/ivanseidel/LinkedList.git"
},
"frameworks": "arduino",
"platforms": "*"
}

View File

@ -0,0 +1,9 @@
name=LinkedList
version=1.2.3
author=Ivan Seidel <ivanseidel@gmail.com>
maintainer=Ivan Seidel <ivanseidel@gmail.com>
sentence=A fully implemented LinkedList made to work with Arduino projects
paragraph=The objective of this library is to create a pattern for projects. If you need to use a List of: int, float, objects, Lists or Wales. This is what you are looking for.
category=Data Processing
url=https://github.com/ivanseidel/LinkedList
architectures=*

View File

@ -65,8 +65,8 @@ build_flags = ${esp82xx_defaults.build_flags}
-DVTABLES_IN_FLASH -DVTABLES_IN_FLASH
[core_2_5_0] [core_2_5_0]
; *** Esp8266 core for Arduino version 2.5.0 release (still not available via platformio) ; *** Esp8266 core for Arduino version 2.5.0
platform = https://github.com/Jason2866/platform-espressif8266.git#Tasmota platform = espressif8266@2.0.0
build_flags = ${esp82xx_defaults.build_flags} build_flags = ${esp82xx_defaults.build_flags}
-Wl,-Teagle.flash.1m.ld -Wl,-Teagle.flash.1m.ld
; lwIP 1.4 (Default) ; lwIP 1.4 (Default)

View File

@ -1,5 +1,26 @@
/* 6.4.1.16 20190211 /* 6.4.1.18 20191221
* Initial support for online template change using command Template (#5177) * Fix some exceptions and watchdogs due to lack of stack space - part 1 (#5215)
* Fix some exceptions and watchdogs due to lack of stack space - part 2
* Add command SetOption62 0/1 to disable retain on Button or Swith hold messages (#5299)
* Add option WifiConfig 7 to allow reset of device in AP mode without admin password (#5297)
* Fix command WebSend when using a port number as regression from 6.4.1.17 (#5304)
*
* 6.4.1.17 20190214
* Change template update by removing possibility to add user module config keeping template as defined (#5222)
* Fix regression from 6.4.1.16 where GPIO9 and GPIO10 connected devices did not work (#5197)
* Fix GUI wifi password acception starting with asteriks (*) (#5231, #5242)
* Add rule expression enabled by define USE_EXPRESSION in my_user_config.h (#5210)
* Add Configure Template menu option to GUI (#5222)
* Remove command SetOption62 as it's functionality is replaced by user changing the device template (#5255)
* Add property LinkCount to state and status 11 message representing number of Wifi Link re-connections
* Add property MqttCount to status 6 message representing number of Mqtt re-connections
* Add property Downtime to state and status 11 message representing the duration of wifi connection loss
* Fix command WebSend intermittent results (#5273)
*
* 6.4.1.16 20190211
* Initial support for online template change using command Template or GUI Configure Other (#5177)
* Add parameter CFG_HOLDER to status 1 message (#5206)
* Update GUI
* *
* 6.4.1.15 20190208 * 6.4.1.15 20190208
* Change image name BE_MINIMAL to FIRMWARE_MINIMAL (#5106) * Change image name BE_MINIMAL to FIRMWARE_MINIMAL (#5106)

View File

@ -44,6 +44,7 @@
#define D_JSON_CHANNEL "Channel" #define D_JSON_CHANNEL "Channel"
#define D_JSON_CO2 "CarbonDioxide" #define D_JSON_CO2 "CarbonDioxide"
#define D_JSON_COMMAND "Command" #define D_JSON_COMMAND "Command"
#define D_JSON_CONFIG_HOLDER "CfgHolder"
#define D_JSON_CONNECT_FAILED "Connect failed" #define D_JSON_CONNECT_FAILED "Connect failed"
#define D_JSON_COREVERSION "Core" #define D_JSON_COREVERSION "Core"
#define D_JSON_COUNT "Count" #define D_JSON_COUNT "Count"
@ -53,6 +54,7 @@
#define D_JSON_DISTANCE "Distance" #define D_JSON_DISTANCE "Distance"
#define D_JSON_DNSSERVER "DNSServer" #define D_JSON_DNSSERVER "DNSServer"
#define D_JSON_DONE "Done" #define D_JSON_DONE "Done"
#define D_JSON_DOWNTIME "Downtime"
#define D_JSON_ECO2 "eCO2" #define D_JSON_ECO2 "eCO2"
#define D_JSON_EMPTY "Empty" #define D_JSON_EMPTY "Empty"
#define D_JSON_ENDDST "EndDST" // End Daylight Savings Time #define D_JSON_ENDDST "EndDST" // End Daylight Savings Time
@ -88,12 +90,14 @@
#define D_JSON_INFRARED "Infrared" #define D_JSON_INFRARED "Infrared"
#define D_JSON_UNKNOWN "Unknown" #define D_JSON_UNKNOWN "Unknown"
#define D_JSON_LIGHT "Light" #define D_JSON_LIGHT "Light"
#define D_JSON_LINK_COUNT "LinkCount"
#define D_JSON_LOCAL_TIME "Local" #define D_JSON_LOCAL_TIME "Local"
#define D_JSON_LOW "Low" #define D_JSON_LOW "Low"
#define D_JSON_MAC "Mac" #define D_JSON_MAC "Mac"
#define D_JSON_MASK "Mask" #define D_JSON_MASK "Mask"
#define D_JSON_MINIMAL "minimal" #define D_JSON_MINIMAL "minimal"
#define D_JSON_MODEL "Model" #define D_JSON_MODEL "Model"
#define D_JSON_MQTT_COUNT "MqttCount"
#define D_JSON_NO "No" #define D_JSON_NO "No"
#define D_JSON_NOISE "Noise" #define D_JSON_NOISE "Noise"
#define D_JSON_NONE "None" #define D_JSON_NONE "None"
@ -244,6 +248,7 @@
#define D_WCFG_4_RETRY "Retry" #define D_WCFG_4_RETRY "Retry"
#define D_WCFG_5_WAIT "Wait" #define D_WCFG_5_WAIT "Wait"
#define D_WCFG_6_SERIAL "Serial" #define D_WCFG_6_SERIAL "Serial"
#define D_WCFG_7_WIFIMANAGER_RESET_ONLY "ManagerRst"
#define D_CMND_FRIENDLYNAME "FriendlyName" #define D_CMND_FRIENDLYNAME "FriendlyName"
#define D_CMND_SWITCHMODE "SwitchMode" #define D_CMND_SWITCHMODE "SwitchMode"
#define D_CMND_INTERLOCK "Interlock" #define D_CMND_INTERLOCK "Interlock"
@ -418,6 +423,7 @@
/********************************************************************************************/ /********************************************************************************************/
#define D_ASTERIX "********" #define D_ASTERIX "********"
#define D_ASTERISK_PWD "****"
#ifndef MY_LANGUAGE #ifndef MY_LANGUAGE
#include "language/en-GB.h" #include "language/en-GB.h"
@ -535,7 +541,8 @@ const char kWifiConfig[MAX_WIFI_OPTION][WCFG_MAX_STRING_LENGTH] PROGMEM = {
D_WCFG_3_WPSCONFIG, D_WCFG_3_WPSCONFIG,
D_WCFG_4_RETRY, D_WCFG_4_RETRY,
D_WCFG_5_WAIT, D_WCFG_5_WAIT,
D_WCFG_6_SERIAL }; D_WCFG_6_SERIAL,
D_WCFG_7_WIFIMANAGER_RESET_ONLY };
const char kPrefixes[3][PRFX_MAX_STRING_LENGTH] PROGMEM = { const char kPrefixes[3][PRFX_MAX_STRING_LENGTH] PROGMEM = {
D_CMND, D_CMND,
D_STAT, D_STAT,
@ -567,6 +574,7 @@ const char HTTP_SNS_CO2[] PROGMEM = "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_M
const char S_MAIN_MENU[] PROGMEM = D_MAIN_MENU; const char S_MAIN_MENU[] PROGMEM = D_MAIN_MENU;
const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION; const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION;
const char S_CONFIGURE_TEMPLATE[] PROGMEM = D_CONFIGURE_TEMPLATE;
const char S_CONFIGURE_MODULE[] PROGMEM = D_CONFIGURE_MODULE; const char S_CONFIGURE_MODULE[] PROGMEM = D_CONFIGURE_MODULE;
const char S_CONFIGURE_WIFI[] PROGMEM = D_CONFIGURE_WIFI; const char S_CONFIGURE_WIFI[] PROGMEM = D_CONFIGURE_WIFI;
const char S_NO_NETWORKS_FOUND[] PROGMEM = D_NO_NETWORKS_FOUND; const char S_NO_NETWORKS_FOUND[] PROGMEM = D_NO_NETWORKS_FOUND;

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele. * Use online command Prefix to translate cmnd, stat and tele.
* *
* Updated until v6.4.0.1 * Updated until v6.4.1.17 (up to commit 590c883b)
\*********************************************************************/ \*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -253,7 +253,7 @@
#define D_MODULE_PARAMETERS "Параметри на модула" #define D_MODULE_PARAMETERS "Параметри на модула"
#define D_MODULE_TYPE "Тип на модула" #define D_MODULE_TYPE "Тип на модула"
#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_PULLUP_ENABLE "Без pull-up за бутон/ключ"
#define D_GPIO "GPIO" #define D_GPIO "GPIO"
#define D_SERIAL_IN "Сериен вход" #define D_SERIAL_IN "Сериен вход"
#define D_SERIAL_OUT "Сериен изход" #define D_SERIAL_OUT "Сериен изход"
@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Период на телеметрия" #define D_TELEMETRY_PERIOD "Период на телеметрия"
#define D_OTHER_PARAMETERS "Други параметри" #define D_OTHER_PARAMETERS "Други параметри"
#define D_TEMPLATE "Модел"
#define D_ACTIVATE "Активирай"
#define D_WEB_ADMIN_PASSWORD "Парола на уеб администратора" #define D_WEB_ADMIN_PASSWORD "Парола на уеб администратора"
#define D_MQTT_ENABLE "Активиране на MQTT" #define D_MQTT_ENABLE "Активиране на MQTT"
#define D_FRIENDLY_NAME "Приятелско име" #define D_FRIENDLY_NAME "Приятелско име"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "Единично" #define D_SINGLE_DEVICE "Единично"
#define D_MULTI_DEVICE "Мулти" #define D_MULTI_DEVICE "Мулти"
#define D_CONFIGURE_TEMPLATE "Конфигуриране на модел"
#define D_TEMPLATE_PARAMETERS "Параметри на модел"
#define D_TEMPLATE_NAME "Име"
#define D_BASE_TYPE "Базиран на"
#define D_TEMPLATE_FLAGS "Флагове"
#define D_ALLOW_ADC0 "ADC0 вход"
#define D_ALLOW_PULLUP "Потребителски избор на pull-up"
#define D_SAVE_CONFIGURATION "Запазване на конфигурацията" #define D_SAVE_CONFIGURATION "Запазване на конфигурацията"
#define D_CONFIGURATION_SAVED "Конфигурацията е запазена" #define D_CONFIGURATION_SAVED "Конфигурацията е запазена"
#define D_CONFIGURATION_RESET "Конфигурацията е изчистена" #define D_CONFIGURATION_RESET "Конфигурацията е изчистена"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Няма" #define D_SENSOR_NONE "Няма"
#define D_SENSOR_USER "Потребит."
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Interval telemetrie" #define D_TELEMETRY_PERIOD "Interval telemetrie"
#define D_OTHER_PARAMETERS "Další nastavení" #define D_OTHER_PARAMETERS "Další nastavení"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Heslo Web administrátora" #define D_WEB_ADMIN_PASSWORD "Heslo Web administrátora"
#define D_MQTT_ENABLE "MQTT aktivní" #define D_MQTT_ENABLE "MQTT aktivní"
#define D_FRIENDLY_NAME "Friendly Name" #define D_FRIENDLY_NAME "Friendly Name"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single device" #define D_SINGLE_DEVICE "single device"
#define D_MULTI_DEVICE "multi device" #define D_MULTI_DEVICE "multi device"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Ulož nastavení" #define D_SAVE_CONFIGURATION "Ulož nastavení"
#define D_CONFIGURATION_SAVED "Nastavení uloženo" #define D_CONFIGURATION_SAVED "Nastavení uloženo"
#define D_CONFIGURATION_RESET "Nastavení resetováno" #define D_CONFIGURATION_RESET "Nastavení resetováno"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Není" #define D_SENSOR_NONE "Není"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele. * Use online command Prefix to translate cmnd, stat and tele.
* *
* Updated until v6.3.0.17 * Updated until v6.4.1.17
\*********************************************************************/ \*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetrieperiode" #define D_TELEMETRY_PERIOD "Telemetrieperiode"
#define D_OTHER_PARAMETERS "Sonstige Einstellungen" #define D_OTHER_PARAMETERS "Sonstige Einstellungen"
#define D_TEMPLATE "Vorlage"
#define D_ACTIVATE "Aktivieren"
#define D_WEB_ADMIN_PASSWORD "Passwort für Web Oberfläche" #define D_WEB_ADMIN_PASSWORD "Passwort für Web Oberfläche"
#define D_MQTT_ENABLE "MQTT aktivieren" #define D_MQTT_ENABLE "MQTT aktivieren"
#define D_FRIENDLY_NAME "Name [friendly name]" #define D_FRIENDLY_NAME "Name [friendly name]"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "Einzelnes Gerät" #define D_SINGLE_DEVICE "Einzelnes Gerät"
#define D_MULTI_DEVICE "Mehrfachgerät" #define D_MULTI_DEVICE "Mehrfachgerät"
#define D_CONFIGURE_TEMPLATE "Vorlage konfigurieren"
#define D_TEMPLATE_PARAMETERS "Vorlage Parameter"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "basiert auf"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "Nutzer pull-up Auswahl"
#define D_SAVE_CONFIGURATION "Konfiguration speichern" #define D_SAVE_CONFIGURATION "Konfiguration speichern"
#define D_CONFIGURATION_SAVED "Konfiguration gespeichert" #define D_CONFIGURATION_SAVED "Konfiguration gespeichert"
#define D_CONFIGURATION_RESET "Konfiguration zurücksetzen" #define D_CONFIGURATION_RESET "Konfiguration zurücksetzen"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None" #define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Περίοδος τηλεμετρίας" #define D_TELEMETRY_PERIOD "Περίοδος τηλεμετρίας"
#define D_OTHER_PARAMETERS "Άλλες παράμετροι" #define D_OTHER_PARAMETERS "Άλλες παράμετροι"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Κωδικός διαχειριστή" #define D_WEB_ADMIN_PASSWORD "Κωδικός διαχειριστή"
#define D_MQTT_ENABLE "Ενεργοποίηση MQTT" #define D_MQTT_ENABLE "Ενεργοποίηση MQTT"
#define D_FRIENDLY_NAME "Φιλική ονομασία" #define D_FRIENDLY_NAME "Φιλική ονομασία"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "μονή συσκευή" #define D_SINGLE_DEVICE "μονή συσκευή"
#define D_MULTI_DEVICE "πολλαπλές συσκευές" #define D_MULTI_DEVICE "πολλαπλές συσκευές"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Αποθήκευση ρυθμίσεων" #define D_SAVE_CONFIGURATION "Αποθήκευση ρυθμίσεων"
#define D_CONFIGURATION_SAVED "Οι ρυθμίσεις αποθηκεύτηκαν" #define D_CONFIGURATION_SAVED "Οι ρυθμίσεις αποθηκεύτηκαν"
#define D_CONFIGURATION_RESET "Επαναφορά ρυθμίσεων" #define D_CONFIGURATION_RESET "Επαναφορά ρυθμίσεων"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Κανένα" #define D_SENSOR_NONE "Κανένα"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetry period" #define D_TELEMETRY_PERIOD "Telemetry period"
#define D_OTHER_PARAMETERS "Other parameters" #define D_OTHER_PARAMETERS "Other parameters"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Web Admin Password" #define D_WEB_ADMIN_PASSWORD "Web Admin Password"
#define D_MQTT_ENABLE "MQTT enable" #define D_MQTT_ENABLE "MQTT enable"
#define D_FRIENDLY_NAME "Friendly Name" #define D_FRIENDLY_NAME "Friendly Name"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single device" #define D_SINGLE_DEVICE "single device"
#define D_MULTI_DEVICE "multi device" #define D_MULTI_DEVICE "multi device"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Save configuration" #define D_SAVE_CONFIGURATION "Save configuration"
#define D_CONFIGURATION_SAVED "Configuration saved" #define D_CONFIGURATION_SAVED "Configuration saved"
#define D_CONFIGURATION_RESET "Configuration reset" #define D_CONFIGURATION_RESET "Configuration reset"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None" #define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Período de Telemetría" #define D_TELEMETRY_PERIOD "Período de Telemetría"
#define D_OTHER_PARAMETERS "Otros parámetros" #define D_OTHER_PARAMETERS "Otros parámetros"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Clave Administrador Web" #define D_WEB_ADMIN_PASSWORD "Clave Administrador Web"
#define D_MQTT_ENABLE "Habilitar MQTT" #define D_MQTT_ENABLE "Habilitar MQTT"
#define D_FRIENDLY_NAME "Nombre Amigable" #define D_FRIENDLY_NAME "Nombre Amigable"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "dispositivo simple" #define D_SINGLE_DEVICE "dispositivo simple"
#define D_MULTI_DEVICE "dispositivo múltiple" #define D_MULTI_DEVICE "dispositivo múltiple"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Grabar configuración" #define D_SAVE_CONFIGURATION "Grabar configuración"
#define D_CONFIGURATION_SAVED "Configuración grabada" #define D_CONFIGURATION_SAVED "Configuración grabada"
#define D_CONFIGURATION_RESET "Configuración restablecida" #define D_CONFIGURATION_RESET "Configuración restablecida"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Ninguno" #define D_SENSOR_NONE "Ninguno"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele. * Use online command Prefix to translate cmnd, stat and tele.
* *
* Updated until v6.3.0.17 * Updated until v6.4.1.17
\*********************************************************************/ \*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -98,8 +98,8 @@
#define D_GAS "Gaz" #define D_GAS "Gaz"
#define D_GATEWAY "Passerelle" #define D_GATEWAY "Passerelle"
#define D_GROUP "Groupe" #define D_GROUP "Groupe"
#define D_HOST "Host" #define D_HOST "Hôte"
#define D_HOSTNAME "Hostname" #define D_HOSTNAME "Nom d'Hôte"
#define D_HUMIDITY "Humidité" #define D_HUMIDITY "Humidité"
#define D_ILLUMINANCE "Éclairement" #define D_ILLUMINANCE "Éclairement"
#define D_IMMEDIATE "immédiat" // Button immediate #define D_IMMEDIATE "immédiat" // Button immediate
@ -138,7 +138,7 @@
#define D_RESTARTING "Redémarre" #define D_RESTARTING "Redémarre"
#define D_RESTART_REASON "Raison du redémarrage" #define D_RESTART_REASON "Raison du redémarrage"
#define D_RESTORE "restaurer" #define D_RESTORE "restaurer"
#define D_RETAINED "retenu" #define D_RETAINED "persistant" // MQTT
#define D_RULE "Règle" #define D_RULE "Règle"
#define D_SAVE "Enregistrer" #define D_SAVE "Enregistrer"
#define D_SENSOR "Capteur" #define D_SENSOR "Capteur"
@ -184,7 +184,7 @@
#define D_LEVEL_10 "level 1-0" #define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1" #define D_LEVEL_01 "level 0-1"
#define D_SERIAL_LOGGING_DISABLED "Journalisation série désactivée" #define D_SERIAL_LOGGING_DISABLED "Journalisation série désactivée"
#define D_SYSLOG_LOGGING_REENABLED "Jounalisation syslog réactivée" #define D_SYSLOG_LOGGING_REENABLED "Jounalisation SysLog réactivée"
#define D_SET_BAUDRATE_TO "Définir le débit à" #define D_SET_BAUDRATE_TO "Définir le débit à"
#define D_RECEIVED_TOPIC "Topic reçu" // Terme MQTT #define D_RECEIVED_TOPIC "Topic reçu" // Terme MQTT
@ -209,7 +209,7 @@
#define D_QUERY_DONE "Requête terminée. Services MQTT trouvés" #define D_QUERY_DONE "Requête terminée. Services MQTT trouvés"
#define D_MQTT_SERVICE_FOUND "Service MQTT trouvé sur" #define D_MQTT_SERVICE_FOUND "Service MQTT trouvé sur"
#define D_FOUND_AT "trouvé à" #define D_FOUND_AT "trouvé à"
#define D_SYSLOG_HOST_NOT_FOUND "Host syslog introuvable" #define D_SYSLOG_HOST_NOT_FOUND "Hôte SysLog introuvable"
// settings.ino // settings.ino
#define D_SAVED_TO_FLASH_AT "Enregistré en flash à" #define D_SAVED_TO_FLASH_AT "Enregistré en flash à"
@ -253,7 +253,7 @@
#define D_MODULE_PARAMETERS "Paramètres module" #define D_MODULE_PARAMETERS "Paramètres module"
#define D_MODULE_TYPE "Type de module" #define D_MODULE_TYPE "Type de module"
#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_PULLUP_ENABLE "Inter. sans pull-up"
#define D_GPIO "GPIO" #define D_GPIO "GPIO"
#define D_SERIAL_IN "Entrée série" #define D_SERIAL_IN "Entrée série"
#define D_SERIAL_OUT "Sortie série" #define D_SERIAL_OUT "Sortie série"
@ -281,13 +281,15 @@
#define D_LOGGING_PARAMETERS "Paramètres du journal" #define D_LOGGING_PARAMETERS "Paramètres du journal"
#define D_SERIAL_LOG_LEVEL "Niveau de journalisation série" #define D_SERIAL_LOG_LEVEL "Niveau de journalisation série"
#define D_WEB_LOG_LEVEL "Niveau de journalisation web" #define D_WEB_LOG_LEVEL "Niveau de journalisation web"
#define D_SYS_LOG_LEVEL "Niveau Syslog" #define D_SYS_LOG_LEVEL "Niveau SysLog"
#define D_MORE_DEBUG "Plus de debug" #define D_MORE_DEBUG "Plus de debug"
#define D_SYSLOG_HOST "Hôte Syslog" #define D_SYSLOG_HOST "Hôte SysLog"
#define D_SYSLOG_PORT "Port Syslog" #define D_SYSLOG_PORT "Port SysLog"
#define D_TELEMETRY_PERIOD "Période télémétrie" #define D_TELEMETRY_PERIOD "Période télémétrie"
#define D_OTHER_PARAMETERS "Autres paramètres" #define D_OTHER_PARAMETERS "Autres paramètres"
#define D_TEMPLATE "Modèle"
#define D_ACTIVATE "Activer"
#define D_WEB_ADMIN_PASSWORD "Mot de passe Web Admin" #define D_WEB_ADMIN_PASSWORD "Mot de passe Web Admin"
#define D_MQTT_ENABLE "MQTT activé" #define D_MQTT_ENABLE "MQTT activé"
#define D_FRIENDLY_NAME "Surnom" #define D_FRIENDLY_NAME "Surnom"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "module unique" #define D_SINGLE_DEVICE "module unique"
#define D_MULTI_DEVICE "multi module" #define D_MULTI_DEVICE "multi module"
#define D_CONFIGURE_TEMPLATE "Configuration du modèle"
#define D_TEMPLATE_PARAMETERS "Paramètres du modèle"
#define D_TEMPLATE_NAME "Nom"
#define D_BASE_TYPE "Basé sur"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "Entrée ADC0"
#define D_ALLOW_PULLUP "Choix de pull-up utilisateur"
#define D_SAVE_CONFIGURATION "Enregistrer la configuration" #define D_SAVE_CONFIGURATION "Enregistrer la configuration"
#define D_CONFIGURATION_SAVED "Configuration enregistrée" #define D_CONFIGURATION_SAVED "Configuration enregistrée"
#define D_CONFIGURATION_RESET "Configuration réinitialisée" #define D_CONFIGURATION_RESET "Configuration réinitialisée"
@ -331,7 +341,7 @@
#define D_UPLOAD_ERR_3 "L'octet magique n'est pas 0xE9" #define D_UPLOAD_ERR_3 "L'octet magique n'est pas 0xE9"
#define D_UPLOAD_ERR_4 "La taille du programme à flasher est plus grande que la taille réelle de la mémoire flash" #define D_UPLOAD_ERR_4 "La taille du programme à flasher est plus grande que la taille réelle de la mémoire flash"
#define D_UPLOAD_ERR_5 "Erreur de comparaison du buffer de téléchargement" #define D_UPLOAD_ERR_5 "Erreur de comparaison du buffer de téléchargement"
#define D_UPLOAD_ERR_6 "Téléchargement échoué. Activer Weblog 3" #define D_UPLOAD_ERR_6 "Téléchargement échoué. Activer WebLog 3"
#define D_UPLOAD_ERR_7 "Téléchargement annulé" #define D_UPLOAD_ERR_7 "Téléchargement annulé"
#define D_UPLOAD_ERR_8 "Fichier invalide" #define D_UPLOAD_ERR_8 "Fichier invalide"
#define D_UPLOAD_ERR_9 "Fichier trop grand" #define D_UPLOAD_ERR_9 "Fichier trop grand"
@ -342,7 +352,7 @@
#define D_UPLOAD_ERROR_CODE "Code d'erreur téléchargement" #define D_UPLOAD_ERROR_CODE "Code d'erreur téléchargement"
#define D_ENTER_COMMAND "Saisir une commande" #define D_ENTER_COMMAND "Saisir une commande"
#define D_ENABLE_WEBLOG_FOR_RESPONSE "Activer Weblog 2 si une réponse est attendue" #define D_ENABLE_WEBLOG_FOR_RESPONSE "Activer WebLog 2 si une réponse est attendue"
#define D_NEED_USER_AND_PASSWORD "Nécessite utilisateur=<username>&password=<password>" #define D_NEED_USER_AND_PASSWORD "Nécessite utilisateur=<username>&password=<password>"
// xdrv_01_mqtt.ino // xdrv_01_mqtt.ino
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Aucun" #define D_SENSOR_NONE "Aucun"
#define D_SENSOR_USER "Utilisateur"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetry period" #define D_TELEMETRY_PERIOD "Telemetry period"
#define D_OTHER_PARAMETERS "פרמטרים שונים" #define D_OTHER_PARAMETERS "פרמטרים שונים"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "סיסמת מנהל - אתר" #define D_WEB_ADMIN_PASSWORD "סיסמת מנהל - אתר"
#define D_MQTT_ENABLE "MQTT אפשר" #define D_MQTT_ENABLE "MQTT אפשר"
#define D_FRIENDLY_NAME "שם ידידותי" #define D_FRIENDLY_NAME "שם ידידותי"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "התקן בודד" #define D_SINGLE_DEVICE "התקן בודד"
#define D_MULTI_DEVICE "התקנים" #define D_MULTI_DEVICE "התקנים"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "שמירת הגדרות" #define D_SAVE_CONFIGURATION "שמירת הגדרות"
#define D_CONFIGURATION_SAVED "הגדרות נשמרו" #define D_CONFIGURATION_SAVED "הגדרות נשמרו"
#define D_CONFIGURATION_RESET "איפוס הגדרות" #define D_CONFIGURATION_RESET "איפוס הגדרות"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None" #define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetria (mp.)" #define D_TELEMETRY_PERIOD "Telemetria (mp.)"
#define D_OTHER_PARAMETERS "Egyéb beállítások" #define D_OTHER_PARAMETERS "Egyéb beállítások"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Web admin jelszó" #define D_WEB_ADMIN_PASSWORD "Web admin jelszó"
#define D_MQTT_ENABLE "MQTT engedélyezése" #define D_MQTT_ENABLE "MQTT engedélyezése"
#define D_FRIENDLY_NAME "Név" #define D_FRIENDLY_NAME "Név"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single device" #define D_SINGLE_DEVICE "single device"
#define D_MULTI_DEVICE "multi device" #define D_MULTI_DEVICE "multi device"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Beállítások mentése" #define D_SAVE_CONFIGURATION "Beállítások mentése"
#define D_CONFIGURATION_SAVED "Beállítások elmentve" #define D_CONFIGURATION_SAVED "Beállítások elmentve"
#define D_CONFIGURATION_RESET "Beállítások visszaállítása" #define D_CONFIGURATION_RESET "Beállítások visszaállítása"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Nincs" #define D_SENSOR_NONE "Nincs"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Periodo Telemetria" #define D_TELEMETRY_PERIOD "Periodo Telemetria"
#define D_OTHER_PARAMETERS "Altri parametri" #define D_OTHER_PARAMETERS "Altri parametri"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Password Amministratore Web" #define D_WEB_ADMIN_PASSWORD "Password Amministratore Web"
#define D_MQTT_ENABLE "Abilita MQTT" #define D_MQTT_ENABLE "Abilita MQTT"
#define D_FRIENDLY_NAME "Nome confidenziale" #define D_FRIENDLY_NAME "Nome confidenziale"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "dispositivo singolo" #define D_SINGLE_DEVICE "dispositivo singolo"
#define D_MULTI_DEVICE "dispositivo multiplo" #define D_MULTI_DEVICE "dispositivo multiplo"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Salva configurazione" #define D_SAVE_CONFIGURATION "Salva configurazione"
#define D_CONFIGURATION_SAVED "Configurazione salvata" #define D_CONFIGURATION_SAVED "Configurazione salvata"
#define D_CONFIGURATION_RESET "Configurazione azzerata" #define D_CONFIGURATION_RESET "Configurazione azzerata"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Nessuno" #define D_SENSOR_NONE "Nessuno"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetry periode" #define D_TELEMETRY_PERIOD "Telemetry periode"
#define D_OTHER_PARAMETERS "Overige parameters" #define D_OTHER_PARAMETERS "Overige parameters"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Web Admin Wachtwoord" #define D_WEB_ADMIN_PASSWORD "Web Admin Wachtwoord"
#define D_MQTT_ENABLE "MQTT ingeschakeld" #define D_MQTT_ENABLE "MQTT ingeschakeld"
#define D_FRIENDLY_NAME "Beschrijvende naam" #define D_FRIENDLY_NAME "Beschrijvende naam"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "een apparaat" #define D_SINGLE_DEVICE "een apparaat"
#define D_MULTI_DEVICE "meer apparaten" #define D_MULTI_DEVICE "meer apparaten"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Bewaar configuratie" #define D_SAVE_CONFIGURATION "Bewaar configuratie"
#define D_CONFIGURATION_SAVED "Configuratie opgeslagen" #define D_CONFIGURATION_SAVED "Configuratie opgeslagen"
#define D_CONFIGURATION_RESET "Configuratie ge-reset" #define D_CONFIGURATION_RESET "Configuratie ge-reset"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Geen" #define D_SENSOR_NONE "Geen"
#define D_SENSOR_USER "Gebruiker"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Okres telemetrii" #define D_TELEMETRY_PERIOD "Okres telemetrii"
#define D_OTHER_PARAMETERS "Inne parametry" #define D_OTHER_PARAMETERS "Inne parametry"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Hasło administratora Web" #define D_WEB_ADMIN_PASSWORD "Hasło administratora Web"
#define D_MQTT_ENABLE "MQTT aktywne" #define D_MQTT_ENABLE "MQTT aktywne"
#define D_FRIENDLY_NAME "Twoja nazwa" #define D_FRIENDLY_NAME "Twoja nazwa"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single device" #define D_SINGLE_DEVICE "single device"
#define D_MULTI_DEVICE "multi device" #define D_MULTI_DEVICE "multi device"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Zapisz ustawienia" #define D_SAVE_CONFIGURATION "Zapisz ustawienia"
#define D_CONFIGURATION_SAVED "Ustawienia zapisane" #define D_CONFIGURATION_SAVED "Ustawienia zapisane"
#define D_CONFIGURATION_RESET "Ustawienia zresetowane" #define D_CONFIGURATION_RESET "Ustawienia zresetowane"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Brak" #define D_SENSOR_NONE "Brak"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Período de telemetria" #define D_TELEMETRY_PERIOD "Período de telemetria"
#define D_OTHER_PARAMETERS "Outros parâmetros" #define D_OTHER_PARAMETERS "Outros parâmetros"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Senha de WEB Admin" #define D_WEB_ADMIN_PASSWORD "Senha de WEB Admin"
#define D_MQTT_ENABLE "MQTT habilitado" #define D_MQTT_ENABLE "MQTT habilitado"
#define D_FRIENDLY_NAME "Nome amigável" #define D_FRIENDLY_NAME "Nome amigável"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "Dispositivo único" #define D_SINGLE_DEVICE "Dispositivo único"
#define D_MULTI_DEVICE "Múltiplos dispositivos" #define D_MULTI_DEVICE "Múltiplos dispositivos"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Gravar configuração" #define D_SAVE_CONFIGURATION "Gravar configuração"
#define D_CONFIGURATION_SAVED "Configuração gravada" #define D_CONFIGURATION_SAVED "Configuração gravada"
#define D_CONFIGURATION_RESET "Reinicialização da configuração" #define D_CONFIGURATION_RESET "Reinicialização da configuração"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Nenhum" #define D_SENSOR_NONE "Nenhum"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Periodo de Telemetria" #define D_TELEMETRY_PERIOD "Periodo de Telemetria"
#define D_OTHER_PARAMETERS "Outros parametros" #define D_OTHER_PARAMETERS "Outros parametros"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Palavra Chave de WEB Admin" #define D_WEB_ADMIN_PASSWORD "Palavra Chave de WEB Admin"
#define D_MQTT_ENABLE "MQTT habilitado" #define D_MQTT_ENABLE "MQTT habilitado"
#define D_FRIENDLY_NAME "Nome amigável" #define D_FRIENDLY_NAME "Nome amigável"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "dispositivo único" #define D_SINGLE_DEVICE "dispositivo único"
#define D_MULTI_DEVICE "multiplos dispositivos" #define D_MULTI_DEVICE "multiplos dispositivos"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Salvar configuração" #define D_SAVE_CONFIGURATION "Salvar configuração"
#define D_CONFIGURATION_SAVED "Configuração guardada" #define D_CONFIGURATION_SAVED "Configuração guardada"
#define D_CONFIGURATION_RESET "Reinicialização da configuração" #define D_CONFIGURATION_RESET "Reinicialização da configuração"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Nenhum" #define D_SENSOR_NONE "Nenhum"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Период телеметрии" #define D_TELEMETRY_PERIOD "Период телеметрии"
#define D_OTHER_PARAMETERS "Параметры Прочие" #define D_OTHER_PARAMETERS "Параметры Прочие"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Пароль Web администратора" #define D_WEB_ADMIN_PASSWORD "Пароль Web администратора"
#define D_MQTT_ENABLE "MQTT активен" #define D_MQTT_ENABLE "MQTT активен"
#define D_FRIENDLY_NAME "Дружественное Имя" #define D_FRIENDLY_NAME "Дружественное Имя"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "одиночное" #define D_SINGLE_DEVICE "одиночное"
#define D_MULTI_DEVICE "мульти" #define D_MULTI_DEVICE "мульти"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Сохранить конфигурацию" #define D_SAVE_CONFIGURATION "Сохранить конфигурацию"
#define D_CONFIGURATION_SAVED "Конфигурация сохранена " #define D_CONFIGURATION_SAVED "Конфигурация сохранена "
#define D_CONFIGURATION_RESET "Конфигурация сброшена" #define D_CONFIGURATION_RESET "Конфигурация сброшена"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "-нет-" #define D_SENSOR_NONE "-нет-"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Interval telemetrie" #define D_TELEMETRY_PERIOD "Interval telemetrie"
#define D_OTHER_PARAMETERS "Ostatné nastavenia" #define D_OTHER_PARAMETERS "Ostatné nastavenia"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Heslo Web administrátora" #define D_WEB_ADMIN_PASSWORD "Heslo Web administrátora"
#define D_MQTT_ENABLE "MQTT aktívne" #define D_MQTT_ENABLE "MQTT aktívne"
#define D_FRIENDLY_NAME "Friendly Name" #define D_FRIENDLY_NAME "Friendly Name"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single device" #define D_SINGLE_DEVICE "single device"
#define D_MULTI_DEVICE "multi device" #define D_MULTI_DEVICE "multi device"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Ulož nastavenia" #define D_SAVE_CONFIGURATION "Ulož nastavenia"
#define D_CONFIGURATION_SAVED "Nastavenia uložené" #define D_CONFIGURATION_SAVED "Nastavenia uložené"
#define D_CONFIGURATION_RESET "Nastavenia resetované" #define D_CONFIGURATION_RESET "Nastavenia resetované"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Žiaden" #define D_SENSOR_NONE "Žiaden"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetriperiod" #define D_TELEMETRY_PERIOD "Telemetriperiod"
#define D_OTHER_PARAMETERS "Andra parametrar" #define D_OTHER_PARAMETERS "Andra parametrar"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Webbadmin-lösenord" #define D_WEB_ADMIN_PASSWORD "Webbadmin-lösenord"
#define D_MQTT_ENABLE "MQTT aktivera" #define D_MQTT_ENABLE "MQTT aktivera"
#define D_FRIENDLY_NAME "Läsbart namn" #define D_FRIENDLY_NAME "Läsbart namn"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "soloenhet" #define D_SINGLE_DEVICE "soloenhet"
#define D_MULTI_DEVICE "multienhet" #define D_MULTI_DEVICE "multienhet"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Spara konfiguration" #define D_SAVE_CONFIGURATION "Spara konfiguration"
#define D_CONFIGURATION_SAVED "Konfiguration sparad" #define D_CONFIGURATION_SAVED "Konfiguration sparad"
#define D_CONFIGURATION_RESET "Konfiguration nollställd" #define D_CONFIGURATION_RESET "Konfiguration nollställd"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Ingen" #define D_SENSOR_NONE "Ingen"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetri peryodu" #define D_TELEMETRY_PERIOD "Telemetri peryodu"
#define D_OTHER_PARAMETERS "Diğer parametreler" #define D_OTHER_PARAMETERS "Diğer parametreler"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Web Yönetici Şifresi" #define D_WEB_ADMIN_PASSWORD "Web Yönetici Şifresi"
#define D_MQTT_ENABLE "MQTT aktif" #define D_MQTT_ENABLE "MQTT aktif"
#define D_FRIENDLY_NAME "Kullanıcı Dostu İsim" #define D_FRIENDLY_NAME "Kullanıcı Dostu İsim"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "tekli cihaz" #define D_SINGLE_DEVICE "tekli cihaz"
#define D_MULTI_DEVICE "çoklu cihaz" #define D_MULTI_DEVICE "çoklu cihaz"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Ayarları Kaydet" #define D_SAVE_CONFIGURATION "Ayarları Kaydet"
#define D_CONFIGURATION_SAVED "Ayarlar kaydedildi" #define D_CONFIGURATION_SAVED "Ayarlar kaydedildi"
#define D_CONFIGURATION_RESET "Ayarlar resetlendi" #define D_CONFIGURATION_RESET "Ayarlar resetlendi"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None" #define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Період телеметрії" #define D_TELEMETRY_PERIOD "Період телеметрії"
#define D_OTHER_PARAMETERS "Параметри Інше" #define D_OTHER_PARAMETERS "Параметри Інше"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Гасло Web адміністратора" #define D_WEB_ADMIN_PASSWORD "Гасло Web адміністратора"
#define D_MQTT_ENABLE "MQTT активний" #define D_MQTT_ENABLE "MQTT активний"
#define D_FRIENDLY_NAME "Дружнє Ім'я" #define D_FRIENDLY_NAME "Дружнє Ім'я"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "одиночне" #define D_SINGLE_DEVICE "одиночне"
#define D_MULTI_DEVICE "мульти" #define D_MULTI_DEVICE "мульти"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Зберегти конфігурацію" #define D_SAVE_CONFIGURATION "Зберегти конфігурацію"
#define D_CONFIGURATION_SAVED "Конфігурація збережена " #define D_CONFIGURATION_SAVED "Конфігурація збережена "
#define D_CONFIGURATION_RESET "Конфігурація скинута" #define D_CONFIGURATION_RESET "Конфігурація скинута"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "-відсутньо-" #define D_SENSOR_NONE "-відсутньо-"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "上报周期" #define D_TELEMETRY_PERIOD "上报周期"
#define D_OTHER_PARAMETERS "其他设置" #define D_OTHER_PARAMETERS "其他设置"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "WEB 管理密码" #define D_WEB_ADMIN_PASSWORD "WEB 管理密码"
#define D_MQTT_ENABLE "启用MQTT" #define D_MQTT_ENABLE "启用MQTT"
#define D_FRIENDLY_NAME "昵称" #define D_FRIENDLY_NAME "昵称"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "单设备" #define D_SINGLE_DEVICE "单设备"
#define D_MULTI_DEVICE "多设备" #define D_MULTI_DEVICE "多设备"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "保存设置" #define D_SAVE_CONFIGURATION "保存设置"
#define D_CONFIGURATION_SAVED "设置已保存" #define D_CONFIGURATION_SAVED "设置已保存"
#define D_CONFIGURATION_RESET "设置已重置" #define D_CONFIGURATION_RESET "设置已重置"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "无" #define D_SENSOR_NONE "无"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "上報周期" #define D_TELEMETRY_PERIOD "上報周期"
#define D_OTHER_PARAMETERS "其他設置" #define D_OTHER_PARAMETERS "其他設置"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "WEB管理密碼" #define D_WEB_ADMIN_PASSWORD "WEB管理密碼"
#define D_MQTT_ENABLE "啟用MQTT" #define D_MQTT_ENABLE "啟用MQTT"
#define D_FRIENDLY_NAME "昵稱" #define D_FRIENDLY_NAME "昵稱"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "單設備" #define D_SINGLE_DEVICE "單設備"
#define D_MULTI_DEVICE "多設備" #define D_MULTI_DEVICE "多設備"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "保存設置" #define D_SAVE_CONFIGURATION "保存設置"
#define D_CONFIGURATION_SAVED "設置已保存" #define D_CONFIGURATION_SAVED "設置已保存"
#define D_CONFIGURATION_RESET "設置已重置" #define D_CONFIGURATION_RESET "設置已重置"
@ -483,6 +493,7 @@
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None" #define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301" #define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_SI7021 "SI7021"

View File

@ -122,6 +122,7 @@
// -- MQTT - Telemetry ---------------------------- // -- MQTT - Telemetry ----------------------------
#define TELE_PERIOD 300 // [TelePeriod] Telemetry (0 = disable, 10 - 3600 seconds) #define TELE_PERIOD 300 // [TelePeriod] Telemetry (0 = disable, 10 - 3600 seconds)
#define TELE_ON_POWER 0 // [SetOption59] send tele/STATE together with stat/RESULT (0 = Disable, 1 = Enable)
// -- MQTT - Domoticz ----------------------------- // -- MQTT - Domoticz -----------------------------
#define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) #define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds)
@ -278,6 +279,7 @@
// -- Rules --------------------------------------- // -- Rules ---------------------------------------
#define USE_RULES // Add support for rules (+4k4 code) #define USE_RULES // Add support for rules (+4k4 code)
#define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem)
// -- Internal Analog input ----------------------- // -- Internal Analog input -----------------------
#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices #define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices

View File

@ -75,7 +75,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t hass_tele_on_power : 1; // bit 9 (v6.3.0.13) uint32_t hass_tele_on_power : 1; // bit 9 (v6.3.0.13)
uint32_t sleep_normal : 1; // bit 10 (v6.3.0.15) - SetOption60 - Enable normal sleep instead of dynamic sleep uint32_t sleep_normal : 1; // bit 10 (v6.3.0.15) - SetOption60 - Enable normal sleep instead of dynamic sleep
uint32_t button_switch_force_local : 1;// bit 11 (v6.3.0.16) - SetOption61 - Force local operation when button/switch topic is set uint32_t button_switch_force_local : 1;// bit 11 (v6.3.0.16) - SetOption61 - Force local operation when button/switch topic is set
uint32_t no_pullup : 1; // bit 12 (v6.4.1.7) - SetOption62 - Force no pull-up (0 = (no)pull-up, 1 = no pull-up) uint32_t no_hold_retain : 1; // bit 12 (v6.4.1.19) - SetOption62 - Don't use retain flag on HOLD messages
uint32_t spare13 : 1; uint32_t spare13 : 1;
uint32_t spare14 : 1; uint32_t spare14 : 1;
uint32_t spare15 : 1; uint32_t spare15 : 1;

View File

@ -661,6 +661,7 @@ void SettingsDefaultSet2(void)
Settings.flag.mqtt_button_retain = MQTT_BUTTON_RETAIN; Settings.flag.mqtt_button_retain = MQTT_BUTTON_RETAIN;
Settings.flag.mqtt_switch_retain = MQTT_SWITCH_RETAIN; Settings.flag.mqtt_switch_retain = MQTT_SWITCH_RETAIN;
Settings.flag3.button_switch_force_local = MQTT_BUTTON_SWITCH_FORCE_LOCAL; Settings.flag3.button_switch_force_local = MQTT_BUTTON_SWITCH_FORCE_LOCAL;
Settings.flag3.hass_tele_on_power = TELE_ON_POWER;
// Settings.flag.mqtt_sensor_retain = 0; // Settings.flag.mqtt_sensor_retain = 0;
// Settings.flag.mqtt_offline = 0; // Settings.flag.mqtt_offline = 0;
// Settings.flag.mqtt_serial = 0; // Settings.flag.mqtt_serial = 0;

View File

@ -104,6 +104,7 @@ typedef unsigned long power_t; // Power (Relay) type
#define PWM_MIN 100 // [PWM_MIN] Minimum frequency - Default: 100 #define PWM_MIN 100 // [PWM_MIN] Minimum frequency - Default: 100
// For Dimmers use double of your mains AC frequecy (100 for 50Hz and 120 for 60Hz) // For Dimmers use double of your mains AC frequecy (100 for 50Hz and 120 for 60Hz)
// For Controlling Servos use 50 and also set PWM_FREQ as 50 (DO NOT USE THESE VALUES FOR DIMMERS) // For Controlling Servos use 50 and also set PWM_FREQ as 50 (DO NOT USE THESE VALUES FOR DIMMERS)
//#define PWM_LIGHTSCHEME0_IGNORE_SLEEP // Do not change sleep value for LightAnimate() scheme 0
#define DEFAULT_POWER_DELTA 80 // Power change percentage #define DEFAULT_POWER_DELTA 80 // Power change percentage
#define MAX_POWER_HOLD 10 // Time in SECONDS to allow max agreed power #define MAX_POWER_HOLD 10 // Time in SECONDS to allow max agreed power
@ -211,7 +212,7 @@ enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_RESTART, DT_ENERGY };
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL};
enum WifiConfigOptions {WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL, MAX_WIFI_OPTION}; enum WifiConfigOptions {WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL, WIFI_MANAGER_RESET_ONLY, MAX_WIFI_OPTION};
enum SwitchModeOptions {TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, MAX_SWITCH_OPTION}; enum SwitchModeOptions {TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, MAX_SWITCH_OPTION};

View File

@ -776,9 +776,6 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
if (10 == pindex) { // SetOption60 enable or disable traditional sleep if (10 == pindex) { // SetOption60 enable or disable traditional sleep
WiFiSetSleepMode(); // Update WiFi sleep mode accordingly WiFiSetSleepMode(); // Update WiFi sleep mode accordingly
} }
if ((12 == pindex) && (my_module_flag.pullup)) { // SetOption62 change input pull-up
restart_flag = 2; // Only restart if module supports it
}
} }
} }
else { // SetOption32 .. 49 else { // SetOption32 .. 49
@ -869,9 +866,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
} }
restart_flag = 2; restart_flag = 2;
} }
uint8_t module = Settings.module; snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, ModuleNr(), ModuleName().c_str());
if (USER_MODULE == Settings.module) { module = 0; } else { module++; }
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, module, ModuleName().c_str());
} }
else if (CMND_MODULES == command_code) { else if (CMND_MODULES == command_code) {
for (uint8_t i = 0; i <= MAXMODULE; i++) { for (uint8_t i = 0; i <= MAXMODULE; i++) {
@ -952,85 +947,29 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
mqtt_data[0] = '\0'; mqtt_data[0] = '\0';
} }
else if (CMND_TEMPLATE == command_code) { else if (CMND_TEMPLATE == command_code) {
// {"NAME":"Generic","GPIO":[17,254,29,254,7,254,254,254,138,254,139,254,254],"FLAG":1,"TYPE":255} // {"NAME":"Generic","GPIO":[17,254,29,254,7,254,254,254,138,254,139,254,254],"FLAG":1,"BASE":255}
bool error = false; bool error = false;
if (!strstr(dataBuf, "{")) { // If no JSON it must be parameter if (!strstr(dataBuf, "{")) { // If no JSON it must be parameter
bool update = false;
if ((payload > 0) && (payload <= MAXMODULE)) { if ((payload > 0) && (payload <= MAXMODULE)) {
ModuleDefault(payload -1); // Copy template module ModuleDefault(payload -1); // Copy template module
if (USER_MODULE == Settings.module) { restart_flag = 2; } if (USER_MODULE == Settings.module) { restart_flag = 2; }
} }
else if (0 == payload) { // Copy current module with user configured GPIO else if (0 == payload) { // Copy current module with user configured GPIO
if (Settings.module < USER_MODULE) { if (Settings.module != USER_MODULE) {
ModuleDefault(Settings.module); ModuleDefault(Settings.module);
update = true;
}
}
if (USER_MODULE == Settings.module) { // Update with latest changes
update = true;
}
if (update) {
uint8_t src = 0;
for (uint8_t dst = 0; dst < sizeof(mycfgio); dst++) {
if (6 == dst) { src = 9; }
if (8 == dst) { src = 12; }
if (Settings.my_gp.io[src] > GPIO_NONE) {
if (Settings.user_template.gp.io[dst] != Settings.my_gp.io[src]) {
Settings.user_template.gp.io[dst] = Settings.my_gp.io[src];
if (USER_MODULE == Settings.module) { restart_flag = 2; }
}
}
src++;
} }
} }
} }
else if (data_len > 9) { // Workaround exception if empty JSON like {} - Needs checks else if (data_len > 9) { // Workaround exception if empty JSON like {} - Needs checks
StaticJsonBuffer<350> jb; // 331 from https://arduinojson.org/v5/assistant/ if (JsonTemplate(dataBuf)) { // Free 336 bytes StaticJsonBuffer stack space by moving code to function
JsonObject& obj = jb.parseObject(dataBuf); if (USER_MODULE == Settings.module) { restart_flag = 2; }
if (!obj.success()) { } else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON);
error = true; error = true;
} else {
// All parameters are optional allowing for partial changes
const char* name = obj[D_JSON_NAME];
if (name != nullptr) {
strlcpy(Settings.user_template.name, name, sizeof(Settings.user_template.name));
}
if (obj[D_JSON_GPIO].success()) {
for (uint8_t i = 0; i < sizeof(mycfgio); i++) {
Settings.user_template.gp.io[i] = obj[D_JSON_GPIO][i] | 0;
} }
} }
if (obj[D_JSON_FLAG].success()) { if (!error) { TemplateJson(); }
uint8_t flag = obj[D_JSON_FLAG] | 0;
memcpy(&Settings.user_template.flag, &flag, sizeof(gpio_flag));
}
if (obj[D_JSON_BASE].success()) {
uint8_t base = obj[D_JSON_BASE];
if ((0 == base) || (base >= MAXMODULE)) { base = 17; } else { base--; }
Settings.user_template_base = base; // Default WEMOS
}
// Validate GPIO
// for (uint8_t i = 0; i < sizeof(mycfgio); i++) {
// For now do not allow non-user configurable GPIO
// if ((Settings.user_template.gp.io[i] > GPIO_FIX_START) && (Settings.user_template.gp.io[i] < GPIO_USER)) {
// Settings.user_template.gp.io[i] = GPIO_NONE;
// };
// }
if (USER_MODULE == Settings.module) { restart_flag = 2; }
}
}
if (!error) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), Settings.user_template.name);
for (uint8_t i = 0; i < sizeof(Settings.user_template.gp); i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (i>0)?",":"", Settings.user_template.gp.io[i]);
}
// snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":\"%d (%s)\"}"),
// mqtt_data, Settings.user_template.flag, Settings.user_template_base +1, AnyModuleName(Settings.user_template_base).c_str());
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"),
mqtt_data, Settings.user_template.flag, Settings.user_template_base +1);
}
} }
else if ((CMND_PWM == command_code) && pwm_present && (index > 0) && (index <= MAX_PWMS)) { else if ((CMND_PWM == command_code) && pwm_present && (index > 0) && (index <= MAX_PWMS)) {
if ((payload >= 0) && (payload <= Settings.pwm_range) && (pin[GPIO_PWM1 + index -1] < 99)) { if ((payload >= 0) && (payload <= Settings.pwm_range) && (pin[GPIO_PWM1 + index -1] < 99)) {
@ -1203,7 +1142,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.sta_ssid[index -1]); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.sta_ssid[index -1]);
} }
else if ((CMND_PASSWORD == command_code) && (index > 0) && (index <= 2)) { else if ((CMND_PASSWORD == command_code) && (index > 0) && (index <= 2)) {
if ((data_len > 0) && (data_len < sizeof(Settings.sta_pwd[0]))) { if ((data_len > 4 || SC_CLEAR == Shortcut(dataBuf) || SC_DEFAULT == Shortcut(dataBuf)) && (data_len < sizeof(Settings.sta_pwd[0]))) {
strlcpy(Settings.sta_pwd[index -1], (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1 == index) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(Settings.sta_pwd[0])); strlcpy(Settings.sta_pwd[index -1], (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1 == index) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(Settings.sta_pwd[0]));
Settings.sta_active = index -1; Settings.sta_active = index -1;
restart_flag = 2; restart_flag = 2;
@ -1336,10 +1275,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
restart_flag = 211; restart_flag = 211;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command , D_JSON_RESET_AND_RESTARTING); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command , D_JSON_RESET_AND_RESTARTING);
break; break;
case 2: case 2 ... 6:
case 3:
case 4:
case 5:
restart_flag = 210 + payload; restart_flag = 210 + payload;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RESET "\":\"" D_JSON_ERASE ", " D_JSON_RESET_AND_RESTARTING "\"}")); snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RESET "\":\"" D_JSON_ERASE ", " D_JSON_RESET_AND_RESTARTING "\"}"));
break; break;
@ -1496,10 +1432,10 @@ bool SendKey(uint8_t key, uint8_t device, uint8_t state)
} }
#ifdef USE_DOMOTICZ #ifdef USE_DOMOTICZ
if (!(DomoticzSendKey(key, device, state, strlen(mqtt_data)))) { if (!(DomoticzSendKey(key, device, state, strlen(mqtt_data)))) {
MqttPublishDirect(stopic, (key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain); MqttPublishDirect(stopic, ((key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain) && (state != 3 || !Settings.flag3.no_hold_retain));
} }
#else #else
MqttPublishDirect(stopic, (key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain); MqttPublishDirect(stopic, ((key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain) && (state != 3 || !Settings.flag3.no_hold_retain));
#endif // USE_DOMOTICZ #endif // USE_DOMOTICZ
result = !Settings.flag3.button_switch_force_local; result = !Settings.flag3.button_switch_force_local;
} else { } else {
@ -1628,8 +1564,6 @@ void StopAllPowerBlink(void)
void ExecuteCommand(char *cmnd, int source) void ExecuteCommand(char *cmnd, int source)
{ {
char stopic[CMDSZ];
char svalue[INPUT_BUFFER_SIZE];
char *start; char *start;
char *token; char *token;
@ -1641,9 +1575,13 @@ void ExecuteCommand(char *cmnd, int source)
start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble
if (start) { token = start +1; } if (start) { token = start +1; }
} }
uint16_t size = (token != NULL) ? strlen(token) : 0;
char stopic[size +2]; // / + \0
snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), (token == NULL) ? "" : token); snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), (token == NULL) ? "" : token);
token = strtok(NULL, ""); token = strtok(NULL, "");
// snprintf_P(svalue, sizeof(svalue), (token == NULL) ? "" : token); // Fails with command FullTopic home/%prefix%/%topic% as it processes %p of %prefix% size = (token != NULL) ? strlen(token) : 0;
char svalue[size +1];
strlcpy(svalue, (token == NULL) ? "" : token, sizeof(svalue)); // Fixed 5.8.0b strlcpy(svalue, (token == NULL) ? "" : token, sizeof(svalue)); // Fixed 5.8.0b
MqttDataHandler(stopic, (uint8_t*)svalue, strlen(svalue)); MqttDataHandler(stopic, (uint8_t*)svalue, strlen(svalue));
} }
@ -1672,13 +1610,13 @@ void PublishStatus(uint8_t payload)
snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]); snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]);
} }
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\"" D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"), snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\"" D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"),
(USER_MODULE == Settings.module)?0:Settings.module +1, stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.switch_topic, stemp2, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_switch_retain, Settings.flag.mqtt_sensor_retain, Settings.flag.mqtt_power_retain); ModuleNr(), stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.switch_topic, stemp2, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_switch_retain, Settings.flag.mqtt_sensor_retain, Settings.flag.mqtt_power_retain);
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS)); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS));
} }
if ((0 == payload) || (1 == payload)) { if ((0 == payload) || (1 == payload)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_JSON_BAUDRATE "\":%d,\"" 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_BOOTCOUNT "\":%d,\"" D_JSON_SAVECOUNT "\":%d,\"" D_JSON_SAVEADDRESS "\":\"%X\"}}"), snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_JSON_BAUDRATE "\":%d,\"" 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,\"" D_JSON_SAVECOUNT "\":%d,\"" D_JSON_SAVEADDRESS "\":\"%X\"}}"),
baudrate, Settings.mqtt_grptopic, Settings.ota_url, GetResetReason().c_str(), GetUptime().c_str(), GetDateAndTime(DT_RESTART).c_str(), Settings.sleep, Settings.bootcount, Settings.save_flag, GetSettingsAddress()); baudrate, Settings.mqtt_grptopic, Settings.ota_url, GetResetReason().c_str(), GetUptime().c_str(), GetDateAndTime(DT_RESTART).c_str(), Settings.sleep, Settings.cfg_holder, Settings.bootcount, Settings.save_flag, GetSettingsAddress());
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "1")); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "1"));
} }
@ -1712,8 +1650,8 @@ void PublishStatus(uint8_t payload)
} }
if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) { if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"MqttType\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"), snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"MqttType\":%d,\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"),
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MqttLibraryType(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE); Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MqttLibraryType(), MqttConnectCount(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6")); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6"));
} }
@ -1805,8 +1743,8 @@ void MqttShowState(void)
MqttShowPWMState(); MqttShowPWMState();
} }
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d}}"), snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d,\"" D_JSON_LINK_COUNT "\":%d,\"" D_JSON_DOWNTIME "\":\"%s\"}}"),
mqtt_data, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WiFi.BSSIDstr().c_str(), WiFi.channel(), WifiGetRssiAsQuality(WiFi.RSSI())); mqtt_data, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WiFi.BSSIDstr().c_str(), WiFi.channel(), WifiGetRssiAsQuality(WiFi.RSSI()), WifiLinkCount(), WifiDowntime().c_str());
} }
bool MqttShowSensor(void) bool MqttShowSensor(void)
@ -2114,14 +2052,33 @@ void Every250mSeconds(void)
} }
} }
if (restart_flag && (backlog_pointer == backlog_index)) { if (restart_flag && (backlog_pointer == backlog_index)) {
if ((214 == restart_flag) || (215 == restart_flag)) { if ((214 == restart_flag) || (215 == restart_flag) || (216 == restart_flag)) {
char storage[sizeof(Settings.sta_ssid) + sizeof(Settings.sta_pwd)]; char storage[sizeof(Settings.sta_ssid) + sizeof(Settings.sta_pwd)];
char storage_mqtt_host[sizeof(Settings.mqtt_host)];
uint16_t storage_mqtt_port;
char storage_mqtt_user[sizeof(Settings.mqtt_user)];
char storage_mqtt_pwd[sizeof(Settings.mqtt_pwd)];
char storage_mqtt_topic[sizeof(Settings.mqtt_topic)];
memcpy(storage, Settings.sta_ssid, sizeof(storage)); // Backup current SSIDs and Passwords memcpy(storage, Settings.sta_ssid, sizeof(storage)); // Backup current SSIDs and Passwords
if (215 == restart_flag) { if (216 == restart_flag) {
memcpy(storage_mqtt_host, Settings.mqtt_host, sizeof(Settings.mqtt_host));
storage_mqtt_port = Settings.mqtt_port;
memcpy(storage_mqtt_user, Settings.mqtt_user, sizeof(Settings.mqtt_user));
memcpy(storage_mqtt_pwd, Settings.mqtt_pwd, sizeof(Settings.mqtt_pwd));
memcpy(storage_mqtt_topic, Settings.mqtt_topic, sizeof(Settings.mqtt_topic));
}
if ((215 == restart_flag) || (216 == restart_flag)) {
SettingsErase(0); // Erase all flash from program end to end of physical flash SettingsErase(0); // Erase all flash from program end to end of physical flash
} }
SettingsDefault(); SettingsDefault();
memcpy(Settings.sta_ssid, storage, sizeof(storage)); // Restore current SSIDs and Passwords memcpy(Settings.sta_ssid, storage, sizeof(storage)); // Restore current SSIDs and Passwords
if (216 == restart_flag) { // Restore the mqtt host, port, username and password
memcpy(Settings.mqtt_host, storage_mqtt_host, sizeof(Settings.mqtt_host));
Settings.mqtt_port = storage_mqtt_port;
memcpy(Settings.mqtt_user, storage_mqtt_user, sizeof(Settings.mqtt_user));
memcpy(Settings.mqtt_pwd, storage_mqtt_pwd, sizeof(Settings.mqtt_pwd));
memcpy(Settings.mqtt_topic, storage_mqtt_topic, sizeof(Settings.mqtt_topic));
}
restart_flag = 2; restart_flag = 2;
} }
else if (213 == restart_flag) { else if (213 == restart_flag) {
@ -2237,7 +2194,8 @@ void ArduinoOTAInit(void)
void SerialInput(void) void SerialInput(void)
{ {
while (Serial.available()) { while (Serial.available()) {
yield(); // yield();
delay(0);
serial_in_byte = Serial.read(); serial_in_byte = Serial.read();
/*-------------------------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------------------------*\
@ -2346,17 +2304,23 @@ void GpioInit(void)
baudrate = APP_BAUDRATE; baudrate = APP_BAUDRATE;
} }
for (uint8_t i = 0; i < sizeof(Settings.user_template.gp); i++) {
if ((Settings.user_template.gp.io[i] >= GPIO_SENSOR_END) && (Settings.user_template.gp.io[i] < GPIO_USER)) {
Settings.user_template.gp.io[i] = GPIO_USER; // Fix not supported sensor ids in template
}
}
myio def_gp; myio def_gp;
ModuleGpios(&def_gp); ModuleGpios(&def_gp);
for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) {
if (Settings.my_gp.io[i] > GPIO_NONE) { if ((Settings.my_gp.io[i] >= GPIO_SENSOR_END) && (Settings.my_gp.io[i] < GPIO_USER)) {
Settings.my_gp.io[i] = GPIO_NONE; // Fix not supported sensor ids in module
}
else if (Settings.my_gp.io[i] > GPIO_NONE) {
my_module.io[i] = Settings.my_gp.io[i]; my_module.io[i] = Settings.my_gp.io[i];
} }
if ((def_gp.io[i] > GPIO_NONE) && (def_gp.io[i] < GPIO_USER)) { if ((def_gp.io[i] > GPIO_NONE) && (def_gp.io[i] < GPIO_USER)) {
my_module.io[i] = def_gp.io[i]; my_module.io[i] = def_gp.io[i];
if (USER_MODULE == Settings.module) {
Settings.my_gp.io[i] = def_gp.io[i]; // Copy user template settings
}
} }
} }
my_module_flag = ModuleFlag(); my_module_flag = ModuleFlag();

View File

@ -335,8 +335,10 @@ typedef struct MYCFGIO {
uint8_t io[MAX_GPIO_PIN - MIN_FLASH_PINS]; uint8_t io[MAX_GPIO_PIN - MIN_FLASH_PINS];
} mycfgio; } mycfgio;
#define GPIO_FLAG_USED 1 // Currently only one flag used
#define GPIO_FLAG_ADC0 1 // Allow ADC0 when define USE_ADC_VCC is disabled #define GPIO_FLAG_ADC0 1 // Allow ADC0 when define USE_ADC_VCC is disabled
#define GPIO_FLAG_PULLUP 2 // Allow input pull-up control using SetOption62 #define GPIO_FLAG_SPARE01 2 // Allow input pull-up control using SetOption62 - Superseded by user template editing
#define GPIO_FLAG_SPARE02 4 #define GPIO_FLAG_SPARE02 4
#define GPIO_FLAG_SPARE03 8 #define GPIO_FLAG_SPARE03 8
#define GPIO_FLAG_SPARE04 16 #define GPIO_FLAG_SPARE04 16
@ -348,7 +350,7 @@ typedef union {
uint8_t data; uint8_t data;
struct { struct {
uint8_t adc0 : 1; // Allow ADC0 when define USE_ADC_VCC is disabled uint8_t adc0 : 1; // Allow ADC0 when define USE_ADC_VCC is disabled
uint8_t pullup : 1; // Allow input pull-up control using SetOption62 uint8_t spare01 : 1;
uint8_t spare02 : 1; uint8_t spare02 : 1;
uint8_t spare03 : 1; uint8_t spare03 : 1;
uint8_t spare04 : 1; uint8_t spare04 : 1;
@ -974,7 +976,6 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_USER, // GPIO15 D8 GPIO_USER, // GPIO15 D8
GPIO_USER, // GPIO16 D0 Wemos Wake GPIO_USER, // GPIO16 D0 Wemos Wake
GPIO_FLAG_ADC0 // ADC0 A0 Analog input GPIO_FLAG_ADC0 // ADC0 A0 Analog input
// + GPIO_FLAG_PULLUP // Allow input pull-up control
}, },
{ "Sonoff Dev", // Sonoff Dev (ESP8266) { "Sonoff Dev", // Sonoff Dev (ESP8266)
GPIO_KEY1, // GPIO00 E-FW Button GPIO_KEY1, // GPIO00 E-FW Button
@ -1503,7 +1504,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_SWT2, // GPIO14 GPIO_SWT2, // GPIO14
GPIO_MCP39F5_RST, // GPIO15 MCP39F501 Reset GPIO_MCP39F5_RST, // GPIO15 MCP39F501 Reset
0, 0,
GPIO_FLAG_PULLUP // Allow input pull-up control 0
}, },
{ "Xiaomi Philips", // Xiaomi Philips bulb (ESP8266) { "Xiaomi Philips", // Xiaomi Philips bulb (ESP8266)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

View File

@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_ #ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_
#define VERSION 0x06040110 #define VERSION 0x06040112
#define D_PROGRAMNAME "Sonoff-Tasmota" #define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends" #define D_AUTHOR "Theo Arends"

View File

@ -154,7 +154,7 @@ char* subStr(char* dest, char* str, const char *delim, int index)
return sub; return sub;
} }
double CharToDouble(char *str) double CharToDouble(const char *str)
{ {
// simple ascii to double, because atof or strtod are too large // simple ascii to double, because atof or strtod are too large
char strbuf[24]; char strbuf[24];
@ -305,27 +305,6 @@ char* UpperCase_P(char* dest, const char* source)
return dest; return dest;
} }
/*
char* LTrim(char* p)
{
while ((*p != '\0') && (isblank(*p))) {
p++; // Trim leading spaces
}
return p;
}
char* RTrim(char* p)
{
char* q = p + strlen(p) -1;
while ((q >= p) && (isblank(*q))) {
q--; // Trim trailing spaces
}
q++;
*q = '\0';
return p;
}
*/
char* Trim(char* p) char* Trim(char* p)
{ {
while ((*p != '\0') && isblank(*p)) { p++; } // Trim leading spaces while ((*p != '\0') && isblank(*p)) { p++; } // Trim leading spaces
@ -505,162 +484,6 @@ String PressureUnit(void)
return (Settings.flag.pressure_conversion) ? String(D_UNIT_MILLIMETER_MERCURY) : String(D_UNIT_PRESSURE); return (Settings.flag.pressure_conversion) ? String(D_UNIT_MILLIMETER_MERCURY) : String(D_UNIT_PRESSURE);
} }
String AnyModuleName(uint8_t index)
{
if (USER_MODULE == index) {
return String(Settings.user_template.name);
} else {
return FPSTR(kModules[index].name);
}
}
String ModuleName()
{
return AnyModuleName(Settings.module);
}
void ModuleGpios(myio *gp)
{
uint8_t *dest = (uint8_t *)gp;
memset(dest, GPIO_NONE, sizeof(myio));
uint8_t src[sizeof(mycfgio)];
if (USER_MODULE == Settings.module) {
// src = Settings.user_template.gp;
memcpy(&src, &Settings.user_template.gp, sizeof(mycfgio));
} else {
memcpy_P(&src, &kModules[Settings.module].gp, sizeof(mycfgio));
}
// 11 85 00 85 85 00 00 00 15 38 85 00 00 81
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)&src, sizeof(mycfgio));
uint8_t j = 0;
for (uint8_t i = 0; i < sizeof(mycfgio); i++) {
if (6 == i) { j = 9; }
if (8 == i) { j = 12; }
dest[j] = src[i];
j++;
}
// 11 85 00 85 85 00 00 00 00 00 00 00 15 38 85 00 00 81
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)gp, sizeof(myio));
}
gpio_flag ModuleFlag()
{
gpio_flag flag;
if (USER_MODULE == Settings.module) {
flag = Settings.user_template.flag;
} else {
memcpy_P(&flag, &kModules[Settings.module].flag, sizeof(gpio_flag));
}
return flag;
}
void ModuleDefault(uint8_t module)
{
if (USER_MODULE == module) { module = WEMOS; } // Generic
Settings.user_template_base = module;
memcpy_P(&Settings.user_template, &kModules[module], sizeof(mytmplt));
}
void SetModuleType()
{
my_module_type = (USER_MODULE == Settings.module) ? Settings.user_template_base : Settings.module;
}
uint8_t ValidPin(uint8_t pin, uint8_t gpio)
{
uint8_t result = gpio;
if ((pin > 5) && (pin < 12)) {
result = GPIO_NONE; // Disable all flash pins
}
if (Settings.flag3.user_esp8285_enable) {
if ((pin == 9) || (pin == 10)) {
result = gpio; // Allow optional flash pins
}
}
return result;
}
bool ValidGPIO(uint8_t pin, uint8_t gpio)
{
bool result = false;
if (USER_MODULE == Settings.module) {
result = (ValidPin(pin, gpio) > GPIO_NONE); // Allow any pin
} else {
result = (GPIO_USER == ValidPin(pin, gpio)); // Only allow GPIO_USER pins
}
return result;
}
bool GetUsedInModule(uint8_t val, uint8_t *arr)
{
int offset = 0;
if (USER_MODULE == Settings.module) { return false; }
if (!val) { return false; } // None
if ((val >= GPIO_KEY1) && (val < GPIO_KEY1 + MAX_KEYS)) {
offset = (GPIO_KEY1_NP - GPIO_KEY1);
}
if ((val >= GPIO_KEY1_NP) && (val < GPIO_KEY1_NP + MAX_KEYS)) {
offset = -(GPIO_KEY1_NP - GPIO_KEY1);
}
if ((val >= GPIO_KEY1_INV) && (val < GPIO_KEY1_INV + MAX_KEYS)) {
offset = -(GPIO_KEY1_INV - GPIO_KEY1);
}
if ((val >= GPIO_KEY1_INV_NP) && (val < GPIO_KEY1_INV_NP + MAX_KEYS)) {
offset = -(GPIO_KEY1_INV_NP - GPIO_KEY1);
}
if ((val >= GPIO_SWT1) && (val < GPIO_SWT1 + MAX_SWITCHES)) {
offset = (GPIO_SWT1_NP - GPIO_SWT1);
}
if ((val >= GPIO_SWT1_NP) && (val < GPIO_SWT1_NP + MAX_SWITCHES)) {
offset = -(GPIO_SWT1_NP - GPIO_SWT1);
}
if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) {
offset = (GPIO_REL1_INV - GPIO_REL1);
}
if ((val >= GPIO_REL1_INV) && (val < GPIO_REL1_INV + MAX_RELAYS)) {
offset = -(GPIO_REL1_INV - GPIO_REL1);
}
if ((val >= GPIO_LED1) && (val < GPIO_LED1 + MAX_LEDS)) {
offset = (GPIO_LED1_INV - GPIO_LED1);
}
if ((val >= GPIO_LED1_INV) && (val < GPIO_LED1_INV + MAX_LEDS)) {
offset = -(GPIO_LED1_INV - GPIO_LED1);
}
if ((val >= GPIO_PWM1) && (val < GPIO_PWM1 + MAX_PWMS)) {
offset = (GPIO_PWM1_INV - GPIO_PWM1);
}
if ((val >= GPIO_PWM1_INV) && (val < GPIO_PWM1_INV + MAX_PWMS)) {
offset = -(GPIO_PWM1_INV - GPIO_PWM1);
}
if ((val >= GPIO_CNTR1) && (val < GPIO_CNTR1 + MAX_COUNTERS)) {
offset = (GPIO_CNTR1_NP - GPIO_CNTR1);
}
if ((val >= GPIO_CNTR1_NP) && (val < GPIO_CNTR1_NP + MAX_COUNTERS)) {
offset = -(GPIO_CNTR1_NP - GPIO_CNTR1);
}
for (uint8_t i = 0; i < MAX_GPIO_PIN; i++) {
if (arr[i] == val) { return true; }
if (arr[i] == val + offset) { return true; }
}
return false;
}
void SetGlobalValues(float temperature, float humidity) void SetGlobalValues(float temperature, float humidity)
{ {
global_update = uptime; global_update = uptime;
@ -872,6 +695,200 @@ void ShowSource(int source)
} }
} }
/*********************************************************************************************\
* GPIO Module and Template management
\*********************************************************************************************/
uint8_t ModuleNr()
{
// 0 = User module (255)
// 1 up = Template module 0 up
return (USER_MODULE == Settings.module) ? 0 : Settings.module +1;
}
String AnyModuleName(uint8_t index)
{
if (USER_MODULE == index) {
return String(Settings.user_template.name);
} else {
return FPSTR(kModules[index].name);
}
}
String ModuleName()
{
return AnyModuleName(Settings.module);
}
void ModuleGpios(myio *gp)
{
uint8_t *dest = (uint8_t *)gp;
memset(dest, GPIO_NONE, sizeof(myio));
uint8_t src[sizeof(mycfgio)];
if (USER_MODULE == Settings.module) {
memcpy(&src, &Settings.user_template.gp, sizeof(mycfgio));
} else {
memcpy_P(&src, &kModules[Settings.module].gp, sizeof(mycfgio));
}
// 11 85 00 85 85 00 00 00 15 38 85 00 00 81
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)&src, sizeof(mycfgio));
uint8_t j = 0;
for (uint8_t i = 0; i < sizeof(mycfgio); i++) {
if (6 == i) { j = 9; }
if (8 == i) { j = 12; }
dest[j] = src[i];
j++;
}
// 11 85 00 85 85 00 00 00 00 00 00 00 15 38 85 00 00 81
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)gp, sizeof(myio));
}
gpio_flag ModuleFlag()
{
gpio_flag flag;
if (USER_MODULE == Settings.module) {
flag = Settings.user_template.flag;
} else {
memcpy_P(&flag, &kModules[Settings.module].flag, sizeof(gpio_flag));
}
return flag;
}
void ModuleDefault(uint8_t module)
{
if (USER_MODULE == module) { module = WEMOS; } // Generic
Settings.user_template_base = module;
memcpy_P(&Settings.user_template, &kModules[module], sizeof(mytmplt));
}
void SetModuleType()
{
my_module_type = (USER_MODULE == Settings.module) ? Settings.user_template_base : Settings.module;
}
uint8_t ValidPin(uint8_t pin, uint8_t gpio)
{
uint8_t result = gpio;
if (((pin > 5) && (pin < 9)) || (11 == pin)) {
result = GPIO_NONE; // Disable flash pins GPIO6, GPIO7, GPIO8 and GPIO11
}
if ((WEMOS == Settings.module) && (!Settings.flag3.user_esp8285_enable)) {
if ((pin == 9) || (pin == 10)) { result = GPIO_NONE; } // Disable possible flash GPIO9 and GPIO10
}
return result;
}
bool ValidGPIO(uint8_t pin, uint8_t gpio)
{
return (GPIO_USER == ValidPin(pin, gpio)); // Only allow GPIO_USER pins
}
bool GetUsedInModule(uint8_t val, uint8_t *arr)
{
int offset = 0;
if (!val) { return false; } // None
if ((val >= GPIO_KEY1) && (val < GPIO_KEY1 + MAX_KEYS)) {
offset = (GPIO_KEY1_NP - GPIO_KEY1);
}
if ((val >= GPIO_KEY1_NP) && (val < GPIO_KEY1_NP + MAX_KEYS)) {
offset = -(GPIO_KEY1_NP - GPIO_KEY1);
}
if ((val >= GPIO_KEY1_INV) && (val < GPIO_KEY1_INV + MAX_KEYS)) {
offset = -(GPIO_KEY1_INV - GPIO_KEY1);
}
if ((val >= GPIO_KEY1_INV_NP) && (val < GPIO_KEY1_INV_NP + MAX_KEYS)) {
offset = -(GPIO_KEY1_INV_NP - GPIO_KEY1);
}
if ((val >= GPIO_SWT1) && (val < GPIO_SWT1 + MAX_SWITCHES)) {
offset = (GPIO_SWT1_NP - GPIO_SWT1);
}
if ((val >= GPIO_SWT1_NP) && (val < GPIO_SWT1_NP + MAX_SWITCHES)) {
offset = -(GPIO_SWT1_NP - GPIO_SWT1);
}
if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) {
offset = (GPIO_REL1_INV - GPIO_REL1);
}
if ((val >= GPIO_REL1_INV) && (val < GPIO_REL1_INV + MAX_RELAYS)) {
offset = -(GPIO_REL1_INV - GPIO_REL1);
}
if ((val >= GPIO_LED1) && (val < GPIO_LED1 + MAX_LEDS)) {
offset = (GPIO_LED1_INV - GPIO_LED1);
}
if ((val >= GPIO_LED1_INV) && (val < GPIO_LED1_INV + MAX_LEDS)) {
offset = -(GPIO_LED1_INV - GPIO_LED1);
}
if ((val >= GPIO_PWM1) && (val < GPIO_PWM1 + MAX_PWMS)) {
offset = (GPIO_PWM1_INV - GPIO_PWM1);
}
if ((val >= GPIO_PWM1_INV) && (val < GPIO_PWM1_INV + MAX_PWMS)) {
offset = -(GPIO_PWM1_INV - GPIO_PWM1);
}
if ((val >= GPIO_CNTR1) && (val < GPIO_CNTR1 + MAX_COUNTERS)) {
offset = (GPIO_CNTR1_NP - GPIO_CNTR1);
}
if ((val >= GPIO_CNTR1_NP) && (val < GPIO_CNTR1_NP + MAX_COUNTERS)) {
offset = -(GPIO_CNTR1_NP - GPIO_CNTR1);
}
for (uint8_t i = 0; i < MAX_GPIO_PIN; i++) {
if (arr[i] == val) { return true; }
if (arr[i] == val + offset) { return true; }
}
return false;
}
bool JsonTemplate(const char* dataBuf)
{
StaticJsonBuffer<350> jb; // 331 from https://arduinojson.org/v5/assistant/
JsonObject& obj = jb.parseObject(dataBuf);
if (!obj.success()) { return false; }
// All parameters are optional allowing for partial changes
const char* name = obj[D_JSON_NAME];
if (name != nullptr) {
strlcpy(Settings.user_template.name, name, sizeof(Settings.user_template.name));
}
if (obj[D_JSON_GPIO].success()) {
for (uint8_t i = 0; i < sizeof(mycfgio); i++) {
Settings.user_template.gp.io[i] = obj[D_JSON_GPIO][i] | 0;
}
}
if (obj[D_JSON_FLAG].success()) {
uint8_t flag = obj[D_JSON_FLAG] | 0;
memcpy(&Settings.user_template.flag, &flag, sizeof(gpio_flag));
}
if (obj[D_JSON_BASE].success()) {
uint8_t base = obj[D_JSON_BASE];
if ((0 == base) || (base >= MAXMODULE)) { base = 17; } else { base--; }
Settings.user_template_base = base; // Default WEMOS
}
return true;
}
void TemplateJson()
{
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), Settings.user_template.name);
for (uint8_t i = 0; i < sizeof(Settings.user_template.gp); i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (i>0)?",":"", Settings.user_template.gp.io[i]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"),
mqtt_data, Settings.user_template.flag, Settings.user_template_base +1);
}
/*********************************************************************************************\ /*********************************************************************************************\
* Sleep aware time scheduler functions borrowed from ESPEasy * Sleep aware time scheduler functions borrowed from ESPEasy
\*********************************************************************************************/ \*********************************************************************************************/

View File

@ -50,12 +50,6 @@ void ButtonInvertFlag(uint8 button_bit)
void ButtonInit(void) void ButtonInit(void)
{ {
if (my_module_flag.pullup) {
if (Settings.flag3.no_pullup) {
key_no_pullup = 0xff;
}
}
buttons_found = 0; buttons_found = 0;
for (uint8_t i = 0; i < MAX_KEYS; i++) { for (uint8_t i = 0; i < MAX_KEYS; i++) {
if (pin[GPIO_KEY1 +i] < 99) { if (pin[GPIO_KEY1 +i] < 99) {

View File

@ -87,6 +87,23 @@ String GetTimeZone(void)
return String(tz); // -03:45 return String(tz); // -03:45
} }
String GetDuration(uint32_t time)
{
char dt[16];
TIME_T ut;
BreakTime(time, ut);
// "P128DT14H35M44S" - ISO8601:2004 - https://en.wikipedia.org/wiki/ISO_8601 Durations
// snprintf_P(dt, sizeof(dt), PSTR("P%dDT%02dH%02dM%02dS"), ut.days, ut.hour, ut.minute, ut.second);
// "128 14:35:44" - OpenVMS
// "128T14:35:44" - Tasmota
snprintf_P(dt, sizeof(dt), PSTR("%dT%02d:%02d:%02d"), ut.days, ut.hour, ut.minute, ut.second);
return String(dt); // 128T14:35:44
}
String GetDT(uint32_t time) String GetDT(uint32_t time)
{ {
// "2017-03-07T11:08:02" - ISO8601:2004 // "2017-03-07T11:08:02" - ISO8601:2004
@ -155,42 +172,26 @@ String GetTime(int type)
return String(stime); // Thu Nov 01 11:41:02 2018 return String(stime); // Thu Nov 01 11:41:02 2018
} }
uint32_t UpTime(void)
{
if (restart_time) {
return utc_time - restart_time;
} else {
return uptime;
}
}
uint32_t MinutesUptime(void)
{
return (UpTime() / 60);
}
String GetUptime(void) String GetUptime(void)
{ {
char dt[16]; return GetDuration(UpTime());
TIME_T ut;
if (restart_time) {
BreakTime(utc_time - restart_time, ut);
} else {
BreakTime(uptime, ut);
}
// "P128DT14H35M44S" - ISO8601:2004 - https://en.wikipedia.org/wiki/ISO_8601 Durations
// snprintf_P(dt, sizeof(dt), PSTR("P%dDT%02dH%02dM%02dS"), ut.days, ut.hour, ut.minute, ut.second);
// "128 14:35:44" - OpenVMS
// "128T14:35:44" - Tasmota
snprintf_P(dt, sizeof(dt), PSTR("%dT%02d:%02d:%02d"), ut.days, ut.hour, ut.minute, ut.second);
return String(dt); // 128T14:35:44
} }
uint32_t GetMinutesUptime(void) uint32_t MinutesPastMidnight(void)
{
TIME_T ut;
if (restart_time) {
BreakTime(utc_time - restart_time, ut);
} else {
BreakTime(uptime, ut);
}
return (ut.days *1440) + (ut.hour *60) + ut.minute;
}
uint32_t GetMinutesPastMidnight(void)
{ {
uint32_t minutes = 0; uint32_t minutes = 0;
@ -322,6 +323,11 @@ uint32_t RuleToTime(TimeRule r, int yr)
return t; return t;
} }
uint32_t UtcTime(void)
{
return utc_time;
}
uint32_t LocalTime(void) uint32_t LocalTime(void)
{ {
return local_time; return local_time;

View File

@ -110,12 +110,6 @@ void SwitchProbe(void)
void SwitchInit(void) void SwitchInit(void)
{ {
if (my_module_flag.pullup) {
if (Settings.flag3.no_pullup) {
switch_no_pullup = 0xffff;
}
}
switches_found = 0; switches_found = 0;
for (uint8_t i = 0; i < MAX_SWITCHES; i++) { for (uint8_t i = 0; i < MAX_SWITCHES; i++) {
lastwallswitch[i] = 1; // Init global to virtual switch state; lastwallswitch[i] = 1; // Init global to virtual switch state;

View File

@ -49,6 +49,9 @@ using namespace axTLS;
*/ */
#include <ESP8266WiFi.h> // Wifi, MQTT, Ota, WifiManager #include <ESP8266WiFi.h> // Wifi, MQTT, Ota, WifiManager
uint32_t wifi_last_event = 0; // Last wifi connection event
uint32_t wifi_downtime = 0; // Wifi down duration
uint16_t wifi_link_count = 0; // Number of wifi re-connect
uint8_t wifi_counter; uint8_t wifi_counter;
uint8_t wifi_retry_init; uint8_t wifi_retry_init;
uint8_t wifi_retry; uint8_t wifi_retry;
@ -171,9 +174,9 @@ void WifiConfig(uint8_t type)
} }
#endif // USE_WPS #endif // USE_WPS
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
else if (WIFI_MANAGER == wifi_config_type) { else if (WIFI_MANAGER == wifi_config_type || WIFI_MANAGER_RESET_ONLY == wifi_config_type) {
AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES)); AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES));
WifiManagerBegin(); WifiManagerBegin(WIFI_MANAGER_RESET_ONLY == wifi_config_type);
} }
#endif // USE_WEBSERVER #endif // USE_WEBSERVER
} }
@ -222,7 +225,8 @@ void WifiBegin(uint8_t flag, uint8_t channel)
delay(200); delay(200);
WiFi.mode(WIFI_STA); // Disable AP mode WiFi.mode(WIFI_STA); // Disable AP mode
WiFiSetSleepMode(); WiFiSetSleepMode();
// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); } // if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); } // B/G/N
// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11G) { WiFi.setPhyMode(WIFI_PHY_MODE_11G); } // B/G
if (!WiFi.getAutoConnect()) { WiFi.setAutoConnect(true); } if (!WiFi.getAutoConnect()) { WiFi.setAutoConnect(true); }
// WiFi.setAutoReconnect(true); // WiFi.setAutoReconnect(true);
switch (flag) { switch (flag) {
@ -339,13 +343,26 @@ void WifiBeginAfterScan()
} }
} }
uint16_t WifiLinkCount()
{
return wifi_link_count;
}
String WifiDowntime()
{
return GetDuration(wifi_downtime);
}
void WifiSetState(uint8_t state) void WifiSetState(uint8_t state)
{ {
if (state == global_state.wifi_down) { if (state == global_state.wifi_down) {
if (state) { if (state) {
rules_flag.wifi_connected = 1; rules_flag.wifi_connected = 1;
wifi_link_count++;
wifi_downtime += UpTime() - wifi_last_event;
} else { } else {
rules_flag.wifi_disconnected = 1; rules_flag.wifi_disconnected = 1;
wifi_last_event = UpTime();
} }
} }
global_state.wifi_down = state ^1; global_state.wifi_down = state ^1;

View File

@ -66,6 +66,7 @@ const char HTTP_SCRIPT_COUNTER[] PROGMEM =
"setTimeout(u,1000);" "setTimeout(u,1000);"
"}" "}"
"}" "}"
"window.onload=u;"
"</script>"; "</script>";
const char HTTP_SCRIPT_ROOT[] PROGMEM = const char HTTP_SCRIPT_ROOT[] PROGMEM =
@ -92,7 +93,8 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM =
"}" "}"
"function lc(p){" "function lc(p){"
"la('?t='+p);" // ?t related to WebGetArg("t", tmp, sizeof(tmp)); "la('?t='+p);" // ?t related to WebGetArg("t", tmp, sizeof(tmp));
"}"; "}"
"window.onload=la();";
const char HTTP_SCRIPT_WIFI[] PROGMEM = const char HTTP_SCRIPT_WIFI[] PROGMEM =
"function c(l){" "function c(l){"
@ -144,33 +146,80 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM =
"lt=setTimeout(l,{a});" "lt=setTimeout(l,{a});"
"return false;" "return false;"
"}" "}"
"window.onload=l;"
"</script>"; "</script>";
const char HTTP_SCRIPT_MODULE1[] PROGMEM =
const char HTTP_SCRIPT_MODULE_TEMPLATE[] PROGMEM =
"var os;" "var os;"
"function sk(s,g){" // s = value, g = id and name "function sk(s,g){" // s = value, g = id and name
"var o=os.replace(/}1/g,\"<option value=\").replace(/}2/g,\"</option>\").replace(\"value='\"+s+\"'\",\"selected value='\"+s+\"'\");" "var o=os.replace(/}1/g,\"<option value=\").replace(/}2/g,\"</option>\");"
"eb('g'+g).innerHTML=o;" "eb('g'+g).innerHTML=o;"
"eb('g'+g).value=s;"
"}" "}"
"function sl(){" "function ld(u,f){"
"a=new XMLHttpRequest();" "var x=new XMLHttpRequest();"
"a.onreadystatechange=function(){" "x.onreadystatechange=function(){"
"if(a.readyState==4&&a.status==200){" "if(this.readyState==4&&this.status==200){"
"f(this);"
"}"
"};"
"x.open('GET',u,true);"
"x.send();"
"}";
const char HTTP_SCRIPT_TEMPLATE[] PROGMEM =
"var c;" // Need a global for BASE
"function x1(b){"
"var i,j,g,k,m,o=b.responseText;"
"k=o.indexOf(\"}1\");" // Template name until }1
"if(eb('s1').value==''){"
"eb('s1').value=o.substring(0,k);" // Set NAME if not yet set
"}"
"m=o.indexOf(\"}3\");" // Sensor names until }3
"os=o.substring(k,m);" // Complete GPIO sensor list
"g=o.substring(m+2).split(',');" // +2 is length "}3"
"j=0;"
"for(i=0;i<13;i++){" // Supports 13 GPIOs
"if(6==i){j=9;}"
"if(8==i){j=12;}"
"sk(g[i],j);" // Set GPIO
"j++;"
"}"
"for(i=0;i<" STR(GPIO_FLAG_USED) ";i++){"
"p=(g[13]>>i)&1;"
"eb('c'+i).checked=p;" // Set FLAG checkboxes
"}"
"if(" STR(USER_MODULE) "==c){"
"eb('g99').value=g[14];" // Set BASE for initial select
"}"
"}"
"function st(t){"
"c=t;" // Needed for initial BASE select
"var a='tp?t='+t;"
"ld(a,x1);" // ?t related to WebGetArg("t", stemp, sizeof(stemp));
"}"
"function x2(a){"
"os=a.responseText;"
"sk(17,99);" // 17 = WEMOS
"st(" STR(USER_MODULE) ");"
"}"
"window.onload=ld('tp?m=1',x2);"; // ?m related to WebServer->hasArg("m")
const char HTTP_SCRIPT_MODULE1[] PROGMEM =
"function x1(a){"
"os=a.responseText;" "os=a.responseText;"
"sk(}4,99);" "sk(}4,99);"
"}" "}"
"};" "function x2(b){"
"a.open('GET','md?m=1',true);" // ?m related to WebServer->hasArg("m")
"a.send();"
"b=new XMLHttpRequest();"
"b.onreadystatechange=function(){"
"if(b.readyState==4&&b.status==200){"
"os=b.responseText;"; "os=b.responseText;";
const char HTTP_SCRIPT_MODULE2[] PROGMEM = const char HTTP_SCRIPT_MODULE2[] PROGMEM =
"}" "}"
"};" "function sl(){"
"b.open('GET','md?g=1',true);" // ?g related to WebServer->hasArg("g") "ld('md?m=1',x1);" // ?m related to WebServer->hasArg("m")
"b.send();" "ld('md?g=1',x2);" // ?m related to WebServer->hasArg("m")
"}"; "}"
"window.onload=sl;";
const char HTTP_SCRIPT_MODULE3[] PROGMEM = const char HTTP_SCRIPT_MODULE3[] PROGMEM =
"}1'%d'>%s (%d)}2"; // "}1" and "}2" means do not use "}x" in Module name and Sensor name "}1'%d'>%s (%d)}2"; // "}1" and "}2" means do not use "}x" in Module name and Sensor name
@ -182,6 +231,7 @@ const char HTTP_SCRIPT_INFO_END[] PROGMEM =
"s=o.replace(/}1/g,\"</td></tr><tr><th>\").replace(/}2/g,\"</th><td>\");" "s=o.replace(/}1/g,\"</td></tr><tr><th>\").replace(/}2/g,\"</th><td>\");"
"eb('i').innerHTML=s;" "eb('i').innerHTML=s;"
"}" "}"
"window.onload=i;"
"</script>"; "</script>";
const char HTTP_HEAD_STYLE[] PROGMEM = const char HTTP_HEAD_STYLE[] PROGMEM =
@ -189,7 +239,10 @@ const char HTTP_HEAD_STYLE[] PROGMEM =
"<style>" "<style>"
"div,fieldset,input,select{padding:5px;font-size:1em;}" "div,fieldset,input,select{padding:5px;font-size:1em;}"
"fieldset{background-color:#f2f2f2;}" // Also update HTTP_TIMER_STYLE
"p{margin:0.5em 0;}"
"input{width:100%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;}" "input{width:100%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;}"
"input[type=checkbox],input[type=radio]{width:1em;margin-right:6px;vertical-align:-1px;}"
"select{width:100%;}" "select{width:100%;}"
"textarea{resize:none;width:98%;height:318px;padding:5px;overflow:auto;}" "textarea{resize:none;width:98%;height:318px;padding:5px;overflow:auto;}"
"body{text-align:center;font-family:verdana;}" "body{text-align:center;font-family:verdana;}"
@ -226,82 +279,121 @@ const char HTTP_MSG_SLIDER2[] PROGMEM =
"<div><input type='range' min='1' max='100' value='%d' onchange='lb(value)'></div>"; "<div><input type='range' min='1' max='100' value='%d' onchange='lb(value)'></div>";
const char HTTP_MSG_RSTRT[] PROGMEM = const char HTTP_MSG_RSTRT[] PROGMEM =
"<br/><div style='text-align:center;'>" D_DEVICE_WILL_RESTART "</div><br/>"; "<br/><div style='text-align:center;'>" D_DEVICE_WILL_RESTART "</div><br/>";
const char HTTP_BTN_MENU1[] PROGMEM = const char HTTP_BTN_MENU1[] PROGMEM =
#ifndef FIRMWARE_MINIMAL
"<br/><form action='cn' method='get'><button>" D_CONFIGURATION "</button></form>"
"<br/><form action='in' method='get'><button>" D_INFORMATION "</button></form>"
#endif
"<br/><form action='up' method='get'><button>" D_FIRMWARE_UPGRADE "</button></form>"
"<br/><form action='cs' method='get'><button>" D_CONSOLE "</button></form>";
const char HTTP_BTN_RSTRT[] PROGMEM =
"<br/><form action='.' method='get' onsubmit='return confirm(\"" D_CONFIRM_RESTART "\");'><button name='rstrt' class='button bred'>" D_RESTART "</button></form>";
const char HTTP_BTN_MENU_MODULE[] PROGMEM =
"<br/><form action='md' method='get'><button>" D_CONFIGURE_MODULE "</button></form>"
"<br/><form action='wi' method='get'><button>" D_CONFIGURE_WIFI "</button></form>";
const char HTTP_BTN_MENU4[] PROGMEM =
"<br/><form action='lg' method='get'><button>" D_CONFIGURE_LOGGING "</button></form>"
"<br/><form action='co' method='get'><button>" D_CONFIGURE_OTHER "</button></form>"
"<br/>" "<br/>"
"<br/><form action='rt' method='get' onsubmit='return confirm(\"" D_CONFIRM_RESET_CONFIGURATION "\");'><button class='button bred'>" D_RESET_CONFIGURATION "</button></form>" #ifndef FIRMWARE_MINIMAL
"<br/><form action='dl' method='get'><button>" D_BACKUP_CONFIGURATION "</button></form>" "<form action='cn' method='get'><button>" D_CONFIGURATION "</button></form>"
"<br/><form action='rs' method='get'><button>" D_RESTORE_CONFIGURATION "</button></form>"; "<p><form action='in' method='get'><button>" D_INFORMATION "</button></form></p>"
#endif
"<form action='up' method='get'><button>" D_FIRMWARE_UPGRADE "</button></form>"
"<p><form action='cs' method='get'><button>" D_CONSOLE "</button></form></p>";
const char HTTP_BTN_RSTRT[] PROGMEM =
"<form action='.' method='get' onsubmit='return confirm(\"" D_CONFIRM_RESTART "\");'><button name='rstrt' class='button bred'>" D_RESTART "</button></form>";
const char HTTP_BTN_MENU_MODULE[] PROGMEM =
"<p><form action='md' method='get'><button>" D_CONFIGURE_MODULE "</button></form></p>"
"<p><form action='wi' method='get'><button>" D_CONFIGURE_WIFI "</button></form></p>";
const char HTTP_BTN_RESET[] PROGMEM =
"<br/>"
"<form action='rt' method='get' onsubmit='return confirm(\"" D_CONFIRM_RESET_CONFIGURATION "\");'><button class='button bred'>" D_RESET_CONFIGURATION "</button></form>";
const char HTTP_BTN_MENU4[] PROGMEM =
"<p><form action='lg' method='get'><button>" D_CONFIGURE_LOGGING "</button></form></p>"
"<p><form action='co' method='get'><button>" D_CONFIGURE_OTHER "</button></form></p>"
"<p><form action='tp' method='get'><button>" D_CONFIGURE_TEMPLATE "</button></form></p>";
const char HTTP_BTN_MENU5[] PROGMEM =
"<p><form action='dl' method='get'><button>" D_BACKUP_CONFIGURATION "</button></form></p>"
"<p><form action='rs' method='get'><button>" D_RESTORE_CONFIGURATION "</button></form></p>";
const char HTTP_BTN_MAIN[] PROGMEM = const char HTTP_BTN_MAIN[] PROGMEM =
"<br/><br/><form action='.' method='get'><button>" D_MAIN_MENU "</button></form>"; "<br/>"
"<form action='.' method='get'><button>" D_MAIN_MENU "</button></form>";
const char HTTP_FORM_LOGIN[] PROGMEM = const char HTTP_FORM_LOGIN[] PROGMEM =
"<form method='post' action='/'>" "<form method='post' action='/'>"
"<br/><b>" D_USER "</b><br/><input name='USER1' placeholder='" D_USER "'><br/>" "<br/><b>" D_USER "</b><br/><input name='USER1' placeholder='" D_USER "'><br/>"
"<br/><b>" D_PASSWORD "</b><br/><input name='PASS1' type='password' placeholder='" D_PASSWORD "'><br/>" "<br/><b>" D_PASSWORD "</b><br/><input name='PASS1' type='password' placeholder='" D_PASSWORD "'><br/>"
"<br/>" "<br/>"
"<br/><button>" D_OK "</button></form>"; "<br/><button>" D_OK "</button></form>";
const char HTTP_BTN_CONF[] PROGMEM =
"<br/><br/><form action='cn' method='get'><button>" D_CONFIGURATION "</button></form>";
const char HTTP_FORM_MODULE[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_MODULE_PARAMETERS "&nbsp;</b></legend><form method='get' action='md'>"
"<br/><b>" D_MODULE_TYPE "</b> ({mt)<br/><select id='g99' name='g99'></select><br/>";
const char HTTP_FORM_MODULE_PULLUP[] PROGMEM = const char HTTP_BTN_CONF[] PROGMEM =
"<br/><input style='width:10%;' id='b1' name='b1' type='checkbox'{r1><b>" D_PULLUP_ENABLE "</b><br/>"; "<br/>"
"<form action='cn' method='get'><button>" D_CONFIGURATION "</button></form>";
const char HTTP_FORM_TEMPLATE[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_TEMPLATE_PARAMETERS "&nbsp;</b></legend>"
"<form method='get' action='tp'>"
"<p><b>" D_TEMPLATE_NAME "</b><br/><input id='s1' name='s1' placeholder='" D_TEMPLATE_NAME "'></p>"
"<p></p><b>" D_BASE_TYPE "</b><br/><select id='g99' name='g99' onchange='st(this.value)'></select><br/>";
const char HTTP_FORM_TEMPLATE_FLAG[] PROGMEM =
"<p></p>" // Keep close so do not use <br/>
"<fieldset><legend><b>&nbsp;" D_TEMPLATE_FLAGS "&nbsp;</b></legend><p>"
"<input id='c0' name='c0' type='checkbox'><b>" D_ALLOW_ADC0 "</b><br/>"
"</p></fieldset>";
const char HTTP_FORM_MODULE[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_MODULE_PARAMETERS "&nbsp;</b></legend>"
"<form method='get' action='md'>"
"<p></p><b>" D_MODULE_TYPE "</b> ({mt)<br/><select id='g99' name='g99'></select><br/>";
const char HTTP_LNK_ITEM[] PROGMEM = const char HTTP_LNK_ITEM[] PROGMEM =
"<div><a href='#p' onclick='c(this)'>{v}</a>&nbsp;({w})&nbsp<span class='q'>{i} {r}%</span></div>"; "<div><a href='#p' onclick='c(this)'>{v}</a>&nbsp;({w})&nbsp<span class='q'>{i} {r}%</span></div>";
const char HTTP_LNK_SCAN[] PROGMEM = const char HTTP_LNK_SCAN[] PROGMEM =
"<div><a href='/wi?scan='>" D_SCAN_FOR_WIFI_NETWORKS "</a></div><br/>"; "<div><a href='/wi?scan='>" D_SCAN_FOR_WIFI_NETWORKS "</a></div><br/>";
const char HTTP_FORM_WIFI[] PROGMEM = const char HTTP_FORM_WIFI[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_WIFI_PARAMETERS "&nbsp;</b></legend><form method='get' action='wi'>" "<fieldset><legend><b>&nbsp;" D_WIFI_PARAMETERS "&nbsp;</b></legend>"
"<br/><b>" D_AP1_SSID "</b> (" STA_SSID1 ")<br/><input id='s1' name='s1' placeholder='" STA_SSID1 "' value='{s1'><br/>" "<form method='get' action='wi'>"
"<br/><b>" D_AP1_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_AP1_PASSWORD "' value='" D_ASTERIX "'><br/>" "<p><b>" D_AP1_SSID "</b> (" STA_SSID1 ")<br/><input id='s1' name='s1' placeholder='" STA_SSID1 "' value='{s1'></p>"
"<br/><b>" D_AP2_SSID "</b> (" STA_SSID2 ")<br/><input id='s2' name='s2' placeholder='" STA_SSID2 "' value='{s2'><br/>" "<p><b>" D_AP1_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_AP1_PASSWORD "' value='" D_ASTERISK_PWD "'></p>"
"<br/><b>" D_AP2_PASSWORD "</b><br/><input id='p2' name='p2' type='password' placeholder='" D_AP2_PASSWORD "' value='" D_ASTERIX "'><br/>" "<p><b>" D_AP2_SSID "</b> (" STA_SSID2 ")<br/><input id='s2' name='s2' placeholder='" STA_SSID2 "' value='{s2'></p>"
"<br/><b>" D_HOSTNAME "</b> (" WIFI_HOSTNAME ")<br/><input id='h' name='h' placeholder='" WIFI_HOSTNAME" ' value='{h1'><br/>"; "<p><b>" D_AP2_PASSWORD "</b><br/><input id='p2' name='p2' type='password' placeholder='" D_AP2_PASSWORD "' value='" D_ASTERISK_PWD "'></p>"
"<p><b>" D_HOSTNAME "</b> (" WIFI_HOSTNAME ")<br/><input id='h' name='h' placeholder='" WIFI_HOSTNAME" ' value='{h1'></p>";
const char HTTP_FORM_LOG1[] PROGMEM = const char HTTP_FORM_LOG1[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_LOGGING_PARAMETERS "&nbsp;</b></legend><form method='get' action='lg'>"; "<fieldset><legend><b>&nbsp;" D_LOGGING_PARAMETERS "&nbsp;</b>"
"</legend><form method='get' action='lg'>";
const char HTTP_FORM_LOG2[] PROGMEM = const char HTTP_FORM_LOG2[] PROGMEM =
"<br/><b>{b0</b> ({b1)<br/><select id='{b2' name='{b2'>" "<p><b>{b0</b> ({b1)<br/><select id='{b2' name='{b2'>"
"<option{a0value='0'>0 " D_NONE "</option>" "<option{a0value='0'>0 " D_NONE "</option>"
"<option{a1value='1'>1 " D_ERROR "</option>" "<option{a1value='1'>1 " D_ERROR "</option>"
"<option{a2value='2'>2 " D_INFO "</option>" "<option{a2value='2'>2 " D_INFO "</option>"
"<option{a3value='3'>3 " D_DEBUG "</option>" "<option{a3value='3'>3 " D_DEBUG "</option>"
"<option{a4value='4'>4 " D_MORE_DEBUG "</option>" "<option{a4value='4'>4 " D_MORE_DEBUG "</option>"
"</select><br/>"; "</select></p>";
const char HTTP_FORM_LOG3[] PROGMEM = const char HTTP_FORM_LOG3[] PROGMEM =
"<br/><b>" D_SYSLOG_HOST "</b> (" SYS_LOG_HOST ")<br/><input id='lh' name='lh' placeholder='" SYS_LOG_HOST "' value='{l2'><br/>" "<p><b>" D_SYSLOG_HOST "</b> (" SYS_LOG_HOST ")<br/><input id='lh' name='lh' placeholder='" SYS_LOG_HOST "' value='{l2'></p>"
"<br/><b>" D_SYSLOG_PORT "</b> (" STR(SYS_LOG_PORT) ")<br/><input id='lp' name='lp' placeholder='" STR(SYS_LOG_PORT) "' value='{l3'><br/>" "<p><b>" D_SYSLOG_PORT "</b> (" STR(SYS_LOG_PORT) ")<br/><input id='lp' name='lp' placeholder='" STR(SYS_LOG_PORT) "' value='{l3'></p>"
"<br/><b>" D_TELEMETRY_PERIOD "</b> (" STR(TELE_PERIOD) ")<br/><input id='lt' name='lt' placeholder='" STR(TELE_PERIOD) "' value='{l4'><br/>"; "<p><b>" D_TELEMETRY_PERIOD "</b> (" STR(TELE_PERIOD) ")<br/><input id='lt' name='lt' placeholder='" STR(TELE_PERIOD) "' value='{l4'></p>";
const char HTTP_FORM_OTHER[] PROGMEM = const char HTTP_FORM_OTHER[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_OTHER_PARAMETERS "&nbsp;</b></legend><form method='get' action='co'>" "<fieldset><legend><b>&nbsp;" D_OTHER_PARAMETERS "&nbsp;</b></legend>"
// "<input id='w' name='w' value='5,1' hidden>" "<form method='get' action='co'>"
"<br/><b>" D_WEB_ADMIN_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_WEB_ADMIN_PASSWORD "' value='" D_ASTERIX "'><br/>" "<p></p>"
"<br/><input style='width:10%;' id='b1' name='b1' type='checkbox'{r1><b>" D_MQTT_ENABLE "</b><br/>"; "<fieldset><legend><b>&nbsp;" D_TEMPLATE "&nbsp;</b></legend>"
"<p><input id='t1' name='t1' placeholder='" D_TEMPLATE "' value='{t1'></p>"
"<p><input id='t2' name='t2' type='checkbox'{t2><b>" D_ACTIVATE "</b></p>"
"</fieldset>"
"<br/>"
"<b>" D_WEB_ADMIN_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_WEB_ADMIN_PASSWORD "' value='" D_ASTERIX "'><br/>"
"<br>"
"<input id='b1' name='b1' type='checkbox'{r1><b>" D_MQTT_ENABLE "</b><br/>"
"<br/>";
const char HTTP_FORM_OTHER2[] PROGMEM = const char HTTP_FORM_OTHER2[] PROGMEM =
"<br/><b>" D_FRIENDLY_NAME " {1</b> ({2)<br/><input id='a{1' name='a{1' placeholder='{2' value='{3'><br/>"; "<b>" D_FRIENDLY_NAME " {1</b> ({2)<br/><input id='a{1' name='a{1' placeholder='{2' value='{3'><p></p>";
#ifdef USE_EMULATION #ifdef USE_EMULATION
const char HTTP_FORM_OTHER3a[] PROGMEM = const char HTTP_FORM_OTHER3a[] PROGMEM =
"<br/><fieldset><legend><b>&nbsp;" D_EMULATION "&nbsp;</b></legend>"; "<p></p>" // Keep close to Friendlynames so do not use <br/>
"<fieldset><legend><b>&nbsp;" D_EMULATION "&nbsp;</b></legend><p>";
const char HTTP_FORM_OTHER3b[] PROGMEM = const char HTTP_FORM_OTHER3b[] PROGMEM =
"<br/><input style='width:10%;' id='r{1' name='b2' type='radio' value='{1'{2><b>{3</b>{4"; // Different id only used for labels "<input id='r{1' name='b2' type='radio' value='{1'{2><b>{3</b>{4<br/>"; // Different id only used for labels
const char HTTP_FORM_OTHER3c[] PROGMEM =
"</p></fieldset>";
#endif // USE_EMULATION #endif // USE_EMULATION
const char HTTP_FORM_END[] PROGMEM = const char HTTP_FORM_END[] PROGMEM =
"<br/><button name='save' type='submit' class='button bgrn'>" D_SAVE "</button></form></fieldset>"; "<br/>"
"<button name='save' type='submit' class='button bgrn'>" D_SAVE "</button>"
"</form></fieldset>";
const char HTTP_FORM_RST[] PROGMEM = const char HTTP_FORM_RST[] PROGMEM =
"<div id='f1' name='f1' style='display:block;'>" "<div id='f1' name='f1' style='display:block;'>"
"<fieldset><legend><b>&nbsp;" D_RESTORE_CONFIGURATION "&nbsp;</b></legend>"; "<fieldset><legend><b>&nbsp;" D_RESTORE_CONFIGURATION "&nbsp;</b></legend>";
@ -309,7 +401,7 @@ const char HTTP_FORM_UPG[] PROGMEM =
"<div id='f1' name='f1' style='display:block;'>" "<div id='f1' name='f1' style='display:block;'>"
"<fieldset><legend><b>&nbsp;" D_UPGRADE_BY_WEBSERVER "&nbsp;</b></legend>" "<fieldset><legend><b>&nbsp;" D_UPGRADE_BY_WEBSERVER "&nbsp;</b></legend>"
"<form method='get' action='u1'>" "<form method='get' action='u1'>"
"<br/>" D_OTA_URL "<br/><input id='o' name='o' placeholder='OTA_URL' value='{o1'><br/>" "<br/><b>" D_OTA_URL "</b><br/><input id='o' name='o' placeholder='OTA_URL' value='{o1'><br/>"
"<br/><button type='submit'>" D_START_UPGRADE "</button></form>" "<br/><button type='submit'>" D_START_UPGRADE "</button></form>"
"</fieldset><br/><br/>" "</fieldset><br/><br/>"
"<fieldset><legend><b>&nbsp;" D_UPGRADE_BY_FILE_UPLOAD "&nbsp;</b></legend>"; "<fieldset><legend><b>&nbsp;" D_UPGRADE_BY_FILE_UPLOAD "&nbsp;</b></legend>";
@ -347,7 +439,7 @@ const char HDR_CTYPE_JSON[] PROGMEM = "application/json";
const char HDR_CTYPE_STREAM[] PROGMEM = "application/octet-stream"; const char HDR_CTYPE_STREAM[] PROGMEM = "application/octet-stream";
#define DNS_PORT 53 #define DNS_PORT 53
enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER}; enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER, HTTP_MANAGER_RESET_ONLY};
DNSServer *DnsServer; DNSServer *DnsServer;
ESP8266WebServer *WebServer; ESP8266WebServer *WebServer;
@ -370,6 +462,10 @@ static void WebGetArg(const char* arg, char* out, size_t max)
// out[max-1] = '\0'; // Ensure terminating NUL // out[max-1] = '\0'; // Ensure terminating NUL
} }
static bool WifiIsInManagerMode(){
return (HTTP_MANAGER == webserver_state || HTTP_MANAGER_RESET_ONLY == webserver_state);
}
void ShowWebSource(int source) void ShowWebSource(int source)
{ {
if ((source > 0) && (source < SRC_MAX)) { if ((source > 0) && (source < SRC_MAX)) {
@ -390,8 +486,13 @@ void StartWebserver(int type, IPAddress ipweb)
if (!Settings.web_refresh) { Settings.web_refresh = HTTP_REFRESH_TIME; } if (!Settings.web_refresh) { Settings.web_refresh = HTTP_REFRESH_TIME; }
if (!webserver_state) { if (!webserver_state) {
if (!WebServer) { if (!WebServer) {
WebServer = new ESP8266WebServer((HTTP_MANAGER==type) ? 80 : WEB_PORT); WebServer = new ESP8266WebServer((HTTP_MANAGER==type || HTTP_MANAGER_RESET_ONLY == type) ? 80 : WEB_PORT);
WebServer->on("/", HandleRoot); WebServer->on("/", HandleRoot);
WebServer->onNotFound(HandleNotFound);
#ifndef FIRMWARE_MINIMAL
WebServer->on("/rt", HandleResetConfiguration);
#endif // FIRMWARE_MINIMAL
if(HTTP_MANAGER_RESET_ONLY != type){
WebServer->on("/up", HandleUpgradeFirmware); WebServer->on("/up", HandleUpgradeFirmware);
WebServer->on("/u1", HandleUpgradeFirmwareStart); // OTA WebServer->on("/u1", HandleUpgradeFirmwareStart); // OTA
WebServer->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop); WebServer->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop);
@ -400,12 +501,12 @@ void StartWebserver(int type, IPAddress ipweb)
WebServer->on("/ax", HandleAjaxConsoleRefresh); WebServer->on("/ax", HandleAjaxConsoleRefresh);
WebServer->on("/ay", HandleAjaxStatusRefresh); WebServer->on("/ay", HandleAjaxStatusRefresh);
WebServer->on("/cm", HandleHttpCommand); WebServer->on("/cm", HandleHttpCommand);
WebServer->onNotFound(HandleNotFound);
#ifndef FIRMWARE_MINIMAL #ifndef FIRMWARE_MINIMAL
WebServer->on("/cn", HandleConfiguration); WebServer->on("/cn", HandleConfiguration);
WebServer->on("/md", HandleModuleConfiguration); WebServer->on("/md", HandleModuleConfiguration);
WebServer->on("/wi", HandleWifiConfiguration); WebServer->on("/wi", HandleWifiConfiguration);
WebServer->on("/lg", HandleLoggingConfiguration); WebServer->on("/lg", HandleLoggingConfiguration);
WebServer->on("/tp", HandleTemplateConfiguration);
WebServer->on("/co", HandleOtherConfiguration); WebServer->on("/co", HandleOtherConfiguration);
WebServer->on("/dl", HandleBackupConfiguration); WebServer->on("/dl", HandleBackupConfiguration);
WebServer->on("/rs", HandleRestoreConfiguration); WebServer->on("/rs", HandleRestoreConfiguration);
@ -418,6 +519,7 @@ void StartWebserver(int type, IPAddress ipweb)
XsnsCall(FUNC_WEB_ADD_HANDLER); XsnsCall(FUNC_WEB_ADD_HANDLER);
#endif // Not FIRMWARE_MINIMAL #endif // Not FIRMWARE_MINIMAL
} }
}
reset_web_log_flag = false; reset_web_log_flag = false;
WebServer->begin(); // Web server start WebServer->begin(); // Web server start
} }
@ -438,7 +540,7 @@ void StopWebserver(void)
} }
} }
void WifiManagerBegin(void) void WifiManagerBegin(bool reset_only)
{ {
// setup AP // setup AP
if (!global_state.wifi_down) { if (!global_state.wifi_down) {
@ -462,7 +564,7 @@ void WifiManagerBegin(void)
DnsServer->setErrorReplyCode(DNSReplyCode::NoError); DnsServer->setErrorReplyCode(DNSReplyCode::NoError);
DnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); DnsServer->start(DNS_PORT, "*", WiFi.softAPIP());
StartWebserver(HTTP_MANAGER, WiFi.softAPIP()); StartWebserver((reset_only ? HTTP_MANAGER_RESET_ONLY : HTTP_MANAGER), WiFi.softAPIP());
} }
void PollDnsWebserver(void) void PollDnsWebserver(void)
@ -485,7 +587,7 @@ void SetHeader(void)
bool WebAuthenticate(void) bool WebAuthenticate(void)
{ {
if (Settings.web_password[0] != 0) { if (Settings.web_password[0] != 0 && HTTP_MANAGER_RESET_ONLY != webserver_state) {
return WebServer->authenticate(WEB_USERNAME, Settings.web_password); return WebServer->authenticate(WEB_USERNAME, Settings.web_password);
} else { } else {
return true; return true;
@ -520,10 +622,9 @@ void ShowPage(String &page, bool auth)
} }
page.replace(F("{j}"), info); page.replace(F("{j}"), info);
if (HTTP_MANAGER == webserver_state) { if (WifiIsInManagerMode()) {
if (WifiConfigCounter()) { if (WifiConfigCounter()) {
page.replace(F("</script>"), FPSTR(HTTP_SCRIPT_COUNTER)); page.replace(F("</script>"), FPSTR(HTTP_SCRIPT_COUNTER));
page.replace(F("<body>"), F("<body onload='u()'>"));
page += FPSTR(HTTP_COUNTER); page += FPSTR(HTTP_COUNTER);
} }
} }
@ -565,14 +666,16 @@ void WebRestart(uint8_t type)
page.replace(F("{v}"), FPSTR(S_RESTART)); page.replace(F("{v}"), FPSTR(S_RESTART));
} }
bool reset_only = (HTTP_MANAGER_RESET_ONLY == webserver_state);
page += FPSTR(HTTP_MSG_RSTRT); page += FPSTR(HTTP_MSG_RSTRT);
if (HTTP_MANAGER == webserver_state) { if (HTTP_MANAGER == webserver_state || reset_only) {
webserver_state = HTTP_ADMIN; webserver_state = HTTP_ADMIN;
} else { } else {
page += FPSTR(HTTP_BTN_MAIN); page += FPSTR(HTTP_BTN_MAIN);
} }
page.replace(F("</script>"), FPSTR(HTTP_SCRIPT_RELOAD)); page.replace(F("</script>"), FPSTR(HTTP_SCRIPT_RELOAD));
ShowPage(page); ShowPage(page, !reset_only);
ShowWebSource(SRC_WEBGUI); ShowWebSource(SRC_WEBGUI);
restart_flag = 2; restart_flag = 2;
@ -600,19 +703,12 @@ void HandleRoot(void)
return; return;
} }
if (HTTP_MANAGER == webserver_state) { if (WifiIsInManagerMode()) {
#ifndef FIRMWARE_MINIMAL #ifndef FIRMWARE_MINIMAL
if ((Settings.web_password[0] != 0) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1"))) { if ((Settings.web_password[0] != 0) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1")) && HTTP_MANAGER_RESET_ONLY != webserver_state) {
HandleWifiLogin(); HandleWifiLogin();
} else { } else {
/* if (!(Settings.web_password[0] != 0) || ((WebServer->arg("USER1") == WEB_USERNAME ) && (WebServer->arg("PASS1") == Settings.web_password ) || HTTP_MANAGER_RESET_ONLY == webserver_state)) {
char tmp1[100];
WebGetArg("USER1", tmp1, sizeof(tmp1));
char tmp2[100];
WebGetArg("PASS1", tmp2, sizeof(tmp2));
if (!(Settings.web_password[0] != 0) || (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, Settings.web_password)))) {
*/
if (!(Settings.web_password[0] != 0) || ((WebServer->arg("USER1") == WEB_USERNAME ) && (WebServer->arg("PASS1") == Settings.web_password ))) {
HandleWifiConfiguration(); HandleWifiConfiguration();
} else { } else {
// wrong user and pass // wrong user and pass
@ -626,7 +722,6 @@ void HandleRoot(void)
page.replace(F("{v}"), FPSTR(S_MAIN_MENU)); page.replace(F("{v}"), FPSTR(S_MAIN_MENU));
page += FPSTR(HTTP_SCRIPT_ROOT); page += FPSTR(HTTP_SCRIPT_ROOT);
page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_HEAD_STYLE);
page.replace(F("<body>"), F("<body onload='la()'>"));
page += F("<div id='l1' name='l1'></div>"); page += F("<div id='l1' name='l1'></div>");
if (devices_present) { if (devices_present) {
@ -792,12 +887,133 @@ void HandleConfiguration(void)
page += String(mqtt_data); page += String(mqtt_data);
page += FPSTR(HTTP_BTN_MENU4); page += FPSTR(HTTP_BTN_MENU4);
page += FPSTR(HTTP_BTN_RESET);
page += FPSTR(HTTP_BTN_MENU5);
page += FPSTR(HTTP_BTN_MAIN); page += FPSTR(HTTP_BTN_MAIN);
ShowPage(page); ShowPage(page);
} }
/*-------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------*/
void HandleTemplateConfiguration(void)
{
if (!HttpCheckPriviledgedAccess()) { return; }
if (WebServer->hasArg("save")) {
TemplateSaveSettings();
WebRestart(1);
return;
}
char stemp[20];
if (WebServer->hasArg("m")) {
String page = "";
for (uint8_t i = 0; i < MAXMODULE; i++) { // "}1'%d'>%s (%d)}2" - "}1'0'>Sonoff Basic (1)}2"
uint8_t midx = pgm_read_byte(kModuleNiceList + i);
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SCRIPT_MODULE3, midx, AnyModuleName(midx).c_str(), midx +1);
page += mqtt_data;
}
WebServer->send(200, FPSTR(HDR_CTYPE_PLAIN), page);
return;
}
WebGetArg("t", stemp, sizeof(stemp));
if (strlen(stemp)) {
uint8_t module = atoi(stemp);
uint8_t module_save = Settings.module;
Settings.module = module;
myio cmodule;
ModuleGpios(&cmodule);
gpio_flag flag = ModuleFlag();
Settings.module = module_save;
String page = AnyModuleName(module); // NAME: Generic
for (uint8_t i = 0; i < sizeof(kGpioNiceList); i++) { // GPIO: }1'0'>None (0)}2}1'17'>Button1 (17)}2...
if (1 == i) {
page += F("}1'255'>" D_SENSOR_USER " (255)}2"); // }1'255'>User (255)}2
}
uint8_t midx = pgm_read_byte(kGpioNiceList + i);
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SCRIPT_MODULE3, midx, GetTextIndexed(stemp, sizeof(stemp), midx, kSensorNames), midx);
page += mqtt_data;
}
page += F("}3"); // }3
mqtt_data[0] = '\0';
for (uint8_t i = 0; i < sizeof(cmodule); i++) { // 17,148,29,149,7,255,255,255,138,255,139,255,255
if ((i < 6) || ((i > 8) && (i != 11))) { // Ignore flash pins GPIO06, 7, 8 and 11
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (i>0)?",":"", cmodule.io[i]);
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,%d,%d"), mqtt_data, flag, Settings.user_template_base); // FLAG: ,1 BASE: ,17
page += mqtt_data;
WebServer->send(200, FPSTR(HDR_CTYPE_PLAIN), page);
return;
}
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TEMPLATE);
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_TEMPLATE));
page += FPSTR(HTTP_SCRIPT_MODULE_TEMPLATE);
page += FPSTR(HTTP_SCRIPT_TEMPLATE);
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_TEMPLATE);
page += F("<br/><table>");
for (uint8_t i = 0; i < 17; i++) {
if ((i < 6) || ((i > 8) && (i != 11))) { // Ignore flash pins GPIO06, 7, 8 and 11
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("<tr><td%s><b>" D_GPIO "%d</b></td><td>%s</td><td%s><select id='g%d' name='g%d'></select></td></tr>"),
(0==i)?" style='width:74px'":"", i, ((9==i)||(10==i))? "<font color='red'>ESP8285</font>" :"", (0==i)?" style='width:176px'":"", i, i);
page += mqtt_data;
}
}
page += F("</table>");
page += FPSTR(HTTP_FORM_TEMPLATE_FLAG);
page += FPSTR(HTTP_FORM_END);
page += FPSTR(HTTP_BTN_CONF);
ShowPage(page);
}
void TemplateSaveSettings(void)
{
char svalue[128];
char tmp[100];
char stemp[20];
WebGetArg("s1", tmp, sizeof(tmp)); // NAME
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_TEMPLATE " {\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), tmp);
uint8_t j = 0;
for (uint8_t i = 0; i < sizeof(Settings.user_template.gp); i++) {
if (6 == i) { j = 9; }
if (8 == i) { j = 12; }
snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), j);
WebGetArg(stemp, tmp, sizeof(tmp)); // GPIO
uint8_t gpio = atoi(tmp);
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s%d"), svalue, (i>0)?",":"", gpio);
j++;
}
uint8_t flag = 0;
for (uint8_t i = 0; i < GPIO_FLAG_USED; i++) {
snprintf_P(stemp, sizeof(stemp), PSTR("c%d"), i);
uint8_t state = WebServer->hasArg(stemp) << i; // FLAG
flag += state;
}
WebGetArg("g99", tmp, sizeof(tmp)); // BASE
uint8_t base = atoi(tmp) +1;
snprintf_P(svalue, sizeof(svalue), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"),
svalue, flag, base);
ExecuteWebCommand(svalue, SRC_WEBGUI);
}
/*-------------------------------------------------------------------------------------------*/
void HandleModuleConfiguration(void) void HandleModuleConfiguration(void)
{ {
if (!HttpCheckPriviledgedAccess()) { return; } if (!HttpCheckPriviledgedAccess()) { return; }
@ -815,13 +1031,6 @@ void HandleModuleConfiguration(void)
if (WebServer->hasArg("m")) { if (WebServer->hasArg("m")) {
String page = ""; String page = "";
/*
for (uint8_t i = 0; i < MAXMODULE; i++) { // "}1'%d'>%s (%d)}2" - "}1'0'>Sonoff Basic (1)}2"
midx = pgm_read_byte(kModuleNiceList + i);
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SCRIPT_MODULE3, midx, AnyModuleName(midx).c_str(), midx +1);
page += mqtt_data;
}
*/
uint8_t vidx = 0; uint8_t vidx = 0;
for (uint8_t i = 0; i <= MAXMODULE; i++) { // "}1'%d'>%s (%d)}2" - "}1'255'>UserTemplate (0)}2" - "}1'0'>Sonoff Basic (1)}2" for (uint8_t i = 0; i <= MAXMODULE; i++) { // "}1'%d'>%s (%d)}2" - "}1'255'>UserTemplate (0)}2" - "}1'0'>Sonoff Basic (1)}2"
if (0 == i) { if (0 == i) {
@ -855,6 +1064,7 @@ void HandleModuleConfiguration(void)
String page = FPSTR(HTTP_HEAD); String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_MODULE)); page.replace(F("{v}"), FPSTR(S_CONFIGURE_MODULE));
page += FPSTR(HTTP_SCRIPT_MODULE_TEMPLATE);
page += FPSTR(HTTP_SCRIPT_MODULE1); page += FPSTR(HTTP_SCRIPT_MODULE1);
page.replace(F("}4"), String(Settings.module)); page.replace(F("}4"), String(Settings.module));
for (uint8_t i = 0; i < sizeof(cmodule); i++) { for (uint8_t i = 0; i < sizeof(cmodule); i++) {
@ -865,21 +1075,14 @@ void HandleModuleConfiguration(void)
} }
page += FPSTR(HTTP_SCRIPT_MODULE2); page += FPSTR(HTTP_SCRIPT_MODULE2);
page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_HEAD_STYLE);
page.replace(F("<body>"), F("<body onload='sl()'>"));
page += FPSTR(HTTP_FORM_MODULE); page += FPSTR(HTTP_FORM_MODULE);
page.replace(F("{mt"), AnyModuleName(MODULE)); page.replace(F("{mt"), AnyModuleName(MODULE));
if (my_module_flag.pullup) {
page += FPSTR(HTTP_FORM_MODULE_PULLUP);
page.replace(F("{r1"), (Settings.flag3.no_pullup) ? F(" checked") : F(""));
}
page += F("<br/><table>"); page += F("<br/><table>");
for (uint8_t i = 0; i < sizeof(cmodule); i++) { for (uint8_t i = 0; i < sizeof(cmodule); i++) {
if (ValidGPIO(i, cmodule.io[i])) { if (ValidGPIO(i, cmodule.io[i])) {
snprintf_P(stemp, 3, PINS_WEMOS +i*2); snprintf_P(stemp, 3, PINS_WEMOS +i*2);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("<tr><td style='width:190px'>%s <b>" D_GPIO "%d</b> %s</td><td style='width:176px'><select id='g%d' name='g%d'></select></td></tr>"), snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("<tr><td style='width:190px'>%s <b>" D_GPIO "%d</b> %s</td><td style='width:176px'><select id='g%d' name='g%d'></select></td></tr>"),
(WEMOS==my_module_type)?stemp:"", i, (0==i)? D_SENSOR_BUTTON "1":(1==i)? D_SERIAL_OUT :(3==i)? D_SERIAL_IN :(9==i)? "<font color='red'>ESP8285</font>" :(10==i)? "<font color='red'>ESP8285</font>" :(12==i)? D_SENSOR_RELAY "1":(13==i)? D_SENSOR_LED "1i":(14==i)? D_SENSOR :"", i, i); (WEMOS==my_module_type)?stemp:"", i, (0==i)? D_SENSOR_BUTTON "1":(1==i)? D_SERIAL_OUT :(3==i)? D_SERIAL_IN :((9==i)||(10==i))? "<font color='red'>ESP8285</font>" :(12==i)? D_SENSOR_RELAY "1":(13==i)? D_SENSOR_LED "1i":(14==i)? D_SENSOR :"", i, i);
page += mqtt_data; page += mqtt_data;
} }
} }
@ -899,11 +1102,6 @@ void ModuleSaveSettings(void)
Settings.last_module = Settings.module; Settings.last_module = Settings.module;
Settings.module = new_module; Settings.module = new_module;
SetModuleType(); SetModuleType();
if (Settings.last_module == new_module) {
if (my_module_flag.pullup) {
Settings.flag3.no_pullup = WebServer->hasArg("b1");
}
}
myio cmodule; myio cmodule;
ModuleGpios(&cmodule); ModuleGpios(&cmodule);
String gpios = ""; String gpios = "";
@ -942,7 +1140,7 @@ void HandleWifiConfiguration(void)
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI); AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI);
if (WebServer->hasArg("save")) { if (WebServer->hasArg("save") && HTTP_MANAGER_RESET_ONLY != webserver_state) {
WifiSaveSettings(); WifiSaveSettings();
WebRestart(2); WebRestart(2);
return; return;
@ -953,10 +1151,12 @@ void HandleWifiConfiguration(void)
page += FPSTR(HTTP_SCRIPT_WIFI); page += FPSTR(HTTP_SCRIPT_WIFI);
page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_HEAD_STYLE);
if(HTTP_MANAGER_RESET_ONLY != webserver_state){
if (WebServer->hasArg("scan")) { if (WebServer->hasArg("scan")) {
#ifdef USE_EMULATION #ifdef USE_EMULATION
UdpDisconnect(); UdpDisconnect();
#endif // USE_EMULATION #endif // USE_EMULATION
int n = WiFi.scanNetworks(); int n = WiFi.scanNetworks();
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_SCAN_DONE)); AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_SCAN_DONE));
@ -1030,13 +1230,17 @@ void HandleWifiConfiguration(void)
page.replace(F("{s1"), Settings.sta_ssid[0]); page.replace(F("{s1"), Settings.sta_ssid[0]);
page.replace(F("{s2"), Settings.sta_ssid[1]); page.replace(F("{s2"), Settings.sta_ssid[1]);
page += FPSTR(HTTP_FORM_END); page += FPSTR(HTTP_FORM_END);
if (HTTP_MANAGER == webserver_state) { }
if (WifiIsInManagerMode()) {
page += FPSTR(HTTP_BTN_RSTRT); page += FPSTR(HTTP_BTN_RSTRT);
#ifndef FIRMWARE_MINIMAL
page += FPSTR(HTTP_BTN_RESET);
#endif // FIRMWARE_MINIMAL
} else { } else {
page += FPSTR(HTTP_BTN_CONF); page += FPSTR(HTTP_BTN_CONF);
} }
// ShowPage(page); // ShowPage(page);
ShowPage(page, !(HTTP_MANAGER == webserver_state)); ShowPage(page, !(WifiIsInManagerMode()));
} }
void WifiSaveSettings(void) void WifiSaveSettings(void)
@ -1053,9 +1257,9 @@ void WifiSaveSettings(void)
WebGetArg("s2", tmp, sizeof(tmp)); WebGetArg("s2", tmp, sizeof(tmp));
strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1])); strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1]));
WebGetArg("p1", tmp, sizeof(tmp)); WebGetArg("p1", tmp, sizeof(tmp));
strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0])); strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strlen(tmp) < 5) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0]));
WebGetArg("p2", tmp, sizeof(tmp)); WebGetArg("p2", tmp, sizeof(tmp));
strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1])); strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strlen(tmp) < 5) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1]));
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"), snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"),
Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]); Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]);
AddLog(LOG_LEVEL_INFO); AddLog(LOG_LEVEL_INFO);
@ -1164,6 +1368,9 @@ void HandleOtherConfiguration(void)
page.replace(F("{v}"), FPSTR(S_CONFIGURE_OTHER)); page.replace(F("{v}"), FPSTR(S_CONFIGURE_OTHER));
page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_OTHER); page += FPSTR(HTTP_FORM_OTHER);
TemplateJson();
page.replace(F("{t1"), mqtt_data);
page.replace(F("{t2"), (USER_MODULE == Settings.module) ? F(" checked disabled") : F(""));
page.replace(F("{r1"), (Settings.flag.mqtt_enabled) ? F(" checked") : F("")); page.replace(F("{r1"), (Settings.flag.mqtt_enabled) ? F(" checked") : F(""));
uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present; uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present;
@ -1175,6 +1382,7 @@ void HandleOtherConfiguration(void)
page.replace(F("{2"), (i) ? stemp : FRIENDLY_NAME); page.replace(F("{2"), (i) ? stemp : FRIENDLY_NAME);
page.replace(F("{3"), Settings.friendlyname[i]); page.replace(F("{3"), Settings.friendlyname[i]);
} }
#ifdef USE_EMULATION #ifdef USE_EMULATION
page += FPSTR(HTTP_FORM_OTHER3a); page += FPSTR(HTTP_FORM_OTHER3a);
for (uint8_t i = 0; i < EMUL_MAX; i++) { for (uint8_t i = 0; i < EMUL_MAX; i++) {
@ -1184,9 +1392,9 @@ void HandleOtherConfiguration(void)
page.replace(F("{3"), (i == EMUL_NONE) ? F(D_NONE) : (i == EMUL_WEMO) ? F(D_BELKIN_WEMO) : F(D_HUE_BRIDGE)); page.replace(F("{3"), (i == EMUL_NONE) ? F(D_NONE) : (i == EMUL_WEMO) ? F(D_BELKIN_WEMO) : F(D_HUE_BRIDGE));
page.replace(F("{4"), (i == EMUL_NONE) ? F("") : (i == EMUL_WEMO) ? F(" " D_SINGLE_DEVICE) : F(" " D_MULTI_DEVICE)); page.replace(F("{4"), (i == EMUL_NONE) ? F("") : (i == EMUL_WEMO) ? F(" " D_SINGLE_DEVICE) : F(" " D_MULTI_DEVICE));
} }
page += F("<br/>"); page += FPSTR(HTTP_FORM_OTHER3c);
page += F("<br/></fieldset>");
#endif // USE_EMULATION #endif // USE_EMULATION
page += FPSTR(HTTP_FORM_END); page += FPSTR(HTTP_FORM_END);
page += FPSTR(HTTP_BTN_CONF); page += FPSTR(HTTP_BTN_CONF);
ShowPage(page); ShowPage(page);
@ -1194,7 +1402,7 @@ void HandleOtherConfiguration(void)
void OtherSaveSettings(void) void OtherSaveSettings(void)
{ {
char tmp[100]; char tmp[128];
char stemp[TOPSZ]; char stemp[TOPSZ];
char stemp2[TOPSZ]; char stemp2[TOPSZ];
@ -1214,6 +1422,18 @@ void OtherSaveSettings(void)
snprintf_P(log_data, sizeof(log_data), PSTR("%s%s %s"), log_data, (i) ? "," : "", Settings.friendlyname[i]); snprintf_P(log_data, sizeof(log_data), PSTR("%s%s %s"), log_data, (i) ? "," : "", Settings.friendlyname[i]);
} }
AddLog(LOG_LEVEL_INFO); AddLog(LOG_LEVEL_INFO);
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];
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_TEMPLATE " %s"), tmp);
ExecuteWebCommand(svalue, SRC_WEBGUI);
if (WebServer->hasArg("t2")) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_MODULE " 0"));
ExecuteWebCommand(svalue, SRC_WEBGUI);
}
}
} }
/*-------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------*/
@ -1276,7 +1496,7 @@ void HandleResetConfiguration(void)
page += F("<div style='text-align:center;'>" D_CONFIGURATION_RESET "</div>"); page += F("<div style='text-align:center;'>" D_CONFIGURATION_RESET "</div>");
page += FPSTR(HTTP_MSG_RSTRT); page += FPSTR(HTTP_MSG_RSTRT);
page += FPSTR(HTTP_BTN_MAIN); page += FPSTR(HTTP_BTN_MAIN);
ShowPage(page); ShowPage(page, HTTP_MANAGER_RESET_ONLY != webserver_state);
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_RESET " 1")); snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_RESET " 1"));
ExecuteWebCommand(svalue, SRC_WEBGUI); ExecuteWebCommand(svalue, SRC_WEBGUI);
@ -1416,7 +1636,6 @@ void HandleInformation(void)
func += F("</td></tr></table>"); func += F("</td></tr></table>");
func += FPSTR(HTTP_SCRIPT_INFO_END); func += FPSTR(HTTP_SCRIPT_INFO_END);
page.replace(F("</script>"), func); page.replace(F("</script>"), func);
page.replace(F("<body>"), F("<body onload='i()'>"));
// page += F("</fieldset>"); // page += F("</fieldset>");
page += FPSTR(HTTP_BTN_MAIN); page += FPSTR(HTTP_BTN_MAIN);
@ -1737,8 +1956,6 @@ void HandleHttpCommand(void)
{ {
if (!HttpCheckPriviledgedAccess(false)) { return; } if (!HttpCheckPriviledgedAccess(false)) { return; }
char svalue[INPUT_BUFFER_SIZE]; // Large to serve Backlog
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_COMMAND)); AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_COMMAND));
uint8_t valid = 1; uint8_t valid = 1;
@ -1753,9 +1970,9 @@ void HandleHttpCommand(void)
String message = F("{\"" D_RSLT_WARNING "\":\""); String message = F("{\"" D_RSLT_WARNING "\":\"");
if (valid) { if (valid) {
uint8_t curridx = web_log_index; uint8_t curridx = web_log_index;
WebGetArg("cmnd", svalue, sizeof(svalue)); String svalue = WebServer->arg("cmnd");
if (strlen(svalue)) { if (svalue.length() && (svalue.length() < INPUT_BUFFER_SIZE)) {
ExecuteWebCommand(svalue, SRC_WEBCOMMAND); ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCONSOLE);
if (web_log_index != curridx) { if (web_log_index != curridx) {
uint8_t counter = curridx; uint8_t counter = curridx;
@ -1770,6 +1987,7 @@ void HandleHttpCommand(void)
if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O]) if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
if (message.length() > 1) { message += F(","); } if (message.length() > 1) { message += F(","); }
size_t JSONlen = len - (JSON - tmp); size_t JSONlen = len - (JSON - tmp);
if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); }
strlcpy(mqtt_data, JSON +1, JSONlen -2); strlcpy(mqtt_data, JSON +1, JSONlen -2);
message += mqtt_data; message += mqtt_data;
} }
@ -1803,7 +2021,6 @@ void HandleConsole(void)
page.replace(F("{v}"), FPSTR(S_CONSOLE)); page.replace(F("{v}"), FPSTR(S_CONSOLE));
page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_HEAD_STYLE);
page.replace(F("</script>"), FPSTR(HTTP_SCRIPT_CONSOL)); page.replace(F("</script>"), FPSTR(HTTP_SCRIPT_CONSOL));
page.replace(F("<body>"), F("<body onload='l()'>"));
page += FPSTR(HTTP_FORM_CMND); page += FPSTR(HTTP_FORM_CMND);
page += FPSTR(HTTP_BTN_MAIN); page += FPSTR(HTTP_BTN_MAIN);
ShowPage(page); ShowPage(page);
@ -1813,19 +2030,19 @@ void HandleAjaxConsoleRefresh(void)
{ {
if (!HttpCheckPriviledgedAccess()) { return; } if (!HttpCheckPriviledgedAccess()) { return; }
char svalue[INPUT_BUFFER_SIZE]; // Large to serve Backlog
bool cflg = true; bool cflg = true;
uint8_t counter = 0; // Initial start, should never be 0 again uint8_t counter = 0; // Initial start, should never be 0 again
WebGetArg("c1", svalue, sizeof(svalue)); String svalue = WebServer->arg("c1");
if (strlen(svalue)) { if (svalue.length() && (svalue.length() < INPUT_BUFFER_SIZE)) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), svalue); snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), svalue.c_str());
AddLog(LOG_LEVEL_INFO); AddLog(LOG_LEVEL_INFO);
ExecuteWebCommand(svalue, SRC_WEBCONSOLE); ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCONSOLE);
} }
WebGetArg("c2", svalue, sizeof(svalue)); char stmp[10];
if (strlen(svalue)) { counter = atoi(svalue); } WebGetArg("c2", stmp, sizeof(stmp));
if (strlen(stmp)) { counter = atoi(stmp); }
bool last_reset_web_log_flag = reset_web_log_flag; bool last_reset_web_log_flag = reset_web_log_flag;
// mqtt_data used as scratch space // mqtt_data used as scratch space
@ -1850,6 +2067,7 @@ void HandleAjaxConsoleRefresh(void)
} else { } else {
cflg = true; cflg = true;
} }
if (len > sizeof(mqtt_data) -2) { len = sizeof(mqtt_data); }
strlcpy(mqtt_data, tmp, len); strlcpy(mqtt_data, tmp, len);
message += mqtt_data; // mqtt_data used as scratch space message += mqtt_data; // mqtt_data used as scratch space
} }
@ -1890,7 +2108,7 @@ void HandleNotFound(void)
/* Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */ /* Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */
bool CaptivePortal(void) bool CaptivePortal(void)
{ {
if ((HTTP_MANAGER == webserver_state) && !ValidIpAddress(WebServer->hostHeader())) { if ((WifiIsInManagerMode()) && !ValidIpAddress(WebServer->hostHeader())) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED)); 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);
@ -1949,90 +2167,91 @@ String UrlEncode(const String& text)
int WebSend(char *buffer) int WebSend(char *buffer)
{ {
/* [sonoff] POWER1 ON --> Sends http://sonoff/cm?cmnd=POWER1 ON // [sonoff] POWER1 ON --> Sends http://sonoff/cm?cmnd=POWER1 ON
* [192.168.178.86:80,admin:joker] POWER1 ON --> Sends http://hostname:80/cm?user=admin&password=joker&cmnd=POWER1 ON // [192.168.178.86:80,admin:joker] POWER1 ON --> Sends http://hostname:80/cm?user=admin&password=joker&cmnd=POWER1 ON
* [sonoff] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123 // [sonoff] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123
* [sonoff,admin:joker] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123 // [sonoff,admin:joker] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123
*/
char *host; char *host;
char *port; char *port;
char *user; char *user;
char *password; char *password;
char *command; char *command;
uint16_t nport = 80;
int status = 1; // Wrong parameters int status = 1; // Wrong parameters
// buffer = | [ 192.168.178.86 : 80 , admin : joker ] POWER1 ON | // buffer = | [ 192.168.178.86 : 80 , admin : joker ] POWER1 ON |
host = strtok_r(buffer, "]", &command); // host = | [ 192.168.178.86 : 80 , admin : joker |, command = | POWER1 ON | host = strtok_r(buffer, "]", &command); // host = | [ 192.168.178.86 : 80 , admin : joker |, command = | POWER1 ON |
if (host && command) { if (host && command) {
String url = F("http://"); // url = |http://|
host = Trim(host); // host = |[ 192.168.178.86 : 80 , admin : joker| host = Trim(host); // host = |[ 192.168.178.86 : 80 , admin : joker|
host++; // host = | 192.168.178.86 : 80 , admin : joker| - Skip [ host++; // host = | 192.168.178.86 : 80 , admin : joker| - Skip [
host = strtok_r(host, ",", &user); // host = | 192.168.178.86 : 80 |, user = | admin : joker| host = strtok_r(host, ",", &user); // host = | 192.168.178.86 : 80 |, user = | admin : joker|
host = strtok_r(host, ":", &port); // host = | 192.168.178.86 |, port = | 80 | host = strtok_r(host, ":", &port); // host = | 192.168.178.86 |, port = | 80 |
host = Trim(host); // host = |192.168.178.86| host = Trim(host); // host = |192.168.178.86|
url += host; // url = |http://192.168.178.86|
if (port) { if (port) {
port = Trim(port); // port = |80| port = Trim(port); // port = |80|
nport = atoi(port); url += F(":"); // url = |http://192.168.178.86:|
url += port; // url = |http://192.168.178.86:80|
} }
if (user) { if (user) {
user = strtok_r(user, ":", &password); // user = | admin |, password = | joker| user = strtok_r(user, ":", &password); // user = | admin |, password = | joker|
user = Trim(user); // user = |admin| user = Trim(user); // user = |admin|
if (password) { password = Trim(password); } // password = |joker| if (password) { password = Trim(password); } // password = |joker|
} }
command = Trim(command); // command = |POWER1 ON| or |/any/link/starting/with/a/slash.php?log=123| command = Trim(command); // command = |POWER1 ON| or |/any/link/starting/with/a/slash.php?log=123|
String nuri = "";
if (command[0] != '/') { if (command[0] != '/') {
nuri = "/cm?"; url += F("/cm?"); // url = |http://192.168.178.86/cm?|
if (user && password) { if (user && password) {
nuri += F("user="); url += F("user="); // url = |http://192.168.178.86/cm?user=|
nuri += user; url += user; // url = |http://192.168.178.86/cm?user=admin|
nuri += F("&password="); url += F("&password="); // url = |http://192.168.178.86/cm?user=admin&password=|
nuri += password; url += password; // url = |http://192.168.178.86/cm?user=admin&password=joker|
nuri += F("&"); url += F("&"); // url = |http://192.168.178.86/cm?user=admin&password=joker&|
} }
nuri += F("cmnd="); url += F("cmnd="); // url = |http://192.168.178.86/cm?cmnd=| or |http://192.168.178.86/cm?user=admin&password=joker&cmnd=|
} }
nuri += command; url += command; // url = |http://192.168.178.86/cm?cmnd=POWER1 ON|
String uri = UrlEncode(nuri);
IPAddress host_ip; //snprintf_P(log_data, sizeof(log_data), PSTR("DBG: Uri |%s|"), url.c_str());
if (WiFi.hostByName(host, host_ip)) {
WiFiClient client;
bool connected = false;
uint8_t retry = 2;
while ((retry > 0) && !connected) {
--retry;
connected = client.connect(host_ip, nport);
if (connected) break;
}
if (connected) {
String url = F("GET ");
url += uri;
url += F(" HTTP/1.1\r\nHost: ");
// url += IPAddress(host_ip).toString();
url += host; // https://tools.ietf.org/html/rfc7230#section-5.4 (#4331)
if (port) {
url += F(":");
url += port;
}
url += F("\r\nConnection: close\r\n\r\n");
//snprintf_P(log_data, sizeof(log_data), PSTR("DBG: Url |%s|"), url.c_str());
//AddLog(LOG_LEVEL_DEBUG); //AddLog(LOG_LEVEL_DEBUG);
client.print(url.c_str()); #if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
client.flush(); HTTPClient http;
client.stop(); if (http.begin(UrlEncode(url))) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON|
#else
WiFiClient http_client;
HTTPClient http;
if (http.begin(http_client, UrlEncode(url))) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON|
#endif
int http_code = http.GET(); // Start connection and send HTTP header
if (http_code > 0) { // http_code will be negative on error
if (http_code == HTTP_CODE_OK || http_code == HTTP_CODE_MOVED_PERMANENTLY) {
/*
// Return received data to the user - Adds 900+ bytes to the code
String result = http.getString(); // File found at server - may need lot of ram or trigger out of memory!
uint16_t j = 0;
for (uint16_t i = 0; i < result.length(); i++) {
char text = result.charAt(i);
if (text > 31) { // Remove control characters like linefeed
mqtt_data[j++] = text;
if (j == sizeof(mqtt_data) -2) { break; }
}
}
mqtt_data[j] = '\0';
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_WEBSEND));
*/
}
status = 0; // No error - Done status = 0; // No error - Done
} else { } else {
status = 2; // Connection failed status = 2; // Connection failed
} }
http.end(); // Clean up connection data
} else { } else {
status = 3; // Host not found status = 3; // Host not found or connection error
} }
} }
return status; return status;

View File

@ -73,6 +73,7 @@ const char kMqttCommands[] PROGMEM =
D_CMND_MQTTUSER "|" D_CMND_MQTTPASSWORD "|" D_CMND_FULLTOPIC "|" D_CMND_PREFIX "|" D_CMND_GROUPTOPIC "|" D_CMND_TOPIC "|" D_CMND_PUBLISH "|" D_CMND_MQTTUSER "|" D_CMND_MQTTPASSWORD "|" D_CMND_FULLTOPIC "|" D_CMND_PREFIX "|" D_CMND_GROUPTOPIC "|" D_CMND_TOPIC "|" D_CMND_PUBLISH "|"
D_CMND_BUTTONTOPIC "|" D_CMND_SWITCHTOPIC "|" D_CMND_BUTTONRETAIN "|" D_CMND_SWITCHRETAIN "|" D_CMND_POWERRETAIN "|" D_CMND_SENSORRETAIN ; D_CMND_BUTTONTOPIC "|" D_CMND_SWITCHTOPIC "|" D_CMND_BUTTONRETAIN "|" D_CMND_SWITCHRETAIN "|" D_CMND_POWERRETAIN "|" D_CMND_SENSORRETAIN ;
uint16_t mqtt_connect_count = 0; // MQTT re-connect count
uint16_t mqtt_retry_counter = 1; // MQTT connection retry counter uint16_t mqtt_retry_counter = 1; // MQTT connection retry counter
uint8_t mqtt_initial_connection_state = 2; // MQTT connection messages state uint8_t mqtt_initial_connection_state = 2; // MQTT connection messages state
bool mqtt_connected = false; // MQTT virtual connection status bool mqtt_connected = false; // MQTT virtual connection status
@ -379,6 +380,11 @@ void MqttPublishPowerBlinkState(uint8_t device)
/*********************************************************************************************/ /*********************************************************************************************/
uint16_t MqttConnectCount()
{
return mqtt_connect_count;
}
void MqttDisconnected(int state) void MqttDisconnected(int state)
{ {
mqtt_connected = false; mqtt_connected = false;
@ -398,6 +404,7 @@ void MqttConnected(void)
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_CONNECTED)); AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_CONNECTED));
mqtt_connected = true; mqtt_connected = true;
mqtt_retry_counter = 0; mqtt_retry_counter = 0;
mqtt_connect_count++;
GetTopic_P(stopic, TELE, mqtt_topic, S_LWT); GetTopic_P(stopic, TELE, mqtt_topic, S_LWT);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_ONLINE)); snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_ONLINE));
@ -868,17 +875,18 @@ bool MqttCommand(void)
const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT; const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT;
const char HTTP_BTN_MENU_MQTT[] PROGMEM = const char HTTP_BTN_MENU_MQTT[] PROGMEM =
"<br/><form action='" WEB_HANDLE_MQTT "' method='get'><button>" D_CONFIGURE_MQTT "</button></form>"; "<p><form action='" WEB_HANDLE_MQTT "' method='get'><button>" D_CONFIGURE_MQTT "</button></form></p>";
const char HTTP_FORM_MQTT[] PROGMEM = const char HTTP_FORM_MQTT[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_MQTT_PARAMETERS "&nbsp;</b></legend><form method='get' action='" WEB_HANDLE_MQTT "'>" "<fieldset><legend><b>&nbsp;" D_MQTT_PARAMETERS "&nbsp;</b></legend>"
"<br/><b>" D_HOST "</b> (" MQTT_HOST ")<br/><input id='mh' name='mh' placeholder='" MQTT_HOST" ' value='{m1'><br/>" "<form method='get' action='" WEB_HANDLE_MQTT "'>"
"<br/><b>" D_PORT "</b> (" STR(MQTT_PORT) ")<br/><input id='ml' name='ml' placeholder='" STR(MQTT_PORT) "' value='{m2'><br/>" "<p><b>" D_HOST "</b> (" MQTT_HOST ")<br/><input id='mh' name='mh' placeholder='" MQTT_HOST" ' value='{m1'></p>"
"<br/><b>" D_CLIENT "</b> ({m0)<br/><input id='mc' name='mc' placeholder='" MQTT_CLIENT_ID "' value='{m3'><br/>" "<p><b>" D_PORT "</b> (" STR(MQTT_PORT) ")<br/><input id='ml' name='ml' placeholder='" STR(MQTT_PORT) "' value='{m2'></p>"
"<br/><b>" D_USER "</b> (" MQTT_USER ")<br/><input id='mu' name='mu' placeholder='" MQTT_USER "' value='{m4'><br/>" "<p><b>" D_CLIENT "</b> ({m0)<br/><input id='mc' name='mc' placeholder='" MQTT_CLIENT_ID "' value='{m3'></p>"
"<br/><b>" D_PASSWORD "</b><br/><input id='mp' name='mp' type='password' placeholder='" D_PASSWORD "' value='" D_ASTERIX "'><br/>" "<p><b>" D_USER "</b> (" MQTT_USER ")<br/><input id='mu' name='mu' placeholder='" MQTT_USER "' value='{m4'></p>"
"<br/><b>" D_TOPIC "</b> = %topic% (" MQTT_TOPIC ")<br/><input id='mt' name='mt' placeholder='" MQTT_TOPIC" ' value='{m6'><br/>" "<p><b>" D_PASSWORD "</b><br/><input id='mp' name='mp' type='password' placeholder='" D_PASSWORD "' value='" D_ASTERISK_PWD "'></p>"
"<br/><b>" D_FULL_TOPIC "</b> (" MQTT_FULLTOPIC ")<br/><input id='mf' name='mf' placeholder='" MQTT_FULLTOPIC" ' value='{m7'><br/>"; "<p><b>" D_TOPIC "</b> = %topic% (" MQTT_TOPIC ")<br/><input id='mt' name='mt' placeholder='" MQTT_TOPIC" ' value='{m6'></p>"
"<p><b>" D_FULL_TOPIC "</b> (" MQTT_FULLTOPIC ")<br/><input id='mf' name='mf' placeholder='" MQTT_FULLTOPIC" ' value='{m7'></p>";
void HandleMqttConfiguration(void) void HandleMqttConfiguration(void)
{ {
@ -938,7 +946,7 @@ void MqttSaveSettings(void)
WebGetArg("mu", tmp, sizeof(tmp)); WebGetArg("mu", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user)); strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user));
WebGetArg("mp", tmp, sizeof(tmp)); WebGetArg("mp", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.mqtt_pwd : tmp, sizeof(Settings.mqtt_pwd)); strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? "" : (!strcmp(tmp, D_ASTERISK_PWD)) ? Settings.mqtt_pwd : tmp, sizeof(Settings.mqtt_pwd));
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"), snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"),
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_topic, Settings.mqtt_fulltopic); Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_topic, Settings.mqtt_fulltopic);
AddLog(LOG_LEVEL_INFO); AddLog(LOG_LEVEL_INFO);

View File

@ -896,7 +896,11 @@ void LightAnimate(void)
} }
} }
else { else {
#ifdef PWM_LIGHTSCHEME0_IGNORE_SLEEP
sleep = (LS_POWER == Settings.light_scheme) ? Settings.sleep : 0; // If no animation then use sleep as is sleep = (LS_POWER == Settings.light_scheme) ? Settings.sleep : 0; // If no animation then use sleep as is
#else
sleep = 0;
#endif // PWM_LIGHTSCHEME0_IGNORE_SLEEP
switch (Settings.light_scheme) { switch (Settings.light_scheme) {
case LS_POWER: case LS_POWER:
LightSetDimmer(Settings.light_dimmer); LightSetDimmer(Settings.light_dimmer);

View File

@ -431,11 +431,13 @@ void DomoticzSensorPowerEnergy(int power, char *energy)
const char S_CONFIGURE_DOMOTICZ[] PROGMEM = D_CONFIGURE_DOMOTICZ; const char S_CONFIGURE_DOMOTICZ[] PROGMEM = D_CONFIGURE_DOMOTICZ;
const char HTTP_BTN_MENU_DOMOTICZ[] PROGMEM = const char HTTP_BTN_MENU_DOMOTICZ[] PROGMEM =
"<br/><form action='" WEB_HANDLE_DOMOTICZ "' method='get'><button>" D_CONFIGURE_DOMOTICZ "</button></form>"; "<p><form action='" WEB_HANDLE_DOMOTICZ "' method='get'><button>" D_CONFIGURE_DOMOTICZ "</button></form></p>";
const char HTTP_FORM_DOMOTICZ[] PROGMEM = const char HTTP_FORM_DOMOTICZ[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_DOMOTICZ_PARAMETERS "&nbsp;</b></legend><form method='post' action='" WEB_HANDLE_DOMOTICZ "'>" "<fieldset><legend><b>&nbsp;" D_DOMOTICZ_PARAMETERS "&nbsp;</b></legend>"
"<br/><table>"; "<form method='post' action='" WEB_HANDLE_DOMOTICZ "'>"
"<br/>"
"<table>";
const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_IDX " {1</b></td><td style='width:70px'><input id='r{1' name='r{1' placeholder='0' value='{2'></td></tr>" "<tr><td style='width:260px'><b>" D_DOMOTICZ_IDX " {1</b></td><td style='width:70px'><input id='r{1' name='r{1' placeholder='0' value='{2'></td></tr>"
"<tr><td style='width:260px'><b>" D_DOMOTICZ_KEY_IDX " {1</b></td><td style='width:70px'><input id='k{1' name='k{1' placeholder='0' value='{3'></td></tr>"; "<tr><td style='width:260px'><b>" D_DOMOTICZ_KEY_IDX " {1</b></td><td style='width:70px'><input id='k{1' name='k{1' placeholder='0' value='{3'></td></tr>";

View File

@ -232,7 +232,7 @@ String GetSun(uint8_t dawn)
return String(stime); return String(stime);
} }
uint16_t GetSunMinutes(uint8_t dawn) uint16_t SunMinutes(uint8_t dawn)
{ {
uint8_t hour[2]; uint8_t hour[2];
uint8_t minute[2]; uint8_t minute[2];
@ -517,7 +517,7 @@ bool TimerCommand(void)
const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER; const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER;
const char HTTP_BTN_MENU_TIMER[] PROGMEM = const char HTTP_BTN_MENU_TIMER[] PROGMEM =
"<br/><form action='" WEB_HANDLE_TIMER "' method='get'><button>" D_CONFIGURE_TIMER "</button></form>"; "<p><form action='" WEB_HANDLE_TIMER "' method='get'><button>" D_CONFIGURE_TIMER "</button></form></p>";
const char HTTP_TIMER_SCRIPT[] PROGMEM = const char HTTP_TIMER_SCRIPT[] PROGMEM =
"var pt=[],ct=99;" "var pt=[],ct=99;"
@ -593,8 +593,8 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM =
"if(ct<99){st();}" // Save changes "if(ct<99){st();}" // Save changes
"ct=t;" "ct=t;"
"o=document.getElementsByClassName('tl');" // Restore style to all tabs/buttons "o=document.getElementsByClassName('tl');" // Restore style to all tabs/buttons
"for(i=0;i<o.length;i++){o[i].style.cssText=\"background-color:#ccc;color:#fff;font-weight:normal;\"}" "for(i=0;i<o.length;i++){o[i].style.cssText=\"background-color:#999;color:#fff;font-weight:normal;\"}"
"e.style.cssText=\"background-color:#fff;color:#000;font-weight:bold;\";" // Change style to tab/button used to open content "e.style.cssText=\"background-color:transparent;color:#000;font-weight:bold;\";" // Change style to tab/button used to open content
"s=pt[ct];" // Get parameters from array "s=pt[ct];" // Get parameters from array
#ifdef USE_SUNRISE #ifdef USE_SUNRISE
"p=(s>>29)&3;eb('b'+p).checked=1;" // Set mode "p=(s>>29)&3;eb('b'+p).checked=1;" // Set mode
@ -637,36 +637,34 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM =
"o=qs('#mw');for(i=0;i<=15;i++){ce((i<10)?('0'+i):i,o);}" // Create window minutes select options "o=qs('#mw');for(i=0;i<=15;i++){ce((i<10)?('0'+i):i,o);}" // Create window minutes select options
"o=qs('#d1');for(i=0;i<}1;i++){ce(i+1,o);}" // Create outputs "o=qs('#d1');for(i=0;i<}1;i++){ce(i+1,o);}" // Create outputs
"var a='" D_DAY3LIST "';" "var a='" D_DAY3LIST "';"
"s='';for(i=0;i<7;i++){s+=\"<input style='width:5%;' id='w\"+i+\"' name='w\"+i+\"' type='checkbox'><b>\"+a.substring(i*3,(i*3)+3)+\"</b>\"}" "s='';for(i=0;i<7;i++){s+=\"<input id='w\"+i+\"' name='w\"+i+\"' type='checkbox'><b>\"+a.substring(i*3,(i*3)+3)+\"</b> \"}"
"eb('ds').innerHTML=s;" // Create weekdays "eb('ds').innerHTML=s;" // Create weekdays
"eb('dP').click();" // Get the element with id='dP' and click on it "eb('dP').click();" // Get the element with id='dP' and click on it
"}"; "}";
const char HTTP_TIMER_STYLE[] PROGMEM = const char HTTP_TIMER_STYLE[] PROGMEM =
".tl{float:left;border-radius:0;border:1px solid #fff;padding:1px;width:6.25%;}" ".tl{float:left;border-radius:0;border:1px solid #f2f2f2;padding:1px;width:6.25%;}" // Border color needs to be the same as Fieldset background color from HTTP_HEAD_STYLE (transparent won't work)
#ifdef USE_SUNRISE
"input[type='radio']{width:13px;height:24px;margin-top:-1px;margin-right:8px;vertical-align:middle;}"
#endif
"</style>"; "</style>";
const char HTTP_FORM_TIMER[] PROGMEM = const char HTTP_FORM_TIMER[] PROGMEM =
"<fieldset style='min-width:470px;text-align:center;'>" "<fieldset style='min-width:470px;text-align:center;'>"
"<legend style='text-align:left;'><b>&nbsp;" D_TIMER_PARAMETERS "&nbsp;</b></legend>" "<legend style='text-align:left;'><b>&nbsp;" D_TIMER_PARAMETERS "&nbsp;</b></legend>"
"<form method='post' action='" WEB_HANDLE_TIMER "' onsubmit='return st();'>" "<form method='post' action='" WEB_HANDLE_TIMER "' onsubmit='return st();'>"
"<br/><input style='width:5%;' id='e0' name='e0' type='checkbox'{e0><b>" D_TIMER_ENABLE "</b><br/><br/><hr/>" "<br/><input id='e0' name='e0' type='checkbox'{e0><b>" D_TIMER_ENABLE "</b><br/><br/><hr/>"
"<input id='t0' name='t0' value='"; "<input id='t0' name='t0' value='";
const char HTTP_FORM_TIMER1[] PROGMEM = const char HTTP_FORM_TIMER1[] PROGMEM =
"' hidden><div id='bt' name='bt'></div><br/><br/><br/>" "' hidden><div id='bt' name='bt'></div><br/><br/><br/>"
"<div id='oa' name='oa'></div><br/>" "<div id='oa' name='oa'></div><br/>"
"<div>" "<div>"
"<input style='width:5%;' id='a0' name='a0' type='checkbox'><b>" D_TIMER_ARM "</b>&emsp;" "<input id='a0' name='a0' type='checkbox'><b>" D_TIMER_ARM "</b>&emsp;"
"<input style='width:5%;' id='r0' name='r0' type='checkbox'><b>" D_TIMER_REPEAT "</b>" "<input id='r0' name='r0' type='checkbox'><b>" D_TIMER_REPEAT "</b>"
"</div><br/>" "</div><br/>"
"<div>" "<div>"
#ifdef USE_SUNRISE #ifdef USE_SUNRISE
"<fieldset style='width:299px;margin:auto;text-align:left;border:0;'>" "<fieldset style='width:299px;margin:auto;text-align:left;border:0;'>" // 299 used in page.replace(F("299")
"<input id='b0' name='rd' type='radio' value='0' onclick='gt();'><b>" D_TIMER_TIME "</b><br/>" "<input id='b0' name='rd' type='radio' value='0' onclick='gt();'><b>" D_TIMER_TIME "</b><br/>"
"<input id='b1' name='rd' type='radio' value='1' onclick='gt();'><b>" D_SUNRISE "</b> (}8)<br/>" "<input id='b1' name='rd' type='radio' value='1' onclick='gt();'><b>" D_SUNRISE "</b> (}8)<br/>"
"<input id='b2' name='rd' type='radio' value='2' onclick='gt();'><b>" D_SUNSET "</b> (}9)<br/>" "<input id='b2' name='rd' type='radio' value='2' onclick='gt();'><b>" D_SUNSET "</b> (}9)<br/>"
"</fieldset>" "</fieldset>"
"<p></p>"
"<span><select style='width:46px;' id='dr' name='dr'></select></span>" "<span><select style='width:46px;' id='dr' name='dr'></select></span>"
"&nbsp;" "&nbsp;"
#else #else

View File

@ -90,6 +90,21 @@
#define MAXIMUM_COMPARE_OPERATOR COMPARE_OPERATOR_SMALLER_EQUAL #define MAXIMUM_COMPARE_OPERATOR COMPARE_OPERATOR_SMALLER_EQUAL
const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<="; const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<=";
#ifdef USE_EXPRESSION
#include <LinkedList.h> // Import LinkedList library
const char kExpressionOperators[] PROGMEM = "+-*/%^";
#define EXPRESSION_OPERATOR_ADD 0
#define EXPRESSION_OPERATOR_SUBTRACT 1
#define EXPRESSION_OPERATOR_MULTIPLY 2
#define EXPRESSION_OPERATOR_DIVIDEDBY 3
#define EXPRESSION_OPERATOR_MODULO 4
#define EXPRESSION_OPERATOR_POWER 5
const uint8_t kExpressionOperatorsPriorities[] PROGMEM = {1, 1, 2, 2, 3, 4};
#define MAX_EXPRESSION_OPERATOR_PRIORITY 4
#endif // USE_EXPRESSION
enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM, CMND_ADD, CMND_SUB, CMND_MULT, CMND_SCALE, CMND_CALC_RESOLUTION }; enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM, CMND_ADD, CMND_SUB, CMND_MULT, CMND_SCALE, CMND_CALC_RESOLUTION };
const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE "|" D_CMND_CALC_RESOLUTION ; const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE "|" D_CMND_CALC_RESOLUTION ;
@ -170,11 +185,11 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
} }
snprintf_P(stemp, sizeof(stemp), PSTR("%%TIME%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%TIME%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
rule_param = String(GetMinutesPastMidnight()); rule_param = String(MinutesPastMidnight());
} }
snprintf_P(stemp, sizeof(stemp), PSTR("%%UPTIME%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%UPTIME%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
rule_param = String(GetMinutesUptime()); rule_param = String(MinutesUptime());
} }
snprintf_P(stemp, sizeof(stemp), PSTR("%%TIMESTAMP%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%TIMESTAMP%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
@ -183,11 +198,11 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
#if defined(USE_TIMERS) && defined(USE_SUNRISE) #if defined(USE_TIMERS) && defined(USE_SUNRISE)
snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNRISE%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNRISE%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
rule_param = String(GetSunMinutes(0)); rule_param = String(SunMinutes(0));
} }
snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNSET%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNSET%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
rule_param = String(GetSunMinutes(1)); rule_param = String(SunMinutes(1));
} }
#endif // USE_TIMERS and USE_SUNRISE #endif // USE_TIMERS and USE_SUNRISE
rule_param.toUpperCase(); rule_param.toUpperCase();
@ -332,12 +347,12 @@ bool RuleSetProcess(uint8_t rule_set, String &event_saved)
snprintf_P(stemp, sizeof(stemp), PSTR("%%mem%d%%"), i +1); snprintf_P(stemp, sizeof(stemp), PSTR("%%mem%d%%"), i +1);
commands.replace(stemp, Settings.mems[i]); commands.replace(stemp, Settings.mems[i]);
} }
commands.replace(F("%time%"), String(GetMinutesPastMidnight())); commands.replace(F("%time%"), String(MinutesPastMidnight()));
commands.replace(F("%uptime%"), String(GetMinutesUptime())); commands.replace(F("%uptime%"), String(MinutesUptime()));
commands.replace(F("%timestamp%"), GetDateAndTime(DT_LOCAL).c_str()); commands.replace(F("%timestamp%"), GetDateAndTime(DT_LOCAL).c_str());
#if defined(USE_TIMERS) && defined(USE_SUNRISE) #if defined(USE_TIMERS) && defined(USE_SUNRISE)
commands.replace(F("%sunrise%"), String(GetSunMinutes(0))); commands.replace(F("%sunrise%"), String(SunMinutes(0)));
commands.replace(F("%sunset%"), String(GetSunMinutes(1))); commands.replace(F("%sunset%"), String(SunMinutes(1)));
#endif // USE_TIMERS and USE_SUNRISE #endif // USE_TIMERS and USE_SUNRISE
char command[commands.length() +1]; char command[commands.length() +1];
@ -490,8 +505,8 @@ void RulesEvery50ms(void)
json_event[0] = '\0'; json_event[0] = '\0';
switch (i) { switch (i) {
case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break; case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break;
case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), GetMinutesPastMidnight()); break; case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), MinutesPastMidnight()); break;
case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), GetMinutesPastMidnight()); break; case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), MinutesPastMidnight()); break;
case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break; case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break;
case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break; case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
case 5: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break; case 5: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break;
@ -534,7 +549,7 @@ void RulesEverySecond(void)
if (RtcTime.valid) { if (RtcTime.valid) {
if ((uptime > 60) && (RtcTime.minute != rules_last_minute)) { // Execute from one minute after restart every minute only once if ((uptime > 60) && (RtcTime.minute != rules_last_minute)) { // Execute from one minute after restart every minute only once
rules_last_minute = RtcTime.minute; rules_last_minute = RtcTime.minute;
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Minute\":%d}}"), GetMinutesPastMidnight()); snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Minute\":%d}}"), MinutesPastMidnight());
RulesProcessEvent(json_event); RulesProcessEvent(json_event);
} }
} }
@ -562,6 +577,310 @@ void RulesTeleperiod(void)
rules_teleperiod = 0; rules_teleperiod = 0;
} }
#ifdef USE_EXPRESSION
/********************************************************************************************/
/*
* Parse a number value
* Input:
* pNumber - A char pointer point to a digit started string (guaranteed)
* value - Reference a double variable used to accept the result
* Output:
* pNumber - Pointer forward to next character after the number
* value - double type, the result value
* Return:
* true - succeed
* false - failed
*/
bool findNextNumber(char * &pNumber, double &value)
{
bool bSucceed = false;
String sNumber = "";
while (*pNumber) {
if (isdigit(*pNumber) || (*pNumber == '.')) {
sNumber += *pNumber;
pNumber++;
} else {
break;
}
}
if (sNumber.length() > 0) {
value = CharToDouble(sNumber.c_str());
bSucceed = true;
}
return bSucceed;
}
/********************************************************************************************/
/*
* Parse a variable (like VAR1, MEM3) and get its value (double type)
* Input:
* pVarname - A char pointer point to a variable name string
* value - Reference a double variable used to accept the result
* Output:
* pVarname - Pointer forward to next character after the variable
* value - double type, the result value
* Return:
* true - succeed
* false - failed
*/
bool findNextVariableValue(char * &pVarname, double &value)
{
bool succeed = true;
value = 0;
String sVarName = "";
while (*pVarname) {
if (isalpha(*pVarname) || isdigit(*pVarname)) {
sVarName.concat(*pVarname);
pVarname++;
} else {
break;
}
}
sVarName.toUpperCase();
if (sVarName.startsWith(F("VAR"))) {
int index = sVarName.substring(3).toInt();
if (index > 0 && index <= MAX_RULE_VARS) {
value = CharToDouble(vars[index -1]);
}
} else if (sVarName.startsWith(F("MEM"))) {
int index = sVarName.substring(3).toInt();
if (index > 0 && index <= MAX_RULE_MEMS) {
value = CharToDouble(Settings.mems[index -1]);
}
} else if (sVarName.equals(F("TIME"))) {
value = MinutesPastMidnight();
} else if (sVarName.equals(F("UPTIME"))) {
value = MinutesUptime();
} else if (sVarName.equals(F("UTCTIME"))) {
value = UtcTime();
} else if (sVarName.equals(F("LOCALTIME"))) {
value = LocalTime();
#if defined(USE_TIMERS) && defined(USE_SUNRISE)
} else if (sVarName.equals(F("SUNRISE"))) {
value = SunMinutes(0);
} else if (sVarName.equals(F("SUNSET"))) {
value = SunMinutes(1);
#endif
} else {
succeed = false;
}
return succeed;
}
/********************************************************************************************/
/*
* Find next object in expression and evaluate it
* An object could be:
* - A float number start with a digit, like 0.787
* - A variable name, like VAR1, MEM3
* - An expression enclosed with a pair of round brackets, (.....)
* Input:
* pointer - A char pointer point to a place of the expression string
* value - Reference a double variable used to accept the result
* Output:
* pointer - Pointer forward to next character after next object
* value - double type, the result value
* Return:
* true - succeed
* false - failed
*/
bool findNextObjectValue(char * &pointer, double &value)
{
bool bSucceed = false;
while (*pointer)
{
if (isspace(*pointer)) { //Skip leading spaces
pointer++;
continue;
}
if (isdigit(*pointer)) { //This object is a number
bSucceed = findNextNumber(pointer, value);
break;
} else if (isalpha(*pointer)) { //Should be a variable like VAR12, MEM1
bSucceed = findNextVariableValue(pointer, value);
break;
} else if (*pointer == '(') { //It is a sub expression bracketed with ()
pointer++;
char * sub_exp_start = pointer; //Find out the sub expression between a pair of parenthesis. "()"
unsigned int sub_exp_len = 0;
//Look for the matched closure parenthesis.")"
bool bFindClosures = false;
uint8_t matchClosures = 1;
while (*pointer)
{
if (*pointer == ')') {
matchClosures--;
if (matchClosures == 0) {
sub_exp_len = pointer - sub_exp_start;
bFindClosures = true;
break;
}
} else if (*pointer == '(') {
matchClosures++;
}
pointer++;
}
if (bFindClosures) {
value = evaluateExpression(sub_exp_start, sub_exp_len);
bSucceed = true;
}
break;
} else { //No number, no variable, no expression, then invalid object.
break;
}
}
return bSucceed;
}
/********************************************************************************************/
/*
* Find next operator in expression
* An operator could be: +, - , * , / , %, ^
* Input:
* pointer - A char pointer point to a place of the expression string
* op - Reference to a variable used to accept the result
* Output:
* pointer - Pointer forward to next character after next operator
* op - The operator. 0, 1, 2, 3, 4, 5
* Return:
* true - succeed
* false - failed
*/
bool findNextOperator(char * &pointer, int8_t &op)
{
bool bSucceed = false;
while (*pointer)
{
if (isspace(*pointer)) { //Skip leading spaces
pointer++;
continue;
}
if (char *pch = strchr(kExpressionOperators, *pointer)) { //If it is an operator
op = (int8_t)(pch - kExpressionOperators);
pointer++;
bSucceed = true;
}
break;
}
return bSucceed;
}
/********************************************************************************************/
/*
* Calculate a simple expression composed by 2 value and 1 operator, like 2 * 3
* Input:
* pointer - A char pointer point to a place of the expression string
* value - Reference a double variable used to accept the result
* Output:
* pointer - Pointer forward to next character after next object
* value - double type, the result value
* Return:
* true - succeed
* false - failed
*/
double calculateTwoValues(double v1, double v2, uint8_t op)
{
switch (op)
{
case EXPRESSION_OPERATOR_ADD:
return v1 + v2;
case EXPRESSION_OPERATOR_SUBTRACT:
return v1 - v2;
case EXPRESSION_OPERATOR_MULTIPLY:
return v1 * v2;
case EXPRESSION_OPERATOR_DIVIDEDBY:
return (0 == v2) ? 0 : (v1 / v2);
case EXPRESSION_OPERATOR_MODULO:
return (0 == v2) ? 0 : (int(v1) % int(v2));
case EXPRESSION_OPERATOR_POWER:
return FastPrecisePow(v1, v2);
}
return 0;
}
/********************************************************************************************/
/*
* Parse and evaluate an expression.
* For example: "10 * ( MEM2 + 1) / 2"
* Right now, only support operators listed here: (order by priority)
* Priority 4: ^ (power)
* Priority 3: % (modulo, always get integer result)
* Priority 2: *, /
* Priority 1: +, -
* Input:
* expression - The expression to be evaluated
* len - Length of the expression
* Return:
* double - result.
* 0 - if the expression is invalid
* An example:
* MEM1 = 3, MEM2 = 6, VAR2 = 15, VAR10 = 80
* At beginning, the expression might be complicated like: 3.14 * (MEM1 * (10 + VAR2 ^2) - 100) % 10 + VAR10 / (2 + MEM2)
* We are going to scan the whole expression, evaluate each object.
* Finally we will have a value list:.
* Order Object Value
* 0 3.14 3.14
* 1 (MEM1 * (10 + VAR2 ^2) - 100) 605
* 2 10 10
* 3 VAR10 80
* 4 (2 + MEM2) 8
* And an operator list:
* Order Operator Priority
* 0 * 2
* 1 % 3
* 2 + 1
* 3 / 2
*/
double evaluateExpression(const char * expression, unsigned int len)
{
char expbuf[len + 1];
memcpy(expbuf, expression, len);
expbuf[len] = '\0';
char * scan_pointer = expbuf;
LinkedList<double> object_values;
LinkedList<int8_t> operators;
int8_t op;
double va;
//Find and add the value of first object
if (findNextObjectValue(scan_pointer, va)) {
object_values.add(va);
} else {
return 0;
}
while (*scan_pointer)
{
if (findNextOperator(scan_pointer, op)
&& *scan_pointer
&& findNextObjectValue(scan_pointer, va))
{
operators.add(op);
object_values.add(va);
} else {
//No operator followed or no more object after this operator, we done.
break;
}
}
//Going to evaluate the whole expression
//Calculate by order of operator priorities. Looking for all operators with specified priority (from High to Low)
for (int8_t priority = MAX_EXPRESSION_OPERATOR_PRIORITY; priority>0; priority--) {
int index = 0;
while (index < operators.size()) {
if (priority == kExpressionOperatorsPriorities[(operators.get(index))]) { //need to calculate the operator first
//get current object value and remove the next object with current operator
va = calculateTwoValues(object_values.get(index), object_values.remove(index + 1), operators.remove(index));
//Replace the current value with the result
object_values.set(index, va);
} else {
index++;
}
}
}
return object_values.get(0);
}
#endif //USE_EXPRESSION
bool RulesCommand(void) bool RulesCommand(void)
{ {
char command[CMDSZ]; char command[CMDSZ];
@ -620,7 +939,12 @@ bool RulesCommand(void)
} }
else if ((CMND_RULETIMER == command_code) && (index > 0) && (index <= MAX_RULE_TIMERS)) { else if ((CMND_RULETIMER == command_code) && (index > 0) && (index <= MAX_RULE_TIMERS)) {
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
#ifdef USE_EXPRESSION
double timer_set = evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len);
rules_timer[index -1] = (timer_set > 0) ? millis() + (1000 * timer_set) : 0;
#else
rules_timer[index -1] = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0; rules_timer[index -1] = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0;
#endif //USE_EXPRESSION
} }
mqtt_data[0] = '\0'; mqtt_data[0] = '\0';
for (uint8_t i = 0; i < MAX_RULE_TIMERS; i++) { for (uint8_t i = 0; i < MAX_RULE_TIMERS; i++) {
@ -636,14 +960,22 @@ bool RulesCommand(void)
} }
else if ((CMND_VAR == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) { else if ((CMND_VAR == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
#ifdef USE_EXPRESSION
dtostrfd(evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len), Settings.flag2.calc_resolution, vars[index -1]);
#else
strlcpy(vars[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(vars[index -1])); strlcpy(vars[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(vars[index -1]));
#endif //USE_EXPRESSION
bitSet(vars_event, index -1); bitSet(vars_event, index -1);
} }
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
} }
else if ((CMND_MEM == command_code) && (index > 0) && (index <= MAX_RULE_MEMS)) { else if ((CMND_MEM == command_code) && (index > 0) && (index <= MAX_RULE_MEMS)) {
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
#ifdef USE_EXPRESSION
dtostrfd(evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len), Settings.flag2.calc_resolution, Settings.mems[index -1]);
#else
strlcpy(Settings.mems[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(Settings.mems[index -1])); strlcpy(Settings.mems[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(Settings.mems[index -1]));
#endif //USE_EXPRESSION
bitSet(mems_event, index -1); bitSet(mems_event, index -1);
} }
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]);

View File

@ -752,20 +752,21 @@ void KnxSensor(uint8_t sensor_type, float value)
const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX; const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX;
const char HTTP_BTN_MENU_KNX[] PROGMEM = const char HTTP_BTN_MENU_KNX[] PROGMEM =
"<br/><form action='kn' method='get'><button>" D_CONFIGURE_KNX "</button></form>"; "<p><form action='kn' method='get'><button>" D_CONFIGURE_KNX "</button></form></p>";
const char HTTP_FORM_KNX[] PROGMEM = const char HTTP_FORM_KNX[] PROGMEM =
"<fieldset><legend style='text-align:left;'><b>&nbsp;" D_KNX_PARAMETERS "&nbsp;</b></legend><form method='post' action='kn'>" "<fieldset><legend style='text-align:left;'><b>&nbsp;" D_KNX_PARAMETERS "&nbsp;</b>"
"</legend><form method='post' action='kn'>"
"<br/><center>" "<br/><center>"
"<b>" D_KNX_PHYSICAL_ADDRESS " </b>" "<b>" D_KNX_PHYSICAL_ADDRESS " </b>"
"<input style='width:12%;' type='number' name='area' min='0' max='15' value='{kna'> . " "<input style='width:12%;' type='number' name='area' min='0' max='15' value='{kna'> . "
"<input style='width:12%;' type='number' name='line' min='0' max='15' value='{knl'> . " "<input style='width:12%;' type='number' name='line' min='0' max='15' value='{knl'> . "
"<input style='width:12%;' type='number' name='member' min='0' max='255' value='{knm'>" "<input style='width:12%;' type='number' name='member' min='0' max='255' value='{knm'>"
"<br/><br/>" D_KNX_PHYSICAL_ADDRESS_NOTE "<br/><br/>" "<br/><br/>" D_KNX_PHYSICAL_ADDRESS_NOTE "<br/><br/>"
"<input style='width:10%;' id='b1' name='b1' type='checkbox'"; "<input id='b1' name='b1' type='checkbox'";
const char HTTP_FORM_KNX1[] PROGMEM = const char HTTP_FORM_KNX1[] PROGMEM =
"><b>" D_KNX_ENABLE " </b><input style='width:10%;' id='b2' name='b2' type='checkbox'"; "><b>" D_KNX_ENABLE "</b>&emsp;<input id='b2' name='b2' type='checkbox'";
const char HTTP_FORM_KNX2[] PROGMEM = const char HTTP_FORM_KNX2[] PROGMEM =
"><b>" D_KNX_ENHANCEMENT "</b><br/></center><br/>" "><b>" D_KNX_ENHANCEMENT "</b><br/></center><br/>"

View File

@ -205,17 +205,17 @@ bool CseCommand(void)
if (CMND_POWERSET == energy_command_code) { if (CMND_POWERSET == energy_command_code) {
if (XdrvMailbox.data_len && power_cycle) { if (XdrvMailbox.data_len && power_cycle) {
Settings.energy_power_calibration = ((unsigned long)CharToDouble(XdrvMailbox.data) * power_cycle) / CSE_PREF; Settings.energy_power_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * power_cycle) / CSE_PREF;
} }
} }
else if (CMND_VOLTAGESET == energy_command_code) { else if (CMND_VOLTAGESET == energy_command_code) {
if (XdrvMailbox.data_len && voltage_cycle) { if (XdrvMailbox.data_len && voltage_cycle) {
Settings.energy_voltage_calibration = ((unsigned long)CharToDouble(XdrvMailbox.data) * voltage_cycle) / CSE_UREF; Settings.energy_voltage_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * voltage_cycle) / CSE_UREF;
} }
} }
else if (CMND_CURRENTSET == energy_command_code) { else if (CMND_CURRENTSET == energy_command_code) {
if (XdrvMailbox.data_len && current_cycle) { if (XdrvMailbox.data_len && current_cycle) {
Settings.energy_current_calibration = ((unsigned long)CharToDouble(XdrvMailbox.data) * current_cycle) / 1000; Settings.energy_current_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * current_cycle) / 1000;
} }
} }
else serviced = false; // Unknown command else serviced = false; // Unknown command

View File

@ -103,7 +103,7 @@ void CounterShow(bool json)
dtostrfd((double)RtcSettings.pulse_counter[i] / 1000000, 6, counter); dtostrfd((double)RtcSettings.pulse_counter[i] / 1000000, 6, counter);
} else { } else {
dsxflg++; dsxflg++;
dtostrfd(RtcSettings.pulse_counter[i], 0, counter); snprintf_P(counter, sizeof(counter), PSTR("%lu"), RtcSettings.pulse_counter[i]);
} }
if (json) { if (json) {

View File

@ -377,19 +377,19 @@ const char HTTP_BTN_MENU_MAIN_HX711[] PROGMEM =
"<br/><form action='" WEB_HANDLE_HX711 "' method='get'><button name='reset'>" D_RESET_HX711 "</button></form>"; "<br/><form action='" WEB_HANDLE_HX711 "' method='get'><button name='reset'>" D_RESET_HX711 "</button></form>";
const char HTTP_BTN_MENU_HX711[] PROGMEM = const char HTTP_BTN_MENU_HX711[] PROGMEM =
"<br/><form action='" WEB_HANDLE_HX711 "' method='get'><button>" D_CONFIGURE_HX711 "</button></form>"; "<p><form action='" WEB_HANDLE_HX711 "' method='get'><button>" D_CONFIGURE_HX711 "</button></form></p>";
const char HTTP_FORM_HX711[] PROGMEM = const char HTTP_FORM_HX711[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_CALIBRATION "&nbsp;</b></legend>" "<fieldset><legend><b>&nbsp;" D_CALIBRATION "&nbsp;</b></legend>"
"<form method='post' action='" WEB_HANDLE_HX711 "'>" "<form method='post' action='" WEB_HANDLE_HX711 "'>"
"<br/><b>" D_REFERENCE_WEIGHT "</b> (" D_UNIT_KILOGRAM ")<br/><input type='number' step='0.001' id='p1' name='p1' placeholder='0' value='{1'><br/>" "<p><b>" D_REFERENCE_WEIGHT "</b> (" D_UNIT_KILOGRAM ")<br/><input type='number' step='0.001' id='p1' name='p1' placeholder='0' value='{1'></p>"
"<br/><button name='calibrate' type='submit'>" D_CALIBRATE "</button><br/>" "<br/><button name='calibrate' type='submit'>" D_CALIBRATE "</button>"
"</form>" "</form>"
"</fieldset><br/><br/>" "</fieldset><br/><br/>"
"<fieldset><legend><b>&nbsp;" D_HX711_PARAMETERS "&nbsp;</b></legend>" "<fieldset><legend><b>&nbsp;" D_HX711_PARAMETERS "&nbsp;</b></legend>"
"<form method='post' action='" WEB_HANDLE_HX711 "'>" "<form method='post' action='" WEB_HANDLE_HX711 "'>"
"<br/><b>" D_ITEM_WEIGHT "</b> (" D_UNIT_KILOGRAM ")<br/><input type='number' max='6.5535' step='0.0001' id='p2' name='p2' placeholder='0.0' value='{2'><br/>"; "<p><b>" D_ITEM_WEIGHT "</b> (" D_UNIT_KILOGRAM ")<br/><input type='number' max='6.5535' step='0.0001' id='p2' name='p2' placeholder='0.0' value='{2'></p>";
void HandleHxAction(void) void HandleHxAction(void)
{ {

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
VER = '2.1.0020' VER = '2.1.0021'
""" """
decode-config.py - Backup/Restore Sonoff-Tasmota configuration data decode-config.py - Backup/Restore Sonoff-Tasmota configuration data
@ -841,9 +841,41 @@ Setting_6_4_1_13.update ({
'mhz19b_abc_disable': ('B', (0x717,1, 7), (None, None, ('Sensor', '"Sensor15 {}".format($)')) ), 'mhz19b_abc_disable': ('B', (0x717,1, 7), (None, None, ('Sensor', '"Sensor15 {}".format($)')) ),
}, 0x717, (None, None, ('*', None)), (None, False) ), }, 0x717, (None, None, ('*', None)), (None, False) ),
}) })
# ======================================================================
Setting_6_4_1_16 = copy.deepcopy(Setting_6_4_1_13)
Setting_6_4_1_16.update({
'user_template_base': ('B', 0x71F, (None, None, ('Management', '"Template {}".format($)')), ('$ + 1','$ - 1') ),
'user_template': ({
'name': ('15s', 0x720, (None, None, ('Management', '"Template {{\\\"NAME\\\":\\\"{}\\\"}}".format($)' )) ),
'gpio00': ('B', 0x72F, (None, None, ('Management', '"Template {{\\\"GPIO\\\":[{},{},{},{},{},{},{},{},{},{},{},{},{}]}}".format(@["user_template"]["gpio00"],@["user_template"]["gpio01"],@["user_template"]["gpio02"],@["user_template"]["gpio03"],@["user_template"]["gpio04"],@["user_template"]["gpio05"],@["user_template"]["gpio09"],@["user_template"]["gpio10"],@["user_template"]["gpio12"],@["user_template"]["gpio13"],@["user_template"]["gpio14"],@["user_template"]["gpio15"],@["user_template"]["gpio16"])')) ),
'gpio01': ('B', 0x730, (None, None, ('Management', None)) ),
'gpio02': ('B', 0x731, (None, None, ('Management', None)) ),
'gpio03': ('B', 0x732, (None, None, ('Management', None)) ),
'gpio04': ('B', 0x733, (None, None, ('Management', None)) ),
'gpio05': ('B', 0x734, (None, None, ('Management', None)) ),
'gpio09': ('B', 0x735, (None, None, ('Management', None)) ),
'gpio10': ('B', 0x736, (None, None, ('Management', None)) ),
'gpio12': ('B', 0x737, (None, None, ('Management', None)) ),
'gpio13': ('B', 0x738, (None, None, ('Management', None)) ),
'gpio14': ('B', 0x739, (None, None, ('Management', None)) ),
'gpio15': ('B', 0x73A, (None, None, ('Management', None)) ),
'gpio16': ('B', 0x73B, (None, None, ('Management', None)) ),
'flag': ({
'value': ('B', 0x73C , (None, None, ('Management', '"Template {{\\\"FLAG\\\":{}}}".format($)')) ),
'adc0': ('B', (0x73C,1,0), (None, None, ('Management', None)) ),
'pullup': ('B', (0x73C,1,1), (None, None, ('Management', None)) ),
}, 0x73C, (None, None, ('Management', None))
),
}, 0x720, (None, None, ('Management', None))
),
})
# ======================================================================
Setting_6_4_1_17 = copy.deepcopy(Setting_6_4_1_16)
Setting_6_4_1_17['flag3'][0].pop('no_pullup',None)
# ====================================================================== # ======================================================================
Settings = [ Settings = [
(0x6040111, 0xe00, Setting_6_4_1_17),
(0x6040110, 0xe00, Setting_6_4_1_16),
(0x604010D, 0xe00, Setting_6_4_1_13), (0x604010D, 0xe00, Setting_6_4_1_13),
(0x604010B, 0xe00, Setting_6_4_1_11), (0x604010B, 0xe00, Setting_6_4_1_11),
(0x6040108, 0xe00, Setting_6_4_1_8), (0x6040108, 0xe00, Setting_6_4_1_8),