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.40=40 MHz
cw01.menu.CrystalFreq.40.build.extra_flags=-DF_CRYSTAL=40000000 -DESP8266
cw01.build.flash_mode=qio
cw01.build.flash_flags=-DFLASHMODE_QIO
cw01.build.flash_mode=dio
cw01.build.flash_flags=-DFLASHMODE_DIO
cw01.build.flash_freq=40
cw01.menu.eesz.4M=4M (no SPIFFS)
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.921600=921600
espectro.menu.baud.921600.upload.speed=921600

View File

@ -1,154 +1,155 @@
# 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-beta3)
version=2.5.0-beta3
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=-fno-exceptions
build.stdcpp_lib=-lstdc++
#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 -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} {build.flash_flags} {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} {build.flash_flags} {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} {build.flash_flags} {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}" {build.exception_flags} -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"
# 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)
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
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=-fno-exceptions
build.stdcpp_lib=-lstdc++
#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 -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"
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
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
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} {build.flash_flags} {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} {build.flash_flags} {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} {build.flash_flags} {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}" {build.exception_flags} -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

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

View File

@ -1,5 +1,26 @@
/* 6.4.1.16 20190211
* Initial support for online template change using command Template (#5177)
/* 6.4.1.18 20191221
* 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
* Change image name BE_MINIMAL to FIRMWARE_MINIMAL (#5106)

View File

@ -44,6 +44,7 @@
#define D_JSON_CHANNEL "Channel"
#define D_JSON_CO2 "CarbonDioxide"
#define D_JSON_COMMAND "Command"
#define D_JSON_CONFIG_HOLDER "CfgHolder"
#define D_JSON_CONNECT_FAILED "Connect failed"
#define D_JSON_COREVERSION "Core"
#define D_JSON_COUNT "Count"
@ -53,6 +54,7 @@
#define D_JSON_DISTANCE "Distance"
#define D_JSON_DNSSERVER "DNSServer"
#define D_JSON_DONE "Done"
#define D_JSON_DOWNTIME "Downtime"
#define D_JSON_ECO2 "eCO2"
#define D_JSON_EMPTY "Empty"
#define D_JSON_ENDDST "EndDST" // End Daylight Savings Time
@ -88,12 +90,14 @@
#define D_JSON_INFRARED "Infrared"
#define D_JSON_UNKNOWN "Unknown"
#define D_JSON_LIGHT "Light"
#define D_JSON_LINK_COUNT "LinkCount"
#define D_JSON_LOCAL_TIME "Local"
#define D_JSON_LOW "Low"
#define D_JSON_MAC "Mac"
#define D_JSON_MASK "Mask"
#define D_JSON_MINIMAL "minimal"
#define D_JSON_MODEL "Model"
#define D_JSON_MQTT_COUNT "MqttCount"
#define D_JSON_NO "No"
#define D_JSON_NOISE "Noise"
#define D_JSON_NONE "None"
@ -244,6 +248,7 @@
#define D_WCFG_4_RETRY "Retry"
#define D_WCFG_5_WAIT "Wait"
#define D_WCFG_6_SERIAL "Serial"
#define D_WCFG_7_WIFIMANAGER_RESET_ONLY "ManagerRst"
#define D_CMND_FRIENDLYNAME "FriendlyName"
#define D_CMND_SWITCHMODE "SwitchMode"
#define D_CMND_INTERLOCK "Interlock"
@ -418,6 +423,7 @@
/********************************************************************************************/
#define D_ASTERIX "********"
#define D_ASTERISK_PWD "****"
#ifndef MY_LANGUAGE
#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_4_RETRY,
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 = {
D_CMND,
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_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_WIFI[] PROGMEM = D_CONFIGURE_WIFI;
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 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)
@ -253,7 +253,7 @@
#define D_MODULE_PARAMETERS "Параметри на модула"
#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_SERIAL_IN "Сериен вход"
#define D_SERIAL_OUT "Сериен изход"
@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Период на телеметрия"
#define D_OTHER_PARAMETERS "Други параметри"
#define D_TEMPLATE "Модел"
#define D_ACTIVATE "Активирай"
#define D_WEB_ADMIN_PASSWORD "Парола на уеб администратора"
#define D_MQTT_ENABLE "Активиране на MQTT"
#define D_FRIENDLY_NAME "Приятелско име"
@ -296,6 +298,14 @@
#define D_SINGLE_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_CONFIGURATION_SAVED "Конфигурацията е запазена"
#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
#define D_SENSOR_NONE "Няма"
#define D_SENSOR_USER "Потребит."
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Interval telemetrie"
#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_MQTT_ENABLE "MQTT aktivní"
#define D_FRIENDLY_NAME "Friendly Name"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single 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_CONFIGURATION_SAVED "Nastavení uloženo"
#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
#define D_SENSOR_NONE "Není"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#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 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)
@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetrieperiode"
#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_MQTT_ENABLE "MQTT aktivieren"
#define D_FRIENDLY_NAME "Name [friendly name]"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "Einzelnes Gerä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_CONFIGURATION_SAVED "Konfiguration gespeichert"
#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
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Περίοδος τηλεμετρίας"
#define D_OTHER_PARAMETERS "Άλλες παράμετροι"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Κωδικός διαχειριστή"
#define D_MQTT_ENABLE "Ενεργοποίηση MQTT"
#define D_FRIENDLY_NAME "Φιλική ονομασία"
@ -296,6 +298,14 @@
#define D_SINGLE_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_CONFIGURATION_SAVED "Οι ρυθμίσεις αποθηκεύτηκαν"
#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
#define D_SENSOR_NONE "Κανένα"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetry period"
#define D_OTHER_PARAMETERS "Other parameters"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Web Admin Password"
#define D_MQTT_ENABLE "MQTT enable"
#define D_FRIENDLY_NAME "Friendly Name"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single 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_CONFIGURATION_SAVED "Configuration saved"
#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
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Período de Telemetría"
#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_MQTT_ENABLE "Habilitar MQTT"
#define D_FRIENDLY_NAME "Nombre Amigable"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "dispositivo simple"
#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_CONFIGURATION_SAVED "Configuración grabada"
#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
#define D_SENSOR_NONE "Ninguno"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#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 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)
@ -98,8 +98,8 @@
#define D_GAS "Gaz"
#define D_GATEWAY "Passerelle"
#define D_GROUP "Groupe"
#define D_HOST "Host"
#define D_HOSTNAME "Hostname"
#define D_HOST "Hôte"
#define D_HOSTNAME "Nom d'Hôte"
#define D_HUMIDITY "Humidité"
#define D_ILLUMINANCE "Éclairement"
#define D_IMMEDIATE "immédiat" // Button immediate
@ -138,7 +138,7 @@
#define D_RESTARTING "Redémarre"
#define D_RESTART_REASON "Raison du redémarrage"
#define D_RESTORE "restaurer"
#define D_RETAINED "retenu"
#define D_RETAINED "persistant" // MQTT
#define D_RULE "Règle"
#define D_SAVE "Enregistrer"
#define D_SENSOR "Capteur"
@ -184,7 +184,7 @@
#define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1"
#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_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_MQTT_SERVICE_FOUND "Service MQTT trouvé sur"
#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
#define D_SAVED_TO_FLASH_AT "Enregistré en flash à"
@ -253,7 +253,7 @@
#define D_MODULE_PARAMETERS "Paramètres 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_SERIAL_IN "Entrée série"
#define D_SERIAL_OUT "Sortie série"
@ -281,13 +281,15 @@
#define D_LOGGING_PARAMETERS "Paramètres du journal"
#define D_SERIAL_LOG_LEVEL "Niveau de journalisation série"
#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_SYSLOG_HOST "Hôte Syslog"
#define D_SYSLOG_PORT "Port Syslog"
#define D_SYSLOG_HOST "Hôte SysLog"
#define D_SYSLOG_PORT "Port SysLog"
#define D_TELEMETRY_PERIOD "Période télémétrie"
#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_MQTT_ENABLE "MQTT activé"
#define D_FRIENDLY_NAME "Surnom"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "module unique"
#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_CONFIGURATION_SAVED "Configuration enregistré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_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_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_8 "Fichier invalide"
#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_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>"
// 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
#define D_SENSOR_NONE "Aucun"
#define D_SENSOR_USER "Utilisateur"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetry period"
#define D_OTHER_PARAMETERS "פרמטרים שונים"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "סיסמת מנהל - אתר"
#define D_MQTT_ENABLE "MQTT אפשר"
#define D_FRIENDLY_NAME "שם ידידותי"
@ -296,6 +298,14 @@
#define D_SINGLE_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_CONFIGURATION_SAVED "הגדרות נשמרו"
#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
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetria (mp.)"
#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_MQTT_ENABLE "MQTT engedélyezése"
#define D_FRIENDLY_NAME "Név"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single 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_CONFIGURATION_SAVED "Beállítások elmentve"
#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
#define D_SENSOR_NONE "Nincs"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Periodo Telemetria"
#define D_OTHER_PARAMETERS "Altri parametri"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Password Amministratore Web"
#define D_MQTT_ENABLE "Abilita MQTT"
#define D_FRIENDLY_NAME "Nome confidenziale"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "dispositivo singolo"
#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_CONFIGURATION_SAVED "Configurazione salvata"
#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
#define D_SENSOR_NONE "Nessuno"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetry periode"
#define D_OTHER_PARAMETERS "Overige parameters"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Web Admin Wachtwoord"
#define D_MQTT_ENABLE "MQTT ingeschakeld"
#define D_FRIENDLY_NAME "Beschrijvende naam"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "een apparaat"
#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_CONFIGURATION_SAVED "Configuratie opgeslagen"
#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
#define D_SENSOR_NONE "Geen"
#define D_SENSOR_USER "Gebruiker"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Okres telemetrii"
#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_MQTT_ENABLE "MQTT aktywne"
#define D_FRIENDLY_NAME "Twoja nazwa"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single 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_CONFIGURATION_SAVED "Ustawienia zapisane"
#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
#define D_SENSOR_NONE "Brak"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Período de telemetria"
#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_MQTT_ENABLE "MQTT habilitado"
#define D_FRIENDLY_NAME "Nome amigável"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "Dispositivo único"
#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_CONFIGURATION_SAVED "Configuração gravada"
#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
#define D_SENSOR_NONE "Nenhum"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Periodo de Telemetria"
#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_MQTT_ENABLE "MQTT habilitado"
#define D_FRIENDLY_NAME "Nome amigável"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "dispositivo único"
#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_CONFIGURATION_SAVED "Configuração guardada"
#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
#define D_SENSOR_NONE "Nenhum"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Период телеметрии"
#define D_OTHER_PARAMETERS "Параметры Прочие"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Пароль Web администратора"
#define D_MQTT_ENABLE "MQTT активен"
#define D_FRIENDLY_NAME "Дружественное Имя"
@ -296,6 +298,14 @@
#define D_SINGLE_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_CONFIGURATION_SAVED "Конфигурация сохранена "
#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
#define D_SENSOR_NONE "-нет-"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Interval telemetrie"
#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_MQTT_ENABLE "MQTT aktívne"
#define D_FRIENDLY_NAME "Friendly Name"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "single 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_CONFIGURATION_SAVED "Nastavenia uložené"
#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
#define D_SENSOR_NONE "Žiaden"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetriperiod"
#define D_OTHER_PARAMETERS "Andra parametrar"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Webbadmin-lösenord"
#define D_MQTT_ENABLE "MQTT aktivera"
#define D_FRIENDLY_NAME "Läsbart namn"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "soloenhet"
#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_CONFIGURATION_SAVED "Konfiguration sparad"
#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
#define D_SENSOR_NONE "Ingen"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Telemetri peryodu"
#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_MQTT_ENABLE "MQTT aktif"
#define D_FRIENDLY_NAME "Kullanıcı Dostu İsim"
@ -296,6 +298,14 @@
#define D_SINGLE_DEVICE "tekli 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_CONFIGURATION_SAVED "Ayarlar kaydedildi"
#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
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "Період телеметрії"
#define D_OTHER_PARAMETERS "Параметри Інше"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Гасло Web адміністратора"
#define D_MQTT_ENABLE "MQTT активний"
#define D_FRIENDLY_NAME "Дружнє Ім'я"
@ -296,6 +298,14 @@
#define D_SINGLE_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_CONFIGURATION_SAVED "Конфігурація збережена "
#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
#define D_SENSOR_NONE "-відсутньо-"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "上报周期"
#define D_OTHER_PARAMETERS "其他设置"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "WEB 管理密码"
#define D_MQTT_ENABLE "启用MQTT"
#define D_FRIENDLY_NAME "昵称"
@ -296,6 +298,14 @@
#define D_SINGLE_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_CONFIGURATION_SAVED "设置已保存"
#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
#define D_SENSOR_NONE "无"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -288,6 +288,8 @@
#define D_TELEMETRY_PERIOD "上報周期"
#define D_OTHER_PARAMETERS "其他設置"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "WEB管理密碼"
#define D_MQTT_ENABLE "啟用MQTT"
#define D_FRIENDLY_NAME "昵稱"
@ -296,6 +298,14 @@
#define D_SINGLE_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_CONFIGURATION_SAVED "設置已保存"
#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
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"

View File

@ -122,6 +122,7 @@
// -- MQTT - Telemetry ----------------------------
#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 -----------------------------
#define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds)
@ -278,6 +279,7 @@
// -- Rules ---------------------------------------
#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 -----------------------
#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 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 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 spare14 : 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_switch_retain = MQTT_SWITCH_RETAIN;
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_offline = 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
// 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)
//#define PWM_LIGHTSCHEME0_IGNORE_SLEEP // Do not change sleep value for LightAnimate() scheme 0
#define DEFAULT_POWER_DELTA 80 // Power change percentage
#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 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};

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
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
@ -869,9 +866,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
}
restart_flag = 2;
}
uint8_t module = Settings.module;
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());
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, ModuleNr(), ModuleName().c_str());
}
else if (CMND_MODULES == command_code) {
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';
}
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;
if (!strstr(dataBuf, "{")) { // If no JSON it must be parameter
bool update = false;
if ((payload > 0) && (payload <= MAXMODULE)) {
ModuleDefault(payload -1); // Copy template module
if (USER_MODULE == Settings.module) { restart_flag = 2; }
}
else if (0 == payload) { // Copy current module with user configured GPIO
if (Settings.module < USER_MODULE) {
if (Settings.module != USER_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
StaticJsonBuffer<350> jb; // 331 from https://arduinojson.org/v5/assistant/
JsonObject& obj = jb.parseObject(dataBuf);
if (!obj.success()) {
else if (data_len > 9) { // Workaround exception if empty JSON like {} - Needs checks
if (JsonTemplate(dataBuf)) { // Free 336 bytes StaticJsonBuffer stack space by moving code to function
if (USER_MODULE == Settings.module) { restart_flag = 2; }
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON);
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()) {
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);
}
if (!error) { TemplateJson(); }
}
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)) {
@ -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]);
}
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]));
Settings.sta_active = index -1;
restart_flag = 2;
@ -1336,10 +1275,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
restart_flag = 211;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command , D_JSON_RESET_AND_RESTARTING);
break;
case 2:
case 3:
case 4:
case 5:
case 2 ... 6:
restart_flag = 210 + payload;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RESET "\":\"" D_JSON_ERASE ", " D_JSON_RESET_AND_RESTARTING "\"}"));
break;
@ -1496,10 +1432,10 @@ bool SendKey(uint8_t key, uint8_t device, uint8_t state)
}
#ifdef USE_DOMOTICZ
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
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
result = !Settings.flag3.button_switch_force_local;
} else {
@ -1628,8 +1564,6 @@ void StopAllPowerBlink(void)
void ExecuteCommand(char *cmnd, int source)
{
char stopic[CMDSZ];
char svalue[INPUT_BUFFER_SIZE];
char *start;
char *token;
@ -1641,9 +1575,13 @@ void ExecuteCommand(char *cmnd, int source)
start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble
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);
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
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(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));
}
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\"}}"),
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());
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.cfg_holder, Settings.bootcount, Settings.save_flag, GetSettingsAddress());
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) {
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}}"),
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MqttLibraryType(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
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(), MqttConnectCount(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6"));
}
@ -1805,8 +1743,8 @@ void MqttShowState(void)
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}}"),
mqtt_data, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WiFi.BSSIDstr().c_str(), WiFi.channel(), WifiGetRssiAsQuality(WiFi.RSSI()));
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()), WifiLinkCount(), WifiDowntime().c_str());
}
bool MqttShowSensor(void)
@ -2114,14 +2052,33 @@ void Every250mSeconds(void)
}
}
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_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
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
}
SettingsDefault();
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;
}
else if (213 == restart_flag) {
@ -2237,7 +2194,8 @@ void ArduinoOTAInit(void)
void SerialInput(void)
{
while (Serial.available()) {
yield();
// yield();
delay(0);
serial_in_byte = Serial.read();
/*-------------------------------------------------------------------------------------------*\
@ -2346,17 +2304,23 @@ void GpioInit(void)
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;
ModuleGpios(&def_gp);
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];
}
if ((def_gp.io[i] > GPIO_NONE) && (def_gp.io[i] < GPIO_USER)) {
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();

View File

@ -335,8 +335,10 @@ typedef struct MYCFGIO {
uint8_t io[MAX_GPIO_PIN - MIN_FLASH_PINS];
} 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_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_SPARE03 8
#define GPIO_FLAG_SPARE04 16
@ -348,7 +350,7 @@ typedef union {
uint8_t data;
struct {
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 spare03 : 1;
uint8_t spare04 : 1;
@ -974,7 +976,6 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_USER, // GPIO15 D8
GPIO_USER, // GPIO16 D0 Wemos Wake
GPIO_FLAG_ADC0 // ADC0 A0 Analog input
// + GPIO_FLAG_PULLUP // Allow input pull-up control
},
{ "Sonoff Dev", // Sonoff Dev (ESP8266)
GPIO_KEY1, // GPIO00 E-FW Button
@ -1503,7 +1504,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_SWT2, // GPIO14
GPIO_MCP39F5_RST, // GPIO15 MCP39F501 Reset
0,
GPIO_FLAG_PULLUP // Allow input pull-up control
0
},
{ "Xiaomi Philips", // Xiaomi Philips bulb (ESP8266)
0, 0, 0, 0, 0, 0,

View File

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

View File

@ -154,7 +154,7 @@ char* subStr(char* dest, char* str, const char *delim, int index)
return sub;
}
double CharToDouble(char *str)
double CharToDouble(const char *str)
{
// simple ascii to double, because atof or strtod are too large
char strbuf[24];
@ -305,27 +305,6 @@ char* UpperCase_P(char* dest, const char* source)
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)
{
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);
}
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)
{
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
\*********************************************************************************************/

View File

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

View File

@ -87,6 +87,23 @@ String GetTimeZone(void)
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)
{
// "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
}
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)
{
char dt[16];
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
return GetDuration(UpTime());
}
uint32_t GetMinutesUptime(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 MinutesPastMidnight(void)
{
uint32_t minutes = 0;
@ -322,6 +323,11 @@ uint32_t RuleToTime(TimeRule r, int yr)
return t;
}
uint32_t UtcTime(void)
{
return utc_time;
}
uint32_t LocalTime(void)
{
return local_time;

View File

@ -110,12 +110,6 @@ void SwitchProbe(void)
void SwitchInit(void)
{
if (my_module_flag.pullup) {
if (Settings.flag3.no_pullup) {
switch_no_pullup = 0xffff;
}
}
switches_found = 0;
for (uint8_t i = 0; i < MAX_SWITCHES; i++) {
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
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_retry_init;
uint8_t wifi_retry;
@ -171,9 +174,9 @@ void WifiConfig(uint8_t type)
}
#endif // USE_WPS
#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));
WifiManagerBegin();
WifiManagerBegin(WIFI_MANAGER_RESET_ONLY == wifi_config_type);
}
#endif // USE_WEBSERVER
}
@ -222,7 +225,8 @@ void WifiBegin(uint8_t flag, uint8_t channel)
delay(200);
WiFi.mode(WIFI_STA); // Disable AP mode
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); }
// WiFi.setAutoReconnect(true);
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)
{
if (state == global_state.wifi_down) {
if (state) {
rules_flag.wifi_connected = 1;
wifi_link_count++;
wifi_downtime += UpTime() - wifi_last_event;
} else {
rules_flag.wifi_disconnected = 1;
wifi_last_event = UpTime();
}
}
global_state.wifi_down = state ^1;

File diff suppressed because it is too large Load Diff

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_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
uint8_t mqtt_initial_connection_state = 2; // MQTT connection messages state
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)
{
mqtt_connected = false;
@ -398,6 +404,7 @@ void MqttConnected(void)
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_CONNECTED));
mqtt_connected = true;
mqtt_retry_counter = 0;
mqtt_connect_count++;
GetTopic_P(stopic, TELE, mqtt_topic, S_LWT);
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 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 =
"<fieldset><legend><b>&nbsp;" D_MQTT_PARAMETERS "&nbsp;</b></legend><form method='get' action='" WEB_HANDLE_MQTT "'>"
"<br/><b>" D_HOST "</b> (" MQTT_HOST ")<br/><input id='mh' name='mh' placeholder='" MQTT_HOST" ' value='{m1'><br/>"
"<br/><b>" D_PORT "</b> (" STR(MQTT_PORT) ")<br/><input id='ml' name='ml' placeholder='" STR(MQTT_PORT) "' value='{m2'><br/>"
"<br/><b>" D_CLIENT "</b> ({m0)<br/><input id='mc' name='mc' placeholder='" MQTT_CLIENT_ID "' value='{m3'><br/>"
"<br/><b>" D_USER "</b> (" MQTT_USER ")<br/><input id='mu' name='mu' placeholder='" MQTT_USER "' value='{m4'><br/>"
"<br/><b>" D_PASSWORD "</b><br/><input id='mp' name='mp' type='password' placeholder='" D_PASSWORD "' value='" D_ASTERIX "'><br/>"
"<br/><b>" D_TOPIC "</b> = %topic% (" MQTT_TOPIC ")<br/><input id='mt' name='mt' placeholder='" MQTT_TOPIC" ' value='{m6'><br/>"
"<br/><b>" D_FULL_TOPIC "</b> (" MQTT_FULLTOPIC ")<br/><input id='mf' name='mf' placeholder='" MQTT_FULLTOPIC" ' value='{m7'><br/>";
"<fieldset><legend><b>&nbsp;" D_MQTT_PARAMETERS "&nbsp;</b></legend>"
"<form method='get' action='" WEB_HANDLE_MQTT "'>"
"<p><b>" D_HOST "</b> (" MQTT_HOST ")<br/><input id='mh' name='mh' placeholder='" MQTT_HOST" ' value='{m1'></p>"
"<p><b>" D_PORT "</b> (" STR(MQTT_PORT) ")<br/><input id='ml' name='ml' placeholder='" STR(MQTT_PORT) "' value='{m2'></p>"
"<p><b>" D_CLIENT "</b> ({m0)<br/><input id='mc' name='mc' placeholder='" MQTT_CLIENT_ID "' value='{m3'></p>"
"<p><b>" D_USER "</b> (" MQTT_USER ")<br/><input id='mu' name='mu' placeholder='" MQTT_USER "' value='{m4'></p>"
"<p><b>" D_PASSWORD "</b><br/><input id='mp' name='mp' type='password' placeholder='" D_PASSWORD "' value='" D_ASTERISK_PWD "'></p>"
"<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)
{
@ -938,7 +946,7 @@ void MqttSaveSettings(void)
WebGetArg("mu", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user));
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"),
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_topic, Settings.mqtt_fulltopic);
AddLog(LOG_LEVEL_INFO);

View File

@ -896,7 +896,11 @@ void LightAnimate(void)
}
}
else {
#ifdef PWM_LIGHTSCHEME0_IGNORE_SLEEP
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) {
case LS_POWER:
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 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 =
"<fieldset><legend><b>&nbsp;" D_DOMOTICZ_PARAMETERS "&nbsp;</b></legend><form method='post' action='" WEB_HANDLE_DOMOTICZ "'>"
"<br/><table>";
"<fieldset><legend><b>&nbsp;" D_DOMOTICZ_PARAMETERS "&nbsp;</b></legend>"
"<form method='post' action='" WEB_HANDLE_DOMOTICZ "'>"
"<br/>"
"<table>";
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_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);
}
uint16_t GetSunMinutes(uint8_t dawn)
uint16_t SunMinutes(uint8_t dawn)
{
uint8_t hour[2];
uint8_t minute[2];
@ -517,7 +517,7 @@ bool TimerCommand(void)
const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER;
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 =
"var pt=[],ct=99;"
@ -593,8 +593,8 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM =
"if(ct<99){st();}" // Save changes
"ct=t;"
"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;\"}"
"e.style.cssText=\"background-color:#fff;color:#000;font-weight:bold;\";" // Change style to tab/button used to open content
"for(i=0;i<o.length;i++){o[i].style.cssText=\"background-color:#999;color:#fff;font-weight:normal;\"}"
"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
#ifdef USE_SUNRISE
"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('#d1');for(i=0;i<}1;i++){ce(i+1,o);}" // Create outputs
"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('dP').click();" // Get the element with id='dP' and click on it
"}";
const char HTTP_TIMER_STYLE[] PROGMEM =
".tl{float:left;border-radius:0;border:1px solid #fff;padding:1px;width:6.25%;}"
#ifdef USE_SUNRISE
"input[type='radio']{width:13px;height:24px;margin-top:-1px;margin-right:8px;vertical-align:middle;}"
#endif
".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)
"</style>";
const char HTTP_FORM_TIMER[] PROGMEM =
"<fieldset style='min-width:470px;text-align:center;'>"
"<legend style='text-align:left;'><b>&nbsp;" D_TIMER_PARAMETERS "&nbsp;</b></legend>"
"<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='";
const char HTTP_FORM_TIMER1[] PROGMEM =
"' hidden><div id='bt' name='bt'></div><br/><br/><br/>"
"<div id='oa' name='oa'></div><br/>"
"<div>"
"<input style='width:5%;' 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='a0' name='a0' type='checkbox'><b>" D_TIMER_ARM "</b>&emsp;"
"<input id='r0' name='r0' type='checkbox'><b>" D_TIMER_REPEAT "</b>"
"</div><br/>"
"<div>"
#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='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/>"
"</fieldset>"
"<p></p>"
"<span><select style='width:46px;' id='dr' name='dr'></select></span>"
"&nbsp;"
#else

View File

@ -90,6 +90,21 @@
#define MAXIMUM_COMPARE_OPERATOR COMPARE_OPERATOR_SMALLER_EQUAL
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 };
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%%"));
if (rule_param.startsWith(stemp)) {
rule_param = String(GetMinutesPastMidnight());
rule_param = String(MinutesPastMidnight());
}
snprintf_P(stemp, sizeof(stemp), PSTR("%%UPTIME%%"));
if (rule_param.startsWith(stemp)) {
rule_param = String(GetMinutesUptime());
rule_param = String(MinutesUptime());
}
snprintf_P(stemp, sizeof(stemp), PSTR("%%TIMESTAMP%%"));
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)
snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNRISE%%"));
if (rule_param.startsWith(stemp)) {
rule_param = String(GetSunMinutes(0));
rule_param = String(SunMinutes(0));
}
snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNSET%%"));
if (rule_param.startsWith(stemp)) {
rule_param = String(GetSunMinutes(1));
rule_param = String(SunMinutes(1));
}
#endif // USE_TIMERS and USE_SUNRISE
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);
commands.replace(stemp, Settings.mems[i]);
}
commands.replace(F("%time%"), String(GetMinutesPastMidnight()));
commands.replace(F("%uptime%"), String(GetMinutesUptime()));
commands.replace(F("%time%"), String(MinutesPastMidnight()));
commands.replace(F("%uptime%"), String(MinutesUptime()));
commands.replace(F("%timestamp%"), GetDateAndTime(DT_LOCAL).c_str());
#if defined(USE_TIMERS) && defined(USE_SUNRISE)
commands.replace(F("%sunrise%"), String(GetSunMinutes(0)));
commands.replace(F("%sunset%"), String(GetSunMinutes(1)));
commands.replace(F("%sunrise%"), String(SunMinutes(0)));
commands.replace(F("%sunset%"), String(SunMinutes(1)));
#endif // USE_TIMERS and USE_SUNRISE
char command[commands.length() +1];
@ -490,8 +505,8 @@ void RulesEvery50ms(void)
json_event[0] = '\0';
switch (i) {
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 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%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}}"), MinutesPastMidnight()); 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 5: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break;
@ -534,7 +549,7 @@ void RulesEverySecond(void)
if (RtcTime.valid) {
if ((uptime > 60) && (RtcTime.minute != rules_last_minute)) { // Execute from one minute after restart every minute only once
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);
}
}
@ -562,6 +577,310 @@ void RulesTeleperiod(void)
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)
{
char command[CMDSZ];
@ -620,7 +939,12 @@ bool RulesCommand(void)
}
else if ((CMND_RULETIMER == command_code) && (index > 0) && (index <= MAX_RULE_TIMERS)) {
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;
#endif //USE_EXPRESSION
}
mqtt_data[0] = '\0';
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)) {
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]));
#endif //USE_EXPRESSION
bitSet(vars_event, 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)) {
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]));
#endif //USE_EXPRESSION
bitSet(mems_event, 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 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 =
"<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>"
"<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='line' min='0' max='15' value='{knl'> . "
"<input style='width:12%;' type='number' name='member' min='0' max='255' value='{knm'>"
"<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 =
"><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 =
"><b>" D_KNX_ENHANCEMENT "</b><br/></center><br/>"

View File

@ -205,17 +205,17 @@ bool CseCommand(void)
if (CMND_POWERSET == energy_command_code) {
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) {
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) {
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

View File

@ -103,7 +103,7 @@ void CounterShow(bool json)
dtostrfd((double)RtcSettings.pulse_counter[i] / 1000000, 6, counter);
} else {
dsxflg++;
dtostrfd(RtcSettings.pulse_counter[i], 0, counter);
snprintf_P(counter, sizeof(counter), PSTR("%lu"), RtcSettings.pulse_counter[i]);
}
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>";
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 =
"<fieldset><legend><b>&nbsp;" D_CALIBRATION "&nbsp;</b></legend>"
"<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/>"
"<br/><button name='calibrate' type='submit'>" D_CALIBRATE "</button><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>"
"</form>"
"</fieldset><br/><br/>"
"<fieldset><legend><b>&nbsp;" D_HX711_PARAMETERS "&nbsp;</b></legend>"
"<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)
{

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
VER = '2.1.0020'
VER = '2.1.0021'
"""
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($)')) ),
}, 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 = [
(0x6040111, 0xe00, Setting_6_4_1_17),
(0x6040110, 0xe00, Setting_6_4_1_16),
(0x604010D, 0xe00, Setting_6_4_1_13),
(0x604010B, 0xe00, Setting_6_4_1_11),
(0x6040108, 0xe00, Setting_6_4_1_8),
@ -2850,4 +2882,4 @@ if __name__ == "__main__":
tasmotacmnds = Mapping2Cmnd(decode_cfg, configmapping)
OutputTasmotaCmnds(tasmotacmnds)
sys.exit(exitcode)
sys.exit(exitcode)