5.12.0 20180209
* Change library PubSubClient.h define MQTT_MAX_PACKET_SIZE from 512 to
1000 for Home Assistant  support
* Change relation of define MESSZ being dependent on PubSubClient.h
define MQTT_MAX_PACKET_SIZE
* Change command color parameter input checks to less strict for Home
Assistant support
* Change command Ina219Mode into command Sensor13
* Change commands HlwPCal, HlwUCal and HlwICal to PowerCal, VoltageCal
and CurrentCal to be used for both Pow and S31 calibration
* Change commands HlwPSet, HlwUSet and HlwISet to PowerSet, VoltageSet
and CurrentSet to be used for both Pow and S31 calibration
* Change uptime from hour to second resulting in a display of
123T13:45:21 where 123 is days
* Change module name Wemos D1 mini into Generic (#1220)
* Change HTML from width=100% to style=width:100% supporting HTML5
(#1358)
* Change OSWATCH_RESET_TIME (Blocked loop) from 30 to 120 seconds to
allow slow networks (#1556)
* Change WIFI_MANAGER_SEC into WIFI_CONFIG_SEC (#1616)
* Change function pointers code to save code space and memory (#1683)
* Change webserver argument processing gaining 5k code space (#1705)
* Change weblog memory usage (#1730, #1793, #1819)
* Update TasmotaSerial library to 1.1.0
* Update language files Italian (#1594), Dutch (#1723) and Spanish
(#1722)
* Fix Non-English JSON temperature unit attachement
* Fix Arilux RF induced exception by moving interrupt handler to iram on
non ESP8266/Arduino lib v2.3.0
* Fix truncated command names and wrong response for DomoticzSwitchIdx
(#1571)
* Fix %-sign issue as printf escape character in Humidity and Sonoff SC
(#1579)
* Fix DS18B20 temperature JSON decimal dot (#1561)
* Fix Energy JSON message (#1621)
* Fix IRSend parameter translation (#1636)
* Fix TSL2561 device detection (#1644, #1825)
* Fix BME680 teleperiod resistance measuring (#1647)
* Fix Energy Monitoring Energy Today and Energy Total reading after
restart (#1648)
* Fix IRReceive Data value (#1663)
* Fix Energy Monitoring Energy Period roll-over (#1688)
* Fix compiler warnings (#1774)
* Fix command PWM response if no PWM channel is configured (#1783)
* Add locale Decimal Separator to Web sensor page
* Add ColorTemperature to light status message
* Add command PowerOnState option 5 which inverts PulseTime and allows
for delayed always on after power on
* Add OtaMagic two step Web server OTA upgrade using filename-minimal
image if OTA free space is too small
* Add support for PMS5003 and PMS7003 particle concentration sensor
* Add command SetOption21 1 to allow Energy Monitoring when power is off
on Sonoff Pow and Sonoff S31 (#1420)
* Add Chinese language file (#1551)
* Add French language file (#1561)
* Add Spanish language file (#1589)
* Add HTTP Allow Cross Origin removed from ESP8266/Arduino lib v2.4.0
(#1572)
* Add Home Assistant MQTT Discovery for switch and light to be enabled
by command SetOption19 1 (#1534) or define
HOME_ASSISTANT_DISCOVERY_ENABLE in user_config.h (#1685)
* Add command State to retrieve device state information (same data as
teleperiod state and status 11 in slightly different JSON format)
* Add optional login to Webserver AP mode (#1587, #1635)
* Add command Sensor15 2 to start MHZ19(B) Zero Point Calibration
(#1643)
* Add support for Sonoff S31 Smart Socket with Power Consumption
Detection (#1626)
* Add command SetOption20 to allow update of Dimmer/Color/Ct without
turning power on (#1719, #1741)
* Add NTP sync time slot based on chip id (#1773)
* Add cursor pointer to web button (#1836)
This commit is contained in:
arendst 2018-02-09 15:44:54 +01:00
parent f60c570eac
commit 600c4b1872
53 changed files with 3791 additions and 5666 deletions

View File

@ -1,7 +1,7 @@
## Sonoff-Tasmota
Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE.
Current version is **5.11.1** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
Current version is **5.12.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
### ATTENTION All versions
@ -43,6 +43,7 @@ The following devices are supported:
- [iTead Sonoff 4CH Pro](https://www.itead.cc/smart-home/sonoff-4ch-pro.html)
- [iTead S20 Smart Socket](https://www.itead.cc/smart-socket.html)
- [Sonoff S22 Smart Socket](https://github.com/arendst/Sonoff-Tasmota/issues/627)
- [iTead Sonoff S31 Smart Socket with Energy Monitoring](https://www.itead.cc/sonoff-s31.html)
- [iTead Slampher](https://www.itead.cc/slampher.html)
- [iTead Sonoff Touch](https://www.itead.cc/sonoff-touch.html)
- [iTead Sonoff T1](https://www.itead.cc/sonoff-t1.html)

File diff suppressed because it is too large Load Diff

View File

@ -1,131 +0,0 @@
# ESP8266 platform
# ------------------------------
# For more info:
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
name=ESP8266 Modules
version=2.4.0
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_flags=-DLWIP_OPEN_SRC
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}/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
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 call_user_start -u _printf_float -u _scanf_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 -laxtls -lespnow -lsmartconfig -lmesh -lwpa2 -lstdc++ -lm -lc -lgcc
compiler.cpp.cmd=xtensa-lx106-elf-g++
compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections
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
## windows-compatible version may be added later
## 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}" {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}" {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}" {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} "{build.path}/arduino.ar" "{object_file}"
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/arduino.ar" {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.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
## 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}" -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"

File diff suppressed because it is too large Load Diff

View File

@ -1,131 +0,0 @@
# ESP8266 platform
# ------------------------------
# For more info:
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
name=ESP8266 Modules
version=2.4.0
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_flags=-DLWIP_OPEN_SRC
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}/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
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 call_user_start -u _printf_float -u _scanf_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 -laxtls -lespnow -lsmartconfig -lairkiss -lmesh -lwpa2 -lstdc++ -lm -lc -lgcc
compiler.cpp.cmd=xtensa-lx106-elf-g++
compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections
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
## windows-compatible version may be added later
## 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}" {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}" {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}" {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} "{build.path}/arduino.ar" "{object_file}"
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/arduino.ar" {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.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
## 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}" -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

@ -24,7 +24,8 @@
// MQTT_MAX_PACKET_SIZE : Maximum packet size
#ifndef MQTT_MAX_PACKET_SIZE
//#define MQTT_MAX_PACKET_SIZE 128
#define MQTT_MAX_PACKET_SIZE 512
//#define MQTT_MAX_PACKET_SIZE 512 // Tasmota
#define MQTT_MAX_PACKET_SIZE 1000 // Tasmota v5.11.1c
#endif
// MQTT_KEEPALIVE : keepAlive interval in Seconds

View File

@ -82,35 +82,56 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin)
if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
return;
}
m_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE);
if (m_buffer == NULL) {
return;
}
m_valid = true;
m_rx_pin = receive_pin;
m_tx_pin = transmit_pin;
m_in_pos = m_out_pos = 0;
// Use getCycleCount() loop to get as exact timing as possible
m_bit_time = ESP.getCpuFreqMHz() *1000000 /TM_SERIAL_BAUDRATE;
pinMode(m_rx_pin, INPUT);
ObjList[m_rx_pin] = this;
attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING);
pinMode(m_tx_pin, OUTPUT);
digitalWrite(m_tx_pin, HIGH);
if (m_rx_pin > -1) {
m_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE);
if (m_buffer == NULL) {
return;
}
// Use getCycleCount() loop to get as exact timing as possible
m_bit_time = ESP.getCpuFreqMHz() *1000000 /TM_SERIAL_BAUDRATE;
pinMode(m_rx_pin, INPUT);
ObjList[m_rx_pin] = this;
attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING);
}
if (m_tx_pin > -1) {
pinMode(m_tx_pin, OUTPUT);
digitalWrite(m_tx_pin, HIGH);
}
m_valid = true;
}
bool TasmotaSerial::isValidGPIOpin(int pin)
{
return (pin >= 0 && pin <= 5) || (pin >= 12 && pin <= 15);
return (pin >= -1 && pin <= 5) || (pin >= 12 && pin <= 15);
}
bool TasmotaSerial::begin(long speed) {
// Use getCycleCount() loop to get as exact timing as possible
m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed;
return m_valid && (speed <= TM_SERIAL_BAUDRATE);
}
bool TasmotaSerial::begin() {
return m_valid;
return begin(TM_SERIAL_BAUDRATE);
}
void TasmotaSerial::flush() {
m_in_pos = m_out_pos = 0;
}
int TasmotaSerial::peek() {
if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) {
return -1;
}
return m_buffer[m_out_pos];
}
int TasmotaSerial::read()
{
if (m_in_pos == m_out_pos) {
if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) {
return -1;
}
uint8_t ch = m_buffer[m_out_pos];
@ -127,11 +148,17 @@ int TasmotaSerial::available()
return avail;
}
//#define TM_SERIAL_WAIT { while (ESP.getCycleCount()-start < wait) optimistic_yield(1); wait += m_bit_time; } // Watchdog timeouts
#ifdef TM_SERIAL_USE_IRAM
#define TM_SERIAL_WAIT { while (ESP.getCycleCount()-start < wait) optimistic_yield(1); wait += m_bit_time; } // Watchdog timeouts
#else
#define TM_SERIAL_WAIT { while (ESP.getCycleCount()-start < wait); wait += m_bit_time; }
#endif
size_t TasmotaSerial::txWrite(uint8_t b)
size_t TasmotaSerial::write(uint8_t b)
{
if (-1 == m_tx_pin) {
return 0;
}
unsigned long wait = m_bit_time;
digitalWrite(m_tx_pin, HIGH);
unsigned long start = ESP.getCycleCount();
@ -149,17 +176,6 @@ size_t TasmotaSerial::txWrite(uint8_t b)
return 1;
}
size_t TasmotaSerial::write(const uint8_t *buffer, size_t size)
{
size_t n = 0;
// Flush input buffer on every write
m_in_pos = m_out_pos = 0;
while(size--) {
n += txWrite(*buffer++);
}
return n;
}
#ifdef TM_SERIAL_USE_IRAM
void ICACHE_RAM_ATTR TasmotaSerial::rxRead()
{
@ -183,7 +199,7 @@ void TasmotaSerial::rxRead()
TM_SERIAL_WAIT;
// Store the received value in the buffer unless we have an overflow
int next = (m_in_pos+1) % TM_SERIAL_BUFFER_SIZE;
if (next != m_out_pos) {
if (next != (int)m_out_pos) {
m_buffer[m_in_pos] = rec;
m_in_pos = next;
}

View File

@ -20,25 +20,37 @@
#ifndef TasmotaSerial_h
#define TasmotaSerial_h
/*********************************************************************************************\
* TasmotaSerial supports 9600 baud with fixed buffer size of 20 bytes using optional no iram
* TasmotaSerial supports up to 9600 baud with fixed buffer size of 64 bytes using optional no iram
*
* Based on EspSoftwareSerial v3.3.1 by Peter Lerup (https://github.com/plerup/espsoftwareserial)
\*********************************************************************************************/
#define TM_SERIAL_BAUDRATE 9600
#define TM_SERIAL_BUFFER_SIZE 20
//#define TM_SERIAL_USE_IRAM // Enable to use iram (+368 bytes)
#define TM_SERIAL_BAUDRATE 9600 // Max supported baudrate
#define TM_SERIAL_BUFFER_SIZE 64 // Receive buffer size
class TasmotaSerial {
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
#define TM_SERIAL_USE_IRAM // Enable to use iram (+368 bytes)
#endif
#include <Stream.h>
class TasmotaSerial : public Stream {
public:
TasmotaSerial(int receive_pin, int transmit_pin);
bool begin(long speed);
bool begin();
size_t write(const uint8_t *buffer, size_t size = 1);
int read();
int available();
int peek();
virtual size_t write(uint8_t byte);
virtual int read();
virtual int available();
virtual void flush();
void rxRead();
using Print::write;
private:
bool isValidGPIOpin(int pin);
size_t txWrite(uint8_t byte);

View File

@ -12,19 +12,24 @@ src_dir = sonoff
; *** Uncomment one of the lines below to build/upload only one environment
;env_default = sonoff
;env_default = sonoff-NL
;env_default = sonoff-CN
;env_default = sonoff-DE
;env_default = sonoff-PL
;env_default = sonoff-ES
;env_default = sonoff-FR
;env_default = sonoff-IT
;env_default = sonoff-NL
;env_default = sonoff-PL
;env_default = sonoff-minimal
;env_default = sonoff-ds18x20
[env:sonoff]
;platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=512
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py
@ -33,6 +38,8 @@ monitor_baud = 115200
; *** Upload Serial reset method for Wemos and NodeMCU
;upload_resetmethod = nodemcu
;upload_port = COM6
;upload_speed = 115200
; *** Upload file to OTA server using SCP
;upload_port = user@host:/path
@ -42,56 +49,101 @@ monitor_baud = 115200
;upload_port = domus1:80/api/upload-arduino.php
;extra_scripts = pio/strip-floats.py, pio/http-uploader.py
[env:sonoff-DE]
[env:sonoff-CN]
;platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=512 -DMY_LANGUAGE=de-DE
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000 -DMY_LANGUAGE=zh-CN
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py
[env:sonoff-DE]
;platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000 -DMY_LANGUAGE=de-DE
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py
[env:sonoff-ES]
;platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000 -DMY_LANGUAGE=es-AR
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py
[env:sonoff-FR]
;platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000 -DMY_LANGUAGE=fr-FR
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py
[env:sonoff-IT]
;platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=512 -DMY_LANGUAGE=it-IT
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000 -DMY_LANGUAGE=it-IT
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py
[env:sonoff-NL]
;platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=512 -DMY_LANGUAGE=nl-NL
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000 -DMY_LANGUAGE=nl-NL
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py
[env:sonoff-PL]
;platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=512 -DMY_LANGUAGE=pl-PL
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000 -DMY_LANGUAGE=pl-PL
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py
[env:sonoff-minimal]
platform = espressif8266
platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
;platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=512 -DBE_MINIMAL
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000 -DBE_MINIMAL
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py
[env:sonoff-ds18x20]
;platform = espressif8266@1.5.0 ; v2.3.0
;platform = espressif8266@1.6.0 ; v2.4.0
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=707 -DUSE_DS18x20 -DMESSZ=600
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=1000 -DUSE_DS18x20
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
extra_scripts = pio/strip-floats.py

View File

@ -1,4 +1,54 @@
/* 5.11.1 20180107
/* 5.12.0 20180209
* Change library PubSubClient.h define MQTT_MAX_PACKET_SIZE from 512 to 1000 for Home Assistant support
* Change relation of define MESSZ being dependent on PubSubClient.h define MQTT_MAX_PACKET_SIZE
* Change command color parameter input checks to less strict for Home Assistant support
* Change command Ina219Mode into command Sensor13
* Change commands HlwPCal, HlwUCal and HlwICal to PowerCal, VoltageCal and CurrentCal to be used for both Pow and S31 calibration
* Change commands HlwPSet, HlwUSet and HlwISet to PowerSet, VoltageSet and CurrentSet to be used for both Pow and S31 calibration
* Change uptime from hour to second resulting in a display of 123T13:45:21 where 123 is days
* Change module name Wemos D1 mini into Generic (#1220)
* Change HTML from width=100% to style=width:100% supporting HTML5 (#1358)
* Change OSWATCH_RESET_TIME (Blocked loop) from 30 to 120 seconds to allow slow networks (#1556)
* Change WIFI_MANAGER_SEC into WIFI_CONFIG_SEC (#1616)
* Change function pointers code to save code space and memory (#1683)
* Change webserver argument processing gaining 5k code space (#1705)
* Change weblog memory usage (#1730, #1793, #1819)
* Update TasmotaSerial library to 1.1.0
* Update language files Italian (#1594), Dutch (#1723) and Spanish (#1722)
* Fix Non-English JSON temperature unit attachement
* Fix Arilux RF induced exception by moving interrupt handler to iram on non ESP8266/Arduino lib v2.3.0
* Fix truncated command names and wrong response for DomoticzSwitchIdx (#1571)
* Fix %-sign issue as printf escape character in Humidity and Sonoff SC (#1579)
* Fix DS18B20 temperature JSON decimal dot (#1561)
* Fix Energy JSON message (#1621)
* Fix IRSend parameter translation (#1636)
* Fix TSL2561 device detection (#1644, #1825)
* Fix BME680 teleperiod resistance measuring (#1647)
* Fix Energy Monitoring Energy Today and Energy Total reading after restart (#1648)
* Fix IRReceive Data value (#1663)
* Fix Energy Monitoring Energy Period roll-over (#1688)
* Fix compiler warnings (#1774)
* Fix command PWM response if no PWM channel is configured (#1783)
* Add locale Decimal Separator to Web sensor page
* Add ColorTemperature to light status message
* Add command PowerOnState option 5 which inverts PulseTime and allows for delayed always on after power on
* Add OtaMagic two step Web server OTA upgrade using filename-minimal image if OTA free space is too small
* Add support for PMS5003 and PMS7003 particle concentration sensor
* Add command SetOption21 1 to allow Energy Monitoring when power is off on Sonoff Pow and Sonoff S31 (#1420)
* Add Chinese language file (#1551)
* Add French language file (#1561)
* Add Spanish language file (#1589)
* Add HTTP Allow Cross Origin removed from ESP8266/Arduino lib v2.4.0 (#1572)
* Add Home Assistant MQTT Discovery for switch and light to be enabled by command SetOption19 1 (#1534) or define HOME_ASSISTANT_DISCOVERY_ENABLE in user_config.h (#1685)
* Add command State to retrieve device state information (same data as teleperiod state and status 11 in slightly different JSON format)
* Add optional login to Webserver AP mode (#1587, #1635)
* Add command Sensor15 2 to start MHZ19(B) Zero Point Calibration (#1643)
* Add support for Sonoff S31 Smart Socket with Power Consumption Detection (#1626)
* Add command SetOption20 to allow update of Dimmer/Color/Ct without turning power on (#1719, #1741)
* Add NTP sync time slot based on chip id (#1773)
* Add cursor pointer to web button (#1836)
*
* 5.11.1 20180107
* Fix Sonoff Pow command handling (#1542)
*
* 5.11.0 20180107

View File

@ -75,6 +75,7 @@
#define D_JSON_LOW "Low"
#define D_JSON_MAC "Mac"
#define D_JSON_MASK "Mask"
#define D_JSON_MINIMAL "minimal"
#define D_JSON_NO "No"
#define D_JSON_NOISE "Noise"
#define D_JSON_NONE "None"
@ -117,6 +118,7 @@
#define D_JSON_WIFI "Wifi"
#define D_JSON_WRONG "Wrong"
#define D_JSON_YESTERDAY "Yesterday"
#define D_JSON_ZERO_POINT_CALIBRATION "Zero Point Calibration"
#define D_RSLT_ENERGY "ENERGY"
#define D_RSLT_INFO "INFO"
@ -165,11 +167,13 @@
#define D_STATUS9_MARGIN "PTH"
#define D_STATUS10_SENSOR "SNS"
#define D_STATUS11_STATUS "STS"
#define D_CMND_STATE "State"
#define D_CMND_POWER "Power"
#define D_CMND_POWERONSTATE "PowerOnState"
#define D_CMND_PULSETIME "PulseTime"
#define D_CMND_BLINKTIME "BlinkTime"
#define D_CMND_BLINKCOUNT "BlinkCount"
#define D_CMND_SENSOR "Sensor"
#define D_CMND_SAVEDATA "SaveData"
#define D_CMND_SETOPTION "SetOption"
#define D_CMND_TEMPERATURE_RESOLUTION "TempRes"
@ -235,7 +239,6 @@
#define D_CMND_LEDSTATE "LedState"
#define D_CMND_CFGDUMP "CfgDump"
#define D_CMND_I2CSCAN "I2CScan"
#define D_CMND_INA219MODE "Ina219Mode"
#define D_CMND_EXCEPTION "Exception"
// Commands xdrv_01_light.ino
@ -254,9 +257,20 @@
// Commands xdrv_02_irremote.ino
#define D_CMND_IRSEND "IRSend"
#define D_JSON_INVALID_JSON "Invalid JSON"
#define D_JSON_PROTOCOL_NOT_SUPPORTED "Protocol not supported"
#define D_JSON_IR_PROTOCOL "PROTOCOL"
#define D_JSON_IR_BITS "BITS"
#define D_JSON_IR_DATA "DATA"
#define D_CMND_IRHVAC "IRHVAC"
#define D_JSON_IRHVAC_VENDOR "VENDOR"
#define D_JSON_IRHVAC_POWER "POWER"
#define D_JSON_IRHVAC_MODE "MODE"
#define D_JSON_IRHVAC_FANSPEED "FANSPEED"
#define D_JSON_IRHVAC_TEMP "TEMP"
#define D_JSON_IRRECEIVED "IrReceived"
// Commands xsns_03_energy.ino
// Commands xdrv_03_energy.ino
#define D_CMND_POWERLOW "PowerLow"
#define D_CMND_POWERHIGH "PowerHigh"
#define D_CMND_VOLTAGELOW "VoltageLow"
@ -264,12 +278,12 @@
#define D_CMND_CURRENTLOW "CurrentLow"
#define D_CMND_CURRENTHIGH "CurrentHigh"
#define D_CMND_ENERGYRESET "EnergyReset"
#define D_CMND_HLWPCAL "HlwPcal"
#define D_CMND_HLWPSET "HlwPset"
#define D_CMND_HLWUCAL "HlwUcal"
#define D_CMND_HLWUSET "HlwUset"
#define D_CMND_HLWICAL "HlwIcal"
#define D_CMND_HLWISET "HlwIset"
#define D_CMND_POWERCAL "PowerCal"
#define D_CMND_POWERSET "PowerSet"
#define D_CMND_VOLTAGECAL "VoltageCal"
#define D_CMND_VOLTAGESET "VoltageSet"
#define D_CMND_CURRENTCAL "CurrentCal"
#define D_CMND_CURRENTSET "CurrentSet"
#define D_CMND_MAXPOWER "MaxPower"
#define D_CMND_MAXPOWERHOLD "MaxPowerHold"
#define D_CMND_MAXPOWERWINDOW "MaxPowerWindow"
@ -359,7 +373,7 @@ const char kUnitNames[] PROGMEM =
D_UNIT_MILLIAMPERE "|"
D_UNIT_MILLISECOND "|"
D_UNIT_MINUTE "|"
D_UNIT_PPM "|"
D_UNIT_PARTS_PER_MILLION "|"
D_UNIT_PRESSURE "|"
D_UNIT_SECOND "|"
D_UNIT_SECTORS "|"
@ -368,6 +382,7 @@ const char kUnitNames[] PROGMEM =
D_UNIT_WATTHOUR ;
const char S_JSON_COMMAND_NVALUE_SPACE_UNIT[] PROGMEM = "{\"%s\":\"%d %s\"}";
const char S_JSON_COMMAND_LVALUE_SPACE_UNIT[] PROGMEM = "{\"%s\":\"%lu %s\"}";
const char S_JSON_COMMAND_SVALUE_SPACE_UNIT[] PROGMEM = "{\"%s\":\"%s %s\"}";
const char S_JSON_COMMAND_NVALUE_UNIT[] PROGMEM = "{\"%s\":\"%d%s\"}";
const char S_JSON_COMMAND_NVALUE_UNIT_NVALUE_UNIT[] PROGMEM = "{\"%s\":\"%d%s (%d%s)\"}";
@ -376,13 +391,18 @@ const char S_JSON_COMMAND_NVALUE_SVALUE[] PROGMEM = "{\"%s\":\"%d (%s)
const char S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE[] PROGMEM = "{\"%s\":\"%d (" D_JSON_ACTIVE " %d)\"}";
const char S_JSON_COMMAND_NVALUE[] PROGMEM = "{\"%s\":%d}";
const char S_JSON_COMMAND_LVALUE[] PROGMEM = "{\"%s\":%lu}";
const char S_JSON_COMMAND_SVALUE[] PROGMEM = "{\"%s\":\"%s\"}";
const char S_JSON_COMMAND_XVALUE[] PROGMEM = "{\"%s\":%s}"; // %s must provide quotes on non-number
const char S_JSON_COMMAND_INDEX_NVALUE[] PROGMEM = "{\"%s%d\":%d}";
const char S_JSON_COMMAND_INDEX_LVALUE[] PROGMEM = "{\"%s%d\":%lu}";
const char S_JSON_COMMAND_INDEX_SVALUE[] PROGMEM = "{\"%s%d\":\"%s\"}";
const char S_JSON_COMMAND_INDEX_SVALUE_SVALUE[] PROGMEM = "{\"%s%d\":\"%s%s\"}";
const char S_JSON_SENSOR_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":%d}";
const char S_JSON_SENSOR_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":\"%s\"}";
const char JSON_SNS_TEMPHUM[] PROGMEM = "%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s}";
const char S_LOG_I2C_FOUND_AT[] PROGMEM = D_LOG_I2C "%s " D_FOUND_AT " 0x%x";
@ -422,13 +442,13 @@ static const char kMonthNames[] = D_MONTH3LIST;
// webserver.ino
#ifdef USE_WEBSERVER
const char HTTP_SNS_TEMP[] PROGMEM = "%s{s}%s " D_TEMPERATURE "{m}%s&deg;%c{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_HUM[] PROGMEM = "%s{s}%s " D_HUMIDITY "{m}%s%{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_HUM[] PROGMEM = "%s{s}%s " D_HUMIDITY "{m}%s%%{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_PRESSURE[] PROGMEM = "%s{s}%s " D_PRESSURE "{m}%s " D_UNIT_PRESSURE "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "%s{s}%s " D_PRESSUREATSEALEVEL "{m}%s " D_UNIT_PRESSURE "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_ANALOG[] PROGMEM = "%s{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#if defined(USE_MHZ19) || defined(USE_SENSEAIR)
const char HTTP_SNS_CO2[] PROGMEM = "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PPM "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_CO2[] PROGMEM = "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_WEBSERVER
const char S_MAIN_MENU[] PROGMEM = D_MAIN_MENU;

View File

@ -30,6 +30,8 @@
*
\*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
// "2017-03-07T11:08:02" - ISO8601:2004
#define D_YEAR_MONTH_SEPARATOR "."
#define D_MONTH_DAY_SEPARATOR "."
@ -149,6 +151,7 @@
#define D_WEB_SERVER "Web-Server"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "WARNING This version does not support persistent settings"
#define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1"
#define D_SERIAL_LOGGING_DISABLED "Serielles logging deaktiviert"
@ -334,19 +337,6 @@
#define D_HUE_POST_ARGS "Hue POST args"
#define D_3_RESPONSE_PACKETS_SENT "3 Antwortpakete gesendet"
// xdrv_02_irremote.ino
#define D_JSON_INVALID_JSON "ungültiger JSON"
#define D_JSON_PROTOCOL_NOT_SUPPORTED "Protokoll nicht unterstützt"
#define D_JSON_IR_PROTOCOL "PROTOKOLL"
#define D_JSON_IR_BITS "BITS"
#define D_JSON_IR_DATA "DATEN"
#define D_JSON_IRHVAC_VENDOR "HERSTELLER"
#define D_JSON_IRHVAC_POWER "STROM"
#define D_JSON_IRHVAC_MODE "MODUS"
#define D_JSON_IRHVAC_FANSPEED "LÜFTERGESCHWINDIGKEIT"
#define D_JSON_IRHVAC_TEMP "TEMPERATUR"
#define D_JSON_IRRECEIVED "IR empfangen"
// xdrv_05_domoticz.ino
#define D_DOMOTICZ_PARAMETERS "Domoticz parameters"
#define D_DOMOTICZ_IDX "Idx"
@ -364,7 +354,7 @@
#define D_DOMOTICZ_AIRQUALITY "AirQuality"
#define D_DOMOTICZ_UPDATE_TIMER "Update timer"
// xsns_03_energy.ino
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energie heute"
#define D_ENERGY_YESTERDAY "Energie gestern"
#define D_ENERGY_TOTAL "Energie insgesamt"
@ -385,8 +375,12 @@
#define D_SENSOR_DID_NOT_ACK_COMMAND "Sensor hat ACK-Befehl nicht ausgeführt"
#define D_SHT1X_FOUND "SHT1X gefunden"
// xsns_18_pms5003.ino
#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter
#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter
#define D_PARTICALS_BEYOND "Particals"
// sonoff_template.h
// Max string length is 8 characters including suffixes
#define D_SENSOR_NONE "None"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
@ -412,6 +406,7 @@
#define D_SENSOR_SPI_CS "SPI CS"
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
// Units
#define D_UNIT_AMPERE "A"
@ -419,11 +414,14 @@
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3"
#define D_UNIT_MICROMETER "um"
#define D_UNIT_MICROSECOND "µs"
#define D_UNIT_MILLIAMPERE "mA"
#define D_UNIT_MILLISECOND "ms"
#define D_UNIT_MINUTE "min"
#define D_UNIT_PPM "ppm"
#define D_UNIT_PARTS_PER_DECILITER "ppd"
#define D_UNIT_PARTS_PER_MILLION "ppm"
#define D_UNIT_PRESSURE "hPa"
#define D_UNIT_SECOND "sek"
#define D_UNIT_SECTORS "Sektoren"

View File

@ -30,6 +30,8 @@
*
\*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
// "2017-03-07T11:08:02" - ISO8601:2004
#define D_YEAR_MONTH_SEPARATOR "-"
#define D_MONTH_DAY_SEPARATOR "-"
@ -149,6 +151,7 @@
#define D_WEB_SERVER "Web Server"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "WARNING This version does not support persistent settings"
#define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1"
#define D_SERIAL_LOGGING_DISABLED "Serial logging disabled"
@ -334,19 +337,6 @@
#define D_HUE_POST_ARGS "Hue POST args"
#define D_3_RESPONSE_PACKETS_SENT "3 response packets sent"
// xdrv_02_irremote.ino
#define D_JSON_INVALID_JSON "Invalid JSON"
#define D_JSON_PROTOCOL_NOT_SUPPORTED "Protocol not supported"
#define D_JSON_IR_PROTOCOL "PROTOCOL"
#define D_JSON_IR_BITS "BITS"
#define D_JSON_IR_DATA "DATA"
#define D_JSON_IRHVAC_VENDOR "VENDOR"
#define D_JSON_IRHVAC_POWER "POWER"
#define D_JSON_IRHVAC_MODE "MODE"
#define D_JSON_IRHVAC_FANSPEED "FANSPEED"
#define D_JSON_IRHVAC_TEMP "TEMP"
#define D_JSON_IRRECEIVED "IrReceived"
// xdrv_05_domoticz.ino
#define D_DOMOTICZ_PARAMETERS "Domoticz parameters"
#define D_DOMOTICZ_IDX "Idx"
@ -364,7 +354,7 @@
#define D_DOMOTICZ_AIRQUALITY "AirQuality"
#define D_DOMOTICZ_UPDATE_TIMER "Update timer"
// xsns_03_energy.ino
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energy Today"
#define D_ENERGY_YESTERDAY "Energy Yesterday"
#define D_ENERGY_TOTAL "Energy Total"
@ -385,8 +375,12 @@
#define D_SENSOR_DID_NOT_ACK_COMMAND "Sensor did not ACK command"
#define D_SHT1X_FOUND "SHT1X found"
// xsns_18_pms5003.ino
#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter
#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter
#define D_PARTICALS_BEYOND "Particals"
// sonoff_template.h
// Max string length is 8 characters including suffixes
#define D_SENSOR_NONE "None"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
@ -412,6 +406,7 @@
#define D_SENSOR_SPI_CS "SPI CS"
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
// Units
#define D_UNIT_AMPERE "A"
@ -419,11 +414,14 @@
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3"
#define D_UNIT_MICROMETER "um"
#define D_UNIT_MICROSECOND "us"
#define D_UNIT_MILLIAMPERE "mA"
#define D_UNIT_MILLISECOND "ms"
#define D_UNIT_MINUTE "Min"
#define D_UNIT_PPM "ppm"
#define D_UNIT_PARTS_PER_DECILITER "ppd"
#define D_UNIT_PARTS_PER_MILLION "ppm"
#define D_UNIT_PRESSURE "hPa"
#define D_UNIT_SECOND "sec"
#define D_UNIT_SECTORS "sectors"

457
sonoff/language/es-AR.h Normal file
View File

@ -0,0 +1,457 @@
/*
es-AR.h - localization for Spanish - Argentina for Sonoff-Tasmota
Copyright (C) 2018 Adrian Scillato
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LANGUAGE_ES_AR_H_
#define _LANGUAGE_ES_AR_H_
/*************************** ATTENTION *******************************\
*
* Due to memory constraints only UTF-8 is supported.
* To save code space keep text as short as possible.
* Time and Date provided by SDK can not be localized (yet).
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
\*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
// "2017-03-07T11:08:02" - ISO8601:2004
#define D_YEAR_MONTH_SEPARATOR "-"
#define D_MONTH_DAY_SEPARATOR "-"
#define D_DATE_TIME_SEPARATOR "T"
#define D_HOUR_MINUTE_SEPARATOR ":"
#define D_MINUTE_SECOND_SEPARATOR ":"
#define D_DAY3LIST "DomLunMarMieJueVieSab"
#define D_MONTH3LIST "EneFebMarAbrMayJunJulAgoSepOctNovDic"
// Non JSON decimal separator
#define D_DECIMAL_SEPARATOR ","
// Common
#define D_ADMIN "Admin"
#define D_AIR_QUALITY "Calidad del Aire"
#define D_AP "AP" // Access Point
#define D_AS "como"
#define D_AUTO "AUTO"
#define D_BLINK "Blink"
#define D_BLINKOFF "BlinkOff"
#define D_BOOT_COUNT "Conteo Reinicios"
#define D_BRIGHTLIGHT "Brillante"
#define D_BUTTON "Botón"
#define D_BY "por" // Written by me
#define D_BYTES "Bytes"
#define D_CELSIUS "Celsius"
#define D_CO2 "CO2"
#define D_CODE "código" // Button code
#define D_COLDLIGHT "Fría"
#define D_COMMAND "Comando"
#define D_CONNECTED "Conectado"
#define D_COUNT "Conteo"
#define D_COUNTER "Contador"
#define D_CURRENT "Corriente" // As in Voltage and Current
#define D_DATA "Datos"
#define D_DARKLIGHT "Oscura"
#define D_DEBUG "Debug"
#define D_DISABLED "Deshabilitado"
#define D_DNS_SERVER "DNS Server"
#define D_DONE "Listo"
#define D_DST_TIME "DST"
#define D_EMULATION "Emulación"
#define D_ENABLED "Habilitado"
#define D_ERASE "Borrar"
#define D_ERROR "Error"
#define D_FAHRENHEIT "Fahrenheit"
#define D_FAILED "Falló"
#define D_FALLBACK "Fallback"
#define D_FALLBACK_TOPIC "FallbackTopic"
#define D_FALSE "Falso"
#define D_FILE "Archivo"
#define D_FREE_MEMORY "Memoria Libre"
#define D_GAS "Gas"
#define D_GATEWAY "Gateway"
#define D_GROUP "Grupo"
#define D_HOST "Host"
#define D_HOSTNAME "Hostname"
#define D_HUMIDITY "Humedad"
#define D_ILLUMINANCE "Luminancia"
#define D_IMMEDIATE "inmediato" // Button immediate
#define D_INDEX "Índice"
#define D_INFO "Información"
#define D_INITIALIZED "Inicializado"
#define D_IP_ADDRESS "Dirección IP"
#define D_LIGHT "Luz"
#define D_LWT "LWT"
#define D_MODULE "Módulo"
#define D_MQTT "MQTT"
#define D_MULTI_PRESS "multi-press"
#define D_NOISE "Ruido"
#define D_NONE "Ninguno"
#define D_OFF "Apagado"
#define D_OFFLINE "Offline"
#define D_OK "Ok"
#define D_ON "Encendido"
#define D_ONLINE "Online"
#define D_PASSWORD "Clave"
#define D_PORT "Puerto"
#define D_POWER_FACTOR "Factor de Potencia"
#define D_POWERUSAGE "Potencia"
#define D_PRESSURE "Presión"
#define D_PRESSUREATSEALEVEL "Presión al nivel del mar"
#define D_PROGRAM_FLASH_SIZE "Tamaño de Flash de Programa"
#define D_PROGRAM_SIZE "Tamaño Programa"
#define D_PROJECT "Proyecto"
#define D_RECEIVED "Recibido"
#define D_RESTART "Reinicio"
#define D_RESTARTING "Reiniciando"
#define D_RESTART_REASON "Causa Reinicio"
#define D_RESTORE "Restauración"
#define D_RETAINED "Grabado"
#define D_SAVE "Grabar"
#define D_SENSOR "Sensor"
#define D_SSID "SSId"
#define D_START "Iniciar"
#define D_STD_TIME "STD"
#define D_STOP "Detener"
#define D_SUBNET_MASK "Máscara Subred"
#define D_SUBSCRIBE_TO "Suscribir a"
#define D_SUCCESSFUL "Exitosa"
#define D_TEMPERATURE "Temperatura"
#define D_TO "a"
#define D_TOGGLE "Conmutar"
#define D_TOPIC "Topic"
#define D_TRANSMIT "Transmitir"
#define D_TRUE "Verdadero"
#define D_UPGRADE "Actualización"
#define D_UPLOAD "Carga"
#define D_UPTIME "Tiempo Encendido"
#define D_USER "Usuario"
#define D_UTC_TIME "UTC"
#define D_UV_LEVEL "Nivel UV"
#define D_VERSION "Versión"
#define D_VOLTAGE "Tensión"
#define D_WARMLIGHT "Cálida"
#define D_WEB_SERVER "Servidor Web"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "Precaución, esta versión no salva los cambios"
#define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1"
#define D_SERIAL_LOGGING_DISABLED "Log serial deshabilitado"
#define D_SYSLOG_LOGGING_REENABLED "Syslog re-habilitado"
#define D_SET_BAUDRATE_TO "Baudrate a"
#define D_RECEIVED_TOPIC "Topic Recibido"
#define D_DATA_SIZE "Tamaño de Datos"
#define D_ANALOG_INPUT "Entrada Analógica"
#define D_FINGERPRINT "Verificar TLS fingerprint..."
#define D_TLS_CONNECT_FAILED_TO "Falló Conección TLS a"
#define D_RETRY_IN "Reintentando"
#define D_VERIFIED "Verificado"
#define D_INSECURE "Conección insegura por Fingerprint no válido"
#define D_CONNECT_FAILED_TO "Falló Conección a"
// support.ino
#define D_OSWATCH "osWatch"
#define D_BLOCKED_LOOP "Ciclo Bloqueado"
#define D_WPS_FAILED_WITH_STATUS "WPSconfig FALLÓ con estado"
#define D_ACTIVE_FOR_3_MINUTES "activo por 3 minutos"
#define D_FAILED_TO_START "falló inicio"
#define D_PATCH_ISSUE_2186 "Patch issue 2186"
#define D_CONNECTING_TO_AP "Connectando a AP"
#define D_IN_MODE "en modo"
#define D_CONNECT_FAILED_NO_IP_ADDRESS "Falló Conección, Dirección IP no recibida"
#define D_CONNECT_FAILED_AP_NOT_REACHED "Falló Conección, AP no pudo ser contactado"
#define D_CONNECT_FAILED_WRONG_PASSWORD "Falló Conección, clave de AP incorrecta"
#define D_CONNECT_FAILED_AP_TIMEOUT "Falló Conección, timeout de AP"
#define D_ATTEMPTING_CONNECTION "Intentando conectar..."
#define D_CHECKING_CONNECTION "Probando conección..."
#define D_QUERY_DONE "Consulta lista. Servicio MQTT encontrado"
#define D_MQTT_SERVICE_FOUND "Servicio MQTT encontrado en"
#define D_FOUND_AT "encontrado en"
#define D_SYSLOG_HOST_NOT_FOUND "Syslog Host no encontrado"
// settings.ino
#define D_SAVED_TO_FLASH_AT "Grabado a la flash en"
#define D_LOADED_FROM_FLASH_AT "Cargado desde flash en"
#define D_USE_DEFAULTS "Usar valores por defecto"
#define D_ERASED_SECTOR "Sector borrado"
// webserver.ino
#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "firmware MÍNIMO - actualice por favor"
#define D_WEBSERVER_ACTIVE_ON "Servidor web activo en"
#define D_WITH_IP_ADDRESS "con dirección IP"
#define D_WEBSERVER_STOPPED "Servidor web detenido"
#define D_FILE_NOT_FOUND "Archivo No Encontrado"
#define D_REDIRECTED "Redireccinado al portal captivo"
#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager como AccessPoint y Estación"
#define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager como AccessPoint"
#define D_TRYING_TO_CONNECT "Intentado conectar dispositivo a la red"
#define D_RESTART_IN "Reinicio en"
#define D_SECONDS "segundos"
#define D_DEVICE_WILL_RESTART "El dispositivo se reiniciará en pocos segundos"
#define D_BUTTON_TOGGLE "Alternar ON/OFF"
#define D_CONFIGURATION "Configuración"
#define D_INFORMATION "Información"
#define D_FIRMWARE_UPGRADE "Actualización Firmware"
#define D_CONSOLE "Consola"
#define D_CONFIRM_RESTART "Confirmar Reinicio"
#define D_CONFIGURE_MODULE "Configuración del Módulo"
#define D_CONFIGURE_WIFI "Configuración WiFi"
#define D_CONFIGURE_MQTT "Configuración MQTT"
#define D_CONFIGURE_DOMOTICZ "Configuración Domoticz"
#define D_CONFIGURE_LOGGING "Configuración Logging"
#define D_CONFIGURE_OTHER "Configuración Extra"
#define D_CONFIRM_RESET_CONFIGURATION "Confirmar Reset Configuración"
#define D_RESET_CONFIGURATION "Reset de Configuración"
#define D_BACKUP_CONFIGURATION "Backup de Configuración"
#define D_RESTORE_CONFIGURATION "Restaurar Configuración"
#define D_MAIN_MENU "Menú Principal"
#define D_MODULE_PARAMETERS "Parámetros del módulo"
#define D_MODULE_TYPE "Tipo módulo"
#define D_GPIO "GPIO"
#define D_SERIAL_IN "Serial In"
#define D_SERIAL_OUT "Serial Out"
#define D_WIFI_PARAMETERS "Parámetros Wifi"
#define D_SCAN_FOR_WIFI_NETWORKS "Buscar redes wifi"
#define D_SCAN_DONE "Busqueda finalizada"
#define D_NO_NETWORKS_FOUND "Ninguna red encontrada"
#define D_REFRESH_TO_SCAN_AGAIN "Recargar página para buscar nuevamente"
#define D_DUPLICATE_ACCESSPOINT "AccessPoint duplicado"
#define D_SKIPPING_LOW_QUALITY "Ignorado debido a baja calidad"
#define D_RSSI "RSSI"
#define D_WEP "WEP"
#define D_WPA_PSK "WPA PSK"
#define D_WPA2_PSK "WPA2 PSK"
#define D_AP1_SSID "SSId AP1"
#define D_AP1_PASSWORD "Clave AP1"
#define D_AP2_SSID "SSId AP2"
#define D_AP2_PASSWORD "Clave AP2"
#define D_MQTT_PARAMETERS "Parámetros MQTT"
#define D_CLIENT "Cliente"
#define D_FULL_TOPIC "Full Topic"
#define D_LOGGING_PARAMETERS "Parámetros Logging"
#define D_SERIAL_LOG_LEVEL "Nivel de log Serial"
#define D_WEB_LOG_LEVEL "Nivel de log Web"
#define D_SYS_LOG_LEVEL "Nivel de Syslog"
#define D_MORE_DEBUG "Mas Debug"
#define D_SYSLOG_HOST "Host del Syslog"
#define D_SYSLOG_PORT "Puerto del Syslog"
#define D_TELEMETRY_PERIOD "Período de Telemetría"
#define D_OTHER_PARAMETERS "Otros parámetros"
#define D_WEB_ADMIN_PASSWORD "Clave Administrador Web"
#define D_MQTT_ENABLE "Habilitar MQTT"
#define D_FRIENDLY_NAME "Nombre Amigable"
#define D_BELKIN_WEMO "Belkin WeMo"
#define D_HUE_BRIDGE "Hue Bridge"
#define D_SINGLE_DEVICE "dispositivo simple"
#define D_MULTI_DEVICE "dispositivo múltiple"
#define D_SAVE_CONFIGURATION "Grabar configuración"
#define D_CONFIGURATION_SAVED "Configuración grabada"
#define D_CONFIGURATION_RESET "Configuración restablecida"
#define D_PROGRAM_VERSION "Versión del Programa"
#define D_BUILD_DATE_AND_TIME "Fecha y Hora de la Compilación"
#define D_CORE_AND_SDK_VERSION "Versión Core/SDK"
#define D_FLASH_WRITE_COUNT "Contador de escritura en Flash"
#define D_MAC_ADDRESS "Dirección MAC"
#define D_MQTT_HOST "Host MQTT"
#define D_MQTT_PORT "Puerto MQTT"
#define D_MQTT_CLIENT "Cliente MQTT"
#define D_MQTT_USER "Usuario MQTT"
#define D_MQTT_TOPIC "Topic MQTT"
#define D_MQTT_GROUP_TOPIC "Group Topic MQTT"
#define D_MQTT_FULL_TOPIC "Full Topic MQTT"
#define D_MDNS_DISCOVERY "mDNS Discovery"
#define D_MDNS_ADVERTISE "mDNS Advertise"
#define D_ESP_CHIP_ID "ESP Chip Id"
#define D_FLASH_CHIP_ID "Flash Chip Id"
#define D_FLASH_CHIP_SIZE "Tamaño Flash"
#define D_FREE_PROGRAM_SPACE "Memoria de Programa Libre"
#define D_UPGRADE_BY_WEBSERVER "Actualizar por servidor web"
#define D_OTA_URL "OTA Url"
#define D_START_UPGRADE "Comenzar actualización"
#define D_UPGRADE_BY_FILE_UPLOAD "Actualizar cargando archivo bin"
#define D_UPLOAD_STARTED "Cargando archivo"
#define D_UPGRADE_STARTED "Actualización iniciada"
#define D_UPLOAD_DONE "Carga finalizada"
#define D_UPLOAD_ERR_1 "Ningún archivo seleccionado"
#define D_UPLOAD_ERR_2 "Espacio insuficiente"
#define D_UPLOAD_ERR_3 "Magic byte no corresponde a 0xE9"
#define D_UPLOAD_ERR_4 "El tamaño de la memoria de programa es mayor que la de la flash"
#define D_UPLOAD_ERR_5 "Error de comparación del buffer de carga"
#define D_UPLOAD_ERR_6 "Carga fallida. Habilitar logging 3"
#define D_UPLOAD_ERR_7 "Carga cancelada"
#define D_UPLOAD_ERR_8 "Archivo no válido"
#define D_UPLOAD_ERR_9 "Archivo muy grande"
#define D_UPLOAD_ERROR_CODE "Código de error de carga"
#define D_ENTER_COMMAND "Ingresar comando"
#define D_ENABLE_WEBLOG_FOR_RESPONSE "Habilitar weblog 2 si desea respuesta"
#define D_NEED_USER_AND_PASSWORD "Se necesita user=<username>&password=<password>"
// xdrv_wemohue.ino
#define D_MULTICAST_DISABLED "Multicast deshabilitado"
#define D_MULTICAST_REJOINED "Multicast (re)conectado"
#define D_MULTICAST_JOIN_FAILED "Conección Multicast fallida"
#define D_FAILED_TO_SEND_RESPONSE "Falla al enviar respuesta"
#define D_WEMO "WeMo"
#define D_WEMO_BASIC_EVENT "Evento base de WeMo"
#define D_WEMO_EVENT_SERVICE "Evento de servicio de WeMo"
#define D_WEMO_META_SERVICE "Meta Servicio de WeMo"
#define D_WEMO_SETUP "Configuración de WeMo"
#define D_RESPONSE_SENT "Respuesta enviada"
#define D_HUE "Hue"
#define D_HUE_BRIDGE_SETUP "Configuración Hue"
#define D_HUE_API_NOT_IMPLEMENTED "API de Hue no implementada"
#define D_HUE_API "Hue API"
#define D_HUE_POST_ARGS "Hue POST args"
#define D_3_RESPONSE_PACKETS_SENT "3 paquetes de respuesta enviados"
// xdrv_05_domoticz.ino
#define D_DOMOTICZ_PARAMETERS "Parámetros Domoticz"
#define D_DOMOTICZ_IDX "Idx"
#define D_DOMOTICZ_KEY_IDX "Key idx"
#define D_DOMOTICZ_SWITCH_IDX "Switch idx"
#define D_DOMOTICZ_SENSOR_IDX "Sensor idx"
#define D_DOMOTICZ_TEMP "Temp"
#define D_DOMOTICZ_TEMP_HUM "Temp,Hum"
#define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Hum,Baro"
#define D_DOMOTICZ_POWER_ENERGY "Potencia,Energía"
#define D_DOMOTICZ_ILLUMINANCE "Luminancia"
#define D_DOMOTICZ_COUNT "Contador"
#define D_DOMOTICZ_VOLTAGE "Voltaje"
#define D_DOMOTICZ_CURRENT "Corriente"
#define D_DOMOTICZ_AIRQUALITY "Calidad del Aire"
#define D_DOMOTICZ_UPDATE_TIMER "Intervalo de refresco"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energía Hoy"
#define D_ENERGY_YESTERDAY "Energía Ayer"
#define D_ENERGY_TOTAL "Energía Total"
// xsns_05_ds18b20.ino
#define D_SENSOR_BUSY "Sensor ocupado"
#define D_SENSOR_CRC_ERROR "Error CRC del Sensor"
#define D_SENSORS_FOUND "Sensores encontrados"
// xsns_06_dht.ino
#define D_TIMEOUT_WAITING_FOR "Espera de timeout por"
#define D_START_SIGNAL_LOW "iniciar señal baja"
#define D_START_SIGNAL_HIGH "iniciar señal alta"
#define D_PULSE "pulso"
#define D_CHECKSUM_FAILURE "Checksum fallido"
// xsns_07_sht1x.ino
#define D_SENSOR_DID_NOT_ACK_COMMAND "Sensor no ha enviado el comando ACK"
#define D_SHT1X_FOUND "SHT1X encontrado"
// xsns_18_pms5003.ino
#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter
#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter
#define D_PARTICALS_BEYOND "Partículas"
// sonoff_template.h
#define D_SENSOR_NONE "Ninguno"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"
#define D_SENSOR_WS2812 "WS2812"
#define D_SENSOR_IRSEND "IR TX"
#define D_SENSOR_SWITCH "Llave" // Suffix "1"
#define D_SENSOR_BUTTON "Botón" // Suffix "1"
#define D_SENSOR_RELAY "Relé" // Suffix "1i"
#define D_SENSOR_LED "Led" // Suffix "1i"
#define D_SENSOR_PWM "PWM" // Suffix "1"
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
#define D_SENSOR_IRRECV "IR RX"
#define D_SENSOR_MHZ_RX "MHZ Rx"
#define D_SENSOR_MHZ_TX "MHZ Tx"
#define D_SENSOR_PZEM_RX "PZEM Rx"
#define D_SENSOR_PZEM_TX "PZEM Tx"
#define D_SENSOR_SAIR_RX "SAir Rx"
#define D_SENSOR_SAIR_TX "SAir Tx"
#define D_SENSOR_SPI_CS "SPI CS"
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3"
#define D_UNIT_MICROMETER "um"
#define D_UNIT_MICROSECOND "us"
#define D_UNIT_MILLIAMPERE "mA"
#define D_UNIT_MILLISECOND "ms"
#define D_UNIT_MINUTE "Min"
#define D_UNIT_PARTS_PER_DECILITER "ppd"
#define D_UNIT_PARTS_PER_MILLION "ppm"
#define D_UNIT_PRESSURE "hPa"
#define D_UNIT_SECOND "seg"
#define D_UNIT_SECTORS "sectores"
#define D_UNIT_VOLT "V"
#define D_UNIT_WATT "W"
#define D_UNIT_WATTHOUR "Wh"
// Log message prefix
#define D_LOG_APPLICATION "APP: " // Application
#define D_LOG_BRIDGE "BRG: " // Bridge
#define D_LOG_CONFIG "CFG: " // Settings
#define D_LOG_COMMAND "CMD: " // Command
#define D_LOG_DEBUG "DBG: " // Debug
#define D_LOG_DHT "DHT: " // DHT sensor
#define D_LOG_DOMOTICZ "DOM: " // Domoticz
#define D_LOG_DSB "DSB: " // DS18xB20 sensor
#define D_LOG_HTTP "HTP: " // HTTP webserver
#define D_LOG_I2C "I2C: " // I2C
#define D_LOG_IRR "IRR: " // Infra Red Received
#define D_LOG_LOG "LOG: " // Logging
#define D_LOG_MODULE "MOD: " // Module
#define D_LOG_MDNS "DNS: " // mDNS
#define D_LOG_MQTT "MQT: " // MQTT
#define D_LOG_OTHER "OTH: " // Other
#define D_LOG_RESULT "RSL: " // Result
#define D_LOG_RFR "RFR: " // RF Received
#define D_LOG_SERIAL "SER: " // Serial
#define D_LOG_SHT1 "SHT: " // SHT1x sensor
#define D_LOG_UPLOAD "UPL: " // Upload
#define D_LOG_UPNP "UPP: " // UPnP
#define D_LOG_WIFI "WIF: " // Wifi
#endif // _LANGUAGE_ES_AR_H_

457
sonoff/language/fr-FR.h Normal file
View File

@ -0,0 +1,457 @@
/*
fr-FR.h - localization for French - France for Sonoff-Tasmota
Copyright (C) 2018 Olivier Francais
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LANGUAGE_FR_FR_H_
#define _LANGUAGE_FR_FR_H_
/*************************** ATTENTION *******************************\
*
* Due to memory constraints only UTF-8 is supported.
* To save code space keep text as short as possible.
* Time and Date provided by SDK can not be localized (yet).
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
\*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
// "2017-03-07T11:08:02" - ISO8601:2004
#define D_YEAR_MONTH_SEPARATOR "-"
#define D_MONTH_DAY_SEPARATOR "-"
#define D_DATE_TIME_SEPARATOR "T"
#define D_HOUR_MINUTE_SEPARATOR ":"
#define D_MINUTE_SECOND_SEPARATOR ":"
#define D_DAY3LIST "DimLunMarMerJeuVenSam"
#define D_MONTH3LIST "JanFevMarAvrMaiJunJulAutSepOctNovDec"
// Non JSON decimal separator
#define D_DECIMAL_SEPARATOR ","
// Common
#define D_ADMIN "Admin"
#define D_AIR_QUALITY "Qualité de l'Air"
#define D_AP "AP" // Access Point
#define D_AS "comme"
#define D_AUTO "AUTO"
#define D_BLINK "Blink"
#define D_BLINKOFF "BlinkOff"
#define D_BOOT_COUNT "Nombre de boot"
#define D_BRIGHTLIGHT "Luminosité"
#define D_BUTTON "Boutton"
#define D_BY "par" // Written by me
#define D_BYTES "Bytes"
#define D_CELSIUS "Celsius"
#define D_CO2 "Dioxyde de carbone"
#define D_CODE "code" // Button code
#define D_COLDLIGHT "Froid"
#define D_COMMAND "Commande"
#define D_CONNECTED "Connecté"
#define D_COUNT "Compte"
#define D_COUNTER "Compteur"
#define D_CURRENT "Courrant" // As in Voltage and Current
#define D_DATA "Data"
#define D_DARKLIGHT "Sombre"
#define D_DEBUG "Debug"
#define D_DISABLED "Désactivé"
#define D_DNS_SERVER "Serveur DNS"
#define D_DONE "Fait"
#define D_DST_TIME "DST"
#define D_EMULATION "Emulation"
#define D_ENABLED "Activé"
#define D_ERASE "Effacer"
#define D_ERROR "Erreur"
#define D_FAHRENHEIT "Fahrenheit"
#define D_FAILED "Echoué"
#define D_FALLBACK "Fallback"
#define D_FALLBACK_TOPIC "Fallback Topic"
#define D_FALSE "Faux"
#define D_FILE "Fichier"
#define D_FREE_MEMORY "Memoire libre"
#define D_GAS "Gaz"
#define D_GATEWAY "Passerelle"
#define D_GROUP "Groupe"
#define D_HOST "Host"
#define D_HOSTNAME "Hostname"
#define D_HUMIDITY "Humidité"
#define D_ILLUMINANCE "Éclairement"
#define D_IMMEDIATE "immediat" // Button immediate
#define D_INDEX "Index"
#define D_INFO "Info"
#define D_INITIALIZED "Initialisé"
#define D_IP_ADDRESS "Adresse IP"
#define D_LIGHT "Lumière"
#define D_LWT "LWT"
#define D_MODULE "Module"
#define D_MQTT "MQTT"
#define D_MULTI_PRESS "multi-pression"
#define D_NOISE "Bruit"
#define D_NONE "None"
#define D_OFF "Off"
#define D_OFFLINE "Déconnecté"
#define D_OK "Ok"
#define D_ON "On"
#define D_ONLINE "Connecté"
#define D_PASSWORD "Mot de passe"
#define D_PORT "Port"
#define D_POWER_FACTOR "Facteur de puissance"
#define D_POWERUSAGE "Puissance"
#define D_PRESSURE "Pression"
#define D_PRESSUREATSEALEVEL "PressionMer"
#define D_PROGRAM_FLASH_SIZE "Taille Flash Programme"
#define D_PROGRAM_SIZE "Taille programme"
#define D_PROJECT "Projet"
#define D_RECEIVED "Reçu"
#define D_RESTART "Redémarrage"
#define D_RESTARTING "Redémarrage"
#define D_RESTART_REASON "Raison redémarrage"
#define D_RESTORE "restorer"
#define D_RETAINED "retenu"
#define D_SAVE "Enregister"
#define D_SENSOR "Capteur"
#define D_SSID "SSID"
#define D_START "Start"
#define D_STD_TIME "STD"
#define D_STOP "Stop"
#define D_SUBNET_MASK "Masque sous réseau"
#define D_SUBSCRIBE_TO "Souscrire à"
#define D_SUCCESSFUL "Réussi"
#define D_TEMPERATURE "Temperature"
#define D_TO "à"
#define D_TOGGLE "Bascule"
#define D_TOPIC "Topic"
#define D_TRANSMIT "Transmettre"
#define D_TRUE "Vrai"
#define D_UPGRADE "upgrade"
#define D_UPLOAD "Upload"
#define D_UPTIME "Uptime"
#define D_USER "Utilisateur"
#define D_UTC_TIME "UTC"
#define D_UV_LEVEL "Niveau UV"
#define D_VERSION "Version"
#define D_VOLTAGE "Voltage"
#define D_WARMLIGHT "Chaud"
#define D_WEB_SERVER "Serveur web"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "ATTENTION Cette version ne supporte pas les réglages persistants"
#define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1"
#define D_SERIAL_LOGGING_DISABLED "Journalisation série désactivé"
#define D_SYSLOG_LOGGING_REENABLED "Jounalisation syslog réactivé"
#define D_SET_BAUDRATE_TO "Definir baudrate à"
#define D_RECEIVED_TOPIC "Topic reçu"
#define D_DATA_SIZE "Taille données"
#define D_ANALOG_INPUT "Analogique"
#define D_FINGERPRINT "Verification empreinte TLS ..."
#define D_TLS_CONNECT_FAILED_TO "Echec de connexion TLS à"
#define D_RETRY_IN "Nouvelle tentative dans"
#define D_VERIFIED "Verifié"
#define D_INSECURE "Connexion non sécurisée car empreinte non vérifée"
#define D_CONNECT_FAILED_TO "Echec de connexion à"
// support.ino
#define D_OSWATCH "osWatch"
#define D_BLOCKED_LOOP "Boucle bloquée"
#define D_WPS_FAILED_WITH_STATUS "WPSconfig ECHOUÉ avec status"
#define D_ACTIVE_FOR_3_MINUTES "actif pour 3 minutes"
#define D_FAILED_TO_START "Echec de démarrage"
#define D_PATCH_ISSUE_2186 "Patch issue 2186"
#define D_CONNECTING_TO_AP "Connexion à l'AP"
#define D_IN_MODE "en mode"
#define D_CONNECT_FAILED_NO_IP_ADDRESS "Echec de connexion car aucune adresse IP n'a été reçue"
#define D_CONNECT_FAILED_AP_NOT_REACHED "Echec de connexion car l'AP ne peut-être contacté"
#define D_CONNECT_FAILED_WRONG_PASSWORD "Echec de connexion car le mot de passe de l'AP est incorrect"
#define D_CONNECT_FAILED_AP_TIMEOUT "Echec de connexion avec l'AP, expiré"
#define D_ATTEMPTING_CONNECTION "Tentative de connexion..."
#define D_CHECKING_CONNECTION "Verification connexion..."
#define D_QUERY_DONE "Requête terminé. 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"
// settings.ino
#define D_SAVED_TO_FLASH_AT "Enregistré dans la flash à"
#define D_LOADED_FROM_FLASH_AT "Chargé de la flash à"
#define D_USE_DEFAULTS "Utiliser par défaut"
#define D_ERASED_SECTOR "Secteur effacé"
// webserver.ino
#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "Firmware MINIMAL - merci de mettre à jour"
#define D_WEBSERVER_ACTIVE_ON "Serveur web actif sur"
#define D_WITH_IP_ADDRESS "avec l'adresse IP"
#define D_WEBSERVER_STOPPED "Serveur web éteint"
#define D_FILE_NOT_FOUND "Fichier introuvable"
#define D_REDIRECTED "Redirection sur le portail captif"
#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager defini AccessPoint et garde station"
#define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager defini AccessPoint"
#define D_TRYING_TO_CONNECT "Tentative de connexion du module au réseau"
#define D_RESTART_IN "Redémarrage dans"
#define D_SECONDS "secondes"
#define D_DEVICE_WILL_RESTART "Le module va redémarrer dans quelques secondes"
#define D_BUTTON_TOGGLE "on/off"
#define D_CONFIGURATION "Configuration"
#define D_INFORMATION "Information"
#define D_FIRMWARE_UPGRADE "Mise à jour Firmware"
#define D_CONSOLE "Console"
#define D_CONFIRM_RESTART "Confirmer redémarrage"
#define D_CONFIGURE_MODULE "Configuration Module"
#define D_CONFIGURE_WIFI "Configuration WiFi"
#define D_CONFIGURE_MQTT "Configuration MQTT"
#define D_CONFIGURE_DOMOTICZ "Configuration Domoticz"
#define D_CONFIGURE_LOGGING "Configuration Logging"
#define D_CONFIGURE_OTHER "Autre configuration"
#define D_CONFIRM_RESET_CONFIGURATION "Confirmer réinitialisation configuration"
#define D_RESET_CONFIGURATION "Réinitialisation Configuration"
#define D_BACKUP_CONFIGURATION "Sauvegarde Configuration"
#define D_RESTORE_CONFIGURATION "Restauration Configuration"
#define D_MAIN_MENU "Menu principal"
#define D_MODULE_PARAMETERS "Paramètres module"
#define D_MODULE_TYPE "Type module"
#define D_GPIO "GPIO"
#define D_SERIAL_IN "Serial In"
#define D_SERIAL_OUT "Serial Out"
#define D_WIFI_PARAMETERS "Paramètres Wifi"
#define D_SCAN_FOR_WIFI_NETWORKS "Scan des réseaux wifi"
#define D_SCAN_DONE "Scan terminé"
#define D_NO_NETWORKS_FOUND "Aucun réseau trouvé"
#define D_REFRESH_TO_SCAN_AGAIN "Rafraichir pour scanner à nouveau"
#define D_DUPLICATE_ACCESSPOINT "AccessPoint dupliqué"
#define D_SKIPPING_LOW_QUALITY "Passe car mauvaise qualité"
#define D_RSSI "RSSI"
#define D_WEP "WEP"
#define D_WPA_PSK "WPA PSK"
#define D_WPA2_PSK "WPA2 PSK"
#define D_AP1_SSID "AP1 SSID"
#define D_AP1_PASSWORD "Mot de passe AP1"
#define D_AP2_SSID "AP2 SSId"
#define D_AP2_PASSWORD "Mot de passe AP2"
#define D_MQTT_PARAMETERS "Paramètres MQTT"
#define D_CLIENT "Client"
#define D_FULL_TOPIC "topic complet"
#define D_LOGGING_PARAMETERS "Paramètres journalisation"
#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_MORE_DEBUG "Plus de debug"
#define D_SYSLOG_HOST "Host syslog"
#define D_SYSLOG_PORT "Host syslog"
#define D_TELEMETRY_PERIOD "Période télémetrie"
#define D_OTHER_PARAMETERS "Autres paramètres"
#define D_WEB_ADMIN_PASSWORD "Mot de passe Web Admin"
#define D_MQTT_ENABLE "MQTT activé"
#define D_FRIENDLY_NAME "Surnom"
#define D_BELKIN_WEMO "Belkin WeMo"
#define D_HUE_BRIDGE "Hue Bridge"
#define D_SINGLE_DEVICE "module unique"
#define D_MULTI_DEVICE "multi module"
#define D_SAVE_CONFIGURATION "Enregistrer configuration"
#define D_CONFIGURATION_SAVED "Configuration enregistré"
#define D_CONFIGURATION_RESET "Configuration réinitialisé"
#define D_PROGRAM_VERSION "Version Programme"
#define D_BUILD_DATE_AND_TIME "Date & Heure de build"
#define D_CORE_AND_SDK_VERSION "Version Core/SDK"
#define D_FLASH_WRITE_COUNT "Compteur écriture flash"
#define D_MAC_ADDRESS "Adresse MAC"
#define D_MQTT_HOST "Hôte MQTT"
#define D_MQTT_PORT "Port MQTT"
#define D_MQTT_CLIENT "Client MQTT"
#define D_MQTT_USER "Utilisateur MQTT"
#define D_MQTT_TOPIC "Topic MQTT"
#define D_MQTT_GROUP_TOPIC "Groupe topic MQTT"
#define D_MQTT_FULL_TOPIC "Topic complet MQTT"
#define D_MDNS_DISCOVERY "Découverte mDNS"
#define D_MDNS_ADVERTISE "Annonce mDNS"
#define D_ESP_CHIP_ID "ESP Chip Id"
#define D_FLASH_CHIP_ID "Flash Chip Id"
#define D_FLASH_CHIP_SIZE "Taille flash"
#define D_FREE_PROGRAM_SPACE "Espace programme libre"
#define D_UPGRADE_BY_WEBSERVER "Mise à jour par serveur web"
#define D_OTA_URL "URL OTA"
#define D_START_UPGRADE "Lancer la mise à jour"
#define D_UPGRADE_BY_FILE_UPLOAD "Mise à jour par téléchargement fichier"
#define D_UPLOAD_STARTED "Téléchargement lancé"
#define D_UPGRADE_STARTED "Mise à jour lancé"
#define D_UPLOAD_DONE "Téléchargement terminé"
#define D_UPLOAD_ERR_1 "Aucun fichier sélectionné"
#define D_UPLOAD_ERR_2 "Espace insuffisant"
#define D_UPLOAD_ERR_3 "Magic byte n'est pas 0xE9"
#define D_UPLOAD_ERR_4 "La taille de la flash programme est plus grande que la taille réelle de la flash"
#define D_UPLOAD_ERR_5 "Erreur comparaison buffer de téléchargement"
#define D_UPLOAD_ERR_6 "Téléchargement échoué. Activation logging 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"
#define D_UPLOAD_ERROR_CODE "Code d'erreur téléchargement"
#define D_ENTER_COMMAND "Saisir commande"
#define D_ENABLE_WEBLOG_FOR_RESPONSE "Activer weblog 2 si response attendue"
#define D_NEED_USER_AND_PASSWORD "Nécessite utilisateur=<username>&password=<password>"
// xdrv_wemohue.ino
#define D_MULTICAST_DISABLED "Multicast désactivé"
#define D_MULTICAST_REJOINED "Multicast (re)joint"
#define D_MULTICAST_JOIN_FAILED "Multicast echec abonnement"
#define D_FAILED_TO_SEND_RESPONSE "Echec d'envoi réponse"
#define D_WEMO "WeMo"
#define D_WEMO_BASIC_EVENT "WeMo basic event"
#define D_WEMO_EVENT_SERVICE "WeMo event service"
#define D_WEMO_META_SERVICE "WeMo meta service"
#define D_WEMO_SETUP "Réglage WeMo"
#define D_RESPONSE_SENT "Response envoyé"
#define D_HUE "Hue"
#define D_HUE_BRIDGE_SETUP "Réglage Hue"
#define D_HUE_API_NOT_IMPLEMENTED "API Hue non implémentée"
#define D_HUE_API "Hue API"
#define D_HUE_POST_ARGS "Hue POST args"
#define D_3_RESPONSE_PACKETS_SENT "3 paquets response envoyés"
// xdrv_05_domoticz.ino
#define D_DOMOTICZ_PARAMETERS "Paramètres Domoticz"
#define D_DOMOTICZ_IDX "Idx"
#define D_DOMOTICZ_KEY_IDX "Key idx"
#define D_DOMOTICZ_SWITCH_IDX "Switch idx"
#define D_DOMOTICZ_SENSOR_IDX "Sensor idx"
#define D_DOMOTICZ_TEMP "Temp"
#define D_DOMOTICZ_TEMP_HUM "Temp,Hum"
#define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Hum,Baro"
#define D_DOMOTICZ_POWER_ENERGY "Power,Energy"
#define D_DOMOTICZ_ILLUMINANCE "Illuminance"
#define D_DOMOTICZ_COUNT "Count"
#define D_DOMOTICZ_VOLTAGE "Voltage"
#define D_DOMOTICZ_CURRENT "Current"
#define D_DOMOTICZ_AIRQUALITY "AirQuality"
#define D_DOMOTICZ_UPDATE_TIMER "Update timer"
// xsns_03_energy.ino
#define D_ENERGY_TODAY "Energie aujourd'hui"
#define D_ENERGY_YESTERDAY "Energie hier"
#define D_ENERGY_TOTAL "Energie totale"
// xsns_05_ds18b20.ino
#define D_SENSOR_BUSY "Capteur occupé"
#define D_SENSOR_CRC_ERROR "Erreur CRC capteur"
#define D_SENSORS_FOUND "Capteur trouvé"
// xsns_06_dht.ino
#define D_TIMEOUT_WAITING_FOR "Expiré attend pour"
#define D_START_SIGNAL_LOW "Signal démarrage bas"
#define D_START_SIGNAL_HIGH "Signal démarrage haut"
#define D_PULSE "pulse"
#define D_CHECKSUM_FAILURE "Echec checksum"
// xsns_07_sht1x.ino
#define D_SENSOR_DID_NOT_ACK_COMMAND "Le capteur n'a pas ACK la commande"
#define D_SHT1X_FOUND "SHT1X found"
// xsns_18_pms5003.ino
#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter
#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter
#define D_PARTICALS_BEYOND "Particules"
// sonoff_template.h
#define D_SENSOR_NONE "None"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"
#define D_SENSOR_WS2812 "WS2812"
#define D_SENSOR_IRSEND "IRsend"
#define D_SENSOR_SWITCH "Switch" // Suffix "1"
#define D_SENSOR_BUTTON "Button" // Suffix "1"
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
#define D_SENSOR_LED "LED" // Suffix "1i"
#define D_SENSOR_PWM "PWM" // Suffix "1"
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
#define D_SENSOR_IRRECV "IRrecv"
#define D_SENSOR_MHZ_RX "MHZ Rx"
#define D_SENSOR_MHZ_TX "MHZ Tx"
#define D_SENSOR_PZEM_RX "PZEM Rx"
#define D_SENSOR_PZEM_TX "PZEM Tx"
#define D_SENSOR_SAIR_RX "SAir Rx"
#define D_SENSOR_SAIR_TX "SAir Tx"
#define D_SENSOR_SPI_CS "SPI CS"
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_HOUR "h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3"
#define D_UNIT_MICROMETER "um"
#define D_UNIT_MICROSECOND "us"
#define D_UNIT_MILLIAMPERE "mA"
#define D_UNIT_MILLISECOND "ms"
#define D_UNIT_MINUTE "Min"
#define D_UNIT_PARTS_PER_DECILITER "ppd"
#define D_UNIT_PARTS_PER_MILLION "ppm"
#define D_UNIT_PRESSURE "hPa"
#define D_UNIT_SECOND "sec"
#define D_UNIT_SECTORS "secteurs"
#define D_UNIT_VOLT "V"
#define D_UNIT_WATT "W"
#define D_UNIT_WATTHOUR "Wh"
// Log message prefix
#define D_LOG_APPLICATION "APP: " // Application
#define D_LOG_BRIDGE "BRG: " // Bridge
#define D_LOG_CONFIG "CFG: " // Settings
#define D_LOG_COMMAND "CMD: " // Command
#define D_LOG_DEBUG "DBG: " // Debug
#define D_LOG_DHT "DHT: " // DHT sensor
#define D_LOG_DOMOTICZ "DOM: " // Domoticz
#define D_LOG_DSB "DSB: " // DS18xB20 sensor
#define D_LOG_HTTP "HTP: " // HTTP webserver
#define D_LOG_I2C "I2C: " // I2C
#define D_LOG_IRR "IRR: " // Infra Red Received
#define D_LOG_LOG "LOG: " // Logging
#define D_LOG_MODULE "MOD: " // Module
#define D_LOG_MDNS "DNS: " // mDNS
#define D_LOG_MQTT "MQT: " // MQTT
#define D_LOG_OTHER "OTH: " // Other
#define D_LOG_RESULT "RSL: " // Result
#define D_LOG_RFR "RFR: " // RF Received
#define D_LOG_SERIAL "SER: " // Serial
#define D_LOG_SHT1 "SHT: " // SHT1x sensor
#define D_LOG_UPLOAD "UPL: " // Upload
#define D_LOG_UPNP "UPP: " // UPnP
#define D_LOG_WIFI "WIF: " // Wifi
#endif // _LANGUAGE_FR_FR_H_

View File

@ -30,6 +30,8 @@
*
\*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
// "2017-03-07T11:08:02" - ISO8601:2004
#define D_YEAR_MONTH_SEPARATOR "-"
#define D_MONTH_DAY_SEPARATOR "-"
@ -51,7 +53,7 @@
#define D_AUTO "AUTO"
#define D_BLINK "Blink"
#define D_BLINKOFF "BlinkOff"
#define D_BOOT_COUNT "Boot Count"
#define D_BOOT_COUNT "Numero di boot"
#define D_BRIGHTLIGHT "Luminoso"
#define D_BUTTON "Pulsante"
#define D_BY "da" // Written by me
@ -60,7 +62,7 @@
#define D_CO2 "CO2"
#define D_CODE "codice" // Button code
#define D_COLDLIGHT "Fredda"
#define D_COMMAND "Command"
#define D_COMMAND "Comando"
#define D_CONNECTED "Connesso"
#define D_COUNT "Conteggio"
#define D_COUNTER "Contatore"
@ -74,30 +76,30 @@
#define D_DST_TIME "DST"
#define D_EMULATION "Emulazione"
#define D_ENABLED "Abilitato"
#define D_ERASE "Erase"
#define D_ERROR "Error"
#define D_ERASE "Cancellare"
#define D_ERROR "Errore"
#define D_FAHRENHEIT "Fahrenheit"
#define D_FAILED "Fallito"
#define D_FALLBACK "Fallback"
#define D_FALLBACK "Riserva"
#define D_FALLBACK_TOPIC "Topic Riserva"
#define D_FALSE "False"
#define D_FALSE "Falso"
#define D_FILE "File"
#define D_FREE_MEMORY "Memoria Libera"
#define D_GAS "Gas"
#define D_GATEWAY "Gateway"
#define D_GROUP "Gruppo"
#define D_HOST "Host"
#define D_HOSTNAME "Hostname"
#define D_HOSTNAME "Nome Host"
#define D_HUMIDITY "Umidita'"
#define D_ILLUMINANCE "Illuminazione"
#define D_IMMEDIATE "immediato" // Button immediate
#define D_INDEX "Index"
#define D_INDEX "Indice"
#define D_INFO "Info"
#define D_INITIALIZED "Inizializzato"
#define D_IP_ADDRESS "Indirizzo IP"
#define D_LIGHT "Luce"
#define D_LWT "LWT"
#define D_MODULE "Module"
#define D_MODULE "Modulo"
#define D_MQTT "MQTT"
#define D_MULTI_PRESS "multi-pressione"
#define D_NOISE "Rumore"
@ -115,10 +117,10 @@
#define D_PRESSUREATSEALEVEL "Pressione al livello del mare"
#define D_PROGRAM_FLASH_SIZE "Dimensione Flash Programma"
#define D_PROGRAM_SIZE "Dimensione Programma"
#define D_PROJECT "Project"
#define D_PROJECT "Progetto"
#define D_RECEIVED "Ricevuto"
#define D_RESTART "Riavvio"
#define D_RESTARTING "Restarting"
#define D_RESTARTING "Riavviando"
#define D_RESTART_REASON "Causa Riavvio"
#define D_RESTORE "ripristino"
#define D_RETAINED "salvato"
@ -130,8 +132,8 @@
#define D_STOP "Stop"
#define D_SUBNET_MASK "Maschera sottorete"
#define D_SUBSCRIBE_TO "Sottoscrivi a"
#define D_SUCCESSFUL "Successful"
#define D_TEMPERATURE "Temperature"
#define D_SUCCESSFUL "Riuscito"
#define D_TEMPERATURE "Temperatura"
#define D_TO "a"
#define D_TOGGLE "Toggle"
#define D_TOPIC "Topic"
@ -143,12 +145,13 @@
#define D_USER "Utente"
#define D_UTC_TIME "UTC"
#define D_UV_LEVEL "Livello UV"
#define D_VERSION "Version"
#define D_VERSION "Versione"
#define D_VOLTAGE "Tensione"
#define D_WARMLIGHT "Calda"
#define D_WEB_SERVER "Web Server"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "ATTENZIONE Questa versione non supporta il salvataggio delle impostazioni"
#define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1"
#define D_SERIAL_LOGGING_DISABLED "Log seriale disabilitato"
@ -334,19 +337,6 @@
#define D_HUE_POST_ARGS "Hue POST argomenti"
#define D_3_RESPONSE_PACKETS_SENT "3 pacchetti di risposta inviati"
// xdrv_02_irremote.ino
#define D_JSON_INVALID_JSON "JSON non valido"
#define D_JSON_PROTOCOL_NOT_SUPPORTED "Protocollo non supportato"
#define D_JSON_IR_PROTOCOL "PROTOCOL"
#define D_JSON_IR_BITS "BITS"
#define D_JSON_IR_DATA "DATA"
#define D_JSON_IRHVAC_VENDOR "VENDOR"
#define D_JSON_IRHVAC_POWER "POWER"
#define D_JSON_IRHVAC_MODE "MODE"
#define D_JSON_IRHVAC_FANSPEED "FANSPEED"
#define D_JSON_IRHVAC_TEMP "TEMP"
#define D_JSON_IRRECEIVED "IrReceived"
// xdrv_05_domoticz.ino
#define D_DOMOTICZ_PARAMETERS "Parametri Domoticz"
#define D_DOMOTICZ_IDX "Idx"
@ -364,7 +354,7 @@
#define D_DOMOTICZ_AIRQUALITY "AirQuality"
#define D_DOMOTICZ_UPDATE_TIMER "Intervallo di aggiornamento"
// xsns_03_energy.ino
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia Oggi"
#define D_ENERGY_YESTERDAY "Energia Ieri"
#define D_ENERGY_TOTAL "Energia Totale"
@ -385,8 +375,12 @@
#define D_SENSOR_DID_NOT_ACK_COMMAND "Sensore non ha eseguito il comando ACK"
#define D_SHT1X_FOUND "SHT1X trovato"
// xsns_18_pms5003.ino
#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter
#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter
#define D_PARTICALS_BEYOND "Particelle"
// sonoff_template.h
// Max string length is 8 characters including suffixes
#define D_SENSOR_NONE "None"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
@ -412,6 +406,7 @@
#define D_SENSOR_SPI_CS "SPI CS"
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
// Units
#define D_UNIT_AMPERE "A"
@ -419,11 +414,14 @@
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3"
#define D_UNIT_MICROMETER "um"
#define D_UNIT_MICROSECOND "us"
#define D_UNIT_MILLIAMPERE "mA"
#define D_UNIT_MILLISECOND "ms"
#define D_UNIT_MINUTE "Min"
#define D_UNIT_PPM "ppm"
#define D_UNIT_PARTS_PER_DECILITER "ppd"
#define D_UNIT_PARTS_PER_MILLION "ppm"
#define D_UNIT_PRESSURE "hPa"
#define D_UNIT_SECOND "sec"
#define D_UNIT_SECTORS "settori"

View File

@ -30,6 +30,8 @@
*
\*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
// "2017-03-07T11:08:02" - ISO8601:2004
#define D_YEAR_MONTH_SEPARATOR "-"
#define D_MONTH_DAY_SEPARATOR "-"
@ -45,7 +47,7 @@
// Common
#define D_ADMIN "Admin"
#define D_AIR_QUALITY "Lucht kwalitiet"
#define D_AIR_QUALITY "Lucht kwaliteit"
#define D_AP "AP" // Access Point
#define D_AS "als"
#define D_AUTO "AUTO"
@ -149,6 +151,7 @@
#define D_WEB_SERVER "Webserver"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "WAARSCHUWING Deze versie bewaart geen instellingen"
#define D_LEVEL_10 "niveau 1-0"
#define D_LEVEL_01 "niveau 0-1"
#define D_SERIAL_LOGGING_DISABLED "Serieel logging uitgeschakeld"
@ -334,19 +337,6 @@
#define D_HUE_POST_ARGS "Hue POST argumenten"
#define D_3_RESPONSE_PACKETS_SENT "3 antwoord paketten verstuurd"
// xdrv_02_irremote.ino
#define D_JSON_INVALID_JSON "Ongeldig JSON"
#define D_JSON_PROTOCOL_NOT_SUPPORTED "Protocol wordt niet ondersteund"
#define D_JSON_IR_PROTOCOL "PROTOCOL"
#define D_JSON_IR_BITS "BITS"
#define D_JSON_IR_DATA "DATA"
#define D_JSON_IRHVAC_VENDOR "VENDOR"
#define D_JSON_IRHVAC_POWER "POWER"
#define D_JSON_IRHVAC_MODE "MODE"
#define D_JSON_IRHVAC_FANSPEED "FANSPEED"
#define D_JSON_IRHVAC_TEMP "TEMP"
#define D_JSON_IRRECEIVED "IrReceived"
// xdrv_05_domoticz.ino
#define D_DOMOTICZ_PARAMETERS "Domoticz parameters"
#define D_DOMOTICZ_IDX "Idx"
@ -364,7 +354,7 @@
#define D_DOMOTICZ_AIRQUALITY "AirQuality"
#define D_DOMOTICZ_UPDATE_TIMER "Bijwerk timer"
// xsns_03_energy.ino
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Verbruik vandaag"
#define D_ENERGY_YESTERDAY "Verbruik gisteren"
#define D_ENERGY_TOTAL "Verbruik totaal"
@ -385,8 +375,12 @@
#define D_SENSOR_DID_NOT_ACK_COMMAND "Geen opdracht ACK van sensor"
#define D_SHT1X_FOUND "SHT1X gevonden"
// xsns_18_pms5003.ino
#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter
#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter
#define D_PARTICALS_BEYOND "Stofdeeltjes"
// sonoff_template.h
// Max string length is 8 characters including suffixes
#define D_SENSOR_NONE "Geen"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
@ -412,6 +406,7 @@
#define D_SENSOR_SPI_CS "SPI CS"
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
// Units
#define D_UNIT_AMPERE "A"
@ -419,11 +414,14 @@
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3"
#define D_UNIT_MICROMETER "um"
#define D_UNIT_MICROSECOND "us"
#define D_UNIT_MILLIAMPERE "mA"
#define D_UNIT_MILLISECOND "ms"
#define D_UNIT_MINUTE "Min"
#define D_UNIT_PPM "ppm"
#define D_UNIT_PARTS_PER_DECILITER "ppd"
#define D_UNIT_PARTS_PER_MILLION "ppm"
#define D_UNIT_PRESSURE "hPa"
#define D_UNIT_SECOND "sec"
#define D_UNIT_SECTORS "sectoren"

View File

@ -30,6 +30,8 @@
*
\*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
// "2017-03-07T11:08:02" - ISO8601:2004
#define D_YEAR_MONTH_SEPARATOR "-"
#define D_MONTH_DAY_SEPARATOR "-"
@ -149,6 +151,7 @@
#define D_WEB_SERVER "Web Server"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "WARNING This version does not support persistent settings"
#define D_LEVEL_10 "poziom 1-0"
#define D_LEVEL_01 "poziom 0-1"
#define D_SERIAL_LOGGING_DISABLED "Wylaczony dziennik na porcie szeregowym"
@ -334,19 +337,6 @@
#define D_HUE_POST_ARGS "Hue POST args"
#define D_3_RESPONSE_PACKETS_SENT "3 pakiety odpowiedzi wysylane"
// xdrv_02_irremote.ino
#define D_JSON_INVALID_JSON "Invalid JSON"
#define D_JSON_PROTOCOL_NOT_SUPPORTED "Protokol nie jest obslugiwany"
#define D_JSON_IR_PROTOCOL "PROTOCOL"
#define D_JSON_IR_BITS "BITS"
#define D_JSON_IR_DATA "DATA"
#define D_JSON_IRHVAC_VENDOR "VENDOR"
#define D_JSON_IRHVAC_POWER "POWER"
#define D_JSON_IRHVAC_MODE "MODE"
#define D_JSON_IRHVAC_FANSPEED "FANSPEED"
#define D_JSON_IRHVAC_TEMP "TEMP"
#define D_JSON_IRRECEIVED "IrReceived"
// xdrv_05_domoticz.ino
#define D_DOMOTICZ_PARAMETERS "Parametry Domoticz"
#define D_DOMOTICZ_IDX "Idx"
@ -364,7 +354,7 @@
#define D_DOMOTICZ_AIRQUALITY "AirQuality"
#define D_DOMOTICZ_UPDATE_TIMER "Zaktualizuj czasomierz"
// xsns_03_energy.ino
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia Dzisiaj"
#define D_ENERGY_YESTERDAY "Energia Wczoraj"
#define D_ENERGY_TOTAL "Energia suma"
@ -385,8 +375,12 @@
#define D_SENSOR_DID_NOT_ACK_COMMAND "Czujnik nie otrzymal komendy ACK"
#define D_SHT1X_FOUND "SHT1X znaleziony"
// xsns_18_pms5003.ino
#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter
#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter
#define D_PARTICALS_BEYOND "Particals"
// sonoff_template.h
// Max string length is 8 characters including suffixes
#define D_SENSOR_NONE "Brak"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
@ -412,6 +406,7 @@
#define D_SENSOR_SPI_CS "SPI CS"
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
// Units
#define D_UNIT_AMPERE "A"
@ -419,11 +414,14 @@
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3"
#define D_UNIT_MICROMETER "um"
#define D_UNIT_MICROSECOND "us"
#define D_UNIT_MILLIAMPERE "mA"
#define D_UNIT_MILLISECOND "ms"
#define D_UNIT_MINUTE "Min"
#define D_UNIT_PPM "ppm"
#define D_UNIT_PARTS_PER_DECILITER "ppd"
#define D_UNIT_PARTS_PER_MILLION "ppm"
#define D_UNIT_PRESSURE "hPa"
#define D_UNIT_SECOND "sec"
#define D_UNIT_SECTORS "sektory"

457
sonoff/language/zh-CN.h Normal file
View File

@ -0,0 +1,457 @@
/*
zh-CN.h - localization for Chinese (Simplified) - China for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends (translated by killadm)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LANGUAGE_ZH_CN_H_
#define _LANGUAGE_ZH_CN_H_
/*************************** ATTENTION *******************************\
*
* Due to memory constraints only UTF-8 is supported.
* To save code space keep text as short as possible.
* Time and Date provided by SDK can not be localized (yet).
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
\*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
// "2017-03-07T11:08:02" - ISO8601:2004
#define D_YEAR_MONTH_SEPARATOR "-"
#define D_MONTH_DAY_SEPARATOR "-"
#define D_DATE_TIME_SEPARATOR "T"
#define D_HOUR_MINUTE_SEPARATOR ":"
#define D_MINUTE_SECOND_SEPARATOR ":"
#define D_DAY3LIST "SunMonTueWedThuFriSat"
#define D_MONTH3LIST "JanFebMarAprMayJunJulAugSepOctNovDec"
// Non JSON decimal separator
#define D_DECIMAL_SEPARATOR "."
// Common
#define D_ADMIN "Admin"
#define D_AIR_QUALITY "空气质量"
#define D_AP "AP" // Access Point
#define D_AS "名称:"
#define D_AUTO "自动"
#define D_BLINK "闪烁"
#define D_BLINKOFF "闪烁关"
#define D_BOOT_COUNT "启动次数"
#define D_BRIGHTLIGHT "亮度"
#define D_BUTTON "按钮"
#define D_BY "by" // Written by me
#define D_BYTES "大小:"
#define D_CELSIUS "摄氏"
#define D_CO2 "二氧化碳"
#define D_CODE "代码" // Button code
#define D_COLDLIGHT "冷"
#define D_COMMAND "命令:"
#define D_CONNECTED "已连接"
#define D_COUNT "数量:"
#define D_COUNTER "Counter"
#define D_CURRENT "电流" // As in Voltage and Current
#define D_DATA "数据:"
#define D_DARKLIGHT "Dark"
#define D_DEBUG "调试"
#define D_DISABLED "禁用"
#define D_DNS_SERVER "DNS服务器"
#define D_DONE "完成"
#define D_DST_TIME "DST"
#define D_EMULATION "设备模拟"
#define D_ENABLED "启用"
#define D_ERASE "擦除"
#define D_ERROR "错误"
#define D_FAHRENHEIT "华氏"
#define D_FAILED "失败"
#define D_FALLBACK "Fallback"
#define D_FALLBACK_TOPIC "Fallback Topic"
#define D_FALSE "False"
#define D_FILE "文件:"
#define D_FREE_MEMORY "空闲内存"
#define D_GAS "气体"
#define D_GATEWAY "网关"
#define D_GROUP "组:"
#define D_HOST "主机"
#define D_HOSTNAME "主机名"
#define D_HUMIDITY "湿度"
#define D_ILLUMINANCE "照度"
#define D_IMMEDIATE "immediate" // Button immediate
#define D_INDEX "索引:"
#define D_INFO "信息"
#define D_INITIALIZED "初始化完成"
#define D_IP_ADDRESS "IP地址"
#define D_LIGHT "灯"
#define D_LWT "LWT"
#define D_MODULE "模块"
#define D_MQTT "MQTT"
#define D_MULTI_PRESS "多次按键"
#define D_NOISE "嘈杂"
#define D_NONE "无"
#define D_OFF "关"
#define D_OFFLINE "离线"
#define D_OK "好"
#define D_ON "开"
#define D_ONLINE "在线"
#define D_PASSWORD "密码"
#define D_PORT "端口"
#define D_POWER_FACTOR "功率因数"
#define D_POWERUSAGE "功率"
#define D_PRESSURE "气压"
#define D_PRESSUREATSEALEVEL "海平面气压"
#define D_PROGRAM_FLASH_SIZE "固件 Flash 大小"
#define D_PROGRAM_SIZE "固件大小"
#define D_PROJECT "项目:"
#define D_RECEIVED "已接收"
#define D_RESTART "重启"
#define D_RESTARTING "正在重启"
#define D_RESTART_REASON "重启原因"
#define D_RESTORE "恢复"
#define D_RETAINED "已保留"
#define D_SAVE "保存"
#define D_SENSOR "传感器"
#define D_SSID "名称"
#define D_START "开始"
#define D_STD_TIME "STD"
#define D_STOP "停止"
#define D_SUBNET_MASK "子网掩码"
#define D_SUBSCRIBE_TO "订阅"
#define D_SUCCESSFUL "成功"
#define D_TEMPERATURE "温度"
#define D_TO "to"
#define D_TOGGLE "切换"
#define D_TOPIC "主题"
#define D_TRANSMIT "发送"
#define D_TRUE "True"
#define D_UPGRADE "升级"
#define D_UPLOAD "上传"
#define D_UPTIME "运行时间"
#define D_USER "用户名"
#define D_UTC_TIME "UTC"
#define D_UV_LEVEL "紫外线水平"
#define D_VERSION "版本"
#define D_VOLTAGE "电压"
#define D_WARMLIGHT "暖"
#define D_WEB_SERVER "Web Server"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "警告:精简固件不支持配置持久化保存"
#define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1"
#define D_SERIAL_LOGGING_DISABLED "串口日志已禁用"
#define D_SYSLOG_LOGGING_REENABLED "Syslog 日志已开启"
#define D_SET_BAUDRATE_TO "设置波特率为:"
#define D_RECEIVED_TOPIC "接收到的主题:"
#define D_DATA_SIZE "数据大小:"
#define D_ANALOG_INPUT "Analog"
#define D_FINGERPRINT "验证 TLS 指纹..."
#define D_TLS_CONNECT_FAILED_TO "TLS 连接失败"
#define D_RETRY_IN "重试倒计时:"
#define D_VERIFIED "验证成功"
#define D_INSECURE "指纹无效导致连接不安全"
#define D_CONNECT_FAILED_TO "连接失败:"
// support.ino
#define D_OSWATCH "osWatch"
#define D_BLOCKED_LOOP "Blocked Loop"
#define D_WPS_FAILED_WITH_STATUS "WPSconfig FAILED with status"
#define D_ACTIVE_FOR_3_MINUTES "active for 3 minutes"
#define D_FAILED_TO_START "未能启动"
#define D_PATCH_ISSUE_2186 "Patch issue 2186"
#define D_CONNECTING_TO_AP "连接到 AP"
#define D_IN_MODE "模式:"
#define D_CONNECT_FAILED_NO_IP_ADDRESS "连接失败因为没有获取到IP地址"
#define D_CONNECT_FAILED_AP_NOT_REACHED "连接失败无法连接AP"
#define D_CONNECT_FAILED_WRONG_PASSWORD "连接失败AP密码不正确"
#define D_CONNECT_FAILED_AP_TIMEOUT "连接失败AP超时"
#define D_ATTEMPTING_CONNECTION "尝试连接..."
#define D_CHECKING_CONNECTION "检查连接..."
#define D_QUERY_DONE "查询完成。 发现MQTT服务"
#define D_MQTT_SERVICE_FOUND "发现MQTT服务:"
#define D_FOUND_AT "found at"
#define D_SYSLOG_HOST_NOT_FOUND "Syslog主机未找到"
// settings.ino
#define D_SAVED_TO_FLASH_AT "保存到 flash:"
#define D_LOADED_FROM_FLASH_AT "从 flash 载入"
#define D_USE_DEFAULTS "使用默认设置"
#define D_ERASED_SECTOR "擦除删除"
// webserver.ino
#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "固件版本过低 - 请升级"
#define D_WEBSERVER_ACTIVE_ON "Web服务器:"
#define D_WITH_IP_ADDRESS "IP地址:"
#define D_WEBSERVER_STOPPED "Web 服务器已停止"
#define D_FILE_NOT_FOUND "文件未找到"
#define D_REDIRECTED "重定向到认证页面"
#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager set AccessPoint and keep Station"
#define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager 设置接入点"
#define D_TRYING_TO_CONNECT "尝试将设备连接到网络"
#define D_RESTART_IN "重启需要"
#define D_SECONDS "秒"
#define D_DEVICE_WILL_RESTART "设备将在几分钟内重启"
#define D_BUTTON_TOGGLE "状态切换"
#define D_CONFIGURATION "设置"
#define D_INFORMATION "信息"
#define D_FIRMWARE_UPGRADE "固件升级"
#define D_CONSOLE "控制台"
#define D_CONFIRM_RESTART "确认重启"
#define D_CONFIGURE_MODULE "模块设置"
#define D_CONFIGURE_WIFI "WiFi设置"
#define D_CONFIGURE_MQTT "MQTT设置"
#define D_CONFIGURE_DOMOTICZ "Domoticz设置"
#define D_CONFIGURE_LOGGING "日志设置"
#define D_CONFIGURE_OTHER "其他设置"
#define D_CONFIRM_RESET_CONFIGURATION "确认重置配置"
#define D_RESET_CONFIGURATION "重置配置"
#define D_BACKUP_CONFIGURATION "备份配置"
#define D_RESTORE_CONFIGURATION "还原配置"
#define D_MAIN_MENU "主菜单"
#define D_MODULE_PARAMETERS "模块设置"
#define D_MODULE_TYPE "模块类型"
#define D_GPIO "GPIO"
#define D_SERIAL_IN "串口输入(RX)"
#define D_SERIAL_OUT "串口输出(TX)"
#define D_WIFI_PARAMETERS "Wifi设置"
#define D_SCAN_FOR_WIFI_NETWORKS "扫描无线网络"
#define D_SCAN_DONE "扫描完毕"
#define D_NO_NETWORKS_FOUND "未找到任何网络"
#define D_REFRESH_TO_SCAN_AGAIN "刷新并重试"
#define D_DUPLICATE_ACCESSPOINT "重复AP"
#define D_SKIPPING_LOW_QUALITY "忽略弱信号网络"
#define D_RSSI "RSSI"
#define D_WEP "WEP"
#define D_WPA_PSK "WPA PSK"
#define D_WPA2_PSK "WPA2 PSK"
#define D_AP1_SSID "AP1 名称"
#define D_AP1_PASSWORD "AP1 密码"
#define D_AP2_SSID "AP2 名称"
#define D_AP2_PASSWORD "AP2 密码"
#define D_MQTT_PARAMETERS "MQTT设置"
#define D_CLIENT "客户端"
#define D_FULL_TOPIC "完整主题"
#define D_LOGGING_PARAMETERS "日志设置"
#define D_SERIAL_LOG_LEVEL "串口日志级别"
#define D_WEB_LOG_LEVEL "Web 日志级别"
#define D_SYS_LOG_LEVEL "Syslog 日志级别"
#define D_MORE_DEBUG "全部调试"
#define D_SYSLOG_HOST "Syslog 主机地址"
#define D_SYSLOG_PORT "Syslog 端口"
#define D_TELEMETRY_PERIOD "上报周期"
#define D_OTHER_PARAMETERS "其他设置"
#define D_WEB_ADMIN_PASSWORD "WEB管理密码"
#define D_MQTT_ENABLE "启用MQTT"
#define D_FRIENDLY_NAME "昵称"
#define D_BELKIN_WEMO "贝尔金 WeMo"
#define D_HUE_BRIDGE "飞利浦 Hue 网桥"
#define D_SINGLE_DEVICE "单设备"
#define D_MULTI_DEVICE "多设备"
#define D_SAVE_CONFIGURATION "保存设置"
#define D_CONFIGURATION_SAVED "设置已保存"
#define D_CONFIGURATION_RESET "设置已重置"
#define D_PROGRAM_VERSION "固件版本"
#define D_BUILD_DATE_AND_TIME "编译时间"
#define D_CORE_AND_SDK_VERSION "内核版本"
#define D_FLASH_WRITE_COUNT "刷机次数"
#define D_MAC_ADDRESS "MAC地址"
#define D_MQTT_HOST "MQTT主机"
#define D_MQTT_PORT "MQTT端口"
#define D_MQTT_CLIENT "MQTT客户端"
#define D_MQTT_USER "MQTT用户名"
#define D_MQTT_TOPIC "MQTT 主题(Topic)"
#define D_MQTT_GROUP_TOPIC "MQTT 主题组(Group Topic)"
#define D_MQTT_FULL_TOPIC "MQTT 完整主题(Full Topic)"
#define D_MDNS_DISCOVERY "mDNS 发现"
#define D_MDNS_ADVERTISE "mDNS 广播"
#define D_ESP_CHIP_ID "ESP芯片ID"
#define D_FLASH_CHIP_ID "Flash芯片ID"
#define D_FLASH_CHIP_SIZE "Flash大小"
#define D_FREE_PROGRAM_SPACE "空闲程序空间"
#define D_UPGRADE_BY_WEBSERVER "通过Web升级"
#define D_OTA_URL "OTA地址"
#define D_START_UPGRADE "开始升级"
#define D_UPGRADE_BY_FILE_UPLOAD "通过文件升级"
#define D_UPLOAD_STARTED "开始上传"
#define D_UPGRADE_STARTED "开始升级"
#define D_UPLOAD_DONE "上传完成"
#define D_UPLOAD_ERR_1 "没有选择文件"
#define D_UPLOAD_ERR_2 "没有足够空间"
#define D_UPLOAD_ERR_3 "固件头不是 0xE9"
#define D_UPLOAD_ERR_4 "固件太大"
#define D_UPLOAD_ERR_5 "上传缓冲区不匹配"
#define D_UPLOAD_ERR_6 "上传失败。 启用日志记录 3"
#define D_UPLOAD_ERR_7 "上传取消"
#define D_UPLOAD_ERR_8 "错误的固件"
#define D_UPLOAD_ERR_9 "固件太大"
#define D_UPLOAD_ERROR_CODE "上传错误代码"
#define D_ENTER_COMMAND "输入命令"
#define D_ENABLE_WEBLOG_FOR_RESPONSE "如果预期响应则启用Weblog 2"
#define D_NEED_USER_AND_PASSWORD "需要 user=<用户名>&password=<密码>"
// xdrv_wemohue.ino
#define D_MULTICAST_DISABLED "组播已禁用"
#define D_MULTICAST_REJOINED "组播已(重新)加入"
#define D_MULTICAST_JOIN_FAILED "组播加入失败"
#define D_FAILED_TO_SEND_RESPONSE "请求发送失败"
#define D_WEMO "WeMo"
#define D_WEMO_BASIC_EVENT "WeMo 基础事件"
#define D_WEMO_EVENT_SERVICE "WeMo 事件服务"
#define D_WEMO_META_SERVICE "WeMo meta 服务"
#define D_WEMO_SETUP "WeMo 设置"
#define D_RESPONSE_SENT "发送请求"
#define D_HUE "Hue"
#define D_HUE_BRIDGE_SETUP "Hue 设置"
#define D_HUE_API_NOT_IMPLEMENTED "Hue API 未实现"
#define D_HUE_API "Hue API"
#define D_HUE_POST_ARGS "Hue POST 参数"
#define D_3_RESPONSE_PACKETS_SENT "3 请求包发送"
// xdrv_05_domoticz.ino
#define D_DOMOTICZ_PARAMETERS "Domoticz 设置"
#define D_DOMOTICZ_IDX "Idx"
#define D_DOMOTICZ_KEY_IDX "Key idx"
#define D_DOMOTICZ_SWITCH_IDX "开关 idx"
#define D_DOMOTICZ_SENSOR_IDX "传感器 idx"
#define D_DOMOTICZ_TEMP "温度"
#define D_DOMOTICZ_TEMP_HUM "温度,湿度"
#define D_DOMOTICZ_TEMP_HUM_BARO "温度,湿度,气压"
#define D_DOMOTICZ_POWER_ENERGY "功率,电量"
#define D_DOMOTICZ_ILLUMINANCE "照度"
#define D_DOMOTICZ_COUNT "数值"
#define D_DOMOTICZ_VOLTAGE "电压"
#define D_DOMOTICZ_CURRENT "电流"
#define D_DOMOTICZ_AIRQUALITY "空气质量"
#define D_DOMOTICZ_UPDATE_TIMER "更新计时器"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "今日用电量"
#define D_ENERGY_YESTERDAY "昨日用电量"
#define D_ENERGY_TOTAL "总用电量"
// xsns_05_ds18b20.ino
#define D_SENSOR_BUSY "传感器正忙"
#define D_SENSOR_CRC_ERROR "传感器 CRC 校验错误"
#define D_SENSORS_FOUND "发现传感器"
// xsns_06_dht.ino
#define D_TIMEOUT_WAITING_FOR "等待超时"
#define D_START_SIGNAL_LOW "开始低电平"
#define D_START_SIGNAL_HIGH "开始高电平"
#define D_PULSE "pulse"
#define D_CHECKSUM_FAILURE "校验失败"
// xsns_07_sht1x.ino
#define D_SENSOR_DID_NOT_ACK_COMMAND "传感器没有确认命令"
#define D_SHT1X_FOUND "发现 SHT1X 传感器"
// xsns_18_pms5003.ino
#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter
#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter
#define D_PARTICALS_BEYOND "颗粒物直径大于"
// sonoff_template.h
#define D_SENSOR_NONE "None"
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"
#define D_SENSOR_WS2812 "WS2812"
#define D_SENSOR_IRSEND "IRsend"
#define D_SENSOR_SWITCH "Switch" // Suffix "1"
#define D_SENSOR_BUTTON "Button" // Suffix "1"
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
#define D_SENSOR_LED "Led" // Suffix "1i"
#define D_SENSOR_PWM "PWM" // Suffix "1"
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
#define D_SENSOR_IRRECV "IRrecv"
#define D_SENSOR_MHZ_RX "MHZ Rx"
#define D_SENSOR_MHZ_TX "MHZ Tx"
#define D_SENSOR_PZEM_RX "PZEM Rx"
#define D_SENSOR_PZEM_TX "PZEM Tx"
#define D_SENSOR_SAIR_RX "SAir Rx"
#define D_SENSOR_SAIR_TX "SAir Tx"
#define D_SENSOR_SPI_CS "SPI CS"
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
// Units
#define D_UNIT_AMPERE "安"
#define D_UNIT_HOUR "时"
#define D_UNIT_KILOOHM "千欧"
#define D_UNIT_KILOWATTHOUR "千瓦时"
#define D_UNIT_LUX "勒克斯"
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "微克/立方米"
#define D_UNIT_MICROMETER "微米"
#define D_UNIT_MICROSECOND "微秒"
#define D_UNIT_MILLIAMPERE "毫安"
#define D_UNIT_MILLISECOND "毫秒"
#define D_UNIT_MINUTE "分"
#define D_UNIT_PARTS_PER_DECILITER "每分升"
#define D_UNIT_PARTS_PER_MILLION "ppm"
#define D_UNIT_PRESSURE "百帕"
#define D_UNIT_SECOND "秒"
#define D_UNIT_SECTORS "扇区"
#define D_UNIT_VOLT "伏"
#define D_UNIT_WATT "瓦"
#define D_UNIT_WATTHOUR "瓦时"
// Log message prefix
#define D_LOG_APPLICATION "APP: " // Application
#define D_LOG_BRIDGE "BRG: " // Bridge
#define D_LOG_CONFIG "CFG: " // Settings
#define D_LOG_COMMAND "CMD: " // Command
#define D_LOG_DEBUG "DBG: " // Debug
#define D_LOG_DHT "DHT: " // DHT sensor
#define D_LOG_DOMOTICZ "DOM: " // Domoticz
#define D_LOG_DSB "DSB: " // DS18xB20 sensor
#define D_LOG_HTTP "HTP: " // HTTP webserver
#define D_LOG_I2C "I2C: " // I2C
#define D_LOG_IRR "IRR: " // Infra Red Received
#define D_LOG_LOG "LOG: " // Logging
#define D_LOG_MODULE "MOD: " // Module
#define D_LOG_MDNS "DNS: " // mDNS
#define D_LOG_MQTT "MQT: " // MQTT
#define D_LOG_OTHER "OTH: " // Other
#define D_LOG_RESULT "RSL: " // Result
#define D_LOG_RFR "RFR: " // RF Received
#define D_LOG_SERIAL "SER: " // Serial
#define D_LOG_SHT1 "SHT: " // SHT1x sensor
#define D_LOG_UPLOAD "UPL: " // Upload
#define D_LOG_UPNP "UPP: " // UPnP
#define D_LOG_WIFI "WIF: " // Wifi
#endif // _LANGUAGE_ZH_CN_H_

View File

@ -44,9 +44,9 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1)
uint32_t decimal_text : 1; // bit 17 (v5.8.1)
uint32_t light_signal : 1; // bit 18 (v5.10.0c)
uint32_t spare19 : 1;
uint32_t voltage_resolution : 1; // Replaced by below
uint32_t spare21 : 1;
uint32_t hass_discovery : 1; // bit 19 (v5.11.1a)
uint32_t not_power_linked : 1; // bit 20 (v5.11.1f)
uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i)
uint32_t spare22 : 1;
uint32_t spare23 : 1;
uint32_t spare24 : 1;
@ -57,15 +57,6 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t spare29 : 1;
uint32_t spare30 : 1;
uint32_t spare31 : 1;
/*
uint32_t wattage_resolution : 1;
uint32_t voltage_resolution : 1;
uint32_t emulation : 2;
uint32_t energy_resolution : 3;
uint32_t pressure_resolution : 2;
uint32_t humidity_resolution : 2;
uint32_t temperature_resolution : 2;
*/
};
} SysBitfield;
@ -161,12 +152,12 @@ struct SYSCFG {
uint16_t domoticz_update_timer; // 340
uint16_t pwm_range; // 342
unsigned long domoticz_relay_idx[MAX_DOMOTICZ_IDX]; // 344
unsigned long domoticz_key_idx[MAX_DOMOTICZ_IDX]; // 354
unsigned long domoticz_relay_idx[MAX_DOMOTICZ_IDX]; // 344
unsigned long domoticz_key_idx[MAX_DOMOTICZ_IDX]; // 354
unsigned long hlw_power_calibration; // 364
unsigned long hlw_voltage_calibration; // 368
unsigned long hlw_current_calibration; // 36C
unsigned long energy_power_calibration; // 364
unsigned long energy_voltage_calibration; // 368
unsigned long energy_current_calibration; // 36C
unsigned long energy_kWhtoday; // 370
unsigned long energy_kWhyesterday; // 374
uint16_t energy_kWhdoy; // 378
@ -177,11 +168,11 @@ struct SYSCFG {
uint16_t energy_min_current; // 382
uint16_t energy_max_current; // 384
uint16_t energy_max_power_limit; // 386 MaxPowerLimit
uint16_t energy_max_power_limit_hold; // 388 MaxPowerLimitHold
uint16_t energy_max_power_limit_window; // 38A MaxPowerLimitWindow
uint16_t energy_max_power_safe_limit; // 38C MaxSafePowerLimit
uint16_t energy_max_power_safe_limit_hold; // 38E MaxSafePowerLimitHold
uint16_t energy_max_power_safe_limit_window; // 390 MaxSafePowerLimitWindow
uint16_t energy_max_power_limit_hold; // 388 MaxPowerLimitHold
uint16_t energy_max_power_limit_window; // 38A MaxPowerLimitWindow
uint16_t energy_max_power_safe_limit; // 38C MaxSafePowerLimit
uint16_t energy_max_power_safe_limit_hold; // 38E MaxSafePowerLimitHold
uint16_t energy_max_power_safe_limit_window; // 390 MaxSafePowerLimitWindow
uint16_t energy_max_energy; // 392 MaxEnergy
uint16_t energy_max_energy_start; // 394 MaxEnergyStart
uint16_t mqtt_retry; // 396
@ -262,7 +253,7 @@ struct SYSCFG {
struct RTCMEM {
uint16_t valid; // 000
byte oswatch_blocked_loop; // 002
uint8_t unused; // 003
uint8_t ota_loader; // 003
unsigned long energy_kWhtoday; // 004
unsigned long energy_kWhtotal; // 008
unsigned long pulse_counter[MAX_COUNTERS]; // 00C
@ -279,6 +270,7 @@ struct TIME_T {
char name_of_month[4];
uint16_t day_of_year;
uint16_t year;
unsigned long days;
unsigned long valid;
} RtcTime;

View File

@ -25,14 +25,28 @@
#define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo (single relay/light) or Hue Bridge emulation (multi relay/light) (EMUL_NONE, EMUL_WEMO or EMUL_HUE)
#endif
#ifndef USE_DISPLAY // Add Display Support for up to eigth Matrices
#ifndef MTX_ADDRESS1 // Add Display Support for up to eigth Matrices
#define MTX_ADDRESS1 0
#endif
#ifndef MTX_ADDRESS2
#define MTX_ADDRESS2 0
#endif
#ifndef MTX_ADDRESS3
#define MTX_ADDRESS3 0
#endif
#ifndef MTX_ADDRESS4
#define MTX_ADDRESS4 0
#endif
#ifndef MTX_ADDRESS5
#define MTX_ADDRESS5 0
#endif
#ifndef MTX_ADDRESS6
#define MTX_ADDRESS6 0
#endif
#ifndef MTX_ADDRESS7
#define MTX_ADDRESS7 0
#endif
#ifndef MTX_ADDRESS8
#define MTX_ADDRESS8 0
#endif
@ -109,7 +123,7 @@ void RtcSettingsDump()
for (row = 0; row < maxrow; row++) {
idx = row * CFG_COLS;
snprintf_P(log_data, sizeof(log_data), PSTR("%04X:"), idx);
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx);
for (col = 0; col < CFG_COLS; col++) {
if (!(col%4)) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
@ -364,7 +378,7 @@ void SettingsDump(char* parms)
for (row = srow; row < maxrow; row++) {
idx = row * CFG_COLS;
snprintf_P(log_data, sizeof(log_data), PSTR("%04X:"), idx);
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx);
for (col = 0; col < CFG_COLS; col++) {
if (!(col%4)) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
@ -416,6 +430,7 @@ void SettingsDefaultSet2()
Settings.flag.mqtt_power_retain = MQTT_POWER_RETAIN;
Settings.flag.mqtt_button_retain = MQTT_BUTTON_RETAIN;
Settings.flag.mqtt_switch_retain = MQTT_SWITCH_RETAIN;
Settings.flag.hass_discovery = HOME_ASSISTANT_DISCOVERY_ENABLE;
Settings.flag2.emulation = EMULATION;
@ -463,9 +478,9 @@ void SettingsDefaultSet2()
// Settings.domoticz_switch_idx[i] = 0;
}
Settings.hlw_power_calibration = HLW_PREF_PULSE;
Settings.hlw_voltage_calibration = HLW_UREF_PULSE;
Settings.hlw_current_calibration = HLW_IREF_PULSE;
Settings.energy_power_calibration = HLW_PREF_PULSE;
Settings.energy_voltage_calibration = HLW_UREF_PULSE;
Settings.energy_current_calibration = HLW_IREF_PULSE;
// Settings.energy_kWhtoday = 0;
// Settings.energy_kWhyesterday = 0;
// Settings.energy_kWhdoy = 0;
@ -830,13 +845,17 @@ void SettingsDelta()
if (Settings.version < 0x05090102) {
Settings.flag2.data = Settings.flag.data;
Settings.flag2.data &= 0xFFE80000;
Settings.flag2.voltage_resolution = Settings.flag.voltage_resolution;
Settings.flag2.voltage_resolution = Settings.flag.not_power_linked;
Settings.flag2.current_resolution = 3;
Settings.ina219_mode = 0;
}
if (Settings.version < 0x050A0009) {
SettingsDefaultSet_5_10_1();
}
if (Settings.version < 0x050B0107) {
Settings.flag.not_power_linked = 0;
}
Settings.version = VERSION;
SettingsSave(1);

View File

@ -80,25 +80,26 @@ typedef unsigned long power_t; // Power (Relay) type
#define STATES 20 // State loops per second
#define SYSLOG_TIMER 600 // Seconds to restore syslog_level
#define SERIALLOG_TIMER 600 // Seconds to disable SerialLog
#define OTA_ATTEMPTS 10 // Number of times to try fetching the new firmware
#define OTA_ATTEMPTS 5 // Number of times to try fetching the new firmware
#define INPUT_BUFFER_SIZE 250 // Max number of characters in (serial) command buffer
#define INPUT_BUFFER_SIZE 255 // Max number of characters in (serial) command buffer
#define CMDSZ 24 // Max number of characters in command
#define TOPSZ 100 // Max number of characters in topic string
#define LOGSZ 400 // Max number of characters in log
#define MIN_MESSZ 893 // Min number of characters in MQTT message
#ifdef USE_MQTT_TLS
#define MAX_LOG_LINES 10 // Max number of lines in weblog
#define WEB_LOG_SIZE 2000 // Max number of characters in weblog
#else
#define MAX_LOG_LINES 20 // Max number of lines in weblog
#define WEB_LOG_SIZE 4000 // Max number of characters in weblog
#endif
#define MAX_BACKLOG 16 // Max number of commands in backlog (chk backlog_index and backlog_pointer code)
#define MIN_BACKLOG_DELAY 2 // Minimal backlog delay in 0.1 seconds
#define APP_BAUDRATE 115200 // Default serial baudrate
#define MAX_STATUS 11 // Max number of status lines
#define XDRV_MAX 10 // Max number of allowed Xdrv drivers (Update xdrv_interface.ino if changed)
#define XSNS_MAX 20 // Max number of allowed Xsns External Sensors (Update xsns_interface.ino if changed)
/*
// Removed from esp8266 core since 20171105
#define min(a,b) ((a)<(b)?(a):(b))
@ -124,6 +125,12 @@ enum LedStateOptions {LED_OFF, LED_POWER, LED_MQTTSUB, LED_POWER_MQTTSUB, LED_MQ
enum EmulationOptions {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
enum TopicOptions { CMND, STAT, TELE, nu1, RESULT_OR_CMND, RESULT_OR_STAT, RESULT_OR_TELE };
enum ExecuteCommandPowerOptions { POWER_OFF, POWER_ON, POWER_TOGGLE, POWER_BLINK, POWER_BLINK_STOP, power_nu1, POWER_OFF_NO_STATE, POWER_ON_NO_STATE, power_nu2, POWER_SHOW_STATE };
enum PowerOnStateOptions { POWER_ALL_OFF, POWER_ALL_ON, POWER_ALL_SAVED_TOGGLE, POWER_ALL_SAVED, POWER_ALL_ALWAYS_ON, POWER_ALL_OFF_PULSETIME_ON };
enum ButtonStates {PRESSED, NOT_PRESSED};
enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_MAX_PARAM8};
@ -137,8 +144,14 @@ enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_R
enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX};
enum XsnsFunctions {FUNC_INIT, FUNC_EVERY_50_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART,
FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR};
FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR};
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };
/*********************************************************************************************\
* Extern global variables
\*********************************************************************************************/
extern uint8_t light_device; // Light device number
#endif // _SONOFF_H_

View File

@ -19,17 +19,17 @@
/*====================================================
Prerequisites:
- Change libraries/PubSubClient/src/PubSubClient.h
#define MQTT_MAX_PACKET_SIZE 512
#define MQTT_MAX_PACKET_SIZE 1000
- Select IDE Tools - Flash Mode: "DOUT"
- Select IDE Tools - Flash Size: "1M (no SPIFFS)"
====================================================*/
#define VERSION 0x050B0100
#define VERSION_STRING "5.11.1" // Would be great to have a macro that fills this from VERSION ...
#define VERSION 0x050C0000 // 5.12.0
// Location specific includes
#include "sonoff.h" // Enumaration used in user_config.h
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
#include "sonoff.h" // Enumeration used in user_config.h
#include "user_config.h" // Fixed user configurable options
#include "user_config_override.h" // Configuration overrides for user_config.h
#include "i18n.h" // Language support configured by user_config.h
@ -38,10 +38,12 @@
// Libraries
#include <PubSubClient.h> // MQTT
// Max message size calculated by PubSubClient is (MQTT_MAX_PACKET_SIZE < 5 + 2 + strlen(topic) + plength)
#if (MQTT_MAX_PACKET_SIZE -TOPSZ -7) < MESSZ // If the max message size is too small, throw an error at compile time. See PubSubClient.cpp line 359
#error "MQTT_MAX_PACKET_SIZE is too small in libraries/PubSubClient/src/PubSubClient.h, increase it to at least 512"
#if (MQTT_MAX_PACKET_SIZE -TOPSZ -7) < MIN_MESSZ // If the max message size is too small, throw an error at compile time. See PubSubClient.cpp line 359
#error "MQTT_MAX_PACKET_SIZE is too small in libraries/PubSubClient/src/PubSubClient.h, increase it to at least 1000"
#endif
#include <Ticker.h> // RTC, Energy, OSWatch
#include <ESP8266WiFi.h> // MQTT, Ota, WifiManager
#include <ESP8266HTTPClient.h> // MQTT, Ota
@ -66,25 +68,25 @@
#include "settings.h"
enum TasmotaCommands {
CMND_BACKLOG, CMND_DELAY, CMND_POWER, CMND_STATUS, CMND_POWERONSTATE, CMND_PULSETIME,
CMND_BLINKTIME, CMND_BLINKCOUNT, CMND_SAVEDATA, CMND_SETOPTION, CMND_TEMPERATURE_RESOLUTION, CMND_HUMIDITY_RESOLUTION,
CMND_BACKLOG, CMND_DELAY, CMND_POWER, CMND_STATUS, CMND_STATE, CMND_POWERONSTATE, CMND_PULSETIME,
CMND_BLINKTIME, CMND_BLINKCOUNT, CMND_SENSOR, CMND_SAVEDATA, CMND_SETOPTION, CMND_TEMPERATURE_RESOLUTION, CMND_HUMIDITY_RESOLUTION,
CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_CURRENT_RESOLUTION, CMND_ENERGY_RESOLUTION, CMND_MODULE, CMND_MODULES,
CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE,
CMND_COUNTERDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG,
CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME,
CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_EMULATION,
CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE,
CMND_CFGDUMP, CMND_I2CSCAN, CMND_INA219MODE, CMND_EXCEPTION };
CMND_CFGDUMP, CMND_I2CSCAN, CMND_EXCEPTION };
const char kTasmotaCommands[] PROGMEM =
D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_STATUS "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|"
D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|"
D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|"
D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SENSOR "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|"
D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_MODULE "|" D_CMND_MODULES "|"
D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" D_CMND_COUNTER "|" D_CMND_COUNTERTYPE "|"
D_CMND_COUNTERDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|"
D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|"
D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_EMULATION "|"
D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|"
D_CMND_CFGDUMP "|" D_CMND_I2CSCAN "|" D_CMND_INA219MODE
D_CMND_CFGDUMP "|" D_CMND_I2CSCAN
#ifdef DEBUG_THEO
"|" D_CMND_EXCEPTION
#endif
@ -107,6 +109,7 @@ const char kOptionBlinkOff[] PROGMEM = "BLINKOFF|" D_BLINKOFF ;
// Global variables
int baudrate = APP_BAUDRATE; // Serial interface baud rate
SerialConfig serial_config = SERIAL_8N1; // Serial interface configuration 8 data bits, No parity, 1 stop bit
byte serial_in_byte; // Received byte
int serial_in_byte_counter = 0; // Index in receive buffer
byte dual_hex_code = 0; // Sonoff dual input flag
@ -120,12 +123,14 @@ int mqtt_connection_flag = 2; // MQTT connection messages flag
int ota_state_flag = 0; // OTA state flag
int ota_result = 0; // OTA result
byte ota_retry_counter = OTA_ATTEMPTS; // OTA retry counter
char *ota_url; // OTA url string
int restart_flag = 0; // Sonoff restart flag
int wifi_state_flag = WIFI_RESTART; // Wifi state flag
int uptime = 0; // Current uptime in hours
//int uptime = 0; // Current uptime in hours
uint32_t uptime = 0; // Counting every second until 4294967295 = 130 year
boolean latest_uptime_flag = true; // Signal latest uptime
int tele_period = 0; // Tele period timer
byte web_log_index = 0; // Index in Web log buffer
byte web_log_index = 1; // Index in Web log buffer (should never be 0)
byte reset_web_log_flag = 0; // Reset web console log
byte devices_present = 0; // Max number of devices supported
int status_update_timer = 0; // Refresh initial status
@ -181,19 +186,17 @@ uint8_t energy_flg = 1; // Energy monitor configured
uint8_t i2c_flg = 0; // I2C configured
uint8_t spi_flg = 0; // SPI configured
uint8_t light_type = 0; // Light types
bool pwm_present = false; // Any PWM channel configured with SetOption15 0
boolean mdns_begun = false;
uint8_t xdrv_present = 0; // Number of drivers found
boolean (*xdrv_func_ptr[XDRV_MAX])(byte); // Driver Function Pointers
uint8_t xsns_present = 0; // Number of External Sensors found
boolean (*xsns_func_ptr[XSNS_MAX])(byte); // External Sensor Function Pointers for simple implementation of sensors
char my_version[33]; // Composed version string
char my_hostname[33]; // Composed Wifi hostname
char mqtt_client[33]; // Composed MQTT Clientname
char serial_in_buffer[INPUT_BUFFER_SIZE + 2]; // Receive buffer
char mqtt_data[MESSZ + TOPSZ]; // MQTT publish buffer (MESSZ) and web page ajax buffer (MESSZ + TOPSZ)
char log_data[TOPSZ + MESSZ]; // Logging
String web_log[MAX_LOG_LINES]; // Web log buffer
char mqtt_client[33]; // Composed MQTT Clientname
char serial_in_buffer[INPUT_BUFFER_SIZE]; // Receive buffer
char mqtt_data[MESSZ]; // MQTT publish buffer and web page ajax buffer
char log_data[LOGSZ]; // Logging
char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer
String backlog[MAX_BACKLOG]; // Command backlog
/********************************************************************************************/
@ -226,6 +229,10 @@ void GetMqttClient(char* output, const char* input, byte size)
void GetTopic_P(char *stopic, byte prefix, char *topic, const char* subtopic)
{
/* prefix 0 = Cmnd
prefix 1 = Stat
prefix 2 = Tele
*/
char romram[CMDSZ];
String fulltopic;
@ -286,7 +293,7 @@ void SetDevicePower(power_t rpower)
{
uint8_t state;
if (4 == Settings.poweronstate) { // All on and stay on
if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { // All on and stay on
power = (1 << devices_present) -1;
rpower = power;
}
@ -305,7 +312,7 @@ void SetDevicePower(power_t rpower)
}
}
XdrvSetPower(bitRead(rpower, devices_present -1));
XdrvSetPower(rpower);
if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
Serial.write(0xA0);
@ -349,18 +356,28 @@ void MqttSubscribe(char *topic)
void MqttPublishDirect(const char* topic, boolean retained)
{
char sretained[CMDSZ];
char slog_type[10];
sretained[0] = '\0';
snprintf_P(slog_type, sizeof(slog_type), PSTR(D_LOG_RESULT));
if (Settings.flag.mqtt_enabled) {
mqtt_data[MESSZ -1] = '\0';
if (MqttClient.publish(topic, mqtt_data, retained)) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT "%s = %s%s"), topic, mqtt_data, (retained) ? " (" D_RETAINED ")" : "");
// MqttClient.loop(); // Do not use here! Will block previous publishes
} else {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_RESULT "%s = %s"), topic, mqtt_data);
snprintf_P(slog_type, sizeof(slog_type), PSTR(D_LOG_MQTT));
if (retained) {
snprintf_P(sretained, sizeof(sretained), PSTR(" (" D_RETAINED ")"));
}
}
} else {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_RESULT "%s = %s"), strrchr(topic,'/')+1, mqtt_data);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s%s = %s"), slog_type, (Settings.flag.mqtt_enabled) ? topic : strrchr(topic,'/')+1, mqtt_data);
if (strlen(log_data) >= (sizeof(log_data) - strlen(sretained) -1)) {
log_data[sizeof(log_data) - strlen(sretained) -5] = '\0';
snprintf_P(log_data, sizeof(log_data), PSTR("%s ..."), log_data);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s%s"), log_data, sretained);
AddLog(LOG_LEVEL_INFO);
if (Settings.ledstate &0x04) {
blinks++;
@ -394,7 +411,7 @@ void MqttPublishPrefixTopic_P(uint8_t prefix, const char* subtopic, boolean reta
* prefix 5 = stat using subtopic or RESULT
* prefix 6 = tele using subtopic or RESULT
*/
char romram[16];
char romram[33];
char stopic[TOPSZ];
snprintf_P(romram, sizeof(romram), ((prefix > 3) && !Settings.flag.mqtt_response) ? S_RSLT_RESULT : subtopic);
@ -414,24 +431,24 @@ void MqttPublishPrefixTopic_P(uint8_t prefix, const char* subtopic)
void MqttPublishPowerState(byte device)
{
char stopic[TOPSZ];
char scommand[16];
char scommand[33];
if ((device < 1) || (device > devices_present)) {
device = 1;
}
GetPowerDevice(scommand, device, sizeof(scommand));
GetTopic_P(stopic, 1, Settings.mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT);
GetTopic_P(stopic, STAT, Settings.mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, scommand, GetStateText(bitRead(power, device -1)));
MqttPublish(stopic);
GetTopic_P(stopic, 1, Settings.mqtt_topic, scommand);
GetTopic_P(stopic, STAT, Settings.mqtt_topic, scommand);
snprintf_P(mqtt_data, sizeof(mqtt_data), GetStateText(bitRead(power, device -1)));
MqttPublish(stopic, Settings.flag.mqtt_power_retain);
}
void MqttPublishPowerBlinkState(byte device)
{
char scommand[16];
char scommand[33];
if ((device < 1) || (device > devices_present)) {
device = 1;
@ -439,7 +456,7 @@ void MqttPublishPowerBlinkState(byte device)
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"" D_JSON_BLINK " %s\"}"),
GetPowerDevice(scommand, device, sizeof(scommand)), GetStateText(bitRead(blink_mask, device -1)));
MqttPublishPrefixTopic_P(5, S_RSLT_POWER);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, S_RSLT_POWER);
}
void MqttConnected()
@ -450,15 +467,15 @@ void MqttConnected()
// Satisfy iobroker (#299)
mqtt_data[0] = '\0';
MqttPublishPrefixTopic_P(0, S_RSLT_POWER);
MqttPublishPrefixTopic_P(CMND, S_RSLT_POWER);
GetTopic_P(stopic, 0, Settings.mqtt_topic, PSTR("#"));
GetTopic_P(stopic, CMND, Settings.mqtt_topic, PSTR("#"));
MqttSubscribe(stopic);
if (strstr(Settings.mqtt_fulltopic, MQTT_TOKEN_TOPIC) != NULL) {
GetTopic_P(stopic, 0, Settings.mqtt_grptopic, PSTR("#"));
GetTopic_P(stopic, CMND, Settings.mqtt_grptopic, PSTR("#"));
MqttSubscribe(stopic);
fallback_topic_flag = 1;
GetTopic_P(stopic, 0, mqtt_client, PSTR("#"));
GetTopic_P(stopic, CMND, mqtt_client, PSTR("#"));
fallback_topic_flag = 0;
MqttSubscribe(stopic);
}
@ -467,26 +484,25 @@ void MqttConnected()
}
if (mqtt_connection_flag) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_VERSION "\":\"" VERSION_STRING "\",\"" D_JSON_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}"),
my_module.name, mqtt_client, Settings.mqtt_grptopic);
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_INFO "1"));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_VERSION "\":\"%s\",\"" D_JSON_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}"),
my_module.name, my_version, mqtt_client, Settings.mqtt_grptopic);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "1"));
#ifdef USE_WEBSERVER
if (Settings.webserver) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"),
(2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str());
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_INFO "2"));
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "2"));
}
#endif // USE_WEBSERVER
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_RESTARTREASON "\":\"%s\"}"),
(GetResetReason() == "Exception") ? ESP.getResetInfo().c_str() : GetResetReason().c_str());
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_INFO "3"));
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "3"));
if (Settings.tele_period) {
tele_period = Settings.tele_period -9;
}
status_update_timer = 2;
#ifdef USE_DOMOTICZ
DomoticzSetUpdateTimer(2);
#endif // USE_DOMOTICZ
XdrvCall(FUNC_MQTT_INIT);
}
mqtt_connection_flag = 0;
}
@ -539,7 +555,7 @@ void MqttReconnect()
#endif // USE_MQTT_TLS
MqttClient.setServer(Settings.mqtt_host, Settings.mqtt_port);
GetTopic_P(stopic, 2, Settings.mqtt_topic, S_LWT);
GetTopic_P(stopic, TELE, Settings.mqtt_topic, S_LWT);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_OFFLINE);
char *mqtt_user = NULL;
@ -570,7 +586,6 @@ boolean MqttCommand(boolean grpflg, char *type, uint16_t index, char *dataBuf, u
char command [CMDSZ];
boolean serviced = true;
char stemp1[TOPSZ];
char stemp2[10];
char scommand[CMDSZ];
uint16_t i;
@ -646,7 +661,7 @@ boolean MqttCommand(boolean grpflg, char *type, uint16_t index, char *dataBuf, u
strlcpy(stemp1, (1 == payload) ? MQTT_FULLTOPIC : dataBuf, sizeof(stemp1));
if (strcmp(stemp1, Settings.mqtt_fulltopic)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
MqttPublishPrefixTopic_P(2, PSTR(D_LWT), true); // Offline or remove previous retained topic
MqttPublishPrefixTopic_P(TELE, PSTR(D_LWT), true); // Offline or remove previous retained topic
strlcpy(Settings.mqtt_fulltopic, stemp1, sizeof(Settings.mqtt_fulltopic));
restart_flag = 2;
}
@ -682,7 +697,7 @@ boolean MqttCommand(boolean grpflg, char *type, uint16_t index, char *dataBuf, u
strlcpy(stemp1, (1 == payload) ? MQTT_TOPIC : dataBuf, sizeof(stemp1));
if (strcmp(stemp1, Settings.mqtt_topic)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
MqttPublishPrefixTopic_P(2, PSTR(D_LWT), true); // Offline or remove previous retained topic
MqttPublishPrefixTopic_P(TELE, PSTR(D_LWT), true); // Offline or remove previous retained topic
strlcpy(Settings.mqtt_topic, stemp1, sizeof(Settings.mqtt_topic));
restart_flag = 2;
}
@ -737,7 +752,7 @@ boolean MqttCommand(boolean grpflg, char *type, uint16_t index, char *dataBuf, u
if ((payload >= 0) && (payload <= 1)) {
if (!payload) {
for(i = 1; i <= devices_present; i++) { // Clear MQTT retain in broker
GetTopic_P(stemp1, 1, Settings.mqtt_topic, GetPowerDevice(scommand, i, sizeof(scommand)));
GetTopic_P(stemp1, STAT, Settings.mqtt_topic, GetPowerDevice(scommand, i, sizeof(scommand)));
mqtt_data[0] = '\0';
MqttPublish(stemp1, Settings.flag.mqtt_power_retain);
}
@ -750,8 +765,8 @@ boolean MqttCommand(boolean grpflg, char *type, uint16_t index, char *dataBuf, u
if ((payload >= 0) && (payload <= 1)) {
if (!payload) {
mqtt_data[0] = '\0';
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_ENERGY), Settings.flag.mqtt_sensor_retain);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_ENERGY), Settings.flag.mqtt_sensor_retain);
}
Settings.flag.mqtt_sensor_retain = payload;
}
@ -784,9 +799,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
char command [CMDSZ];
char stemp1[TOPSZ];
char *p;
char *mtopic = NULL;
char *type = NULL;
byte otype = 0;
byte ptype = 0;
byte jsflg = 0;
byte lines = 1;
@ -917,18 +930,23 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
fallback_topic_flag = 0;
return;
}
else if (CMND_STATE == command_code) {
mqtt_data[0] = '\0';
MqttShowState();
}
else if ((CMND_POWERONSTATE == command_code) && (Settings.module != MOTOR)) {
/* 0 = Keep relays off after power on
* 1 = Turn relays on after power on
* 1 = Turn relays on after power on, if PulseTime set wait for PulseTime seconds, and turn relays off
* 2 = Toggle relays after power on
* 3 = Set relays to last saved state after power on
* 4 = Turn relays on and disable any relay control (used for Sonoff Pow to always measure power)
* 5 = Keep relays off after power on, if PulseTime set wait for PulseTime seconds, and turn relays on
*/
if ((payload >= 0) && (payload <= 4)) {
if ((payload >= POWER_ALL_OFF) && (payload <= POWER_ALL_OFF_PULSETIME_ON)) {
Settings.poweronstate = payload;
if (4 == Settings.poweronstate) {
if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) {
for (byte i = 1; i <= devices_present; i++) {
ExecuteCommandPower(i, 1);
ExecuteCommandPower(i, POWER_ON);
}
}
}
@ -970,7 +988,18 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, (Settings.save_data > 1) ? stemp1 : GetStateText(Settings.save_data));
}
else if ((CMND_SETOPTION == command_code) && ((index >= 0) && (index <= 18)) || ((index > 31) && (index <= P_MAX_PARAM8 +31))) {
else if (CMND_SENSOR == command_code) {
XdrvMailbox.topic = command;
XdrvMailbox.index = index;
XdrvMailbox.payload = payload;
XdrvMailbox.data_len = data_len;
XdrvMailbox.data = dataBuf;
XsnsCall(FUNC_COMMAND);
// if (!XsnsCall(FUNC_COMMAND)) {
// type = NULL;
// }
}
else if ((CMND_SETOPTION == command_code) && ((index <= 21) || ((index > 31) && (index <= P_MAX_PARAM8 + 31)))) {
if (index <= 31) {
ptype = 0; // SetOption0 .. 31
} else {
@ -983,6 +1012,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
switch (index) {
case 3: // mqtt
case 15: // pwm_control
case 19: // hass_discovery
restart_flag = 2;
case 0: // save_state
case 1: // button_restrict
@ -997,6 +1027,8 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
case 16: // ws_clock_reverse
case 17: // decimal_text
case 18: // light_signal
case 20: // not_power_linked
case 21: // no_power_on_check
bitWrite(Settings.flag.data, index, payload);
}
if (12 == index) { // stop_flash_rotate
@ -1092,9 +1124,9 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
jsflg = 1;
snprintf_P(stemp1, sizeof(stemp1), kModules[i].name);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i +1, stemp1);
if ((strlen(mqtt_data) > 300) || (i == MAXMODULE -1)) {
if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == MAXMODULE -1)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]}"), mqtt_data);
MqttPublishPrefixTopic_P(5, type);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
jsflg = 0;
lines++;
}
@ -1121,8 +1153,8 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
}
jsflg = 1;
snprintf_P(stemp1, sizeof(stemp1), kSensors[Settings.my_gp.io[i]]);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_GPIO "%d\":\"%d (%s)\""), mqtt_data, i, Settings.my_gp.io[i], stemp1);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_GPIO "%d\":\"%d (%s)\""),
mqtt_data, i, Settings.my_gp.io[i], GetTextIndexed(stemp1, sizeof(stemp1), Settings.my_gp.io[i], kSensorNames));
}
}
if (jsflg) {
@ -1139,18 +1171,17 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
}
jsflg = 1;
snprintf_P(stemp1, sizeof(stemp1), kSensors[i]);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i, stemp1);
if ((strlen(mqtt_data) > 300) || (i == GPIO_SENSOR_END -1)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i, GetTextIndexed(stemp1, sizeof(stemp1), i, kSensorNames));
if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == GPIO_SENSOR_END -1)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]}"), mqtt_data);
MqttPublishPrefixTopic_P(5, type);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
jsflg = 0;
lines++;
}
}
mqtt_data[0] = '\0';
}
else if ((CMND_PWM == command_code) && !light_type && (index > 0) && (index <= MAX_PWMS)) {
else if ((CMND_PWM == command_code) && pwm_present && (index > 0) && (index <= MAX_PWMS)) {
if ((payload >= 0) && (payload <= Settings.pwm_range) && (pin[GPIO_PWM1 + index -1] < 99)) {
Settings.pwm_value[index -1] = payload;
analogWrite(pin[GPIO_PWM1 + index -1], bitRead(pwm_inverted, index -1) ? Settings.pwm_range - payload : payload);
@ -1175,7 +1206,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
else if (CMND_PWMRANGE == command_code) {
if ((1 == payload) || ((payload > 254) && (payload < 1024))) {
Settings.pwm_range = (1 == payload) ? PWM_RANGE : payload;
for (byte i; i < MAX_PWMS; i++) {
for (byte i = 0; i < MAX_PWMS; i++) {
if (Settings.pwm_value[i] > Settings.pwm_range) {
Settings.pwm_value[i] = Settings.pwm_range;
}
@ -1189,7 +1220,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
RtcSettings.pulse_counter[index -1] = payload16;
Settings.pulse_counter[index -1] = payload16;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, index, RtcSettings.pulse_counter[index -1]);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_LVALUE, command, index, RtcSettings.pulse_counter[index -1]);
}
else if ((CMND_COUNTERTYPE == command_code) && (index > 0) && (index <= MAX_COUNTERS)) {
if ((payload >= 0) && (payload <= 1) && (pin[GPIO_CNTR1 + index -1] < 99)) {
@ -1222,9 +1253,9 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
// We also need at least 3 chars to make a valid version number string.
if (((1 == data_len) && (1 == payload)) || ((data_len >= 3) && NewerVersion(dataBuf))) {
ota_state_flag = 3;
snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_VERSION " " VERSION_STRING " " D_JSON_FROM " %s\"}", command, Settings.ota_url);
snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}", command, my_version, Settings.ota_url);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_ONE_OR_GT "\"}", command, VERSION_STRING);
snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_ONE_OR_GT "\"}", command, my_version);
}
}
else if (CMND_OTAURL == command_code) {
@ -1471,15 +1502,6 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
I2cScan(mqtt_data, sizeof(mqtt_data));
}
#endif // USE_I2C
#ifdef USE_INA219
else if (CMND_INA219MODE == command_code) {
if ((payload >= 0) && (payload <= 2)) {
Settings.ina219_mode = payload;
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.ina219_mode);
}
#endif // USE_INA219
else if (Settings.flag.mqtt_enabled && MqttCommand(grpflg, type, index, dataBuf, data_len, payload, payload16)) {
// Serviced
}
@ -1505,7 +1527,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len)
type = (char*)topicBuf;
}
if (mqtt_data[0] != '\0') {
MqttPublishPrefixTopic_P(5, type);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
}
fallback_topic_flag = 0;
}
@ -1524,7 +1546,6 @@ boolean send_button_power(byte key, byte device, byte state)
char stopic[TOPSZ];
char scommand[CMDSZ];
char stemp1[10];
boolean result = false;
char *key_topic = (key) ? Settings.switch_topic : Settings.button_topic;
@ -1532,7 +1553,7 @@ boolean send_button_power(byte key, byte device, byte state)
if (!key && (device > devices_present)) {
device = 1;
}
GetTopic_P(stopic, 0, key_topic, GetPowerDevice(scommand, device, sizeof(scommand), key));
GetTopic_P(stopic, CMND, key_topic, GetPowerDevice(scommand, device, sizeof(scommand), key));
if (9 == state) {
mqtt_data[0] = '\0';
} else {
@ -1566,7 +1587,7 @@ void ExecuteCommandPower(byte device, byte state)
// state 9 = Show power state
uint8_t publish_power = 1;
if ((6 == state) || (7 == state)) {
if ((POWER_OFF_NO_STATE == state) || (POWER_ON_NO_STATE == state)) {
state &= 1;
publish_power = 0;
}
@ -1577,7 +1598,7 @@ void ExecuteCommandPower(byte device, byte state)
pulse_timer[(device -1)] = 0;
}
power_t mask = 1 << (device -1);
if (state <= 2) {
if (state <= POWER_TOGGLE) {
if ((blink_mask & mask)) {
blink_mask &= (POWER_MASK ^ mask); // Clear device mask
MqttPublishPowerBlinkState(device);
@ -1587,19 +1608,19 @@ void ExecuteCommandPower(byte device, byte state)
for (byte i = 0; i < devices_present; i++) {
power_t imask = 1 << i;
if ((power & imask) && (mask != imask)) {
ExecuteCommandPower(i +1, 0);
ExecuteCommandPower(i +1, POWER_OFF);
}
}
interlock_mutex = 0;
}
switch (state) {
case 0: { // Off
case POWER_OFF: {
power &= (POWER_MASK ^ mask);
break; }
case 1: // On
case POWER_ON:
power |= mask;
break;
case 2: // Toggle
case POWER_TOGGLE:
power ^= mask;
}
SetDevicePower(power);
@ -1607,10 +1628,11 @@ void ExecuteCommandPower(byte device, byte state)
DomoticzUpdatePowerState(device);
#endif // USE_DOMOTICZ
if (device <= MAX_PULSETIMERS) {
pulse_timer[(device -1)] = (power & mask) ? Settings.pulse_timer[(device -1)] : 0;
// pulse_timer[(device -1)] = (power & mask) ? Settings.pulse_timer[(device -1)] : 0;
pulse_timer[(device -1)] = (((POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate) ? ~power : power) & mask) ? Settings.pulse_timer[(device -1)] : 0;
}
}
else if (3 == state) { // Blink
else if (POWER_BLINK == state) {
if (!(blink_mask & mask)) {
blink_powersave = (blink_powersave & (POWER_MASK ^ mask)) | (power & mask); // Save state
blink_power = (power >> (device -1))&1; // Prep to Toggle
@ -1621,7 +1643,7 @@ void ExecuteCommandPower(byte device, byte state)
MqttPublishPowerBlinkState(device);
return;
}
else if (4 == state) { // No Blink
else if (POWER_BLINK_STOP == state) {
byte flag = (blink_mask & mask);
blink_mask &= (POWER_MASK ^ mask); // Clear device mask
MqttPublishPowerBlinkState(device);
@ -1693,14 +1715,14 @@ void PublishStatus(uint8_t payload)
}
if ((0 == payload) || (1 == payload)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_JSON_BAUDRATE "\":%d,\"" D_CMND_GROUPTOPIC "\":\"%s\",\"" D_CMND_OTAURL "\":\"%s\",\"" D_JSON_UPTIME "\":%d,\"" D_CMND_SLEEP "\":%d,\"" D_JSON_BOOTCOUNT "\":%d,\"" D_JSON_SAVECOUNT "\":%d,\"" D_JSON_SAVEADDRESS "\":\"%X\"}}"),
baudrate, Settings.mqtt_grptopic, Settings.ota_url, uptime, 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_UPTIME "\":\"%s\",\"" D_CMND_SLEEP "\":%d,\"" D_JSON_BOOTCOUNT "\":%d,\"" D_JSON_SAVECOUNT "\":%d,\"" D_JSON_SAVEADDRESS "\":\"%X\"}}"),
baudrate, Settings.mqtt_grptopic, Settings.ota_url, GetUptime().c_str(), Settings.sleep, Settings.bootcount, Settings.save_flag, GetSettingsAddress());
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "1"));
}
if ((0 == payload) || (2 == payload)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS2_FIRMWARE "\":{\"" D_JSON_VERSION "\":\"" VERSION_STRING "\",\"" D_JSON_BUILDDATETIME "\":\"%s\",\"" D_JSON_BOOTVERSION "\":%d,\"" D_JSON_COREVERSION "\":\"" ARDUINO_ESP8266_RELEASE "\",\"" D_JSON_SDKVERSION "\":\"%s\"}}"),
GetBuildDateAndTime().c_str(), ESP.getBootVersion(), ESP.getSdkVersion());
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS2_FIRMWARE "\":{\"" D_JSON_VERSION "\":\"%s\",\"" D_JSON_BUILDDATETIME "\":\"%s\",\"" D_JSON_BOOTVERSION "\":%d,\"" D_JSON_COREVERSION "\":\"" ARDUINO_ESP8266_RELEASE "\",\"" D_JSON_SDKVERSION "\":\"%s\"}}"),
my_version, GetBuildDateAndTime().c_str(), ESP.getBootVersion(), ESP.getSdkVersion());
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "2"));
}
@ -1765,16 +1787,22 @@ void PublishStatus(uint8_t payload)
void MqttShowState()
{
char stemp1[16];
char stemp1[33];
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{\"" D_JSON_TIME "\":\"%s\",\"" D_JSON_UPTIME "\":%d"), mqtt_data, GetDateAndTime().c_str(), uptime);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{\"" D_JSON_TIME "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\""), mqtt_data, GetDateAndTime().c_str(), GetUptime().c_str());
#ifdef USE_ADC_VCC
dtostrfd((double)ESP.getVcc()/1000, 3, stemp1);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_VCC "\":%s"), mqtt_data, stemp1);
#endif
for (byte i = 0; i < devices_present; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":\"%s\""), mqtt_data, GetPowerDevice(stemp1, i +1, sizeof(stemp1)), GetStateText(bitRead(power, i)));
if (i == light_device -1) {
LightState(1);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":\"%s\""), mqtt_data, GetPowerDevice(stemp1, i +1, sizeof(stemp1)), GetStateText(bitRead(power, i)));
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_RSSI "\":%d,\"" D_JSON_APMAC_ADDRESS "\":\"%s\"}}"),
mqtt_data, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WifiGetRssiAsQuality(WiFi.RSSI()), WiFi.BSSIDstr().c_str());
}
@ -1791,7 +1819,7 @@ boolean MqttShowSensor()
}
XsnsCall(FUNC_JSON_APPEND);
boolean json_data_available = (strlen(mqtt_data) - json_data_start);
if (strstr_P(mqtt_data, PSTR(D_TEMPERATURE))) {
if (strstr_P(mqtt_data, PSTR(D_JSON_TEMPERATURE))) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_TEMPERATURE_UNIT "\":\"%c\""), mqtt_data, TempUnit());
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
@ -1806,6 +1834,8 @@ boolean MqttShowSensor()
void PerformEverySecond()
{
uptime++;
if (blockgpio0) {
blockgpio0--;
}
@ -1855,11 +1885,11 @@ void PerformEverySecond()
mqtt_data[0] = '\0';
MqttShowState();
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_STATE));
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE));
mqtt_data[0] = '\0';
if (MqttShowSensor()) {
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
}
}
@ -1870,9 +1900,8 @@ void PerformEverySecond()
if ((2 == RtcTime.minute) && latest_uptime_flag) {
latest_uptime_flag = false;
uptime++;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"" D_JSON_UPTIME "\":%d}"), GetDateAndTime().c_str(), uptime);
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_UPTIME));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\"}"), GetDateAndTime().c_str(), GetUptime().c_str());
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_UPTIME));
}
if ((3 == RtcTime.minute) && !latest_uptime_flag) {
latest_uptime_flag = true;
@ -1890,129 +1919,130 @@ void ButtonHandler()
char scmnd[20];
uint8_t maxdev = (devices_present > MAX_KEYS) ? MAX_KEYS : devices_present;
for (byte i = 0; i < maxdev; i++) {
for (byte button_index = 0; button_index < maxdev; button_index++) {
button = NOT_PRESSED;
button_present = 0;
if (!i && ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module))) {
if (!button_index && ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module))) {
button_present = 1;
if (dual_button_code) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), dual_button_code);
AddLog(LOG_LEVEL_DEBUG);
button = PRESSED;
if (0xF500 == dual_button_code) { // Button hold
holdbutton[i] = (Settings.param[P_HOLD_TIME] * (STATES / 10)) -1;
holdbutton[button_index] = (Settings.param[P_HOLD_TIME] * (STATES / 10)) -1;
}
dual_button_code = 0;
}
} else {
if ((pin[GPIO_KEY1 +i] < 99) && !blockgpio0) {
if ((pin[GPIO_KEY1 +button_index] < 99) && !blockgpio0) {
button_present = 1;
button = digitalRead(pin[GPIO_KEY1 +i]);
button = digitalRead(pin[GPIO_KEY1 +button_index]);
}
}
if (button_present) {
if (SONOFF_4CHPRO == Settings.module) {
if (holdbutton[i]) {
holdbutton[i]--;
if (holdbutton[button_index]) {
holdbutton[button_index]--;
}
boolean button_pressed = false;
if ((PRESSED == button) && (NOT_PRESSED == lastbutton[i])) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " %d " D_LEVEL_10), i +1);
if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_10), button_index +1);
AddLog(LOG_LEVEL_DEBUG);
holdbutton[i] = STATES;
holdbutton[button_index] = STATES;
button_pressed = true;
}
if ((NOT_PRESSED == button) && (PRESSED == lastbutton[i])) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " %d " D_LEVEL_01), i +1);
if ((NOT_PRESSED == button) && (PRESSED == lastbutton[button_index])) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1);
AddLog(LOG_LEVEL_DEBUG);
if (!holdbutton[i]) { // Do not allow within 1 second
if (!holdbutton[button_index]) { // Do not allow within 1 second
button_pressed = true;
}
}
if (button_pressed) {
if (!send_button_power(0, i +1, 2)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(i +1, 2); // Execute Toggle command internally
if (!send_button_power(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(button_index +1, POWER_TOGGLE); // Execute Toggle command internally
}
}
} else {
if ((PRESSED == button) && (NOT_PRESSED == lastbutton[i])) {
if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) {
if (Settings.flag.button_single) { // Allow only single button press for immediate action
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " %d " D_IMMEDIATE), i +1);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1);
AddLog(LOG_LEVEL_DEBUG);
if (!send_button_power(0, i +1, 2)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(i +1, 2); // Execute Toggle command internally
if (!send_button_power(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(button_index +1, POWER_TOGGLE); // Execute Toggle command internally
}
} else {
multipress[i] = (multiwindow[i]) ? multipress[i] +1 : 1;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " %d " D_MULTI_PRESS " %d"), i +1, multipress[i]);
multipress[button_index] = (multiwindow[button_index]) ? multipress[button_index] +1 : 1;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, multipress[button_index]);
AddLog(LOG_LEVEL_DEBUG);
multiwindow[i] = STATES /2; // 0.5 second multi press window
multiwindow[button_index] = STATES /2; // 0.5 second multi press window
}
blinks = 201;
}
if (NOT_PRESSED == button) {
holdbutton[i] = 0;
holdbutton[button_index] = 0;
} else {
holdbutton[i]++;
holdbutton[button_index]++;
if (Settings.flag.button_single) { // Allow only single button press for immediate action
if (holdbutton[i] == Settings.param[P_HOLD_TIME] * (STATES / 10) * 4) { // Button hold for four times longer
if (holdbutton[button_index] == Settings.param[P_HOLD_TIME] * (STATES / 10) * 4) { // Button hold for four times longer
// Settings.flag.button_single = 0;
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only
ExecuteCommand(scmnd);
}
} else {
if (holdbutton[i] == Settings.param[P_HOLD_TIME] * (STATES / 10)) { // Button hold
multipress[i] = 0;
if (holdbutton[button_index] == Settings.param[P_HOLD_TIME] * (STATES / 10)) { // Button hold
multipress[button_index] = 0;
if (!Settings.flag.button_restrict) { // No button restriction
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1"));
ExecuteCommand(scmnd);
} else {
send_button_power(0, i +1, 3); // Execute Hold command via MQTT if ButtonTopic is set
send_button_power(0, button_index +1, 3); // Execute Hold command via MQTT if ButtonTopic is set
}
}
}
}
if (!Settings.flag.button_single) { // Allow multi-press
if (multiwindow[i]) {
multiwindow[i]--;
if (multiwindow[button_index]) {
multiwindow[button_index]--;
} else {
if (!restart_flag && !holdbutton[i] && (multipress[i] > 0) && (multipress[i] < MAX_BUTTON_COMMANDS +3)) {
if (!restart_flag && !holdbutton[button_index] && (multipress[button_index] > 0) && (multipress[button_index] < MAX_BUTTON_COMMANDS +3)) {
boolean single_press = false;
if (multipress[i] < 3) { // Single or Double press
if (multipress[button_index] < 3) { // Single or Double press
if ((SONOFF_DUAL_R2 == Settings.module) || (SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
single_press = true;
} else {
single_press = (Settings.flag.button_swap +1 == multipress[i]);
multipress[i] = 1;
single_press = (Settings.flag.button_swap +1 == multipress[button_index]);
multipress[button_index] = 1;
}
}
if (single_press && send_button_power(0, i + multipress[i], 2)) { // Execute Toggle command via MQTT if ButtonTopic is set
if (single_press && send_button_power(0, button_index + multipress[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
// Success
} else {
if (multipress[i] < 3) { // Single or Double press
if (multipress[button_index] < 3) { // Single or Double press
if (WifiState()) { // WPSconfig, Smartconfig or Wifimanager active
restart_flag = 1;
} else {
ExecuteCommandPower(i + multipress[i], 2); // Execute Toggle command internally
ExecuteCommandPower(button_index + multipress[button_index], POWER_TOGGLE); // Execute Toggle command internally
}
} else { // 3 - 7 press
if (!Settings.flag.button_restrict) {
snprintf_P(scmnd, sizeof(scmnd), kCommands[multipress[i] -3]);
snprintf_P(scmnd, sizeof(scmnd), kCommands[multipress[button_index] -3]);
ExecuteCommand(scmnd);
}
}
}
multipress[i] = 0;
multipress[button_index] = 0;
}
}
}
}
}
lastbutton[i] = button;
lastbutton[button_index] = button;
}
}
@ -2085,7 +2115,7 @@ void SwitchHandler()
if (switchflag < 3) {
if (!send_button_power(1, i +1, switchflag)) { // Execute command via MQTT
ExecuteCommandPower(i +1, switchflag); // Execute command internally (if i < devices_present)
ExecuteCommandPower(i +1, switchflag); // Execute command internally (if i < devices_present)
}
}
@ -2136,7 +2166,8 @@ void StateLoop()
if ((pulse_timer[i] > 0) && (pulse_timer[i] < 112)) {
pulse_timer[i]--;
if (!pulse_timer[i]) {
ExecuteCommandPower(i +1, 0);
// ExecuteCommandPower(i +1, POWER_OFF);
ExecuteCommandPower(i +1, (POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate) ? POWER_ON : POWER_OFF);
}
}
}
@ -2224,6 +2255,8 @@ void StateLoop()
if (ota_state_flag && (backlog_pointer == backlog_index)) {
ota_state_flag--;
if (2 == ota_state_flag) {
ota_url = Settings.ota_url;
RtcSettings.ota_loader = 0; // Try requested image first
ota_retry_counter = OTA_ATTEMPTS;
ESPhttpUpdate.rebootOnUpdate(false);
SettingsSave(1); // Free flash for OTA update
@ -2241,10 +2274,32 @@ void StateLoop()
ota_result = 0;
ota_retry_counter--;
if (ota_retry_counter) {
// snprintf_P(log_data, sizeof(log_data), PSTR("OTA: Attempt %d"), OTA_ATTEMPTS - ota_retry_counter);
// AddLog(LOG_LEVEL_INFO);
ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(Settings.ota_url));
#ifndef BE_MINIMAL
if (RtcSettings.ota_loader) {
char *pch = strrchr(Settings.ota_url, '-'); // Change from filename-DE.bin into filename-minimal.bin
char *ech = strrchr(Settings.ota_url, '.'); // Change from filename.bin into filename-minimal.bin
if (!pch) {
pch = ech;
}
if (pch) {
strlcpy(mqtt_data, Settings.ota_url, pch - Settings.ota_url +1);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s-" D_JSON_MINIMAL "%s"), mqtt_data, ech); // Minimal filename must be filename-minimal
ota_url = mqtt_data; // Try minimal image
}
}
#endif // BE_MINIMAL
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "%s"), ota_url);
AddLog(LOG_LEVEL_DEBUG);
ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(ota_url));
if (!ota_result) {
#ifndef BE_MINIMAL
int ota_error = ESPhttpUpdate.getLastError();
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Ota error %d"), ota_error);
// AddLog(LOG_LEVEL_DEBUG);
if ((HTTP_UE_TOO_LESS_SPACE == ota_error) || (HTTP_UE_BIN_FOR_WRONG_FLASH == ota_error)) {
RtcSettings.ota_loader = 1; // Try minimal image next
}
#endif // BE_MINIMAL
ota_state_flag = 2; // Upgrade failed - retry
}
}
@ -2258,7 +2313,7 @@ void StateLoop()
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_JSON_FAILED " %s"), ESPhttpUpdate.getLastErrorString().c_str());
}
restart_flag = 2; // Restart anyway to keep memory clean webserver
MqttPublishPrefixTopic_P(1, PSTR(D_CMND_UPGRADE));
MqttPublishPrefixTopic_P(STAT, PSTR(D_CMND_UPGRADE));
}
}
break;
@ -2368,6 +2423,17 @@ void SerialInput()
}
}
/*-------------------------------------------------------------------------------------------*\
* Sonoff S31 4800 baud serial interface
\*-------------------------------------------------------------------------------------------*/
if (SONOFF_S31 == Settings.module) {
if (CseSerialInput()) {
serial_in_byte_counter = 0;
Serial.flush();
return;
}
}
/*-------------------------------------------------------------------------------------------*/
if (serial_in_byte > 127) { // binary data...
@ -2398,7 +2464,7 @@ void SerialInput()
else if (serial_in_byte == '\n') {
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? LOG_LEVEL_INFO : Settings.seriallog_level;
seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (byte)LOG_LEVEL_INFO : Settings.seriallog_level;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), serial_in_buffer);
AddLog(LOG_LEVEL_INFO);
ExecuteCommand(serial_in_buffer);
@ -2579,6 +2645,7 @@ void GpioInit()
if (!light_type) {
for (byte i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
if (pin[GPIO_PWM1 +i] < 99) {
pwm_present = true;
pinMode(pin[GPIO_PWM1 +i], OUTPUT);
analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - Settings.pwm_value[i] : Settings.pwm_value[i]);
}
@ -2591,7 +2658,7 @@ void GpioInit()
}
SetLedPower(Settings.ledstate &8);
XDrvInit();
XdrvCall(FUNC_INIT);
}
extern "C" {
@ -2607,6 +2674,16 @@ void setup()
Serial.println();
seriallog_level = LOG_LEVEL_INFO; // Allow specific serial messages until config loaded
snprintf_P(my_version, sizeof(my_version), PSTR("%d.%d.%d"), VERSION >> 24 & 0xff, VERSION >> 16 & 0xff, VERSION >> 8 & 0xff);
if (VERSION & 0x1f) {
idx = strlen(my_version);
my_version[idx] = 96 + (VERSION & 0x1f);
my_version[idx +1] = 0;
}
#ifdef BE_MINIMAL
snprintf_P(my_version, sizeof(my_version), PSTR("%s-" D_JSON_MINIMAL), my_version);
#endif // BE_MINIMAL
SettingsLoad();
SettingsDelta();
@ -2641,28 +2718,29 @@ void setup()
GetMqttClient(mqtt_client, Settings.mqtt_client, sizeof(mqtt_client));
if (MOTOR == Settings.module) {
Settings.poweronstate = 1; // Needs always on else in limbo!
Settings.poweronstate = POWER_ALL_ON; // Needs always on else in limbo!
}
if (4 == Settings.poweronstate) { // Allways on
if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) {
SetDevicePower(1);
} else {
if ((resetInfo.reason == REASON_DEFAULT_RST) || (resetInfo.reason == REASON_EXT_SYS_RST)) {
switch (Settings.poweronstate) {
case 0: // All off
case POWER_ALL_OFF:
case POWER_ALL_OFF_PULSETIME_ON:
power = 0;
SetDevicePower(power);
break;
case 1: // All on
case POWER_ALL_ON: // All on
power = (1 << devices_present) -1;
SetDevicePower(power);
break;
case 2: // All saved state toggle
power = Settings.power & ((1 << devices_present) -1) ^ POWER_MASK;
case POWER_ALL_SAVED_TOGGLE:
power = (Settings.power & ((1 << devices_present) -1)) ^ POWER_MASK;
if (Settings.flag.save_state) {
SetDevicePower(power);
}
break;
case 3: // All saved state
case POWER_ALL_SAVED:
power = Settings.power & ((1 << devices_present) -1);
if (Settings.flag.save_state) {
SetDevicePower(power);
@ -2682,19 +2760,23 @@ void setup()
if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) {
bitWrite(power, i, digitalRead(pin[GPIO_REL1 +i]) ^ bitRead(rel_inverted, i));
}
if ((i < MAX_PULSETIMERS) && bitRead(power, i)) {
if ((i < MAX_PULSETIMERS) && (bitRead(power, i) || (POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate))) {
pulse_timer[i] = Settings.pulse_timer[i];
}
}
blink_powersave = power;
snprintf_P(log_data, sizeof(log_data), PSTR(D_PROJECT " %s %s (" D_CMND_TOPIC " %s, " D_FALLBACK " %s, " D_CMND_GROUPTOPIC " %s) " D_VERSION " " VERSION_STRING),
PROJECT, Settings.friendlyname[0], Settings.mqtt_topic, mqtt_client, Settings.mqtt_grptopic);
snprintf_P(log_data, sizeof(log_data), PSTR(D_PROJECT " %s %s (" D_CMND_TOPIC " %s, " D_FALLBACK " %s, " D_CMND_GROUPTOPIC " %s) " D_VERSION " %s"),
PROJECT, Settings.friendlyname[0], Settings.mqtt_topic, mqtt_client, Settings.mqtt_grptopic, my_version);
AddLog(LOG_LEVEL_INFO);
#ifdef BE_MINIMAL
snprintf_P(log_data, sizeof(log_data), PSTR(D_WARNING_MINIMAL_VERSION));
AddLog(LOG_LEVEL_INFO);
#endif // BE_MINIMAL
RtcInit();
XSnsInit();
XsnsCall(FUNC_INIT);
}
void loop()

View File

@ -52,6 +52,9 @@ void WifiWpsStatusCallback(wps_cb_status status);
#ifdef USE_DOMOTICZ
#undef USE_DOMOTICZ // Disable Domoticz
#endif
#ifdef USE_HOME_ASSISTANT
#undef USE_HOME_ASSISTANT // Disable Home Assistant
#endif
//#ifdef USE_WEBSERVER
//#undef USE_WEBSERVER // Disable Webserver
//#endif
@ -79,9 +82,21 @@ void WifiWpsStatusCallback(wps_cb_status status);
#ifdef USE_DHT
#undef USE_DHT // Disable internal DHT sensor
#endif
#ifdef USE_DISPLAY
#undef USE_DISPLAY // Disable Display support
#endif
#ifdef USE_MHZ19
#undef USE_MHZ19 // Disable support for MH-Z19 CO2 sensor
#endif
#ifdef USE_SENSEAIR
#undef USE_SENSEAIR // Disable support for SenseAir K30, K70 and S8 CO2 sensor
#endif
#ifdef USE_IR_REMOTE
#undef USE_IR_REMOTE // Disable IR driver
#endif
#ifdef USE_ARILUX_RF
#undef USE_ARILUX_RF // Disable support for Arilux RF remote controller
#endif
#ifdef DEBUG_THEO
#undef DEBUG_THEO // Disable debug code
#endif
@ -100,10 +115,12 @@ void WifiWpsStatusCallback(wps_cb_status status);
#endif
#ifndef MESSZ
#define MESSZ 405 // Max number of characters in JSON message string (6 x DS18x20 sensors)
//#define MESSZ 405 // Max number of characters in JSON message string (6 x DS18x20 sensors)
//#define MESSZ 893 // Max number of characters in JSON message string (Hass discovery and nice MQTT_MAX_PACKET_SIZE = 1000)
#define MESSZ (MQTT_MAX_PACKET_SIZE -TOPSZ -7) // Max number of characters in JSON message string (6 x DS18x20 sensors)
#endif
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
//#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
#ifndef ARDUINO_ESP8266_RELEASE
#define ARDUINO_ESP8266_RELEASE "STAGED"
#endif

View File

@ -86,78 +86,10 @@ enum UserSelectablePins {
GPIO_SAIR_RX, // SenseAir Serial interface
GPIO_SPI_CS, // SPI Chip Select
GPIO_SPI_DC, // SPI Data Direction
GPIO_BACKLIGHT,
GPIO_BACKLIGHT, // Display backlight control
GPIO_PMS5003, // Plantower PMS5003 Serial interface
GPIO_SENSOR_END };
// Text in webpage Module Parameters and commands GPIOS and GPIO
const char kSensors[GPIO_SENSOR_END][9] PROGMEM = {
D_SENSOR_NONE,
D_SENSOR_DHT11,
D_SENSOR_AM2301,
D_SENSOR_SI7021,
D_SENSOR_DS18X20,
D_SENSOR_I2C_SCL,
D_SENSOR_I2C_SDA,
D_SENSOR_WS2812,
D_SENSOR_IRSEND,
D_SENSOR_SWITCH "1",
D_SENSOR_SWITCH "2",
D_SENSOR_SWITCH "3",
D_SENSOR_SWITCH "4",
D_SENSOR_BUTTON "1",
D_SENSOR_BUTTON "2",
D_SENSOR_BUTTON "3",
D_SENSOR_BUTTON "4",
D_SENSOR_RELAY "1",
D_SENSOR_RELAY "2",
D_SENSOR_RELAY "3",
D_SENSOR_RELAY "4",
D_SENSOR_RELAY "5",
D_SENSOR_RELAY "6",
D_SENSOR_RELAY "7",
D_SENSOR_RELAY "8",
D_SENSOR_RELAY "1i",
D_SENSOR_RELAY "2i",
D_SENSOR_RELAY "3i",
D_SENSOR_RELAY "4i",
D_SENSOR_RELAY "5i",
D_SENSOR_RELAY "6i",
D_SENSOR_RELAY "7i",
D_SENSOR_RELAY "8i",
D_SENSOR_PWM "1",
D_SENSOR_PWM "2",
D_SENSOR_PWM "3",
D_SENSOR_PWM "4",
D_SENSOR_PWM "5",
D_SENSOR_COUNTER "1",
D_SENSOR_COUNTER "2",
D_SENSOR_COUNTER "3",
D_SENSOR_COUNTER "4",
D_SENSOR_PWM "1i",
D_SENSOR_PWM "2i",
D_SENSOR_PWM "3i",
D_SENSOR_PWM "4i",
D_SENSOR_PWM "5i",
D_SENSOR_IRRECV,
D_SENSOR_LED "1",
D_SENSOR_LED "2",
D_SENSOR_LED "3",
D_SENSOR_LED "4",
D_SENSOR_LED "1i",
D_SENSOR_LED "2i",
D_SENSOR_LED "3i",
D_SENSOR_LED "4i",
D_SENSOR_MHZ_TX,
D_SENSOR_MHZ_RX,
D_SENSOR_PZEM_TX,
D_SENSOR_PZEM_RX,
D_SENSOR_SAIR_TX,
D_SENSOR_SAIR_RX,
D_SENSOR_SPI_CS,
D_SENSOR_SPI_DC,
D_SENSOR_BACKLIGHT
};
// Programmer selectable GPIO functionality offset by user selectable GPIOs
enum ProgramSelectablePins {
GPIO_RXD = GPIO_SENSOR_END, // Serial interface
@ -175,6 +107,30 @@ enum ProgramSelectablePins {
GPIO_USER, // User configurable
GPIO_MAX };
// Text in webpage Module Parameters and commands GPIOS and GPIO
const char kSensorNames[] PROGMEM =
D_SENSOR_NONE "|"
D_SENSOR_DHT11 "|" D_SENSOR_AM2301 "|" D_SENSOR_SI7021 "|"
D_SENSOR_DS18X20 "|"
D_SENSOR_I2C_SCL "|" D_SENSOR_I2C_SDA "|"
D_SENSOR_WS2812 "|"
D_SENSOR_IRSEND "|"
D_SENSOR_SWITCH "1|" D_SENSOR_SWITCH "2|" D_SENSOR_SWITCH "3|" D_SENSOR_SWITCH "4|"
D_SENSOR_BUTTON "1|" D_SENSOR_BUTTON "2|" D_SENSOR_BUTTON "3|" D_SENSOR_BUTTON "4|"
D_SENSOR_RELAY "1|" D_SENSOR_RELAY "2|" D_SENSOR_RELAY "3|" D_SENSOR_RELAY "4|" D_SENSOR_RELAY "5|" D_SENSOR_RELAY "6|" D_SENSOR_RELAY "7|" D_SENSOR_RELAY "8|"
D_SENSOR_RELAY "1i|" D_SENSOR_RELAY "2i|" D_SENSOR_RELAY "3i|" D_SENSOR_RELAY "4i|" D_SENSOR_RELAY "5i|" D_SENSOR_RELAY "6i|" D_SENSOR_RELAY "7i|" D_SENSOR_RELAY "8i|"
D_SENSOR_PWM "1|" D_SENSOR_PWM "2|" D_SENSOR_PWM "3|" D_SENSOR_PWM "4|" D_SENSOR_PWM "5|"
D_SENSOR_COUNTER "1|" D_SENSOR_COUNTER "2|" D_SENSOR_COUNTER "3|" D_SENSOR_COUNTER "4|"
D_SENSOR_PWM "1i|" D_SENSOR_PWM "2i|" D_SENSOR_PWM "3i|" D_SENSOR_PWM "4i|" D_SENSOR_PWM "5i|"
D_SENSOR_IRRECV "|"
D_SENSOR_LED "1|" D_SENSOR_LED "2|" D_SENSOR_LED "3|" D_SENSOR_LED "4|"
D_SENSOR_LED "1i|" D_SENSOR_LED "2i|" D_SENSOR_LED "3i|" D_SENSOR_LED "4i|"
D_SENSOR_MHZ_TX "|" D_SENSOR_MHZ_RX "|"
D_SENSOR_PZEM_TX "|" D_SENSOR_PZEM_RX "|"
D_SENSOR_SAIR_TX "|" D_SENSOR_SAIR_RX "|"
D_SENSOR_SPI_CS "|" D_SENSOR_SPI_DC "|" D_SENSOR_BACKLIGHT "|"
D_SENSOR_PMS5003;
/********************************************************************************************/
// Supported hardware modules
@ -219,6 +175,7 @@ enum SupportedModules {
ARILUX_LC11,
SONOFF_DUAL_R2,
ARILUX_LC06,
SONOFF_S31,
MAXMODULE };
/********************************************************************************************/
@ -243,6 +200,7 @@ const uint8_t kNiceList[MAXMODULE] PROGMEM = {
SONOFF_DUAL,
SONOFF_DUAL_R2,
SONOFF_POW,
SONOFF_S31,
SONOFF_4CH,
SONOFF_4CHPRO,
SONOFF_SV,
@ -499,7 +457,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On)
0, 0
},
{ "WeMos D1 mini", // WeMos and NodeMCU hardware (ESP8266)
{ "Generic", // Any ESP8266/ESP8285 device like WeMos and NodeMCU hardware (ESP8266)
GPIO_USER, // GPIO00 D3 Wemos Button Shield
GPIO_USER, // GPIO01 TX Serial RXD
GPIO_USER, // GPIO02 D4 Wemos DHT Shield
@ -815,6 +773,17 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_PWM1, // GPIO14 RGB LED Red
GPIO_USER, // GPIO15 RGBW LED White
0, 0
},
{ "Sonoff S31", // Sonoff S31 (ESP8266)
GPIO_KEY1, // GPIO00 Button
0, // GPIO01 Serial RXD 4800 baud 8E1 CSE7766 energy sensor
0,
0, // GPIO03 Serial TXD
0, 0,
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
0, 0, 0, 0
}
};
@ -859,6 +828,44 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
0, 0, 0
}
{ "SMPW701E", // SM-PW701E WLAN Socket (#1190)
0, 0, 0, 0,
GPIO_LED1_INV, // GPIO04 Blue Led (0 = On, 1 = Off)
0, // GPIO05 IR or RF receiver (optional)
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_REL1, // GPIO12 Relay and Red Led (0 = Off, 1 = On)
GPIO_KEY1, // GPIO13 Button
0, 0, 0, 0
}
{ "SWA1", // Smart Plugs (ESP8266)
0,
GPIO_USER, // GPIO01
0,
GPIO_USER, // GPIO03
GPIO_LED1_INV, // GPIO04 Blue LED
GPIO_REL1, // GPIO05 Red LED and relay
0, 0, 0, 0, 0, 0, // Flash connection
0,
GPIO_KEY1, // GPIO13 Button (normally GPIO00)
GPIO_USER, // GPIO14
0, 0, 0
}
{ "MagicHome v2.3", // Magic Home (aka Flux-light) (ESP8266) (#1353)
0, 0,
GPIO_LED1_INV, // GPIO02 Blue onboard LED
0,
GPIO_USER, // GPIO04 IR receiver (optional)
GPIO_PWM2, // GPIO05 RGB LED Green
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_PWM1, // GPIO12 RGB LED Red
GPIO_PWM3, // GPIO13 RGB LED Blue
0,
GPIO_PWM4, // GPIO15 RGBW LED White
0, 0
},
*/
#endif // _SONOFF_TEMPLATE_H_

View File

@ -26,7 +26,7 @@ unsigned long syslog_host_refresh = 0;
Ticker tickerOSWatch;
#define OSWATCH_RESET_TIME 30
#define OSWATCH_RESET_TIME 120
static unsigned long oswatch_last_loop_time;
byte oswatch_blocked_loop = 0;
@ -145,86 +145,56 @@ Decoding 14 results
#endif // DEBUG_THEO
/*********************************************************************************************\
* General
* Miscellaneous
\*********************************************************************************************/
char* _dtostrf(double number, unsigned char prec, char *s, bool i18n)
#ifdef ARDUINO_ESP8266_RELEASE_2_3_0
// Functions not available in 2.3.0
// http://clc-wiki.net/wiki/C_standard_library:string.h:memchr
void* memchr(const void* ptr, int value, size_t num)
{
bool negative = false;
if (isnan(number)) {
strcpy_P(s, PSTR("nan"));
return s;
}
if (isinf(number)) {
strcpy_P(s, PSTR("inf"));
return s;
}
char decimal = '.';
if (i18n) {
decimal = D_DECIMAL_SEPARATOR[0];
}
char* out = s;
// Handle negative numbers
if (number < 0.0) {
negative = true;
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
// I optimized out most of the divisions
double rounding = 2.0;
for (uint8_t i = 0; i < prec; ++i) {
rounding *= 10.0;
}
rounding = 1.0 / rounding;
number += rounding;
// Figure out how big our number really is
double tenpow = 1.0;
int digitcount = 1;
while (number >= 10.0 * tenpow) {
tenpow *= 10.0;
digitcount++;
}
number /= tenpow;
// Handle negative sign
if (negative) {
*out++ = '-';
}
// Print the digits, and if necessary, the decimal point
digitcount += prec;
int8_t digit = 0;
while (digitcount-- > 0) {
digit = (int8_t)number;
if (digit > 9) {
digit = 9; // insurance
unsigned char *p = (unsigned char*)ptr;
while (num--) {
if (*p != (unsigned char)value) {
p++;
} else {
return p;
}
*out++ = (char)('0' | digit);
if ((digitcount == prec) && (prec > 0)) {
*out++ = decimal;
}
number -= digit;
number *= 10.0;
}
// make sure the string is terminated
*out = 0;
return s;
return 0;
}
char* dtostrfd(double number, unsigned char prec, char *s) // Always decimal dot
// http://clc-wiki.net/wiki/C_standard_library:string.h:strspn
// Get span until any character in string
size_t strcspn(const char *str1, const char *str2)
{
return _dtostrf(number, prec, s, 0);
size_t ret = 0;
while (*str1) {
if (strchr(str2, *str1)) { // Slow
return ret;
} else {
str1++;
ret++;
}
}
return ret;
}
#endif // ARDUINO_ESP8266_RELEASE_2_3_0
// Get span until single character in string
size_t strchrspn(const char *str1, int character)
{
size_t ret = 0;
char *start = (char*)str1;
char *end = strchr(str1, character);
if (end) ret = end - start;
return ret;
}
char* dtostrfi(double number, unsigned char prec, char *s) // Use localized decimal dot
char* dtostrfd(double number, unsigned char prec, char *s)
{
return _dtostrf(number, prec, s, 1);
return dtostrf(number, 1, prec, s);
}
boolean ParseIp(uint32_t* addr, const char* str)
@ -328,12 +298,127 @@ char* GetPowerDevice(char* dest, uint8_t idx, size_t size)
return GetPowerDevice(dest, idx, size, 0);
}
float ConvertTemp(float c)
{
float result = c;
if (!isnan(c) && Settings.flag.temperature_conversion) {
result = c * 1.8 + 32; // Fahrenheit
}
return result;
}
char TempUnit()
{
return (Settings.flag.temperature_conversion) ? 'F' : 'C';
}
double FastPrecisePow(double a, double b)
{
// https://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/
// calculate approximation with fraction of the exponent
int e = (int)b;
union {
double d;
int x[2];
} u = { a };
u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447);
u.x[0] = 0;
// exponentiation by squaring with the exponent's integer part
// double r = u.d makes everything much slower, not sure why
double r = 1.0;
while (e) {
if (e & 1) {
r *= a;
}
a *= a;
e >>= 1;
}
return r * u.d;
}
char* GetTextIndexed(char* destination, size_t destination_size, uint16_t index, const char* haystack)
{
// Returns empty string if not found
// Returns text of found
char* write = destination;
const char* read = haystack;
index++;
while (index--) {
size_t size = destination_size -1;
write = destination;
char ch = '.';
while ((ch != '\0') && (ch != '|')) {
ch = pgm_read_byte(read++);
if (size && (ch != '|')) {
*write++ = ch;
size--;
}
}
if (0 == ch) {
if (index) {
write = destination;
}
break;
}
}
*write = '\0';
return destination;
}
int GetCommandCode(char* destination, size_t destination_size, const char* needle, const char* haystack)
{
// Returns -1 of not found
// Returns index and command if found
int result = -1;
const char* read = haystack;
char* write = destination;
while (true) {
result++;
size_t size = destination_size -1;
write = destination;
char ch = '.';
while ((ch != '\0') && (ch != '|')) {
ch = pgm_read_byte(read++);
if (size && (ch != '|')) {
*write++ = ch;
size--;
}
}
*write = '\0';
if (!strcasecmp(needle, destination)) {
break;
}
if (0 == ch) {
result = -1;
break;
}
}
return result;
}
void SetSerialBaudrate(int baudrate)
{
if (Serial.baudRate() != baudrate) {
if (seriallog_level) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_SET_BAUDRATE_TO " %d"), baudrate);
AddLog(LOG_LEVEL_INFO);
}
delay(100);
Serial.flush();
Serial.begin(baudrate, serial_config);
delay(10);
Serial.println();
}
}
/*********************************************************************************************\
* Wifi
\*********************************************************************************************/
#define WIFI_CONFIG_SEC 180 // seconds before restart
#define WIFI_MANAGER_SEC 180 // seconds before restart
#define WIFI_CHECK_SEC 20 // seconds
#define WIFI_RETRY_SEC 30 // seconds
@ -361,7 +446,7 @@ int WifiGetRssiAsQuality(int rssi)
boolean WifiConfigCounter()
{
if (wifi_config_counter) {
wifi_config_counter = WIFI_MANAGER_SEC;
wifi_config_counter = WIFI_CONFIG_SEC;
}
return (wifi_config_counter);
}
@ -612,6 +697,12 @@ void WifiCheck(uint8_t param)
WifiCheckIp();
}
if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0) && !wifi_config_type) {
#ifdef BE_MINIMAL
if (1 == RtcSettings.ota_loader) {
RtcSettings.ota_loader = 0;
ota_state_flag = 3;
}
#endif // BE_MINIMAL
#ifdef USE_DISCOVERY
if (!mdns_begun) {
mdns_begun = MDNS.begin(my_hostname);
@ -902,22 +993,21 @@ uint32_t standard_time = 0;
uint32_t ntp_time = 0;
uint32_t midnight = 1451602800;
uint8_t midnight_now = 0;
uint8_t ntp_sync_minute = 0;
String GetBuildDateAndTime()
{
// "2017-03-07T11:08:02" - ISO8601:2004
char bdt[21];
char *str;
char *p;
char *smonth;
char mdate[] = __DATE__; // "Mar 7 2017"
int month;
int day;
int year;
char *smonth = mdate;
int day = 0;
int year = 0;
// sscanf(mdate, "%s %d %d", bdt, &day, &year); // Not implemented in 2.3.0 and probably too many code
// sscanf(mdate, "%s %d %d", bdt, &day, &year); // Not implemented in 2.3.0 and probably too much code
byte i = 0;
for (str = strtok_r(mdate, " ", &p); str && i < 3; str = strtok_r(NULL, " ", &p)) {
for (char *str = strtok_r(mdate, " ", &p); str && i < 3; str = strtok_r(NULL, " ", &p)) {
switch (i++) {
case 0: // Month
smonth = str;
@ -929,7 +1019,7 @@ String GetBuildDateAndTime()
year = atoi(str);
}
}
month = (strstr(kMonthNamesEnglish, smonth) -kMonthNamesEnglish) /3 +1;
int month = (strstr(kMonthNamesEnglish, smonth) -kMonthNamesEnglish) /3 +1;
snprintf_P(bdt, sizeof(bdt), PSTR("%d" D_YEAR_MONTH_SEPARATOR "%02d" D_MONTH_DAY_SEPARATOR "%02d" D_DATE_TIME_SEPARATOR "%s"), year, month, day, __TIME__);
return String(bdt);
}
@ -958,6 +1048,22 @@ String GetUtcDateAndTime()
return String(dt);
}
String GetUptime()
{
char dt[16];
TIME_T ut;
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("%d" D_DATE_TIME_SEPARATOR "%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), ut.days, ut.hour, ut.minute, ut.second);
return String(dt);
}
void BreakTime(uint32_t time_input, TIME_T &tm)
{
// break the given time_input into time components
@ -977,6 +1083,7 @@ void BreakTime(uint32_t time_input, TIME_T &tm)
time /= 60; // now it is hours
tm.hour = time % 24;
time /= 24; // now it is days
tm.days = time;
tm.day_of_week = ((time + 4) % 7) + 1; // Sunday is day 1
year = 0;
@ -1049,34 +1156,34 @@ uint32_t MakeTime(TIME_T &tm)
uint32_t RuleToTime(TimeChangeRule r, int yr)
{
TIME_T tm;
uint32_t t;
uint8_t m;
uint8_t w; // temp copies of r.month and r.week
TIME_T tm;
uint32_t t;
uint8_t m;
uint8_t w; // temp copies of r.month and r.week
m = r.month;
w = r.week;
if (0 == w) { // Last week = 0
if (++m > 12) { // for "Last", go to the next month
m = 1;
yr++;
}
w = 1; // and treat as first week of next month, subtract 7 days later
m = r.month;
w = r.week;
if (0 == w) { // Last week = 0
if (++m > 12) { // for "Last", go to the next month
m = 1;
yr++;
}
w = 1; // and treat as first week of next month, subtract 7 days later
}
tm.hour = r.hour;
tm.minute = 0;
tm.second = 0;
tm.day_of_month = 1;
tm.month = m;
tm.year = yr - 1970;
t = MakeTime(tm); // First day of the month, or first day of next month for "Last" rules
BreakTime(t, tm);
t += (7 * (w - 1) + (r.dow - tm.day_of_week + 7) % 7) * SECS_PER_DAY;
if (0 == r.week) {
t -= 7 * SECS_PER_DAY; //back up a week if this is a "Last" rule
}
return t;
tm.hour = r.hour;
tm.minute = 0;
tm.second = 0;
tm.day_of_month = 1;
tm.month = m;
tm.year = yr - 1970;
t = MakeTime(tm); // First day of the month, or first day of next month for "Last" rules
BreakTime(t, tm);
t += (7 * (w - 1) + (r.dow - tm.day_of_week + 7) % 7) * SECS_PER_DAY;
if (0 == r.week) {
t -= 7 * SECS_PER_DAY; // back up a week if this is a "Last" rule
}
return t;
}
String GetTime(int type)
@ -1104,43 +1211,32 @@ uint32_t Midnight()
boolean MidnightNow()
{
boolean mnflg = midnight_now;
if (mnflg) {
midnight_now = 0;
}
if (mnflg) midnight_now = 0;
return mnflg;
}
void RtcSecond()
{
byte ntpsync;
uint32_t stdoffset;
uint32_t dstoffset;
TIME_T tmpTime;
ntpsync = 0;
if (RtcTime.year < 2016) {
if (WL_CONNECTED == WiFi.status()) {
ntpsync = 1; // Initial NTP sync
}
} else {
if ((1 == RtcTime.minute) && (1 == RtcTime.second)) {
ntpsync = 1; // Hourly NTP sync at xx:01:01
}
}
if (ntpsync) {
if ((ntp_sync_minute > 59) && (3 == RtcTime.minute)) ntp_sync_minute = 1; // If sync prepare for a new cycle
uint8_t offset = (uptime < 30) ? RtcTime.second : (((ESP.getChipId() & 0xF) * 3) + 3) ; // First try ASAP to sync. If fails try once every 60 seconds based on chip id
if ((WL_CONNECTED == WiFi.status()) && (offset == RtcTime.second) && ((RtcTime.year < 2016) || (ntp_sync_minute == RtcTime.minute))) {
ntp_time = sntp_get_current_timestamp();
if (ntp_time) {
utc_time = ntp_time;
ntp_sync_minute = 60; // Sync so block further requests
BreakTime(utc_time, tmpTime);
RtcTime.year = tmpTime.year + 1970;
daylight_saving_time = RuleToTime(DaylightSavingTime, RtcTime.year);
standard_time = RuleToTime(StandardTime, RtcTime.year);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "(" D_UTC_TIME ") %s"), GetTime(0).c_str());
AddLog(LOG_LEVEL_DEBUG);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "(" D_DST_TIME ") %s"), GetTime(2).c_str());
AddLog(LOG_LEVEL_DEBUG);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "(" D_STD_TIME ") %s"), GetTime(3).c_str());
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "(" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"),
GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str());
AddLog(LOG_LEVEL_DEBUG);
} else {
ntp_sync_minute++; // Try again in next minute
}
}
utc_time++;
@ -1184,127 +1280,6 @@ void RtcInit()
TickerRtc.attach(1, RtcSecond);
}
/*********************************************************************************************\
* Miscellaneous
\*********************************************************************************************/
float ConvertTemp(float c)
{
float result = c;
if (!isnan(c) && Settings.flag.temperature_conversion) {
result = c * 1.8 + 32; // Fahrenheit
}
return result;
}
char TempUnit()
{
return (Settings.flag.temperature_conversion) ? 'F' : 'C';
}
double FastPrecisePow(double a, double b)
{
// https://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/
// calculate approximation with fraction of the exponent
int e = (int)b;
union {
double d;
int x[2];
} u = { a };
u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447);
u.x[0] = 0;
// exponentiation by squaring with the exponent's integer part
// double r = u.d makes everything much slower, not sure why
double r = 1.0;
while (e) {
if (e & 1) {
r *= a;
}
a *= a;
e >>= 1;
}
return r * u.d;
}
char* GetTextIndexed(char* destination, size_t destination_size, uint16_t index, const char* haystack)
{
// Returns empty string if not found
// Returns text of found
char* write = destination;
const char* read = haystack;
index++;
while (index--) {
size_t size = destination_size -1;
write = destination;
char ch = '.';
while ((ch != '\0') && (ch != '|')) {
ch = pgm_read_byte(read++);
if (size && (ch != '|')) {
*write++ = ch;
size--;
}
}
if (0 == ch) {
if (index) {
write = destination;
}
break;
}
}
*write = '\0';
return destination;
}
int GetCommandCode(char* destination, size_t destination_size, const char* needle, const char* haystack)
{
// Returns -1 of not found
// Returns index and command if found
int result = -1;
const char* read = haystack;
char* write = destination;
size_t maxcopy = (strlen(needle) > destination_size) ? destination_size : strlen(needle);
while (true) {
result++;
size_t size = destination_size -1;
write = destination;
char ch = '.';
while ((ch != '\0') && (ch != '|')) {
ch = pgm_read_byte(read++);
if (size && (ch != '|')) {
*write++ = ch;
size--;
}
}
*write = '\0';
if (!strcasecmp(needle, destination)) {
break;
}
if (0 == ch) {
result = -1;
break;
}
}
return result;
}
void SetSerialBaudrate(int baudrate)
{
if (Serial.baudRate() != baudrate) {
if (seriallog_level) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_SET_BAUDRATE_TO " %d"), baudrate);
AddLog(LOG_LEVEL_INFO);
}
delay(100);
Serial.flush();
Serial.begin(baudrate);
delay(10);
Serial.println();
}
}
#ifndef USE_ADC_VCC
/*********************************************************************************************\
* ADC support
@ -1363,6 +1338,32 @@ boolean Xsns02(byte function)
*
\*********************************************************************************************/
#ifdef USE_WEBSERVER
void GetLog(byte idx, char** entry_pp, size_t* len_p)
{
char* entry_p = NULL;
size_t len = 0;
if (idx) {
char* it = web_log;
do {
byte cur_idx = *it;
it++;
size_t tmp = strchrspn(it, '\1');
tmp++; // Skip terminating '\1'
if (cur_idx == idx) { // Found the requested entry
len = tmp;
entry_p = it;
break;
}
it += tmp;
} while (it < web_log + WEB_LOG_SIZE && *it != '\0');
}
*entry_pp = entry_p;
*len_p = len;
}
#endif // USE_WEBSERVER
void Syslog()
{
// Destroys log_data
@ -1389,20 +1390,29 @@ void Syslog()
void AddLog(byte loglevel)
{
char mxtime[9]; // 13:45:21
char mxtime[10]; // "13:45:21 "
snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second);
snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d "), RtcTime.hour, RtcTime.minute, RtcTime.second);
if (loglevel <= seriallog_level) {
Serial.printf("%s %s\n", mxtime, log_data);
Serial.printf("%s%s\n", mxtime, log_data);
}
#ifdef USE_WEBSERVER
if (Settings.webserver && (loglevel <= Settings.weblog_level)) {
web_log[web_log_index] = String(mxtime) + " " + String(log_data);
web_log_index++;
if (web_log_index > MAX_LOG_LINES -1) {
web_log_index = 0;
// Delimited, zero-terminated buffer of log lines.
// Each entry has this format: [index][log data]['\1']
if (!web_log_index) web_log_index++; // Index 0 is not allowed as it is the end of char string
while (web_log_index == web_log[0] || // If log already holds the next index, remove it
strlen(web_log) + strlen(log_data) + 13 > WEB_LOG_SIZE) // 13 = web_log_index + mxtime + '\1' + '\0'
{
char* it = web_log;
it++; // Skip web_log_index
it += strchrspn(it, '\1'); // Skip log line
it++; // Skip delimiting "\1"
memmove(web_log, it, WEB_LOG_SIZE -(it-web_log)); // Move buffer forward to remove oldest log line
}
snprintf_P(web_log, sizeof(web_log), PSTR("%s%c%s%s\1"), web_log, web_log_index++, mxtime, log_data);
if (!web_log_index) web_log_index++; // Index 0 is not allowed as it is the end of char string
}
#endif // USE_WEBSERVER
if ((WL_CONNECTED == WiFi.status()) && (loglevel <= syslog_level)) {
@ -1426,6 +1436,15 @@ void AddLog_P(byte loglevel, const char *formatP, const char *formatP2)
AddLog(loglevel);
}
void AddLogSerial(byte loglevel)
{
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_SERIAL D_RECEIVED));
for (byte i = 0; i < serial_in_byte_counter; i++) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, serial_in_buffer[i]);
}
AddLog(loglevel);
}
/*********************************************************************************************\
*
\*********************************************************************************************/

View File

@ -29,11 +29,14 @@
\*********************************************************************************************/
// -- Localization --------------------------------
//#define MY_LANGUAGE en-GB // English in Great Britain. Enabled by Default
//#define MY_LANGUAGE nl-NL // Dutch in the Netherlands
//#define MY_LANGUAGE de-DE // German in Germany
//#define MY_LANGUAGE pl-PL // Polish in Poland
//#define MY_LANGUAGE en-GB // English in Great Britain. Enabled by Default
//#define MY_LANGUAGE es-AR // Spanish in Argentina
//#define MY_LANGUAGE fr-FR // French in France
//#define MY_LANGUAGE it-IT // Italian in Italy
//#define MY_LANGUAGE nl-NL // Dutch in the Netherlands
//#define MY_LANGUAGE pl-PL // Polish in Poland
//#define MY_LANGUAGE zh-CN // Chinese (Simplified) in China
// -- Project -------------------------------------
#define PROJECT "sonoff" // PROJECT is used as the default topic delimiter and OTA file name
@ -116,6 +119,11 @@
#define DOMOTICZ_OUT_TOPIC "domoticz/out" // Domoticz Output Topic
#define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) (Optional)
// -- MQTT - Home Assistant Discovery -------------
#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+1k4 code)
#define HOME_ASSISTANT_DISCOVERY_PREFIX "homeassistant" // Home Assistant discovery prefix
#define HOME_ASSISTANT_DISCOVERY_ENABLE 0 // [SetOption19] Home Assistant Discovery (0 = Disable, 1 = Enable)
// -- HTTP ----------------------------------------
#define USE_WEBSERVER // Enable web server and wifi manager (+66k code, +8k mem) - Disable by //
#define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin)
@ -161,11 +169,10 @@
#define PRESSURE_RESOLUTION 1 // [PressRes] Maximum number of decimals (0 - 3) showing sensor Pressure
#define ENERGY_RESOLUTION 3 // [EnergyRes] Maximum number of decimals (0 - 5) showing energy usage in kWh
// -- Sensor code selection -----------------------
// -- Internal Analog input -----------------------
#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
// -- One wire sensors ----------------------------
// WARNING: Select none for default one DS18B20 sensor or enable one of the following two options for multiple sensors
//#define USE_DS18x20 // Optional for more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code)
//#define USE_DS18x20_LEGACY // Optional for more than one DS18x20 sensors with dynamic scan using library OneWire (+1k5 code)
@ -186,14 +193,15 @@
// #define USE_INA219 // Add I2C code for INA219 Low voltage and current sensor (+1k code)
#endif // USE_I2C
//#define USE_SPI // SPI using library TasmotaTFT
// -- Carbon dioxide (CO2) sensors ----------------
// -- Serial sensors ------------------------------
#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code)
#define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code)
#define CO2_LOW 800 // Below this CO2 value show green light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
#define CO2_HIGH 1200 // Above this CO2 value show red light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
#define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code)
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
// -- Low level interface devices -----------------
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram)
// #define USE_IR_HVAC // Support for HVAC system using IR (+2k code)
#define USE_IR_RECEIVE // Support for IR receiver (+5k5 code, 264 iram)
@ -202,7 +210,7 @@
#define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB, 2 - RGBW, 3 - GRBW)
// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
#define USE_ARILUX_RF // Add support for Arilux RF remote controller (+0k8 code)
#define USE_ARILUX_RF // Add support for Arilux RF remote controller (+0k8 code, 252 iram (non 2.3.0))
/*********************************************************************************************\
* Compile a minimal version if upgrade memory gets tight ONLY TO BE USED FOR UPGRADE STEP 1!

View File

@ -37,7 +37,7 @@ const char HTTP_HEAD[] PROGMEM =
"<script>"
"var cn,x,lt;"
"cn=120;"
"cn=180;"
"x=null;" // Allow for abortion
"function u(){"
"if(cn>=0){"
@ -60,7 +60,7 @@ const char HTTP_HEAD[] PROGMEM =
"x=new XMLHttpRequest();"
"x.onreadystatechange=function(){"
"if(x.readyState==4&&x.status==200){"
"var s=x.responseText.replace(/{s}/g,\"<tr><th>\").replace(/{m}/g,\"</th><td>\").replace(/{e}/g,\"</td></tr>\").replace(/{t}/g,\"%'><div style='text-align:center;font-weight:\");"
"var s=x.responseText.replace(/{t}/g,\"<table style='width:100%'>\").replace(/{s}/g,\"<tr><th>\").replace(/{m}/g,\"</th><td>\").replace(/{e}/g,\"</td></tr>\").replace(/{c}/g,\"%'><div style='text-align:center;font-weight:\");"
"document.getElementById('l1').innerHTML=s;"
"}"
"};"
@ -73,7 +73,9 @@ const char HTTP_HEAD[] PROGMEM =
"}"
"function lc(p){"
"la('?t='+p);"
"}"
"}";
const char HTTP_HEAD_STYLE[] PROGMEM =
"</script>"
"<style>"
@ -83,7 +85,7 @@ const char HTTP_HEAD[] PROGMEM =
"textarea{resize:none;width:98%;height:318px;padding:5px;overflow:auto;}"
"body{text-align:center;font-family:verdana;}"
"td{padding:0px;}"
"button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;-webkit-transition-duration:0.4s;transition-duration:0.4s;}"
"button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;-webkit-transition-duration:0.4s;transition-duration:0.4s;cursor:pointer;}"
"button:hover{background-color:#006cba;}"
"a{text-decoration:none;}"
".p{float:left;text-align:left;}"
@ -96,10 +98,14 @@ const char HTTP_HEAD[] PROGMEM =
#ifdef BE_MINIMAL
"<div style='text-align:center;color:red;'><h3>" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "</h3></div>"
#endif
#ifdef LANGUAGE_MODULE_NAME
"<div style='text-align:center;'><h3>" D_MODULE " {ha</h3><h2>{h}</h2></div>";
#else
"<div style='text-align:center;'><h3>{ha " D_MODULE "</h3><h2>{h}</h2></div>";
#endif
const char HTTP_SCRIPT_CONSOL[] PROGMEM =
"var sn=0;" // Scroll position
"var id=99;" // Get most of weblog initially
"var id=0;" // Get most of weblog initially
"function l(p){" // Console log and command service
"var c,o,t;"
"clearTimeout(lt);"
@ -190,6 +196,12 @@ const char HTTP_BTN_MENU4[] PROGMEM =
"<br/><form action='rs' method='get'><button>" D_RESTORE_CONFIGURATION "</button></form>";
const char HTTP_BTN_MAIN[] PROGMEM =
"<br/><br/><form action='.' method='get'><button>" D_MAIN_MENU "</button></form>";
const char HTTP_FORM_LOGIN[] PROGMEM =
"<form method='post' action='/'>"
"<br/><b>" D_USER "</b><br/><input name='USER1' placeholder='" D_USER "'><br/>"
"<br/><b>" D_PASSWORD "</b><br/><input name='PASS1' type='password' placeholder='" D_PASSWORD "'><br/>"
"<br/>"
"<br/><button>" D_OK "</button></form>";
const char HTTP_BTN_CONF[] PROGMEM =
"<br/><br/><form action='cn' method='get'><button>" D_CONFIGURATION "</button></form>";
const char HTTP_FORM_MODULE[] PROGMEM =
@ -204,9 +216,9 @@ const char HTTP_FORM_WIFI[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_WIFI_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='1' hidden><input id='r' name='r' value='1' hidden>"
"<br/><b>" D_AP1_SSID "</b> (" STA_SSID1 ")<br/><input id='s1' name='s1' placeholder='" STA_SSID1 "' value='{s1'><br/>"
"<br/><b>" D_AP1_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" STA_PASS1 "' value='{p1'><br/>"
"<br/><b>" D_AP1_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_AP1_PASSWORD "' value='********'><br/>"
"<br/><b>" D_AP2_SSID "</b> (" STA_SSID2 ")<br/><input id='s2' name='s2' placeholder='" STA_SSID2 "' value='{s2'><br/>"
"<br/><b>" D_AP2_PASSWORD "</b><br/><input id='p2' name='p2' type='password' placeholder='" STA_PASS2 "' value='{p2'><br/>"
"<br/><b>" D_AP2_PASSWORD "</b><br/><input id='p2' name='p2' type='password' placeholder='" D_AP2_PASSWORD "' value='********'><br/>"
"<br/><b>" D_HOSTNAME "</b> (" WIFI_HOSTNAME ")<br/><input id='h' name='h' placeholder='" WIFI_HOSTNAME" ' value='{h1'><br/>";
const char HTTP_FORM_MQTT[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_MQTT_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
@ -236,7 +248,7 @@ const char HTTP_FORM_LOG3[] PROGMEM =
const char HTTP_FORM_OTHER[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_OTHER_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='5' hidden><input id='r' name='r' value='1' hidden>"
"<br/><b>" D_WEB_ADMIN_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" WEB_PASSWORD "' value='{p1'><br/>"
"<br/><b>" D_WEB_ADMIN_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_WEB_ADMIN_PASSWORD "' value='********'><br/>"
"<br/><input style='width:10%;' id='b1' name='b1' type='checkbox'{r1><b>" D_MQTT_ENABLE "</b><br/>";
const char HTTP_FORM_OTHER2[] PROGMEM =
"<br/><b>" D_FRIENDLY_NAME " {1</b> ({2)<br/><input id='a{1' name='a{1' placeholder='{2' value='{3'><br/>";
@ -244,8 +256,8 @@ const char HTTP_FORM_OTHER[] PROGMEM =
const char HTTP_FORM_OTHER3a[] PROGMEM =
"<br/><fieldset><legend><b>&nbsp;" D_EMULATION "&nbsp;</b></legend>";
const char HTTP_FORM_OTHER3b[] PROGMEM =
"<br/><input style='width:10%;' id='b2' name='b2' type='radio' value='{1'{2><b>{3</b>{4";
#endif // USE_EMULATION
"<br/><input style='width:10%;' id='r{1' name='b2' type='radio' value='{1'{2><b>{3</b>{4"; // Different id only used for labels
#endif // USE_EMULATION
const char HTTP_FORM_END[] PROGMEM =
"<br/><button type='submit'>" D_SAVE "</button></form></fieldset>";
const char HTTP_FORM_RST[] PROGMEM =
@ -267,18 +279,18 @@ const char HTTP_FORM_RST_UPG[] PROGMEM =
"</div>"
"<div id='f2' name='f2' style='display:none;text-align:center;'><b>" D_UPLOAD_STARTED " ...</b></div>";
const char HTTP_FORM_CMND[] PROGMEM =
"<br/><textarea readonly id='t1' name='t1' cols='" STR(MESSZ) "' wrap='off'></textarea><br/><br/>"
"<br/><textarea readonly id='t1' name='t1' cols='340' wrap='off'></textarea><br/><br/>"
"<form method='get' onsubmit='return l(1);'>"
"<input id='c1' name='c1' placeholder='" D_ENTER_COMMAND "' autofocus><br/>"
// "<br/><button type='submit'>Send command</button>"
"</form>";
const char HTTP_TABLE100[] PROGMEM =
"<table width='100%'>";
"<table style='width:100%'>";
const char HTTP_COUNTER[] PROGMEM =
"<br/><div id='t' name='t' style='text-align:center;'></div>";
const char HTTP_END[] PROGMEM =
"<br/>"
"<div style='text-align:right;font-size:11px;'><hr/><a href='" D_WEBLINK "' target='_blank' style='color:#aaa;'>" D_PROGRAMNAME " " VERSION_STRING " " D_BY " " D_AUTHOR "</a></div>"
"<div style='text-align:right;font-size:11px;'><hr/><a href='" D_WEBLINK "' target='_blank' style='color:#aaa;'>" D_PROGRAMNAME " {mv " D_BY " " D_AUTHOR "</a></div>"
"</div>"
"</body>"
"</html>";
@ -302,6 +314,14 @@ uint8_t upload_error = 0;
uint8_t upload_file_type;
uint8_t upload_progress_dot_count;
// Helper function to avoid code duplication (saves 4k Flash)
static void WebGetArg(const char* arg, char* out, size_t max)
{
String s = WebServer->arg(arg);
strncpy(out, s.c_str(), max);
out[max-1] = '\0'; // Ensure terminating NUL
}
void StartWebserver(int type, IPAddress ipweb)
{
if (!webserver_state) {
@ -402,18 +422,24 @@ void PollDnsWebserver()
}
}
/*********************************************************************************************/
void SetHeader()
{
WebServer->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate"));
WebServer->sendHeader(F("Pragma"), F("no-cache"));
WebServer->sendHeader(F("Expires"), F("-1"));
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
WebServer->sendHeader(F("Access-Control-Allow-Origin"), F("*"));
#endif
}
void ShowPage(String &page)
void ShowPage(String &page, bool auth)
{
if((HTTP_ADMIN == webserver_state) && (Settings.web_password[0] != 0) && !WebServer->authenticate(WEB_USERNAME, Settings.web_password)) {
if (auth && (Settings.web_password[0] != 0) && !WebServer->authenticate(WEB_USERNAME, Settings.web_password)) {
return WebServer->requestAuthentication();
}
page.replace(F("{ha"), my_module.name);
page.replace(F("{h}"), Settings.friendlyname[0]);
if (HTTP_MANAGER == webserver_state) {
@ -423,13 +449,29 @@ void ShowPage(String &page)
}
}
page += FPSTR(HTTP_END);
page.replace(F("{mv"), my_version);
SetHeader();
WebServer->send(200, FPSTR(HDR_CTYPE_HTML), page);
}
void ShowPage(String &page)
{
ShowPage(page, true);
}
/*********************************************************************************************/
void HandleWifiLogin()
{
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR( D_CONFIGURE_WIFI ));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_LOGIN);
ShowPage(page, false); // false means show page no matter if the client has or has not credentials
}
void HandleRoot()
{
// AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_MAIN_MENU));
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_MAIN_MENU);
if (CaptivePortal()) { // If captive portal redirect instead of displaying the page.
@ -437,31 +479,47 @@ void HandleRoot()
}
if (HTTP_MANAGER == webserver_state) {
HandleWifiConfiguration();
if ((Settings.web_password[0] != 0) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1"))) {
HandleWifiLogin();
} else {
/*
char tmp1[100];
WebGetArg("USER1", tmp1, sizeof(tmp1));
char tmp2[100];
WebGetArg("PASS1", tmp2, sizeof(tmp2));
if (!(Settings.web_password[0] != 0) || (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, Settings.web_password)))) {
*/
if (!(Settings.web_password[0] != 0) || ((WebServer->arg("USER1") == WEB_USERNAME ) && (WebServer->arg("PASS1") == Settings.web_password ))) {
HandleWifiConfiguration();
} else {
// wrong user and pass
HandleWifiLogin();
}
}
} else {
char stemp[10];
char line[160];
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_MAIN_MENU));
page += FPSTR(HTTP_HEAD_STYLE);
page.replace(F("<body>"), F("<body onload='la()'>"));
page += F("<div id='l1' name='l1'></div>");
if (devices_present) {
if (light_type) {
if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) {
snprintf_P(line, sizeof(line), HTTP_MSG_SLIDER1, LightGetColorTemp());
page += line;
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER1, LightGetColorTemp());
page += mqtt_data;
}
snprintf_P(line, sizeof(line), HTTP_MSG_SLIDER2, Settings.light_dimmer);
page += line;
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER2, Settings.light_dimmer);
page += mqtt_data;
}
page += FPSTR(HTTP_TABLE100);
page += F("<tr>");
for (byte idx = 1; idx <= devices_present; idx++) {
snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx);
snprintf_P(line, sizeof(line), PSTR("<td width='%d%'><button onclick='la(\"?o=%d\");'>%s%s</button></td>"),
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("<td style='width:%d%'><button onclick='la(\"?o=%d\");'>%s%s</button></td>"),
100 / devices_present, idx, (devices_present < 5) ? D_BUTTON_TOGGLE : "", (devices_present > 1) ? stemp : "");
page += line;
page += mqtt_data;
}
page += F("</tr></table>");
}
@ -475,8 +533,8 @@ void HandleRoot()
}
for (byte j = 0; j < 4; j++) {
idx++;
snprintf_P(line, sizeof(line), PSTR("<td width='25%'><button onclick='la(\"?k=%d\");'>%d</button></td>"), idx, idx);
page += line;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("<td style='width:25%'><button onclick='la(\"?k=%d\");'>%d</button></td>"), idx, idx);
page += mqtt_data;
}
}
page += F("</tr></table>");
@ -493,54 +551,49 @@ void HandleRoot()
void HandleAjaxStatusRefresh()
{
char svalue[80];
char tmp[100];
if (strlen(WebServer->arg("o").c_str())) {
ExecuteCommandPower(atoi(WebServer->arg("o").c_str()), 2);
WebGetArg("o", tmp, sizeof(tmp));
if (strlen(tmp)) {
ExecuteCommandPower(atoi(tmp), POWER_TOGGLE);
}
if (strlen(WebServer->arg("d").c_str())) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_DIMMER " %s"), WebServer->arg("d").c_str());
WebGetArg("d", tmp, sizeof(tmp));
if (strlen(tmp)) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_DIMMER " %s"), tmp);
ExecuteCommand(svalue);
}
if (strlen(WebServer->arg("t").c_str())) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_COLORTEMPERATURE " %s"), WebServer->arg("t").c_str());
WebGetArg("t", tmp, sizeof(tmp));
if (strlen(tmp)) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_COLORTEMPERATURE " %s"), tmp);
ExecuteCommand(svalue);
}
if (strlen(WebServer->arg("k").c_str())) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_RFKEY "%s"), WebServer->arg("k").c_str());
WebGetArg("k", tmp, sizeof(tmp));
if (strlen(tmp)) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_RFKEY "%s"), tmp);
ExecuteCommand(svalue);
}
String page = "";
mqtt_data[0] = '\0';
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{t}"));
XsnsCall(FUNC_WEB_APPEND);
if (strlen(mqtt_data)) {
page += FPSTR(HTTP_TABLE100);
page += mqtt_data;
page += F("</table>");
if (D_DECIMAL_SEPARATOR[0] != '.') {
for (uint16_t i = 0; i < strlen(mqtt_data); i++) {
if ('.' == mqtt_data[i]) {
mqtt_data[i] = D_DECIMAL_SEPARATOR[0];
}
}
}
char line[80];
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s</table>"), mqtt_data);
if (devices_present) {
page += FPSTR(HTTP_TABLE100);
page += F("<tr>");
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{t}<tr>"), mqtt_data);
uint8_t fsize = (devices_present < 5) ? 70 - (devices_present * 8) : 32;
for (byte idx = 1; idx <= devices_present; idx++) {
snprintf_P(svalue, sizeof(svalue), PSTR("%d"), bitRead(power, idx -1));
// snprintf_P(line, sizeof(line), PSTR("<td style='width:%d%'><div style='text-align:center;font-weight:%s;font-size:%dpx'>%s</div></td>"),
snprintf_P(line, sizeof(line), PSTR("<td width='%d{t}%s;font-size:%dpx'>%s</div></td>"), // {t} = %'><div style='text-align:center;font-weight:
100 / devices_present, (bitRead(power, idx -1)) ? "bold" : "normal", fsize, (devices_present < 5) ? GetStateText(bitRead(power, idx -1)) : svalue);
page += line;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s<td style='width:%d{c}%s;font-size:%dpx'>%s</div></td>"), // {c} = %'><div style='text-align:center;font-weight:
mqtt_data, 100 / devices_present, (bitRead(power, idx -1)) ? "bold" : "normal", fsize, (devices_present < 5) ? GetStateText(bitRead(power, idx -1)) : svalue);
}
page += F("</tr></table>");
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s</tr></table>"), mqtt_data);
}
/*
* Will interrupt user action when selected
if (light_type) {
snprintf_P(line, sizeof(line), PSTR("<input type='range' min='1' max='100' value='%d' onchange='lb(value)'>"),
Settings.light_dimmer);
page += line;
}
*/
WebServer->send(200, FPSTR(HDR_CTYPE_HTML), page);
WebServer->send(200, FPSTR(HDR_CTYPE_HTML), mqtt_data);
}
boolean HttpUser()
@ -561,6 +614,7 @@ void HandleConfiguration()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURATION));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_BTN_MENU2);
if (Settings.flag.mqtt_enabled) {
page += FPSTR(HTTP_BTN_MENU3);
@ -632,56 +686,57 @@ void HandleModuleConfiguration()
return;
}
char stemp[20];
char line[160];
uint8_t midx;
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MODULE);
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_MODULE));
page += FPSTR(HTTP_FORM_MODULE);
snprintf_P(stemp, sizeof(stemp), kModules[MODULE].name);
page.replace(F("{mt"), stemp);
page += FPSTR(HTTP_SCRIPT_MODULE1);
for (byte i = 0; i < MAXMODULE; i++) {
midx = pgm_read_byte(kNiceList + i);
snprintf_P(stemp, sizeof(stemp), kModules[midx].name);
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SCRIPT_MODULE2, midx, midx +1, stemp);
page += mqtt_data;
}
page += FPSTR(HTTP_SCRIPT_MODULE3);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("sk(%d,99);o0=\""), Settings.module); // g99
page += mqtt_data;
mytmplt cmodule;
memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule));
String func = FPSTR(HTTP_SCRIPT_MODULE1);
for (byte i = 0; i < MAXMODULE; i++) {
midx = pgm_read_byte(kNiceList + i);
snprintf_P(stemp, sizeof(stemp), kModules[midx].name);
snprintf_P(line, sizeof(line), HTTP_SCRIPT_MODULE2, midx, midx +1, stemp);
func += line;
}
func += FPSTR(HTTP_SCRIPT_MODULE3);
snprintf_P(line, sizeof(line), PSTR("sk(%d,99);o0=\""), Settings.module); // g99
func += line;
for (byte j = 0; j < GPIO_SENSOR_END; j++) {
if (!GetUsedInModule(j, cmodule.gp.io)) {
snprintf_P(stemp, sizeof(stemp), kSensors[j]);
snprintf_P(line, sizeof(line), HTTP_SCRIPT_MODULE2, j, j, stemp);
func += line;
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SCRIPT_MODULE2, j, j, GetTextIndexed(stemp, sizeof(stemp), j, kSensorNames));
page += mqtt_data;
}
}
func += FPSTR(HTTP_SCRIPT_MODULE3);
page += FPSTR(HTTP_SCRIPT_MODULE3);
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (GPIO_USER == cmodule.gp.io[i]) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("sk(%d,%d);"), my_module.gp.io[i], i); // g0 - g16
page += mqtt_data;
}
}
page += F("}");
page += FPSTR(HTTP_HEAD_STYLE);
page.replace(F("<body>"), F("<body onload='sl()'>"));
page += FPSTR(HTTP_FORM_MODULE);
snprintf_P(stemp, sizeof(stemp), kModules[MODULE].name);
page.replace(F("{mt"), stemp);
page += F("<br/><table>");
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (GPIO_USER == cmodule.gp.io[i]) {
snprintf_P(stemp, 3, PINS_WEMOS +i*2);
snprintf_P(line, sizeof(line), PSTR("<tr><td width='190'>%s <b>" D_GPIO "%d</b> %s</td><td width='126'><select id='g%d' name='g%d'></select></td></tr>"),
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("<tr><td style='width:190px'>%s <b>" D_GPIO "%d</b> %s</td><td style='width:126px'><select id='g%d' name='g%d'></select></td></tr>"),
(WEMOS==Settings.module)?stemp:"", i, (0==i)? D_SENSOR_BUTTON "1":(1==i)? D_SERIAL_OUT :(3==i)? D_SERIAL_IN :(12==i)? D_SENSOR_RELAY "1":(13==i)? D_SENSOR_LED "1i":(14==i)? D_SENSOR :"", i, i);
page += line;
snprintf_P(line, sizeof(line), PSTR("sk(%d,%d);"), my_module.gp.io[i], i); // g0 - g16
func += line;
page += mqtt_data;
}
}
page += F("</table>");
func += F("}</script>");
page.replace(F("</script>"), func);
page.replace(F("<body>"), F("<body onload='sl()'>"));
page += FPSTR(HTTP_FORM_END);
page += FPSTR(HTTP_BTN_CONF);
ShowPage(page);
@ -707,6 +762,7 @@ void HandleWifi(boolean scan)
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_WIFI));
page += FPSTR(HTTP_HEAD_STYLE);
if (scan) {
#ifdef USE_EMULATION
@ -786,16 +842,15 @@ void HandleWifi(boolean scan)
page += FPSTR(HTTP_FORM_WIFI);
page.replace(F("{h1"), Settings.hostname);
page.replace(F("{s1"), Settings.sta_ssid[0]);
page.replace(F("{p1"), Settings.sta_pwd[0]);
page.replace(F("{s2"), Settings.sta_ssid[1]);
page.replace(F("{p2"), Settings.sta_pwd[1]);
page += FPSTR(HTTP_FORM_END);
if (HTTP_MANAGER == webserver_state) {
page += FPSTR(HTTP_BTN_RSTRT);
} else {
page += FPSTR(HTTP_BTN_CONF);
}
ShowPage(page);
// ShowPage(page);
ShowPage(page, !(HTTP_MANAGER == webserver_state));
}
void HandleMqttConfiguration()
@ -807,6 +862,7 @@ void HandleMqttConfiguration()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_MQTT));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_MQTT);
char str[sizeof(Settings.mqtt_client)];
GetMqttClient(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client));
@ -832,6 +888,7 @@ void HandleLoggingConfiguration()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_LOGGING));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_LOG1);
for (byte idx = 0; idx < 3; idx++) {
page += FPSTR(HTTP_FORM_LOG2);
@ -881,13 +938,17 @@ void HandleOtherConfiguration()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_OTHER));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_OTHER);
page.replace(F("{p1"), Settings.web_password);
page.replace(F("{r1"), (Settings.flag.mqtt_enabled) ? F(" checked") : F(""));
page += FPSTR(HTTP_FORM_OTHER2);
page.replace(F("{1"), F("1"));
page.replace(F("{2"), FRIENDLY_NAME);
page.replace(F("{3"), Settings.friendlyname[0]);
uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present;
for (byte i = 0; i < maxfn; i++) {
page += FPSTR(HTTP_FORM_OTHER2);
page.replace(F("{1"), String(i +1));
snprintf_P(stemp, sizeof(stemp), PSTR(FRIENDLY_NAME"%d"), i +1);
page.replace(F("{2"), (i) ? stemp : FRIENDLY_NAME);
page.replace(F("{3"), Settings.friendlyname[i]);
}
#ifdef USE_EMULATION
page += FPSTR(HTTP_FORM_OTHER3a);
for (byte i = 0; i < EMUL_MAX; i++) {
@ -898,14 +959,6 @@ void HandleOtherConfiguration()
page.replace(F("{4"), (i == EMUL_NONE) ? F("") : (i == EMUL_WEMO) ? F(" " D_SINGLE_DEVICE) : F(" " D_MULTI_DEVICE));
}
page += F("<br/>");
uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present;
for (byte i = 1; i < maxfn; i++) {
page += FPSTR(HTTP_FORM_OTHER2);
page.replace(F("{1"), String(i +1));
snprintf_P(stemp, sizeof(stemp), PSTR(FRIENDLY_NAME"%d"), i +1);
page.replace(F("{2"), stemp);
page.replace(F("{3"), Settings.friendlyname[i]);
}
page += F("<br/></fieldset>");
#endif // USE_EMULATION
page += FPSTR(HTTP_FORM_END);
@ -926,8 +979,7 @@ void HandleBackupConfiguration()
WebServer->setContentLength(sizeof(buffer));
char attachment[100];
snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_" VERSION_STRING ".dmp"),
Settings.friendlyname[0]);
snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"), Settings.friendlyname[0], my_version);
WebServer->sendHeader(F("Content-Disposition"), attachment);
WebServer->send(200, FPSTR(HDR_CTYPE_STREAM), "");
memcpy(buffer, &Settings, sizeof(buffer));
@ -955,57 +1007,81 @@ void HandleSaveSettings()
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_SAVE_CONFIGURATION);
if (strlen(WebServer->arg("w").c_str())) {
what = atoi(WebServer->arg("w").c_str());
char tmp[100];
WebGetArg("w", tmp, sizeof(tmp));
if (strlen(tmp)) {
what = atoi(tmp);
}
switch (what) {
case 1:
strlcpy(Settings.hostname, (!strlen(WebServer->arg("h").c_str())) ? WIFI_HOSTNAME : WebServer->arg("h").c_str(), sizeof(Settings.hostname));
WebGetArg("h", tmp, sizeof(tmp));
strlcpy(Settings.hostname, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp, sizeof(Settings.hostname));
if (strstr(Settings.hostname,"%")) {
strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname));
}
strlcpy(Settings.sta_ssid[0], (!strlen(WebServer->arg("s1").c_str())) ? STA_SSID1 : WebServer->arg("s1").c_str(), sizeof(Settings.sta_ssid[0]));
strlcpy(Settings.sta_pwd[0], (!strlen(WebServer->arg("p1").c_str())) ? STA_PASS1 : WebServer->arg("p1").c_str(), sizeof(Settings.sta_pwd[0]));
strlcpy(Settings.sta_ssid[1], (!strlen(WebServer->arg("s2").c_str())) ? STA_SSID2 : WebServer->arg("s2").c_str(), sizeof(Settings.sta_ssid[1]));
strlcpy(Settings.sta_pwd[1], (!strlen(WebServer->arg("p2").c_str())) ? STA_PASS2 : WebServer->arg("p2").c_str(), sizeof(Settings.sta_pwd[1]));
WebGetArg("s1", tmp, sizeof(tmp));
strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? STA_SSID1 : tmp, sizeof(Settings.sta_ssid[0]));
WebGetArg("s2", tmp, sizeof(tmp));
strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1]));
// WebGetArg("s1", tmp, sizeof(tmp));
// strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[0]));
// WebGetArg("s2", tmp, sizeof(tmp));
// strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[1]));
WebGetArg("p1", tmp, sizeof(tmp));
strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0]));
WebGetArg("p2", tmp, sizeof(tmp));
strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1]));
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_PASSWORD "1 %s, " D_CMND_SSID "2 %s, " D_CMND_PASSWORD "2 %s"),
Settings.hostname, Settings.sta_ssid[0], Settings.sta_pwd[0], Settings.sta_ssid[1], Settings.sta_pwd[1]);
AddLog(LOG_LEVEL_INFO);
result += F("<br/>" D_TRYING_TO_CONNECT "<br/>");
break;
case 2:
strlcpy(stemp, (!strlen(WebServer->arg("mt").c_str())) ? MQTT_TOPIC : WebServer->arg("mt").c_str(), sizeof(stemp));
WebGetArg("mt", tmp, sizeof(tmp));
strlcpy(stemp, (!strlen(tmp)) ? MQTT_TOPIC : tmp, sizeof(stemp));
MakeValidMqtt(0, stemp);
strlcpy(stemp2, (!strlen(WebServer->arg("mf").c_str())) ? MQTT_FULLTOPIC : WebServer->arg("mf").c_str(), sizeof(stemp2));
WebGetArg("mf", tmp, sizeof(tmp));
strlcpy(stemp2, (!strlen(tmp)) ? MQTT_FULLTOPIC : tmp, sizeof(stemp2));
MakeValidMqtt(1,stemp2);
if ((strcmp(stemp, Settings.mqtt_topic)) || (strcmp(stemp2, Settings.mqtt_fulltopic))) {
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
MqttPublishPrefixTopic_P(2, S_LWT, true); // Offline or remove previous retained topic
MqttPublishPrefixTopic_P(TELE, S_LWT, true); // Offline or remove previous retained topic
}
strlcpy(Settings.mqtt_topic, stemp, sizeof(Settings.mqtt_topic));
strlcpy(Settings.mqtt_fulltopic, stemp2, sizeof(Settings.mqtt_fulltopic));
strlcpy(Settings.mqtt_host, (!strlen(WebServer->arg("mh").c_str())) ? MQTT_HOST : (!strcmp(WebServer->arg("mh").c_str(),"0")) ? "" : WebServer->arg("mh").c_str(), sizeof(Settings.mqtt_host));
Settings.mqtt_port = (!strlen(WebServer->arg("ml").c_str())) ? MQTT_PORT : atoi(WebServer->arg("ml").c_str());
strlcpy(Settings.mqtt_client, (!strlen(WebServer->arg("mc").c_str())) ? MQTT_CLIENT_ID : WebServer->arg("mc").c_str(), sizeof(Settings.mqtt_client));
strlcpy(Settings.mqtt_user, (!strlen(WebServer->arg("mu").c_str())) ? MQTT_USER : (!strcmp(WebServer->arg("mu").c_str(),"0")) ? "" : WebServer->arg("mu").c_str(), sizeof(Settings.mqtt_user));
strlcpy(Settings.mqtt_pwd, (!strlen(WebServer->arg("mp").c_str())) ? MQTT_PASS : (!strcmp(WebServer->arg("mp").c_str(),"0")) ? "" : WebServer->arg("mp").c_str(), sizeof(Settings.mqtt_pwd));
WebGetArg("mh", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_host, (!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_host));
WebGetArg("ml", tmp, sizeof(tmp));
Settings.mqtt_port = (!strlen(tmp)) ? MQTT_PORT : atoi(tmp);
WebGetArg("mc", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_client, (!strlen(tmp)) ? MQTT_CLIENT_ID : tmp, sizeof(Settings.mqtt_client));
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)) ? MQTT_PASS : (!strcmp(tmp,"0")) ? "" : 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_MQTTPASSWORD " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"),
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_pwd, Settings.mqtt_topic, Settings.mqtt_fulltopic);
AddLog(LOG_LEVEL_INFO);
break;
case 3:
Settings.seriallog_level = (!strlen(WebServer->arg("ls").c_str())) ? SERIAL_LOG_LEVEL : atoi(WebServer->arg("ls").c_str());
Settings.weblog_level = (!strlen(WebServer->arg("lw").c_str())) ? WEB_LOG_LEVEL : atoi(WebServer->arg("lw").c_str());
Settings.syslog_level = (!strlen(WebServer->arg("ll").c_str())) ? SYS_LOG_LEVEL : atoi(WebServer->arg("ll").c_str());
WebGetArg("ls", tmp, sizeof(tmp));
Settings.seriallog_level = (!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp);
WebGetArg("lw", tmp, sizeof(tmp));
Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp);
WebGetArg("ll", tmp, sizeof(tmp));
Settings.syslog_level = (!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp);
syslog_level = Settings.syslog_level;
syslog_timer = 0;
strlcpy(Settings.syslog_host, (!strlen(WebServer->arg("lh").c_str())) ? SYS_LOG_HOST : WebServer->arg("lh").c_str(), sizeof(Settings.syslog_host));
Settings.syslog_port = (!strlen(WebServer->arg("lp").c_str())) ? SYS_LOG_PORT : atoi(WebServer->arg("lp").c_str());
Settings.tele_period = (!strlen(WebServer->arg("lt").c_str())) ? TELE_PERIOD : atoi(WebServer->arg("lt").c_str());
WebGetArg("lh", tmp, sizeof(tmp));
strlcpy(Settings.syslog_host, (!strlen(tmp)) ? SYS_LOG_HOST : tmp, sizeof(Settings.syslog_host));
WebGetArg("lp", tmp, sizeof(tmp));
Settings.syslog_port = (!strlen(tmp)) ? SYS_LOG_PORT : atoi(tmp);
WebGetArg("lt", tmp, sizeof(tmp));
Settings.tele_period = (!strlen(tmp)) ? TELE_PERIOD : atoi(tmp);
if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) {
Settings.tele_period = 10; // Do not allow periods < 10 seconds
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"),
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"),
Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period);
AddLog(LOG_LEVEL_INFO);
break;
@ -1015,21 +1091,28 @@ snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D
break;
#endif // USE_DOMOTICZ
case 5:
strlcpy(Settings.web_password, (!strlen(WebServer->arg("p1").c_str())) ? WEB_PASSWORD : (!strcmp(WebServer->arg("p1").c_str(),"0")) ? "" : WebServer->arg("p1").c_str(), sizeof(Settings.web_password));
WebGetArg("p1", tmp, sizeof(tmp));
strlcpy(Settings.web_password, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.web_password : tmp, sizeof(Settings.web_password));
Settings.flag.mqtt_enabled = WebServer->hasArg("b1");
#ifdef USE_EMULATION
Settings.flag2.emulation = (!strlen(WebServer->arg("b2").c_str())) ? 0 : atoi(WebServer->arg("b2").c_str());
WebGetArg("b2", tmp, sizeof(tmp));
Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp);
#endif // USE_EMULATION
strlcpy(Settings.friendlyname[0], (!strlen(WebServer->arg("a1").c_str())) ? FRIENDLY_NAME : WebServer->arg("a1").c_str(), sizeof(Settings.friendlyname[0]));
strlcpy(Settings.friendlyname[1], (!strlen(WebServer->arg("a2").c_str())) ? FRIENDLY_NAME"2" : WebServer->arg("a2").c_str(), sizeof(Settings.friendlyname[1]));
strlcpy(Settings.friendlyname[2], (!strlen(WebServer->arg("a3").c_str())) ? FRIENDLY_NAME"3" : WebServer->arg("a3").c_str(), sizeof(Settings.friendlyname[2]));
strlcpy(Settings.friendlyname[3], (!strlen(WebServer->arg("a4").c_str())) ? FRIENDLY_NAME"4" : WebServer->arg("a4").c_str(), sizeof(Settings.friendlyname[3]));
WebGetArg("a1", tmp, sizeof(tmp));
strlcpy(Settings.friendlyname[0], (!strlen(tmp)) ? FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[0]));
WebGetArg("a2", tmp, sizeof(tmp));
strlcpy(Settings.friendlyname[1], (!strlen(tmp)) ? FRIENDLY_NAME"2" : tmp, sizeof(Settings.friendlyname[1]));
WebGetArg("a3", tmp, sizeof(tmp));
strlcpy(Settings.friendlyname[2], (!strlen(tmp)) ? FRIENDLY_NAME"3" : tmp, sizeof(Settings.friendlyname[2]));
WebGetArg("a4", tmp, sizeof(tmp));
strlcpy(Settings.friendlyname[3], (!strlen(tmp)) ? FRIENDLY_NAME"4" : tmp, sizeof(Settings.friendlyname[3]));
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME " %s, %s, %s, %s"),
GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation, Settings.friendlyname[0], Settings.friendlyname[1], Settings.friendlyname[2], Settings.friendlyname[3]);
AddLog(LOG_LEVEL_INFO);
break;
case 6:
byte new_module = (!strlen(WebServer->arg("g99").c_str())) ? MODULE : atoi(WebServer->arg("g99").c_str());
WebGetArg("g99", tmp, sizeof(tmp));
byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp);
Settings.last_module = Settings.module;
Settings.module = new_module;
mytmplt cmodule;
@ -1041,7 +1124,8 @@ snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D
} else {
if (GPIO_USER == cmodule.gp.io[i]) {
snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i);
Settings.my_gp.io[i] = (!strlen(WebServer->arg(stemp).c_str())) ? 0 : atoi(WebServer->arg(stemp).c_str());
WebGetArg(stemp, tmp, sizeof(tmp));
Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]);
}
}
@ -1052,10 +1136,12 @@ snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D
break;
}
restart = (!strlen(WebServer->arg("r").c_str())) ? 1 : atoi(WebServer->arg("r").c_str());
WebGetArg("r", tmp, sizeof(tmp));
restart = (!strlen(tmp)) ? 1 : atoi(tmp);
if (restart) {
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_SAVE_CONFIGURATION));
page += FPSTR(HTTP_HEAD_STYLE);
page += F("<div style='text-align:center;'><b>" D_CONFIGURATION_SAVED "</b><br/>");
page += result;
page += F("</div>");
@ -1079,12 +1165,13 @@ void HandleResetConfiguration()
return;
}
char svalue[16];
char svalue[33];
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESET_CONFIGURATION);
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_RESET_CONFIGURATION));
page += FPSTR(HTTP_HEAD_STYLE);
page += F("<div style='text-align:center;'>" D_CONFIGURATION_RESET "</div>");
page += FPSTR(HTTP_MSG_RSTRT);
page += FPSTR(HTTP_BTN_MAIN);
@ -1103,6 +1190,7 @@ void HandleRestoreConfiguration()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_RESTORE_CONFIGURATION));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_RST);
page += FPSTR(HTTP_FORM_RST_UPG);
page.replace(F("{r1"), F(D_RESTORE));
@ -1122,6 +1210,7 @@ void HandleUpgradeFirmware()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_FIRMWARE_UPGRADE));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_UPG);
page.replace(F("{o1"), Settings.ota_url);
page += FPSTR(HTTP_FORM_RST_UPG);
@ -1143,13 +1232,16 @@ void HandleUpgradeFirmwareStart()
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_UPGRADE_STARTED));
WifiConfigCounter();
if (strlen(WebServer->arg("o").c_str())) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_OTAURL " %s"), WebServer->arg("o").c_str());
char tmp[100];
WebGetArg("o", tmp, sizeof(tmp));
if (strlen(tmp)) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_OTAURL " %s"), tmp);
ExecuteCommand(svalue);
}
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_INFORMATION));
page += FPSTR(HTTP_HEAD_STYLE);
page += F("<div style='text-align:center;'><b>" D_UPGRADE_STARTED " ...</b></div>");
page += FPSTR(HTTP_MSG_RSTRT);
page += FPSTR(HTTP_BTN_MAIN);
@ -1174,6 +1266,7 @@ void HandleUploadDone()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_INFORMATION));
page += FPSTR(HTTP_HEAD_STYLE);
page += F("<div style='text-align:center;'><b>" D_UPLOAD " <font color='");
if (upload_error) {
page += F("red'>" D_FAILED "</font></b><br/><br/>");
@ -1235,6 +1328,9 @@ void HandleUploadLoop()
#ifdef USE_EMULATION
UdpDisconnect();
#endif // USE_EMULATION
#ifdef USE_ARILUX_RF
AriluxRfDisable(); // Prevent restart exception on Arilux Interrupt routine
#endif // USE_ARILUX_RF
if (Settings.flag.mqtt_enabled) {
MqttClient.disconnect();
}
@ -1333,7 +1429,11 @@ void HandleHttpCommand()
uint8_t valid = 1;
if (Settings.web_password[0] != 0) {
if (!(!strcmp(WebServer->arg("user").c_str(),WEB_USERNAME) && !strcmp(WebServer->arg("password").c_str(),Settings.web_password))) {
char tmp1[100];
WebGetArg("user", tmp1, sizeof(tmp1));
char tmp2[100];
WebGetArg("password", tmp2, sizeof(tmp2));
if (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, Settings.web_password))) {
valid = 0;
}
}
@ -1341,9 +1441,8 @@ void HandleHttpCommand()
String message = F("{\"" D_RSLT_WARNING "\":\"");
if (valid) {
byte curridx = web_log_index;
if (strlen(WebServer->arg("cmnd").c_str())) {
// snprintf_P(svalue, sizeof(svalue), WebServer->arg("cmnd").c_str()); // Processes FullTopic %p
strlcpy(svalue, WebServer->arg("cmnd").c_str(), sizeof(svalue)); // Fixed 5.8.0b
WebGetArg("cmnd", svalue, sizeof(svalue));
if (strlen(svalue)) {
// byte syslog_now = syslog_level;
// syslog_level = 0; // Disable UDP syslog to not trigger hardware WDT - Seems to work fine since 5.7.1d (global logging)
ExecuteCommand(svalue);
@ -1354,19 +1453,23 @@ void HandleHttpCommand()
byte counter = curridx;
message = F("{");
do {
if (web_log[counter].length()) {
char* tmp;
size_t len;
GetLog(counter, &tmp, &len);
if (len) {
// [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
if (web_log[counter].indexOf("{") > 0) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
char* JSON = (char*)memchr(tmp, '{', len);
if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
if (message.length() > 1) {
message += F(",");
}
message += web_log[counter].substring(web_log[counter].indexOf("{")+1,web_log[counter].length()-1);
size_t JSONlen = len - (JSON - tmp);
strlcpy(mqtt_data, JSON +1, JSONlen -2);
message += mqtt_data;
}
}
counter++;
if (counter > MAX_LOG_LINES -1) {
counter = 0;
}
if (!counter) counter++; // Skip 0 as it is not allowed
} while (counter != web_log_index);
message += F("}");
} else {
@ -1375,6 +1478,7 @@ void HandleHttpCommand()
} else {
message += F(D_NEED_USER_AND_PASSWORD "\"}");
}
SetHeader();
WebServer->send(200, FPSTR(HDR_CTYPE_JSON), message);
}
@ -1388,6 +1492,7 @@ void HandleConsole()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONSOLE));
page += FPSTR(HTTP_HEAD_STYLE);
page.replace(F("</script>"), FPSTR(HTTP_SCRIPT_CONSOL));
page.replace(F("<body>"), F("<body onload='l()'>"));
page += FPSTR(HTTP_FORM_CMND);
@ -1402,11 +1507,10 @@ void HandleAjaxConsoleRefresh()
}
char svalue[INPUT_BUFFER_SIZE]; // big to serve Backlog
byte cflg = 1;
byte counter = 99;
byte counter = 0; // Initial start, should never be 0 again
if (strlen(WebServer->arg("c1").c_str())) {
// snprintf_P(svalue, sizeof(svalue), WebServer->arg("c1").c_str()); // Processes FullTopic %p
strlcpy(svalue, WebServer->arg("c1").c_str(), sizeof(svalue)); // Fixed 5.8.0b
WebGetArg("c1", svalue, sizeof(svalue));
if (strlen(svalue)) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), svalue);
AddLog(LOG_LEVEL_INFO);
// byte syslog_now = syslog_level;
@ -1415,43 +1519,46 @@ void HandleAjaxConsoleRefresh()
// syslog_level = syslog_now;
}
if (strlen(WebServer->arg("c2").c_str())) {
counter = atoi(WebServer->arg("c2").c_str());
WebGetArg("c2", svalue, sizeof(svalue));
if (strlen(svalue)) {
counter = atoi(svalue);
}
String message = F("<r><i>");
message += String(web_log_index);
message += F("</i><j>");
message += String(reset_web_log_flag);
byte last_reset_web_log_flag = reset_web_log_flag;
String message = F("}9"); // Cannot load mqtt_data here as <> will be encoded by replacements below
if (!reset_web_log_flag) {
counter = 99;
counter = 0;
reset_web_log_flag = 1;
}
message += F("</j><l>");
if (counter != web_log_index) {
if (99 == counter) {
if (!counter) {
counter = web_log_index;
cflg = 0;
}
do {
if (web_log[counter].length()) {
char* tmp;
size_t len;
GetLog(counter, &tmp, &len);
if (len) {
if (cflg) {
message += F("\n");
} else {
cflg = 1;
}
String nextline = web_log[counter];
nextline.replace(F("<"), F("%3C")); // XML encoding to fix blank console log in concert with javascript decodeURIComponent
nextline.replace(F(">"), F("%3E"));
nextline.replace(F("&"), F("%26"));
message += nextline;
strlcpy(mqtt_data, tmp, len);
message += mqtt_data;
}
counter++;
if (counter > MAX_LOG_LINES -1) {
counter = 0;
}
if (!counter) counter++; // Skip 0 as it is not allowed
} while (counter != web_log_index);
// XML encoding to fix blank console log in concert with javascript decodeURIComponent
message.replace(F("%"), F("%25")); // Needs to be done first as otherwise the % in %26 will also be converted
message.replace(F("&"), F("%26"));
message.replace(F("<"), F("%3C"));
message.replace(F(">"), F("%3E"));
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("<r><i>%d</i><j>%d</j><l>"), web_log_index, last_reset_web_log_flag);
message.replace(F("}9"), mqtt_data); // Save to load here
message += F("</l></r>");
WebServer->send(200, FPSTR(HDR_CTYPE_XML), message);
}
@ -1469,6 +1576,7 @@ void HandleInformation()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_INFORMATION));
page += FPSTR(HTTP_HEAD_STYLE);
// page += F("<fieldset><legend><b>&nbsp;Information&nbsp;</b></legend>");
page += F("<style>td{padding:0px 5px;}</style>");
@ -1478,11 +1586,11 @@ void HandleInformation()
// }1 = </td></tr><tr><th>
// }2 = </th><td>
String func = FPSTR(HTTP_SCRIPT_INFO_BEGIN);
func += F("<table width='100%'><tr><th>");
func += F(D_PROGRAM_VERSION "}2" VERSION_STRING);
func += F("<table style='width:100%'><tr><th>");
func += F(D_PROGRAM_VERSION "}2"); func += my_version;
func += F("}1" D_BUILD_DATE_AND_TIME "}2"); func += GetBuildDateAndTime();
func += F("}1" D_CORE_AND_SDK_VERSION "}2" ARDUINO_ESP8266_RELEASE "/"); func += String(ESP.getSdkVersion());
func += F("}1" D_UPTIME "}2"); func += String(uptime); func += F(" Hours");
func += F("}1" D_UPTIME "}2"); func += GetUptime();
snprintf_P(stopic, sizeof(stopic), PSTR(" at %X"), GetSettingsAddress());
func += F("}1" D_FLASH_WRITE_COUNT "}2"); func += String(Settings.save_flag); func += stopic;
func += F("}1" D_BOOT_COUNT "}2"); func += String(Settings.bootcount);
@ -1517,7 +1625,7 @@ void HandleInformation()
func += F("}1" D_MQTT_USER "}2"); func += Settings.mqtt_user;
func += F("}1" D_MQTT_TOPIC "}2"); func += Settings.mqtt_topic;
func += F("}1" D_MQTT_GROUP_TOPIC "}2"); func += Settings.mqtt_grptopic;
GetTopic_P(stopic, 0, Settings.mqtt_topic, "");
GetTopic_P(stopic, CMND, Settings.mqtt_topic, "");
func += F("}1" D_MQTT_FULL_TOPIC "}2"); func += stopic;
} else {
@ -1580,6 +1688,7 @@ void HandleRestart()
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_RESTART));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_MSG_RSTRT);
if (HTTP_MANAGER == webserver_state) {
webserver_state = HTTP_ADMIN;
@ -1609,18 +1718,13 @@ void HandleNotFound()
} else
#endif // USE_EMULATION
{
String message = F(D_FILE_NOT_FOUND "\n\nURI: ");
message += WebServer->uri();
message += F("\nMethod: ");
message += (WebServer->method() == HTTP_GET) ? F("GET") : F("POST");
message += F("\nArguments: ");
message += WebServer->args();
message += F("\n");
for ( uint8_t i = 0; i < WebServer->args(); i++ ) {
message += " " + WebServer->argName(i) + ": " + WebServer->arg(i) + "\n";
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"),
WebServer->uri().c_str(), (WebServer->method() == HTTP_GET) ? "GET" : "POST", WebServer->args());
for (uint8_t i = 0; i < WebServer->args(); i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s %s: %s\n"), mqtt_data, WebServer->argName(i).c_str(), WebServer->arg(i).c_str());
}
SetHeader();
WebServer->send(404, FPSTR(HDR_CTYPE_PLAIN), message);
WebServer->send(404, FPSTR(HDR_CTYPE_PLAIN), mqtt_data);
}
}
@ -1631,8 +1735,8 @@ boolean CaptivePortal()
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED));
WebServer->sendHeader(F("Location"), String("http://") + WebServer->client().localIP().toString(), true);
WebServer->send(302, FPSTR(HDR_CTYPE_PLAIN), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
WebServer->client().stop(); // Stop is needed because we sent no content length
WebServer->send(302, FPSTR(HDR_CTYPE_PLAIN), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
WebServer->client().stop(); // Stop is needed because we sent no content length
return true;
}
return false;

View File

@ -99,6 +99,7 @@ uint8_t light_signal_color[5];
uint8_t light_wheel = 0;
uint8_t light_subtype = 0;
uint8_t light_device = 0;
uint8_t light_power = 0;
uint8_t light_update = 1;
uint8_t light_wakeup_active = 0;
@ -107,7 +108,7 @@ uint16_t light_wakeup_counter = 0;
uint8_t light_fixed_color_index = 1;
unsigned long strip_timer_counter = 0; // Bars and Gradient
unsigned long strip_timer_counter = 0; // Bars and Gradient
#ifdef USE_ARILUX_RF
/*********************************************************************************************\
@ -132,9 +133,12 @@ unsigned int arilux_rf_repeat_count = 0;
uint8_t arilux_rf_toggle = 0;
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
#ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves RF misses
//void AriluxRfInterrupt() ICACHE_RAM_ATTR; // As iram is tight and it works this way too
void AriluxRfInterrupt() ICACHE_RAM_ATTR; // As iram is tight and it works this way too
#endif // USE_WS2812_DMA
#endif // ARDUINO_ESP8266_RELEASE_2_3_0
void AriluxRfInterrupt()
{
@ -188,7 +192,7 @@ void AriluxRfHandler()
AddLog(LOG_LEVEL_DEBUG);
if (hostcode == stored_hostcode) {
char command[16];
char command[33];
char value = '-';
command[0] = '\0';
uint8_t keycode = arilux_rf_received_value & 0xFF;
@ -248,8 +252,8 @@ void AriluxRfInit()
void AriluxRfDisable()
{
if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_LED2] < 99)) {
digitalWrite(pin[GPIO_LED2], bitRead(led_inverted, 1)); // Turn off RF
detachInterrupt(pin[GPIO_ARIRFRCV]);
digitalWrite(pin[GPIO_LED2], bitRead(led_inverted, 1)); // Turn off RF
}
}
#endif // USE_ARILUX_RF
@ -337,6 +341,7 @@ void LightInit()
{
uint8_t max_scheme = LS_MAX -1;
light_device = devices_present;
light_subtype = light_type &7;
if (light_type < LT_PWM6) { // PWM
@ -364,13 +369,9 @@ void LightInit()
}
}
if (pin[GPIO_ARIRFRCV] < 99) {
#ifdef USE_ARILUX_RF
AriluxRfInit();
#else
if (pin[GPIO_LED2] < 99) {
digitalWrite(pin[GPIO_LED2], bitRead(led_inverted, 1)); // Turn off RF
}
#endif // USE_ARILUX_RF
}
}
#ifdef USE_WS2812 // ************************************************************************
@ -526,33 +527,58 @@ char* LightGetColor(uint8_t type, char* scolor)
void LightPowerOn()
{
if (Settings.light_dimmer && !(light_power)) {
ExecuteCommandPower(devices_present, 1);
ExecuteCommandPower(light_device, POWER_ON);
}
}
void LightState(uint8_t append)
{
char scolor[25];
char scommand[33];
if (append) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{"));
}
GetPowerDevice(scommand, light_device, sizeof(scommand));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d"),
mqtt_data, scommand, GetStateText(light_power), Settings.light_dimmer);
if (light_subtype > LST_SINGLE) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_COLOR "\":\"%s\""), mqtt_data, LightGetColor(0, scolor));
}
if ((LST_COLDWARM == light_subtype) || (LST_RGBWC == light_subtype)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_COLORTEMPERATURE "\":%d"), mqtt_data, LightGetColorTemp());
}
if (append) {
if (light_subtype >= LST_RGB) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_SCHEME "\":%d"), mqtt_data, Settings.light_scheme);
}
if (LT_WS2812 == light_type) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_WIDTH "\":%d"), mqtt_data, Settings.light_width);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_FADE "\":\"%s\",\"" D_CMND_SPEED "\":%d,\"" D_CMND_LEDTABLE "\":\"%s\""),
mqtt_data, GetStateText(Settings.light_fade), Settings.light_speed, GetStateText(Settings.light_correction));
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
}
}
void LightPreparePower()
{
char scolor[25];
char scommand[16];
if (Settings.light_dimmer && !(light_power)) {
ExecuteCommandPower(devices_present, 7); // No publishPowerState
if (!Settings.flag.not_power_linked) {
ExecuteCommandPower(light_device, POWER_ON_NO_STATE);
}
}
else if (!Settings.light_dimmer && light_power) {
ExecuteCommandPower(devices_present, 6); // No publishPowerState
ExecuteCommandPower(light_device, POWER_OFF_NO_STATE);
}
#ifdef USE_DOMOTICZ
DomoticzUpdatePowerState(devices_present);
DomoticzUpdatePowerState(light_device);
#endif // USE_DOMOTICZ
GetPowerDevice(scommand, devices_present, sizeof(scommand));
if (light_subtype > LST_SINGLE) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d,\"" D_CMND_COLOR "\":\"%s\"}"),
scommand, GetStateText(light_power), Settings.light_dimmer, LightGetColor(0, scolor));
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d}"),
scommand, GetStateText(light_power), Settings.light_dimmer);
}
LightState(0);
}
void LightFade()
@ -636,7 +662,8 @@ void LightRandomColor()
void LightSetPower()
{
light_power = XdrvMailbox.index;
// light_power = XdrvMailbox.index;
light_power = bitRead(XdrvMailbox.index, light_device -1);
if (light_wakeup_active) {
light_wakeup_active--;
}
@ -649,7 +676,7 @@ void LightSetPower()
void LightAnimate()
{
uint8_t cur_col[5];
uint16_t light_still_on;
uint16_t light_still_on = 0;
strip_timer_counter++;
if (!light_power) { // Power Off
@ -701,7 +728,7 @@ void LightAnimate()
}
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_WAKEUP "\":\"" D_JSON_DONE "\"}"));
MqttPublishPrefixTopic_P(2, PSTR(D_CMND_WAKEUP));
MqttPublishPrefixTopic_P(TELE, PSTR(D_CMND_WAKEUP));
light_wakeup_active = 0;
Settings.light_scheme = LS_POWER;
}
@ -865,21 +892,6 @@ void LightHsbToRgb()
/********************************************************************************************/
void LightReplaceHsb(String *response)
{
if (light_subtype > LST_COLDWARM) {
LightRgbToHsb();
response->replace("{h}", String((uint16_t)(65535.0f * light_hue)));
response->replace("{s}", String((uint8_t)(254.0f * light_saturation)));
response->replace("{b}", String((uint8_t)(254.0f * light_brightness)));
} else {
response->replace("{h}", "0");
response->replace("{s}", "0");
// response->replace("{b}", String((uint8_t)(2.54f * (float)Settings.light_dimmer)));
response->replace("{b}", String((uint8_t)(0.01f * (float)Settings.light_dimmer)));
}
}
void LightGetHsb(float *hue, float *sat, float *bri)
{
if (light_subtype > LST_COLDWARM) {
@ -908,7 +920,7 @@ void LightSetHsb(float hue, float sat, float bri, uint16_t ct)
LightSetColor();
}
LightPreparePower();
MqttPublishPrefixTopic_P(5, PSTR(D_CMND_COLOR));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_COLOR));
} else {
uint8_t tmp = (uint8_t)(bri * 100);
Settings.light_dimmer = tmp;
@ -917,10 +929,10 @@ void LightSetHsb(float hue, float sat, float bri, uint16_t ct)
LightSetColorTemp(ct);
}
LightPreparePower();
MqttPublishPrefixTopic_P(5, PSTR(D_CMND_COLOR));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_COLOR));
} else {
LightPreparePower();
MqttPublishPrefixTopic_P(5, PSTR(D_CMND_DIMMER));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_DIMMER));
}
}
}
@ -962,7 +974,8 @@ boolean LightColorEntry(char *buffer, uint8_t buffer_length)
light_entry_color[i++] = atoi(str);
}
}
entry_type = (light_subtype == i) ? 2 : 0; // Decimal
// entry_type = (light_subtype == i) ? 2 : 0; // Decimal
entry_type = 2; // Decimal
}
else if ((2 * light_subtype) == buffer_length) { // Hexadecimal entry
for (byte i = 0; i < light_subtype; i++) {
@ -1181,7 +1194,7 @@ boolean LightCommand()
scolor[6] = '\0'; // RGB only
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,%d,%d,%d,%d,%d"),
scolor, Settings.light_fade, Settings.light_correction, Settings.light_scheme, Settings.light_speed, Settings.light_width);
MqttPublishPrefixTopic_P(1, XdrvMailbox.topic);
MqttPublishPrefixTopic_P(STAT, XdrvMailbox.topic);
mqtt_data[0] = '\0';
}
else {
@ -1211,11 +1224,14 @@ boolean Xdrv01(byte function)
case FUNC_EVERY_50_MSECOND:
LightAnimate();
#ifdef USE_ARILUX_RF
if (pin[GPIO_ARIRFRCV] < 99) {
AriluxRfHandler();
}
if (pin[GPIO_ARIRFRCV] < 99) AriluxRfHandler();
#endif // USE_ARILUX_RF
break;
#ifdef USE_ARILUX_RF
case FUNC_EVERY_SECOND:
if (10 == uptime) AriluxRfInit(); // Needs rest before enabling RF interrupts
break;
#endif // USE_ARILUX_RF
case FUNC_COMMAND:
result = LightCommand();
break;

View File

@ -107,9 +107,9 @@ void IrReceiveCheck()
if ((iridx < 0) || (iridx > 14)) {
iridx = 0;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":\"%X\"}}"),
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, results.value);
MqttPublishPrefixTopic_P(6, PSTR(D_JSON_IRRECEIVED));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":\"%lX\"}}"),
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, (uint32_t)results.value);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED));
#ifdef USE_DOMOTICZ
unsigned long value = results.value | (iridx << 28); // [Protocol:4, Data:28]
DomoticzSensor(DZ_COUNT, value); // Send data as Domoticz Counter value
@ -132,7 +132,6 @@ boolean IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H
byte data[HVAC_TOSHIBA_DATALEN] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00};
char *p;
char *token;
uint8_t mode;
if (HVAC_Mode == NULL) {
@ -176,7 +175,7 @@ boolean IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H
else {
Temp = HVAC_Temp;
}
data[5] = (byte)Temp - 17 << 4;
data[5] = (byte)(Temp - 17) << 4;
data[HVAC_TOSHIBA_DATALEN - 1] = 0;
for (int x = 0; x < HVAC_TOSHIBA_DATALEN - 1; x++) {
@ -219,7 +218,6 @@ boolean IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H
boolean IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp)
{
char *p;
char *token;
uint8_t mode;
mitsubir->stateReset();
@ -286,12 +284,6 @@ boolean IrSendCommand()
uint32_t bits = 0;
uint32_t data = 0;
const char *HVAC_Mode;
const char *HVAC_FanMode;
const char *HVAC_Vendor;
int HVAC_Temp = 21;
boolean HVAC_Power = true;
for (uint16_t i = 0; i <= sizeof(dataBufUc); i++) {
dataBufUc[i] = toupper(XdrvMailbox.data[i]);
}
@ -309,21 +301,26 @@ boolean IrSendCommand()
data = ir_json[D_JSON_IR_DATA];
if (protocol && bits && data) {
int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols);
snprintf_P(log_data, sizeof(log_data), PSTR("IRS: protocol_text %s, protocol %s, bits %d, data %d, protocol_code %d"),
protocol_text, protocol, bits, data, protocol_code);
AddLog(LOG_LEVEL_DEBUG);
switch (protocol_code) {
case NEC:
irsend->sendNEC(data, bits); break;
irsend->sendNEC(data, (bits > NEC_BITS) ? NEC_BITS : bits); break;
case SONY:
irsend->sendSony(data, bits); break;
irsend->sendSony(data, (bits > SONY_20_BITS) ? SONY_20_BITS : bits, 2); break;
case RC5:
irsend->sendRC5(data, bits); break;
case RC6:
irsend->sendRC6(data, bits); break;
case DISH:
irsend->sendDISH(data, bits); break;
irsend->sendDISH(data, (bits > DISH_BITS) ? DISH_BITS : bits); break;
case JVC:
irsend->sendJVC(data, bits, 1); break;
irsend->sendJVC(data, (bits > JVC_BITS) ? JVC_BITS : bits, 1); break;
case SAMSUNG:
irsend->sendSAMSUNG(data, bits); break;
irsend->sendSAMSUNG(data, (bits > SAMSUNG_BITS) ? SAMSUNG_BITS : bits); break;
case PANASONIC:
irsend->sendPanasonic(bits, data); break;
default:
@ -344,6 +341,12 @@ boolean IrSendCommand()
}
#ifdef USE_IR_HVAC
else if (!strcasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_IRHVAC))) {
const char *HVAC_Mode;
const char *HVAC_FanMode;
const char *HVAC_Vendor;
int HVAC_Temp = 21;
boolean HVAC_Power = true;
if (XdrvMailbox.data_len) {
StaticJsonBuffer<164> jsonBufer;
JsonObject &root = jsonBufer.parseObject(dataBufUc);

View File

@ -1,5 +1,5 @@
/*
xsns_03_energy.ino - HLW8012 (Sonoff Pow) and PZEM004T energy sensor support for Sonoff-Tasmota
xdrv_03_energy.ino - HLW8012 (Sonoff Pow) and PZEM004T energy sensor support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
@ -26,17 +26,17 @@
#define FEATURE_POWER_LIMIT true
enum EnergyHardware { ENERGY_NONE, ENERGY_HLW8012, ENERGY_PZEM004T };
enum EnergyHardware { ENERGY_NONE, ENERGY_HLW8012, ENERGY_CSE7766, ENERGY_PZEM004T };
enum EnergyCommands {
CMND_POWERLOW, CMND_POWERHIGH, CMND_VOLTAGELOW, CMND_VOLTAGEHIGH, CMND_CURRENTLOW, CMND_CURRENTHIGH,
CMND_HLWPCAL, CMND_HLWPSET, CMND_HLWUCAL, CMND_HLWUSET, CMND_HLWICAL, CMND_HLWISET,
CMND_POWERCAL, CMND_POWERSET, CMND_VOLTAGECAL, CMND_VOLTAGESET, CMND_CURRENTCAL, CMND_CURRENTSET,
CMND_ENERGYRESET, CMND_MAXENERGY, CMND_MAXENERGYSTART,
CMND_MAXPOWER, CMND_MAXPOWERHOLD, CMND_MAXPOWERWINDOW,
CMND_SAFEPOWER, CMND_SAFEPOWERHOLD, CMND_SAFEPOWERWINDOW };
const char kEnergyCommands[] PROGMEM =
D_CMND_POWERLOW "|" D_CMND_POWERHIGH "|" D_CMND_VOLTAGELOW "|" D_CMND_VOLTAGEHIGH "|" D_CMND_CURRENTLOW "|" D_CMND_CURRENTHIGH "|"
D_CMND_HLWPCAL "|" D_CMND_HLWPSET "|" D_CMND_HLWUCAL "|" D_CMND_HLWUSET "|" D_CMND_HLWICAL "|" D_CMND_HLWISET "|"
D_CMND_POWERCAL "|" D_CMND_POWERSET "|" D_CMND_VOLTAGECAL "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTCAL "|" D_CMND_CURRENTSET "|"
D_CMND_ENERGYRESET "|" D_CMND_MAXENERGY "|" D_CMND_MAXENERGYSTART "|"
D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|"
D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW ;
@ -47,9 +47,11 @@ float energy_power = 0; // 123.1 W
float energy_power_factor = 0; // 0.12
float energy_daily = 0; // 12.123 kWh
float energy_total = 0; // 12345.12345 kWh
float energy_start = 0; // 12345.12345 kWh total from yesterday
float energy_start = 0; // 12345.12345 kWh total previous
unsigned long energy_kWhtoday; // 1212312345 Wh * 10^-5 (deca micro Watt hours) - 5763924 = 0.05763924 kWh = 0.058 kWh = energy_daily
unsigned long energy_period = 0; //
unsigned long energy_period = 0; // 1212312345 Wh * 10^-5 (deca micro Watt hours) - 5763924 = 0.05763924 kWh = 0.058 kWh = energy_daily
bool energy_power_on = true;
byte energy_min_power_flag = 0;
byte energy_max_power_flag = 0;
@ -67,12 +69,20 @@ uint16_t energy_mplh_counter = 0;
uint16_t energy_mplw_counter = 0;
#endif // FEATURE_POWER_LIMIT
byte energy_startup = 1;
byte energy_fifth_second = 0;
Ticker ticker_energy;
/********************************************************************************************/
void EnergyUpdateToday()
{
RtcSettings.energy_kWhtoday = energy_kWhtoday;
energy_daily = (float)energy_kWhtoday / 100000000;
energy_total = (float)(RtcSettings.energy_kWhtotal + (energy_kWhtoday / 1000)) / 100000;
}
/*********************************************************************************************\
* HLW8012 - Energy
* HLW8012 - Energy (Sonoff Pow)
*
* Based on Source: Shenzhen Heli Technology Co., Ltd
\*********************************************************************************************/
@ -136,18 +146,13 @@ void HlwCf1Interrupt() // Service Voltage and Current
void HlwEverySecond()
{
unsigned long hlw_len;
unsigned long hlw_temp;
if (hlw_energy_period_counter) {
hlw_len = 10000 / hlw_energy_period_counter;
hlw_energy_period_counter = 0;
if (hlw_len) {
hlw_temp = ((HLW_PREF * Settings.hlw_power_calibration) / hlw_len) / 36;
energy_kWhtoday += hlw_temp;
RtcSettings.energy_kWhtoday = energy_kWhtoday;
energy_total = (float)(RtcSettings.energy_kWhtotal + (energy_kWhtoday / 1000)) / 100000;
energy_daily = (float)energy_kWhtoday / 100000000;
energy_kWhtoday += ((HLW_PREF * Settings.energy_power_calibration) / hlw_len) / 36;
EnergyUpdateToday();
}
}
}
@ -163,8 +168,8 @@ void HlwEvery200ms()
hlw_load_off = 1;
}
if (hlw_cf_pulse_length && (power &1) && !hlw_load_off) {
hlw_w = (HLW_PREF * Settings.hlw_power_calibration) / hlw_cf_pulse_length;
if (hlw_cf_pulse_length && energy_power_on && !hlw_load_off) {
hlw_w = (HLW_PREF * Settings.energy_power_calibration) / hlw_cf_pulse_length;
energy_power = (float)hlw_w / 10;
} else {
energy_power = 0;
@ -185,8 +190,8 @@ void HlwEvery200ms()
hlw_cf1_voltage_pulse_length = hlw_cf1_pulse_length;
hlw_cf1_voltage_max_pulse_counter = hlw_cf1_pulse_counter;
if (hlw_cf1_voltage_pulse_length && (power &1)) { // If powered on always provide voltage
hlw_u = (HLW_UREF * Settings.hlw_voltage_calibration) / hlw_cf1_voltage_pulse_length;
if (hlw_cf1_voltage_pulse_length && energy_power_on) { // If powered on always provide voltage
hlw_u = (HLW_UREF * Settings.energy_voltage_calibration) / hlw_cf1_voltage_pulse_length;
energy_voltage = (float)hlw_u / 10;
} else {
energy_voltage = 0;
@ -197,7 +202,7 @@ void HlwEvery200ms()
hlw_cf1_current_max_pulse_counter = hlw_cf1_pulse_counter;
if (hlw_cf1_current_pulse_length && energy_power) { // No current if no power being consumed
hlw_i = (HLW_IREF * Settings.hlw_current_calibration) / hlw_cf1_current_pulse_length;
hlw_i = (HLW_IREF * Settings.energy_current_calibration) / hlw_cf1_current_pulse_length;
energy_current = (float)hlw_i / 1000;
} else {
energy_current = 0;
@ -211,10 +216,10 @@ void HlwEvery200ms()
void HlwInit()
{
if (!Settings.hlw_power_calibration || (4975 == Settings.hlw_power_calibration)) {
Settings.hlw_power_calibration = HLW_PREF_PULSE;
Settings.hlw_voltage_calibration = HLW_UREF_PULSE;
Settings.hlw_current_calibration = HLW_IREF_PULSE;
if (!Settings.energy_power_calibration || (4975 == Settings.energy_power_calibration)) {
Settings.energy_power_calibration = HLW_PREF_PULSE;
Settings.energy_voltage_calibration = HLW_UREF_PULSE;
Settings.energy_current_calibration = HLW_IREF_PULSE;
}
hlw_cf_pulse_length = 0;
@ -241,6 +246,145 @@ void HlwInit()
hlw_cf1_timer = 0;
}
/*********************************************************************************************\
* CSE7766 - Energy (Sonoff S31)
*
* Based on datasheet from http://www.chipsea.com/UploadFiles/2017/08/11144342F01B5662.pdf
\*********************************************************************************************/
#define CSE_NOT_CALIBRATED 0xAA
#define CSE_PULSES_NOT_INITIALIZED -1
#define CSE_PREF 1000
#define CSE_UREF 100
uint8_t cse_receive_flag = 0;
long voltage_cycle = 0;
long current_cycle = 0;
long power_cycle = 0;
long cf_pulses = 0;
long cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED;
void CseReceived()
{
AddLogSerial(LOG_LEVEL_DEBUG_MORE);
uint8_t header = serial_in_buffer[0];
if ((header & 0xFC) == 0xFC) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Abnormal hardware"));
return;
}
// Calculate checksum
uint8_t checksum = 0;
for (byte i = 2; i < 23; i++) checksum += serial_in_buffer[i];
if (checksum != serial_in_buffer[23]) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE));
return;
}
// Get chip calibration data (coefficients) and use as initial defaults
if (HLW_UREF_PULSE == Settings.energy_voltage_calibration) {
long voltage_coefficient = 191200; // uSec
if (CSE_NOT_CALIBRATED != header) {
voltage_coefficient = serial_in_buffer[2] << 16 | serial_in_buffer[3] << 8 | serial_in_buffer[4];
}
Settings.energy_voltage_calibration = voltage_coefficient / CSE_UREF;
}
if (HLW_IREF_PULSE == Settings.energy_current_calibration) {
long current_coefficient = 16140; // uSec
if (CSE_NOT_CALIBRATED != header) {
current_coefficient = serial_in_buffer[8] << 16 | serial_in_buffer[9] << 8 | serial_in_buffer[10];
}
Settings.energy_current_calibration = current_coefficient;
}
if (HLW_PREF_PULSE == Settings.energy_power_calibration) {
long power_coefficient = 5364000; // uSec
if (CSE_NOT_CALIBRATED != header) {
power_coefficient = serial_in_buffer[14] << 16 | serial_in_buffer[15] << 8 | serial_in_buffer[16];
}
Settings.energy_power_calibration = power_coefficient / CSE_PREF;
}
uint8_t adjustement = serial_in_buffer[20];
voltage_cycle = serial_in_buffer[5] << 16 | serial_in_buffer[6] << 8 | serial_in_buffer[7];
current_cycle = serial_in_buffer[11] << 16 | serial_in_buffer[12] << 8 | serial_in_buffer[13];
power_cycle = serial_in_buffer[17] << 16 | serial_in_buffer[18] << 8 | serial_in_buffer[19];
cf_pulses = serial_in_buffer[21] << 8 | serial_in_buffer[22];
// if (adjustement & 0x80) { // CF overflow
// cf_pulses += 0x10000;
// }
if (energy_power_on) { // Powered on
if (adjustement & 0x40) { // Voltage valid
energy_voltage = (float)(Settings.energy_voltage_calibration * CSE_UREF) / (float)voltage_cycle;
}
if (adjustement & 0x10) { // Power valid
if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range
energy_power = 0;
} else {
energy_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)power_cycle;
}
} else {
energy_power = 0; // Powered on but no load
}
if (adjustement & 0x20) { // Current valid
if (0 == energy_power) {
energy_current = 0;
} else {
energy_current = (float)Settings.energy_current_calibration / (float)current_cycle;
}
}
} else { // Powered off
energy_voltage = 0;
energy_power = 0;
energy_current = 0;
}
}
bool CseSerialInput()
{
if (cse_receive_flag) {
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
if (24 == serial_in_byte_counter) {
CseReceived();
cse_receive_flag = 0;
return 1;
}
} else {
if (0x5A == serial_in_byte) { // 0x5A - Packet header 2
cse_receive_flag = 1;
} else {
serial_in_byte_counter = 0;
}
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
}
serial_in_byte = 0; // Discard
return 0;
}
void CseEverySecond()
{
long cf_frequency = 0;
if (CSE_PULSES_NOT_INITIALIZED == cf_pulses_last_time) {
cf_pulses_last_time = cf_pulses; // Init after restart
} else {
if (cf_pulses < cf_pulses_last_time) { // Rolled over after 65535 pulses
cf_frequency = (65536 - cf_pulses_last_time) + cf_pulses;
} else {
cf_frequency = cf_pulses - cf_pulses_last_time;
}
if (cf_frequency && energy_power) {
cf_pulses_last_time = cf_pulses;
energy_kWhtoday += (cf_frequency * Settings.energy_power_calibration) / 36;
EnergyUpdateToday();
}
}
}
#ifdef USE_PZEM004T
/*********************************************************************************************\
* PZEM004T - Energy
@ -285,9 +429,7 @@ IPAddress pzem_ip(192, 168, 1, 1);
uint8_t PzemCrc(uint8_t *data)
{
uint16_t crc = 0;
for (uint8_t i = 0; i < sizeof(PZEMCommand) -1; i++) {
crc += *data++;
}
for (uint8_t i = 0; i < sizeof(PZEMCommand) -1; i++) crc += *data++;
return (uint8_t)(crc & 0xFF);
}
@ -296,20 +438,19 @@ void PzemSend(uint8_t cmd)
PZEMCommand pzem;
pzem.command = cmd;
for (int i = 0; i < sizeof(pzem.addr); i++) {
pzem.addr[i] = pzem_ip[i];
}
for (uint8_t i = 0; i < sizeof(pzem.addr); i++) pzem.addr[i] = pzem_ip[i];
pzem.data = 0;
uint8_t *bytes = (uint8_t*)&pzem;
pzem.crc = PzemCrc(bytes);
PzemSerial->flush();
PzemSerial->write(bytes, sizeof(pzem));
}
bool PzemReceiveReady()
{
return PzemSerial->available() >= sizeof(PZEMCommand);
return PzemSerial->available() >= (int)sizeof(PZEMCommand);
}
bool PzemRecieve(uint8_t resp, float *data)
@ -374,31 +515,24 @@ void PzemEvery200ms()
float value = 0;
if (PzemRecieve(pzem_responses[pzem_read_state], &value)) {
switch (pzem_read_state) {
case 1:
energy_voltage = value; // 230.2V
case 1: // Voltage as 230.2V
energy_voltage = value;
break;
case 2:
energy_current = value; // 17.32A
case 2: // Current as 17.32A
energy_current = value;
break;
case 3:
energy_power = value; // 20W
case 3: // Power as 20W
energy_power = value;
break;
case 4:
energy_total = value / 1000; // 99999Wh
if (!energy_startup) {
if (energy_total < energy_start) {
energy_start = energy_total;
Settings.hlw_power_calibration = energy_start * 1000;
}
energy_kWhtoday = (energy_total - energy_start) * 100000000;
energy_daily = (float)energy_kWhtoday / 100000000;
}
case 4: // Total energy as 99999Wh
if (!energy_start || (value < energy_start)) energy_start = value; // Init after restart and hanlde roll-over if any
energy_kWhtoday += (value - energy_start) * 100000;
energy_start = value;
EnergyUpdateToday();
break;
}
pzem_read_state++;
if (5 == pzem_read_state) {
pzem_read_state = 1;
}
if (5 == pzem_read_state) pzem_read_state = 1;
}
}
@ -426,9 +560,8 @@ void Energy200ms()
if (5 == energy_fifth_second) {
energy_fifth_second = 0;
if (ENERGY_HLW8012 == energy_flg) {
HlwEverySecond();
}
if (ENERGY_HLW8012 == energy_flg) HlwEverySecond();
if (ENERGY_CSE7766 == energy_flg) CseEverySecond();
if (RtcTime.valid) {
if (LocalTime() == Midnight()) {
@ -436,42 +569,27 @@ void Energy200ms()
Settings.energy_kWhtotal += (energy_kWhtoday / 1000);
RtcSettings.energy_kWhtotal = Settings.energy_kWhtotal;
energy_kWhtoday = 0;
RtcSettings.energy_kWhtoday = energy_kWhtoday;
#ifdef USE_PZEM004T
if (ENERGY_PZEM004T == energy_flg) {
energy_start = energy_total;
Settings.hlw_power_calibration = energy_start * 1000;
}
#endif // USE_PZEM004T
energy_period = energy_kWhtoday;
EnergyUpdateToday();
energy_max_energy_state = 3;
}
if ((RtcTime.hour == Settings.energy_max_energy_start) && (3 == energy_max_energy_state)) {
energy_max_energy_state = 0;
}
if (energy_startup && (RtcTime.day_of_year == Settings.energy_kWhdoy)) {
energy_kWhtoday = Settings.energy_kWhtoday;
RtcSettings.energy_kWhtoday = energy_kWhtoday;
energy_start = (float)Settings.hlw_power_calibration / 1000; // Used by PZEM004T to store total yesterday
energy_startup = 0;
}
}
}
if (ENERGY_HLW8012 == energy_flg) {
HlwEvery200ms();
energy_power_on = (power &1) | Settings.flag.no_power_on_check;
if (ENERGY_HLW8012 == energy_flg) HlwEvery200ms();
#ifdef USE_PZEM004T
}
else if (ENERGY_PZEM004T == energy_flg) {
PzemEvery200ms();
if (ENERGY_PZEM004T == energy_flg) PzemEvery200ms();
#endif // USE_PZEM004T
}
float power_factor = 0;
if (energy_voltage && energy_current && energy_power) {
power_factor = energy_power / (energy_voltage * energy_current);
if (power_factor > 1) {
power_factor = 1;
}
if (power_factor > 1) power_factor = 1;
}
energy_power_factor = power_factor;
}
@ -480,6 +598,7 @@ void EnergySaveState()
{
Settings.energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0;
Settings.energy_kWhtoday = energy_kWhtoday;
RtcSettings.energy_kWhtoday = energy_kWhtoday;
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
}
@ -487,9 +606,7 @@ boolean EnergyMargin(byte type, uint16_t margin, uint16_t value, byte &flag, byt
{
byte change;
if (!margin) {
return false;
}
if (!margin) return false;
change = save_flag;
if (type) {
flag = (value > margin);
@ -507,10 +624,10 @@ void EnergySetPowerSteadyCounter()
void EnergyMarginCheck()
{
uint16_t energy_daily_u;
uint16_t energy_power_u;
uint16_t energy_voltage_u;
uint16_t energy_current_u;
uint16_t energy_daily_u = 0;
uint16_t energy_power_u = 0;
uint16_t energy_voltage_u = 0;
uint16_t energy_current_u = 0;
boolean flag;
boolean jsonflg;
@ -519,7 +636,7 @@ void EnergyMarginCheck()
return;
}
if (power && (Settings.energy_min_power || Settings.energy_max_power || Settings.energy_min_voltage || Settings.energy_max_voltage || Settings.energy_min_current || Settings.energy_max_current)) {
if (energy_power_on && (Settings.energy_min_power || Settings.energy_max_power || Settings.energy_min_voltage || Settings.energy_max_voltage || Settings.energy_min_current || Settings.energy_max_current)) {
energy_power_u = (uint16_t)(energy_power);
energy_voltage_u = (uint16_t)(energy_voltage);
energy_current_u = (uint16_t)(energy_current * 1000);
@ -555,7 +672,7 @@ void EnergyMarginCheck()
}
if (jsonflg) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_MARGINS));
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_MARGINS));
EnergyMqttShow();
}
}
@ -570,9 +687,9 @@ void EnergyMarginCheck()
energy_mplh_counter--;
if (!energy_mplh_counter) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_MAXPOWERREACHED "\":\"%d%s\"}"), energy_power_u, (Settings.flag.value_units) ? " " D_UNIT_WATT : "");
MqttPublishPrefixTopic_P(1, S_RSLT_WARNING);
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow();
ExecuteCommandPower(1, 0);
ExecuteCommandPower(1, POWER_OFF);
if (!energy_mplr_counter) {
energy_mplr_counter = Settings.param[P_MAX_POWER_RETRY] +1;
}
@ -593,11 +710,11 @@ void EnergyMarginCheck()
energy_mplr_counter--;
if (energy_mplr_counter) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1));
MqttPublishPrefixTopic_P(5, PSTR(D_JSON_POWERMONITOR));
ExecuteCommandPower(1, 1);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR));
ExecuteCommandPower(1, POWER_ON);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_MAXPOWERREACHEDRETRY "\":\"%s\"}"), GetStateText(0));
MqttPublishPrefixTopic_P(1, S_RSLT_WARNING);
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow();
}
}
@ -611,16 +728,16 @@ void EnergyMarginCheck()
if (!energy_max_energy_state && (RtcTime.hour == Settings.energy_max_energy_start)) {
energy_max_energy_state = 1;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1));
MqttPublishPrefixTopic_P(5, PSTR(D_JSON_ENERGYMONITOR));
ExecuteCommandPower(1, 1);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR));
ExecuteCommandPower(1, POWER_ON);
}
else if ((1 == energy_max_energy_state) && (energy_daily_u >= Settings.energy_max_energy)) {
energy_max_energy_state = 2;
dtostrfd(energy_daily, 3, mqtt_data);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_MAXENERGYREACHED "\":\"%s%s\"}"), mqtt_data, (Settings.flag.value_units) ? " " D_UNIT_KILOWATTHOUR : "");
MqttPublishPrefixTopic_P(1, S_RSLT_WARNING);
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow();
ExecuteCommandPower(1, 0);
ExecuteCommandPower(1, POWER_OFF);
}
}
#endif // FEATURE_POWER_LIMIT
@ -631,7 +748,8 @@ void EnergyMqttShow()
// {"Time":"2017-12-16T11:48:55","ENERGY":{"Total":0.212,"Yesterday":0.000,"Today":0.014,"Period":2.0,"Power":22.0,"Factor":1.00,"Voltage":213.6,"Current":0.100}}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime().c_str());
EnergyShow(1);
MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_ENERGY), Settings.flag.mqtt_sensor_retain);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_ENERGY), Settings.flag.mqtt_sensor_retain);
}
/*********************************************************************************************\
@ -697,8 +815,10 @@ boolean EnergyCommand()
switch (XdrvMailbox.index) {
case 1:
energy_kWhtoday = lnum *100000;
RtcSettings.energy_kWhtoday = energy_kWhtoday;
energy_period = energy_kWhtoday;
Settings.energy_kWhtoday = energy_kWhtoday;
RtcSettings.energy_kWhtoday = energy_kWhtoday;
energy_daily = (float)energy_kWhtoday / 100000000;
break;
case 2:
Settings.energy_kWhyesterday = lnum *100000;
@ -719,51 +839,68 @@ boolean EnergyCommand()
command, energy_total_chr, energy_yesterday_chr, stoday_energy);
status_flag = 1;
}
else if ((ENERGY_HLW8012 == energy_flg) && (CMND_HLWPCAL == command_code)) {
else if (((ENERGY_HLW8012 == energy_flg) || (ENERGY_CSE7766 == energy_flg)) && (CMND_POWERCAL == command_code)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 32001)) {
Settings.hlw_power_calibration = (XdrvMailbox.payload > 4000) ? XdrvMailbox.payload : HLW_PREF_PULSE; // 12530
Settings.energy_power_calibration = (XdrvMailbox.payload > 4000) ? XdrvMailbox.payload : HLW_PREF_PULSE; // HLW = 12530, CSE = 5364
}
nvalue = Settings.hlw_power_calibration;
nvalue = Settings.energy_power_calibration;
unit = UNIT_MICROSECOND;
}
else if ((ENERGY_HLW8012 == energy_flg) && (CMND_HLWPSET == command_code)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 3601) && hlw_cf_pulse_length) {
Settings.hlw_power_calibration = (XdrvMailbox.payload * 10 * hlw_cf_pulse_length) / HLW_PREF;
else if (((ENERGY_HLW8012 == energy_flg) || (ENERGY_CSE7766 == energy_flg)) && (CMND_POWERSET == command_code)) { // Watt
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 3601)) {
if ((ENERGY_HLW8012 == energy_flg) && hlw_cf_pulse_length) {
Settings.energy_power_calibration = (XdrvMailbox.payload * 10 * hlw_cf_pulse_length) / HLW_PREF;
}
else if ((ENERGY_CSE7766 == energy_flg) && power_cycle) {
Settings.energy_power_calibration = (XdrvMailbox.payload * power_cycle) / CSE_PREF;
}
}
snprintf_P(command, sizeof(command), PSTR(D_CMND_HLWPCAL));
nvalue = Settings.hlw_power_calibration;
snprintf_P(command, sizeof(command), PSTR(D_CMND_POWERCAL));
nvalue = Settings.energy_power_calibration;
unit = UNIT_MICROSECOND;
}
else if ((ENERGY_HLW8012 == energy_flg) && (CMND_HLWUCAL == command_code)) {
else if (((ENERGY_HLW8012 == energy_flg) || (ENERGY_CSE7766 == energy_flg)) && (CMND_VOLTAGECAL == command_code)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 32001)) {
Settings.hlw_voltage_calibration = (XdrvMailbox.payload > 999) ? XdrvMailbox.payload : HLW_UREF_PULSE; // 1950
Settings.energy_voltage_calibration = (XdrvMailbox.payload > 999) ? XdrvMailbox.payload : HLW_UREF_PULSE; // HLW = 1950, CSE = 1912
}
nvalue = Settings.hlw_voltage_calibration;
nvalue = Settings.energy_voltage_calibration;
unit = UNIT_MICROSECOND;
}
else if ((ENERGY_HLW8012 == energy_flg) && (CMND_HLWUSET == command_code)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 501) && hlw_cf1_voltage_pulse_length) {
Settings.hlw_voltage_calibration = (XdrvMailbox.payload * 10 * hlw_cf1_voltage_pulse_length) / HLW_UREF;
else if (((ENERGY_HLW8012 == energy_flg) || (ENERGY_CSE7766 == energy_flg)) && (CMND_VOLTAGESET == command_code)) { // Volt
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 501)) {
if ((ENERGY_HLW8012 == energy_flg) && hlw_cf1_voltage_pulse_length) {
Settings.energy_voltage_calibration = (XdrvMailbox.payload * 10 * hlw_cf1_voltage_pulse_length) / HLW_UREF;
}
else if ((ENERGY_CSE7766 == energy_flg) && voltage_cycle) {
Settings.energy_voltage_calibration = (XdrvMailbox.payload * voltage_cycle) / CSE_UREF;
}
}
snprintf_P(command, sizeof(command), PSTR(D_CMND_HLWUCAL));
nvalue = Settings.hlw_voltage_calibration;
snprintf_P(command, sizeof(command), PSTR(D_CMND_VOLTAGECAL));
nvalue = Settings.energy_voltage_calibration;
unit = UNIT_MICROSECOND;
}
else if ((ENERGY_HLW8012 == energy_flg) && (CMND_HLWICAL == command_code)) {
else if (((ENERGY_HLW8012 == energy_flg) || (ENERGY_CSE7766 == energy_flg)) && (CMND_CURRENTCAL == command_code)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 32001)) {
Settings.hlw_current_calibration = (XdrvMailbox.payload > 1100) ? XdrvMailbox.payload : HLW_IREF_PULSE; // 3500
Settings.energy_current_calibration = (XdrvMailbox.payload > 1100) ? XdrvMailbox.payload : HLW_IREF_PULSE; // HLW = 3500, CSE = 16140
}
nvalue = Settings.hlw_current_calibration;
nvalue = Settings.energy_current_calibration;
unit = UNIT_MICROSECOND;
}
else if ((ENERGY_HLW8012 == energy_flg) && (CMND_HLWISET == command_code)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 16001) && hlw_cf1_current_pulse_length) {
Settings.hlw_current_calibration = (XdrvMailbox.payload * hlw_cf1_current_pulse_length) / HLW_IREF;
else if (((ENERGY_HLW8012 == energy_flg) || (ENERGY_CSE7766 == energy_flg)) && (CMND_CURRENTSET == command_code)) { // milliAmpere
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 16001)) {
if ((ENERGY_HLW8012 == energy_flg) && hlw_cf1_current_pulse_length) {
Settings.energy_current_calibration = (XdrvMailbox.payload * hlw_cf1_current_pulse_length) / HLW_IREF;
}
else if ((ENERGY_CSE7766 == energy_flg) && current_cycle) {
Settings.energy_current_calibration = (XdrvMailbox.payload * current_cycle) / 1000;
}
}
snprintf_P(command, sizeof(command), PSTR(D_CMND_HLWICAL));
nvalue = Settings.hlw_current_calibration;
snprintf_P(command, sizeof(command), PSTR(D_CMND_CURRENTCAL));
nvalue = Settings.energy_current_calibration;
unit = UNIT_MICROSECOND;
}
#if FEATURE_POWER_LIMIT
else if (CMND_MAXPOWER == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
@ -828,9 +965,9 @@ boolean EnergyCommand()
}
if (!status_flag) {
if (Settings.flag.value_units) {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SPACE_UNIT, command, nvalue, GetTextIndexed(sunit, sizeof(sunit), unit, kUnitNames));
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_LVALUE_SPACE_UNIT, command, nvalue, GetTextIndexed(sunit, sizeof(sunit), unit, kUnitNames));
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, nvalue);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_LVALUE, command, nvalue);
}
}
return serviced;
@ -838,30 +975,42 @@ boolean EnergyCommand()
/********************************************************************************************/
void EnergyInit()
void EnergyDrvInit()
{
energy_flg = ENERGY_NONE;
if ((pin[GPIO_HLW_SEL] < 99) && (pin[GPIO_HLW_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)) {
if ((pin[GPIO_HLW_SEL] < 99) && (pin[GPIO_HLW_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)) { // Sonoff Pow
energy_flg = ENERGY_HLW8012;
HlwInit();
} else if (SONOFF_S31 == Settings.module) { // Sonoff S31
baudrate = 4800;
serial_config = SERIAL_8E1;
energy_flg = ENERGY_CSE7766;
#ifdef USE_PZEM004T
} else if ((pin[GPIO_PZEM_RX] < 99) && (pin[GPIO_PZEM_TX])) {
if (PzemInit()) {
energy_flg = ENERGY_PZEM004T;
}
} else if ((pin[GPIO_PZEM_RX] < 99) && (pin[GPIO_PZEM_TX])) { // Any device with a Pzem004T
energy_flg = ENERGY_PZEM004T;
#endif // USE_PZEM004T
}
}
void EnergySnsInit()
{
if (ENERGY_HLW8012 == energy_flg) HlwInit();
#ifdef USE_PZEM004T
if ((ENERGY_PZEM004T == energy_flg) && !PzemInit()) { // PzemInit needs to be done here as earlier (serial) interrupts may lead to Exceptions
energy_flg = ENERGY_NONE;
}
#endif // USE_PZEM004T
if (energy_flg) {
energy_kWhtoday = (RtcSettingsValid()) ? RtcSettings.energy_kWhtoday : 0;
energy_startup = 1;
energy_kWhtoday = (RtcSettingsValid()) ? RtcSettings.energy_kWhtoday : (RtcTime.day_of_year == Settings.energy_kWhdoy) ? Settings.energy_kWhtoday : 0;
energy_period = energy_kWhtoday;
EnergyUpdateToday();
ticker_energy.attach_ms(200, Energy200ms);
}
}
#ifdef USE_WEBSERVER
const char HTTP_ENERGY_SNS[] PROGMEM =
const char HTTP_ENERGY_SNS[] PROGMEM = "%s"
"{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"
"{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"
"{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"
@ -887,9 +1036,7 @@ void EnergyShow(boolean json)
float energy = 0;
if (show_energy_period) {
if (energy_period) {
energy = (float)(energy_kWhtoday - energy_period) / 100000;
}
if (energy_period) energy = (float)(energy_kWhtoday - energy_period) / 100000;
energy_period = energy_kWhtoday;
}
@ -916,7 +1063,7 @@ void EnergyShow(boolean json)
#endif // USE_DOMOTICZ
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS, energy_voltage_chr, energy_current_chr, energy_power_chr, energy_power_factor_chr, energy_daily_chr, energy_yesterday_chr, energy_total_chr);
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS, mqtt_data, energy_voltage_chr, energy_current_chr, energy_power_chr, energy_power_factor_chr, energy_daily_chr, energy_yesterday_chr, energy_total_chr);
#endif // USE_WEBSERVER
}
}
@ -933,6 +1080,9 @@ boolean Xdrv03(byte function)
if (energy_flg) {
switch (function) {
case FUNC_INIT:
EnergyDrvInit();
break;
case FUNC_COMMAND:
result = EnergyCommand();
break;
@ -953,7 +1103,7 @@ boolean Xsns03(byte function)
if (energy_flg) {
switch (function) {
case FUNC_INIT:
EnergyInit();
EnergySnsInit();
break;
case FUNC_EVERY_SECOND:
EnergyMarginCheck();

View File

@ -41,7 +41,7 @@ void SonoffBridgeLearnFailed()
{
sonoff_bridge_learn_active = 0;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, D_CMND_RFKEY, sonoff_bridge_learn_key, D_JSON_LEARN_FAILED);
MqttPublishPrefixTopic_P(5, PSTR(D_CMND_RFKEY));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_RFKEY));
}
void SonoffBridgeReceived()
@ -50,15 +50,9 @@ void SonoffBridgeReceived()
uint16_t low_time = 0;
uint16_t high_time = 0;
uint32_t received_id = 0;
char svalue[90];
char rfkey[8];
svalue[0] = '\0';
for (byte i = 0; i < serial_in_byte_counter; i++) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%02X "), svalue, serial_in_buffer[i]);
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_BRIDGE D_RECEIVED " %s"), svalue);
AddLog(LOG_LEVEL_DEBUG);
AddLogSerial(LOG_LEVEL_DEBUG);
if (0xA2 == serial_in_buffer[0]) { // Learn timeout
SonoffBridgeLearnFailed();
@ -72,7 +66,7 @@ void SonoffBridgeReceived()
Settings.rf_code[sonoff_bridge_learn_key][i] = serial_in_buffer[i +1];
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, D_CMND_RFKEY, sonoff_bridge_learn_key, D_JSON_LEARNED);
MqttPublishPrefixTopic_P(5, PSTR(D_CMND_RFKEY));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_RFKEY));
} else {
SonoffBridgeLearnFailed();
}
@ -102,7 +96,7 @@ void SonoffBridgeReceived()
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":\"%06X\",\"" D_CMND_RFKEY "\":%s}}"),
sync_time, low_time, high_time, received_id, rfkey);
MqttPublishPrefixTopic_P(6, PSTR(D_JSON_RFRECEIVED));
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED));
#ifdef USE_DOMOTICZ
DomoticzSensor(DZ_COUNT, received_id); // Send rid as Domoticz Counter value
#endif // USE_DOMOTICZ

View File

@ -25,20 +25,18 @@ const char HTTP_FORM_DOMOTICZ[] PROGMEM =
"<input id='w' name='w' value='4' hidden><input id='r' name='r' value='1' hidden>"
"<br/><table>";
const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM =
"<tr><td width='260'><b>" D_DOMOTICZ_IDX " {1</b></td><td width='70'><input id='r{1' name='r{1' placeholder='0' value='{2'></td></tr>"
"<tr><td width='260'><b>" D_DOMOTICZ_KEY_IDX " {1</b></td><td width='70'><input id='k{1' name='k{1' placeholder='0' value='{3'></td></tr>";
"<tr><td style='width:260px'><b>" D_DOMOTICZ_IDX " {1</b></td><td style='width:70px'><input id='r{1' name='r{1' placeholder='0' value='{2'></td></tr>"
"<tr><td style='width:260px'><b>" D_DOMOTICZ_KEY_IDX " {1</b></td><td style='width:70px'><input id='k{1' name='k{1' placeholder='0' value='{3'></td></tr>";
const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM =
"<tr><td width='260'><b>" D_DOMOTICZ_SWITCH_IDX " {1</b></td><td width='70'><input id='s{1' name='s{1' placeholder='0' value='{4'></td></tr>";
"<tr><td style='width:260px'><b>" D_DOMOTICZ_SWITCH_IDX " {1</b></td><td style='width:70px'><input id='s{1' name='s{1' placeholder='0' value='{4'></td></tr>";
const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM =
"<tr><td width='260'><b>" D_DOMOTICZ_SENSOR_IDX " {1</b> {2</td><td width='70'><input id='l{1' name='l{1' placeholder='0' value='{5'></td></tr>";
"<tr><td style='width:260px'><b>" D_DOMOTICZ_SENSOR_IDX " {1</b> {2</td><td style='width:70px'><input id='l{1' name='l{1' placeholder='0' value='{5'></td></tr>";
const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM =
"<tr><td width='260'><b>" D_DOMOTICZ_UPDATE_TIMER "</b> (" STR(DOMOTICZ_UPDATE_TIMER) ")</td><td width='70'><input id='ut' name='ut' placeholder='" STR(DOMOTICZ_UPDATE_TIMER) "' value='{6'</td></tr>";
"<tr><td style='width:260px'><b>" D_DOMOTICZ_UPDATE_TIMER "</b> (" STR(DOMOTICZ_UPDATE_TIMER) ")</td><td style='width:70px'><input id='ut' name='ut' placeholder='" STR(DOMOTICZ_UPDATE_TIMER) "' value='{6'</td></tr>";
#endif // USE_WEBSERVER
enum DomoticzCommands {
CMND_IDX, CMND_KEYIDX, CMND_SWITCHIDX, CMND_SENSORIDX, CMND_UPDATETIMER };
const char kDomoticzCommands[] PROGMEM =
D_CMND_IDX "|" D_CMND_KEYIDX "|" D_CMND_SWITCHIDX "|" D_CMND_SENSORIDX "|" D_CMND_UPDATETIMER ;
enum DomoticzCommands { CMND_IDX, CMND_KEYIDX, CMND_SWITCHIDX, CMND_SENSORIDX, CMND_UPDATETIMER };
const char kDomoticzCommands[] PROGMEM = D_CMND_IDX "|" D_CMND_KEYIDX "|" D_CMND_SWITCHIDX "|" D_CMND_SENSORIDX "|" D_CMND_UPDATETIMER ;
//enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_MAX_SENSORS};
@ -50,6 +48,7 @@ const char kDomoticzSensors[] PROGMEM =
D_DOMOTICZ_TEMP "|" D_DOMOTICZ_TEMP_HUM "|" D_DOMOTICZ_TEMP_HUM_BARO "|" D_DOMOTICZ_POWER_ENERGY "|" D_DOMOTICZ_ILLUMINANCE "|" D_DOMOTICZ_COUNT "|" D_DOMOTICZ_VOLTAGE "|" D_DOMOTICZ_CURRENT "|" D_DOMOTICZ_AIRQUALITY ;
const char S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DOMOTICZ "%s%d\":%d}";
const char S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE[] PROGMEM = "{\"" D_CMND_DOMOTICZ "%s%d\":%lu}";
char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC;
char domoticz_out_topic[] = DOMOTICZ_OUT_TOPIC;
@ -94,11 +93,6 @@ void DomoticzMqttUpdate()
}
}
void DomoticzSetUpdateTimer(uint16_t value)
{
domoticz_update_timer = value;
}
void DomoticzMqttSubscribe()
{
uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present;
@ -134,7 +128,6 @@ void DomoticzMqttSubscribe()
boolean DomoticzMqttData()
{
char stemp1[10];
char scommand[10];
unsigned long idx = 0;
int16_t nvalue;
int16_t found = 0;
@ -172,7 +165,7 @@ boolean DomoticzMqttData()
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue);
found = 1;
} else {
if (((power >> i) &1) == nvalue) {
if (((power >> i) &1) == (power_t)nvalue) {
return 1;
}
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_POWER "%s"), (devices_present > 1) ? stemp1 : "");
@ -212,19 +205,19 @@ boolean DomoticzCommand()
Settings.domoticz_relay_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_relay_idx[XdrvMailbox.index -1]);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE, command, XdrvMailbox.index, Settings.domoticz_relay_idx[XdrvMailbox.index -1]);
}
else if ((CMND_KEYIDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) {
if (XdrvMailbox.payload >= 0) {
Settings.domoticz_key_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_key_idx[XdrvMailbox.index -1]);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE, command, XdrvMailbox.index, Settings.domoticz_key_idx[XdrvMailbox.index -1]);
}
else if ((CMND_SWITCHIDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) {
if (XdrvMailbox.payload >= 0) {
Settings.domoticz_switch_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_key_idx[XdrvMailbox.index -1]);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_switch_idx[XdrvMailbox.index -1]);
}
else if ((CMND_SENSORIDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= DZ_MAX_SENSORS)) {
if (XdrvMailbox.payload >= 0) {
@ -339,10 +332,10 @@ void HandleDomoticzConfiguration()
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ);
char stemp[32];
char *sensortype;
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_DOMOTICZ));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_DOMOTICZ);
for (int i = 0; i < MAX_DOMOTICZ_IDX; i++) {
if (i < devices_present) {
@ -374,22 +367,28 @@ void DomoticzSaveSettings()
{
char stemp[20];
char ssensor_indices[6 * MAX_DOMOTICZ_SNS_IDX];
char tmp[100];
for (byte i = 0; i < MAX_DOMOTICZ_IDX; i++) {
snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i +1);
Settings.domoticz_relay_idx[i] = (!strlen(WebServer->arg(stemp).c_str())) ? 0 : atoi(WebServer->arg(stemp).c_str());
WebGetArg(stemp, tmp, sizeof(tmp));
Settings.domoticz_relay_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i +1);
Settings.domoticz_key_idx[i] = (!strlen(WebServer->arg(stemp).c_str())) ? 0 : atoi(WebServer->arg(stemp).c_str());
WebGetArg(stemp, tmp, sizeof(tmp));
Settings.domoticz_key_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i +1);
Settings.domoticz_switch_idx[i] = (!strlen(WebServer->arg(stemp).c_str())) ? 0 : atoi(WebServer->arg(stemp).c_str());
WebGetArg(stemp, tmp, sizeof(tmp));
Settings.domoticz_switch_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
}
ssensor_indices[0] = '\0';
for (byte i = 0; i < DZ_MAX_SENSORS; i++) {
snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i +1);
Settings.domoticz_sensor_idx[i] = (!strlen(WebServer->arg(stemp).c_str())) ? 0 : atoi(WebServer->arg(stemp).c_str());
WebGetArg(stemp, tmp, sizeof(tmp));
Settings.domoticz_sensor_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
snprintf_P(ssensor_indices, sizeof(ssensor_indices), PSTR("%s%s%d"), ssensor_indices, (strlen(ssensor_indices)) ? "," : "", Settings.domoticz_sensor_idx[i]);
}
Settings.domoticz_update_timer = (!strlen(WebServer->arg("ut").c_str())) ? DOMOTICZ_UPDATE_TIMER : atoi(WebServer->arg("ut").c_str());
WebGetArg("ut", tmp, sizeof(tmp));
Settings.domoticz_update_timer = (!strlen(tmp)) ? DOMOTICZ_UPDATE_TIMER : atoi(tmp);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DOMOTICZ D_CMND_IDX " %d,%d,%d,%d, " D_CMND_KEYIDX " %d,%d,%d,%d, " D_CMND_SWITCHIDX " %d,%d,%d,%d, " D_CMND_SENSORIDX " %s, " D_CMND_UPDATETIMER " %d"),
Settings.domoticz_relay_idx[0], Settings.domoticz_relay_idx[1], Settings.domoticz_relay_idx[2], Settings.domoticz_relay_idx[3],
@ -398,6 +397,7 @@ void DomoticzSaveSettings()
ssensor_indices, Settings.domoticz_update_timer);
AddLog(LOG_LEVEL_INFO);
}
#endif // USE_WEBSERVER
/*********************************************************************************************\
* Interface
@ -417,6 +417,9 @@ boolean Xdrv05(byte function)
case FUNC_MQTT_SUBSCRIBE:
DomoticzMqttSubscribe();
break;
case FUNC_MQTT_INIT:
domoticz_update_timer = 2;
break;
case FUNC_MQTT_DATA:
result = DomoticzMqttData();
break;
@ -431,5 +434,4 @@ boolean Xdrv05(byte function)
return result;
}
#endif // USE_WEBSERVER
#endif // USE_DOMOTICZ

View File

@ -0,0 +1,165 @@
/*
xdrv_07_home_assistant.ino - home assistant support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_HOME_ASSISTANT
const char HASS_DISCOVER_SWITCH[] PROGMEM =
"{\"name\":\"%s\"," // dualr2 1
"\"command_topic\":\"%s\"," // cmnd/dualr2/POWER2
"\"state_topic\":\"%s\"," // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",")
"\"value_template\":\"{{value_json.%s}}\"," // POWER2
"\"payload_off\":\"%s\"," // OFF
"\"payload_on\":\"%s\"," // ON
// "\"optimistic\":\"false\"," // false is Hass default when state_topic is set
"\"availability_topic\":\"%s\"," // tele/dualr2/LWT
"\"payload_available\":\"" D_ONLINE "\"," // Online
"\"payload_not_available\":\"" D_OFFLINE "\""; // Offline
const char HASS_DISCOVER_LIGHT_DIMMER[] PROGMEM =
"%s,\"brightness_command_topic\":\"%s\"," // cmnd/led2/Dimmer
"\"brightness_state_topic\":\"%s\"," // stat/led2/RESULT
"\"brightness_scale\":100," // 100%
"\"on_command_type\":\"brightness\"," // power on (first), power on (last), no power on (brightness)
"\"brightness_value_template\":\"{{value_json." D_CMND_DIMMER "}}\"";
const char HASS_DISCOVER_LIGHT_COLOR[] PROGMEM =
"%s,\"rgb_command_topic\":\"%s\"," // cmnd/led2/Color
"\"rgb_state_topic\":\"%s\"," // stat/led2/RESULT
"\"rgb_value_template\":\"{{value_json." D_CMND_COLOR "}}\"";
// "\"rgb_value_template\":\"{{value_json." D_CMND_COLOR " | join(',')}}\"";
const char HASS_DISCOVER_LIGHT_CT[] PROGMEM =
"%s,\"color_temp_command_topic\":\"%s\"," // cmnd/led2/CT
"\"color_temp_state_topic\":\"%s\"," // stat/led2/RESULT
"\"color_temp_value_template\":\"{{value_json." D_CMND_COLORTEMPERATURE "}}\"";
/*
const char HASS_DISCOVER_LIGHT_SCHEME[] PROGMEM =
"%s,\"effect_command_topic\":\"%s\"," // cmnd/led2/Scheme
"\"effect_state_topic\":\"%s\"," // stat/led2/RESULT
"\"effect_value_template\":\"{{value_json." D_CMND_SCHEME "}}\","
"\"effect_list\":\"[0, 1, 2, 3, 4]\""; // Needs to be a Python string list providing Scheme parameter values (Unable to get this functional)
*/
/*
#1690 - investigate
effect_list:
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
*/
void HAssDiscovery()
{
char sidx[8];
char stopic[TOPSZ];
bool is_light = false;
// Configure Tasmota for default Home Assistant parameters to keep discovery message as short as possible
if (Settings.flag.hass_discovery) {
Settings.flag.mqtt_response = 0; // Response always as RESULT and not as uppercase command
Settings.flag.decimal_text = 1; // Respond with decimal color values
// Settings.light_scheme = 0; // To just control color it needs to be Scheme 0
// strncpy_P(Settings.mqtt_fulltopic, PSTR("%prefix%/%topic%/"), sizeof(Settings.mqtt_fulltopic)); // Make MQTT topic as short as possible to make this process posible within MQTT_MAX_PACKET_SIZE
}
for (int i = 1; i <= devices_present; i++) {
is_light = ((i == devices_present) && (light_type));
snprintf_P(sidx, sizeof(sidx), PSTR("_%d"), i);
snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s%s/config"), (is_light) ? "light" : "switch", Settings.mqtt_topic, (1 == devices_present) ? "" : sidx);
mqtt_data[0] = '\0';
if (Settings.flag.hass_discovery) {
char name[33];
char value_template[33];
char command_topic[TOPSZ];
char state_topic[TOPSZ];
char availability_topic[TOPSZ];
if (i > MAX_FRIENDLYNAMES) {
snprintf_P(name, sizeof(name), PSTR("%s %d"), Settings.friendlyname[0], i);
} else {
snprintf_P(name, sizeof(name), Settings.friendlyname[i -1]);
}
GetPowerDevice(value_template, i, sizeof(value_template));
GetTopic_P(command_topic, CMND, Settings.mqtt_topic, value_template);
GetTopic_P(state_topic, STAT, Settings.mqtt_topic, S_RSLT_RESULT);
GetTopic_P(availability_topic, TELE, Settings.mqtt_topic, S_LWT);
snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SWITCH, name, command_topic, state_topic, value_template, Settings.state_text[0], Settings.state_text[1], availability_topic);
if (is_light) {
char brightness_command_topic[TOPSZ];
GetTopic_P(brightness_command_topic, CMND, Settings.mqtt_topic, D_CMND_DIMMER);
snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_DIMMER, mqtt_data, brightness_command_topic, state_topic);
if (light_subtype >= LST_RGB) {
char rgb_command_topic[TOPSZ];
GetTopic_P(rgb_command_topic, CMND, Settings.mqtt_topic, D_CMND_COLOR);
snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_COLOR, mqtt_data, rgb_command_topic, state_topic);
/*
char effect_command_topic[TOPSZ];
GetTopic_P(effect_command_topic, CMND, Settings.mqtt_topic, D_CMND_SCHEME);
snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_SCHEME, mqtt_data, effect_command_topic, state_topic);
*/
}
if ((LST_COLDWARM == light_subtype) || (LST_RGBWC == light_subtype)) {
char color_temp_command_topic[TOPSZ];
GetTopic_P(color_temp_command_topic, CMND, Settings.mqtt_topic, D_CMND_COLORTEMPERATURE);
snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_CT, mqtt_data, color_temp_command_topic, state_topic);
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
}
MqttPublish(stopic, true);
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
#define XDRV_07
boolean Xdrv07(byte function)
{
boolean result = false;
if (Settings.flag.mqtt_enabled) {
switch (function) {
case FUNC_MQTT_INIT:
HAssDiscovery();
break;
}
}
return result;
}
#endif // USE_HOME_ASSISTANT

View File

@ -17,58 +17,127 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
void XDrvInit()
{
for (byte i = 0; i < XDRV_MAX; i++) {
xdrv_func_ptr[i] = NULL;
}
xdrv_present = 0;
boolean (* const xdrv_func_ptr[])(byte) PROGMEM = { // Driver Function Pointers
#ifdef XDRV_01
xdrv_func_ptr[xdrv_present++] = &Xdrv01;
&Xdrv01,
#endif
#ifdef XDRV_02
xdrv_func_ptr[xdrv_present++] = &Xdrv02;
&Xdrv02,
#endif
#ifdef XDRV_03
xdrv_func_ptr[xdrv_present++] = &Xdrv03;
&Xdrv03,
#endif
#ifdef XDRV_04
xdrv_func_ptr[xdrv_present++] = &Xdrv04;
&Xdrv04,
#endif
#ifdef XDRV_05
xdrv_func_ptr[xdrv_present++] = &Xdrv05;
&Xdrv05,
#endif
#ifdef XDRV_06
xdrv_func_ptr[xdrv_present++] = &Xdrv06;
&Xdrv06,
#endif
#ifdef XDRV_07
xdrv_func_ptr[xdrv_present++] = &Xdrv07;
&Xdrv07,
#endif
#ifdef XDRV_08
xdrv_func_ptr[xdrv_present++] = &Xdrv08;
&Xdrv08,
#endif
#ifdef XDRV_09
xdrv_func_ptr[xdrv_present++] = &Xdrv09;
&Xdrv09,
#endif
#ifdef XDRV_10
xdrv_func_ptr[xdrv_present++] = &Xdrv10;
&Xdrv10,
#endif
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "Drivers %d"), xdrv_present);
// AddLog(LOG_LEVEL_DEBUG);
#ifdef XDRV_11
&Xdrv11,
#endif
XdrvCall(FUNC_INIT);
}
#ifdef XDRV_12
&Xdrv12,
#endif
#ifdef XDRV_13
&Xdrv13,
#endif
#ifdef XDRV_14
&Xdrv14,
#endif
#ifdef XDRV_15
&Xdrv15,
#endif
#ifdef XDRV_16
&Xdrv16,
#endif
#ifdef XDRV_17
&Xdrv17,
#endif
#ifdef XDRV_18
&Xdrv18,
#endif
#ifdef XDRV_19
&Xdrv19,
#endif
#ifdef XDRV_20
&Xdrv20,
#endif
// Optional user defined drivers in range 91 - 99
#ifdef XDRV_91
&Xdrv91,
#endif
#ifdef XDRV_92
&Xdrv92,
#endif
#ifdef XDRV_93
&Xdrv93,
#endif
#ifdef XDRV_94
&Xdrv94,
#endif
#ifdef XDRV_95
&Xdrv95,
#endif
#ifdef XDRV_96
&Xdrv96,
#endif
#ifdef XDRV_97
&Xdrv97,
#endif
#ifdef XDRV_98
&Xdrv98,
#endif
#ifdef XDRV_99
&Xdrv99
#endif
};
const uint8_t xdrv_present = sizeof(xdrv_func_ptr) / sizeof(xdrv_func_ptr[0]); // Number of drivers found
boolean XdrvCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload)
{
@ -82,7 +151,7 @@ boolean XdrvCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_len
return XdrvCall(FUNC_COMMAND);
}
void XdrvSetPower(uint8_t mpower)
void XdrvSetPower(power_t mpower)
{
// XdrvMailbox.valid = 1;
XdrvMailbox.index = mpower;
@ -102,6 +171,16 @@ boolean XdrvMqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t
/*********************************************************************************************\
* Function call to all xdrv
*
* FUNC_INIT
* FUNC_MQTT_SUBSCRIBE
* FUNC_MQTT_INIT
* return FUNC_MQTT_DATA
* return FUNC_COMMAND
* FUNC_SET_POWER
* FUNC_SHOW_SENSOR
* FUNC_EVERY_SECOND
* FUNC_EVERY_50_MSECOND
\*********************************************************************************************/
boolean XdrvCall(byte Function)

View File

@ -388,10 +388,10 @@ void HandleUpnpEvent()
//differentiate get and set state
if (request.indexOf(F("SetBinaryState")) > 0) {
if (request.indexOf(F("State>1</Binary")) > 0) {
ExecuteCommandPower(devices_present, 1);
ExecuteCommandPower(devices_present, POWER_ON);
}
else if (request.indexOf(F("State>0</Binary")) > 0) {
ExecuteCommandPower(devices_present, 0);
ExecuteCommandPower(devices_present, POWER_OFF);
}
}
else if(request.indexOf(F("GetBinaryState")) > 0){
@ -452,8 +452,8 @@ const char HUE_DESCRIPTION_XML[] PROGMEM =
"</device>"
"</root>\r\n"
"\r\n";
const char HueLightStatus_JSON[] PROGMEM =
"\"on\":{state},"
const char HUE_LIGHTS_STATUS_JSON[] PROGMEM =
"{\"on\":{state},"
"\"bri\":{b},"
"\"hue\":{h},"
"\"sat\":{s},"
@ -462,19 +462,18 @@ const char HueLightStatus_JSON[] PROGMEM =
"\"alert\":\"none\","
"\"effect\":\"none\","
"\"colormode\":\"hs\","
"\"reachable\":true";
const char HUE_LIGHTS_STATUS_JSON[] PROGMEM =
"\"type\":\"Extended color light\","
"\"reachable\":true}";
const char HUE_LIGHTS_STATUS_JSON2[] PROGMEM =
",\"type\":\"Extended color light\","
"\"name\":\"{j1\","
"\"modelid\":\"LCT007\","
"\"uniqueid\":\"{j2\","
"\"swversion\":\"5.50.1.19085\""
"}";
"\"swversion\":\"5.50.1.19085\"}";
const char HUE_GROUP0_STATUS_JSON[] PROGMEM =
"{\"name\":\"Group 0\","
"\"lights\":[{l1],"
"\"type\":\"LightGroup\","
"\"action\":{";
"\"action\":";
// "\"scene\":\"none\",";
const char HueConfigResponse_JSON[] PROGMEM =
"{\"name\":\"Philips hue\","
@ -556,18 +555,27 @@ void HueConfig(String *path)
WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response);
}
void HueLightStatus(byte device, String *response)
void HueLightStatus1(byte device, String *response)
{
*response += FPSTR(HueLightStatus_JSON);
response->replace("{state}", (power & (1 << (device-1))) ? "true" : "false");
float hue = 0;
float sat = 0;
float bri = 0;
if (light_type) {
LightReplaceHsb(response);
} else {
response->replace("{h}", "0");
response->replace("{s}", "0");
response->replace("{b}", "0");
LightGetHsb(&hue, &sat, &bri);
}
*response += FPSTR(HUE_LIGHTS_STATUS_JSON);
response->replace("{state}", (power & (1 << (device-1))) ? "true" : "false");
response->replace("{h}", String((uint16_t)(65535.0f * hue)));
response->replace("{s}", String((uint8_t)(254.0f * sat)));
response->replace("{b}", String((uint8_t)(254.0f * bri)));
}
void HueLightStatus2(byte device, String *response)
{
*response += FPSTR(HUE_LIGHTS_STATUS_JSON2);
response->replace("{j1", Settings.friendlyname[device-1]);
response->replace("{j2", GetHueDeviceId(device));
}
void HueGlobalConfig(String *path)
@ -579,12 +587,9 @@ void HueGlobalConfig(String *path)
response = F("{\"lights\":{\"");
for (uint8_t i = 1; i <= maxhue; i++) {
response += i;
response += F("\":{\"state\":{");
HueLightStatus(i, &response);
response += "},";
response += FPSTR(HUE_LIGHTS_STATUS_JSON);
response.replace("{j1", Settings.friendlyname[i-1]);
response.replace("{j2", GetHueDeviceId(i));
response += F("\":{\"state\":");
HueLightStatus1(i, &response);
HueLightStatus2(i, &response);
if (i < maxhue) {
response += ",\"";
}
@ -611,7 +616,6 @@ void HueLights(String *path)
String response;
uint8_t device = 1;
uint16_t tmp = 0;
int16_t pos = 0;
float bri = 0;
float hue = 0;
float sat = 0;
@ -619,7 +623,6 @@ void HueLights(String *path)
bool resp = false;
bool on = false;
bool change = false;
char id[4];
uint8_t maxhue = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present;
path->remove(0,path->indexOf("/lights")); // Remove until /lights
@ -627,12 +630,9 @@ void HueLights(String *path)
response = "{\"";
for (uint8_t i = 1; i <= maxhue; i++) {
response += i;
response += F("\":{\"state\":{");
HueLightStatus(i, &response);
response += "},";
response += FPSTR(HUE_LIGHTS_STATUS_JSON);
response.replace("{j1", Settings.friendlyname[i-1]);
response.replace("{j2", GetHueDeviceId(i));
response += F("\":{\"state\":");
HueLightStatus1(i, &response);
HueLightStatus2(i, &response);
if (i < maxhue) {
response += ",\"";
}
@ -661,10 +661,10 @@ void HueLights(String *path)
on = hue_json["on"];
switch(on)
{
case false : ExecuteCommandPower(device, 0);
case false : ExecuteCommandPower(device, POWER_OFF);
response.replace("{re", "false");
break;
case true : ExecuteCommandPower(device, 1);
case true : ExecuteCommandPower(device, POWER_ON);
response.replace("{re", "true");
break;
default : response.replace("{re", (power & (1 << (device-1))) ? "true" : "false");
@ -674,7 +674,7 @@ void HueLights(String *path)
}
if (light_type) {
LightGetHsb(&hue,&sat,&bri);
LightGetHsb(&hue, &sat, &bri);
}
if (hue_json.containsKey("bri")) {
@ -749,12 +749,9 @@ void HueLights(String *path)
if ((device < 1) || (device > maxhue)) {
device = 1;
}
response += F("{\"state\":{");
HueLightStatus(device, &response);
response += "},";
response += FPSTR(HUE_LIGHTS_STATUS_JSON);
response.replace("{j1", Settings.friendlyname[device-1]);
response.replace("{j2", GetHueDeviceId(device));
response += F("{\"state\":");
HueLightStatus1(device, &response);
HueLightStatus2(device, &response);
WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response);
}
else {
@ -777,8 +774,8 @@ void HueGroups(String *path)
lights += ",\"" + String(i) + "\"";
}
response.replace("{l1", lights);
HueLightStatus(1, &response);
response += F("}}");
HueLightStatus1(1, &response);
response += F("}");
}
WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response);

View File

@ -105,7 +105,7 @@ void SonoffScSerialInput(char *rcvstat)
#ifdef USE_WEBSERVER
const char HTTP_SNS_SCPLUS[] PROGMEM =
"%s{s}" D_LIGHT "{m}%d%{e}{s}" D_NOISE "{m}%d%{e}{s}" D_AIR_QUALITY "{m}%d%{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
"%s{s}" D_LIGHT "{m}%d%%{e}{s}" D_NOISE "{m}%d%%{e}{s}" D_AIR_QUALITY "{m}%d%%{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_WEBSERVER
void SonoffScShow(boolean json)

View File

@ -192,7 +192,7 @@ void Ds18b20Show(boolean json)
if (Ds18b20Read(t)) { // Check if read failed
char temperature[10];
dtostrfi(t, Settings.flag2.temperature_resolution, temperature);
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
if(json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"DS18B20\":{\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, temperature);

View File

@ -404,8 +404,13 @@ boolean Xsns05(byte function)
case FUNC_INIT:
Ds18x20Init();
break;
// case FUNC_EVERY_SECOND:
// if ((Settings.tele_period - tele_period) &3 == 3) {
// Ds18x20Convert(); // Start conversion every four seconds, takes up to one second
// }
// break;
case FUNC_PREP_BEFORE_TELEPERIOD:
Ds18x20Convert(); // Start conversion, takes up to one second
Ds18x20Convert(); // Start conversion, takes up to one second
break;
case FUNC_JSON_APPEND:
Ds18x20Show(1);
@ -413,7 +418,7 @@ boolean Xsns05(byte function)
#ifdef USE_WEBSERVER
case FUNC_WEB_APPEND:
Ds18x20Show(0);
Ds18x20Convert(); // Start conversion, takes up to one second
Ds18x20Convert(); // Start conversion, takes up to one second
break;
#endif // USE_WEBSERVER
}

View File

@ -40,8 +40,8 @@ struct DHTSTRUCT {
char stype[12];
uint32_t lastreadtime;
uint8_t lastresult;
float t;
float h = 0;
float t = NAN;
float h = NAN;
} Dht[DHT_MAX_SENSORS];
void DhtReadPrep()
@ -56,7 +56,7 @@ int32_t DhtExpectPulse(byte sensor, bool level)
int32_t count = 0;
while (digitalRead(Dht[sensor].pin) == level) {
if (count++ >= dht_max_cycles) {
if (count++ >= (int32_t)dht_max_cycles) {
return -1; // Timeout
}
}
@ -141,7 +141,7 @@ void DhtRead(byte sensor)
boolean DhtReadTempHum(byte sensor, float &t, float &h)
{
if (!Dht[sensor].h) {
if (NAN == Dht[sensor].h) {
t = NAN;
h = NAN;
} else {
@ -203,7 +203,7 @@ void DhtInit()
pinMode(Dht[i].pin, INPUT_PULLUP);
Dht[i].lastreadtime = 0;
Dht[i].lastresult = 0;
strcpy_P(Dht[i].stype, kSensors[Dht[i].type]);
GetTextIndexed(Dht[i].stype, sizeof(Dht[i].stype), Dht[i].type, kSensorNames);
if (dht_sensors > 1) {
snprintf_P(Dht[i].stype, sizeof(Dht[i].stype), PSTR("%s-%02d"), Dht[i].stype, Dht[i].pin);
}
@ -214,11 +214,11 @@ void DhtShow(boolean json)
{
char temperature[10];
char humidity[10];
float t;
float h;
byte dsxflg = 0;
for (byte i = 0; i < dht_sensors; i++) {
float t = NAN;
float h = NAN;
if (DhtReadTempHum(i, t, h)) { // Read temperature
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
dtostrfd(h, Settings.flag2.humidity_resolution, humidity);

View File

@ -206,6 +206,7 @@ float HtuCompensatedHumidity(float humidity, float temperature)
if(temperature > 0.00 && temperature < 80.00) {
return (-0.15)*(25-temperature)+humidity;
}
return humidity;
}
/********************************************************************************************/

View File

@ -98,16 +98,16 @@ boolean Bmp180Calibration()
return false;
}
if ((cal_ac1 == 0xFFFF) |
(cal_ac2 == 0xFFFF) |
(cal_ac3 == 0xFFFF) |
if ((cal_ac1 == (int16_t)0xFFFF) |
(cal_ac2 == (int16_t)0xFFFF) |
(cal_ac3 == (int16_t)0xFFFF) |
(cal_ac4 == 0xFFFF) |
(cal_ac5 == 0xFFFF) |
(cal_ac6 == 0xFFFF) |
(cal_b1 == 0xFFFF) |
(cal_b2 == 0xFFFF) |
(cal_mc == 0xFFFF) |
(cal_md == 0xFFFF)) {
(cal_b1 == (int16_t)0xFFFF) |
(cal_b2 == (int16_t)0xFFFF) |
(cal_mc == (int16_t)0xFFFF) |
(cal_md == (int16_t)0xFFFF)) {
return false;
}
return true;
@ -128,9 +128,6 @@ double Bmp180ReadTemperature()
double Bmp180ReadPressure()
{
int32_t p;
uint8_t msb;
uint8_t lsb;
uint8_t xlsb;
I2cWrite8(bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution
delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution
@ -504,8 +501,14 @@ boolean Xsns09(byte function)
switch (function) {
case FUNC_PREP_BEFORE_TELEPERIOD:
BmpDetect();
break;
case FUNC_EVERY_SECOND:
#ifdef USE_BME680
Bme680PerformReading();
if ((Settings.tele_period - tele_period) < 300) { // 5 minute stabilization time
if (tele_period &1) {
Bme680PerformReading(); // Keep BME680 busy every two seconds
}
}
#endif // USE_BME680
break;
case FUNC_JSON_APPEND:

View File

@ -19,6 +19,9 @@
#ifdef USE_I2C
#ifdef USE_INA219
#define XSNS_13 13
/*********************************************************************************************\
* INA219 - Low voltage (max 32V!) Current sensor
*
@ -152,6 +155,23 @@ float Ina219GetCurrent_mA()
return value;
}
/*********************************************************************************************\
* Command Sensor13
\*********************************************************************************************/
bool Ina219CommandSensor()
{
boolean serviced = true;
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {
Settings.ina219_mode = XdrvMailbox.payload;
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_NVALUE, XSNS_13, Settings.ina219_mode);
return serviced;
}
/********************************************************************************************/
void Ina219Detect()
@ -211,14 +231,17 @@ void Ina219Show(boolean json)
* Interface
\*********************************************************************************************/
#define XSNS_13
boolean Xsns13(byte function)
{
boolean result = false;
if (i2c_flg) {
switch (function) {
case FUNC_COMMAND:
if ((XSNS_13 == XdrvMailbox.index) && (ina219_type)) {
result = Ina219CommandSensor();
}
break;
case FUNC_PREP_BEFORE_TELEPERIOD:
Ina219Detect();
break;

View File

@ -18,6 +18,9 @@
*/
#ifdef USE_MHZ19
#define XSNS_15 15
/*********************************************************************************************\
* MH-Z19 - CO2 sensor
*
@ -71,6 +74,7 @@ const char kMhzTypes[] PROGMEM = "MHZ19|MHZ19B";
const uint8_t mhz_cmnd_read_ppm[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
const uint8_t mhz_cmnd_abc_enable[9] = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6};
const uint8_t mhz_cmnd_abc_disable[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86};
const uint8_t mhz_cmnd_zeropoint[9] = {0xff, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78};
uint8_t mhz_type = 1;
uint16_t mhz_last_ppm = 0;
@ -134,6 +138,7 @@ void Mhz50ms()
if (6 == mhz_timer) { // MH-Z19 measuring cycle takes 1005 +5% ms
mhz_timer = 0;
MhzSerial->flush();
MhzSerial->write(mhz_cmnd_read_ppm, 9);
}
@ -207,6 +212,34 @@ void Mhz50ms()
}
}
/*********************************************************************************************\
* Command Sensor15
\*********************************************************************************************/
/*
0 - ABC Off
1 - ABC On
2 - Manual start = ABC Off
3 - Optional filter settings
*/
bool MhzCommandSensor()
{
boolean serviced = true;
switch (XdrvMailbox.payload) {
case 2:
MhzSerial->write(mhz_cmnd_zeropoint, 9);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_ZERO_POINT_CALIBRATION);
break;
default:
serviced = false;
}
return serviced;
}
/*********************************************************************************************/
void MhzInit()
@ -243,8 +276,6 @@ void MhzShow(boolean json)
* Interface
\*********************************************************************************************/
#define XSNS_15
boolean Xsns15(byte function)
{
boolean result = false;
@ -257,6 +288,11 @@ boolean Xsns15(byte function)
case FUNC_EVERY_50_MSECOND:
Mhz50ms();
break;
case FUNC_COMMAND:
if (XSNS_15 == XdrvMailbox.index) {
result = MhzCommandSensor();
}
break;
case FUNC_JSON_APPEND:
MhzShow(1);
break;

View File

@ -31,27 +31,30 @@
uint8_t tsl2561_address;
uint8_t tsl2561_addresses[] = { TSL2561_ADDR_LOW, TSL2561_ADDR_FLOAT, TSL2561_ADDR_HIGH };
uint8_t tsl2561_type = 0;
//TSL2561 tsl(TSL2561_ADDR_FLOAT);
TSL2561 *tsl;
TSL2561 *tsl = 0;
void Tsl2561Detect()
{
if (tsl2561_type) {
if (tsl) {
return;
}
for (byte i = 0; i < sizeof(tsl2561_addresses); i++) {
tsl2561_address = tsl2561_addresses[i];
tsl = new TSL2561(tsl2561_address);
if (tsl->begin()) {
tsl->setGain(TSL2561_GAIN_16X);
tsl->setTiming(TSL2561_INTEGRATIONTIME_101MS);
tsl2561_type = 1;
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "TSL2561", tsl2561_address);
AddLog(LOG_LEVEL_DEBUG);
break;
if (I2cDevice(tsl2561_address)) {
tsl = new TSL2561(tsl2561_address);
if (tsl->begin()) {
tsl->setGain(TSL2561_GAIN_16X);
tsl->setTiming(TSL2561_INTEGRATIONTIME_101MS);
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "TSL2561", tsl2561_address);
AddLog(LOG_LEVEL_DEBUG);
break;
} else {
delete tsl;
tsl = 0;
}
}
}
}
@ -63,8 +66,23 @@ const char HTTP_SNS_TSL2561[] PROGMEM =
void Tsl2561Show(boolean json)
{
if (tsl2561_type) {
uint16_t illuminance = tsl->getLuminosity(TSL2561_VISIBLE);
if (tsl) {
union {
uint32_t full;
struct { uint16_t both, ir; };
} light;
light.full = tsl->getFullLuminosity();
uint32_t illuminance = 0;
if ((light.full == 0 || light.full == 0xffffffff)) {
if (!I2cDevice(tsl2561_address)) {
delete tsl;
tsl = 0;
}
} else {
illuminance = tsl->calculateLux(light.both, light.ir);
}
snprintf(log_data, sizeof(log_data), PSTR(D_ILLUMINANCE " 0x%08lx = b 0x%04x, i 0x%04x -> %lu " D_UNIT_LUX), light.full, light.both, light.ir, illuminance);
AddLog(LOG_LEVEL_DEBUG);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"TSL2561\":{\"" D_JSON_ILLUMINANCE "\":%d}"), mqtt_data, illuminance);
@ -108,4 +126,4 @@ boolean Xsns16(byte function)
}
#endif // USE_TSL2561
#endif // USE_I2C
#endif // USE_I2C

View File

@ -74,6 +74,7 @@ void ModbusSend(uint8_t function_code, uint16_t start_address, uint16_t register
frame[7] = (uint8_t)((crc >> 8) & 0xFF);
frame[6] = (uint8_t)(crc & 0xFF);
SensairSerial->flush();
SensairSerial->write(frame, sizeof(frame));
}

173
sonoff/xsns_18_pms5003.ino Normal file
View File

@ -0,0 +1,173 @@
/*
xsns_18_pms5003.ino - PMS5003-7003 particle concentration sensor support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_PMS5003
/*********************************************************************************************\
* PlanTower PMS5003 and PMS7003 particle concentration sensor
* For background information see http://aqicn.org/sensor/pms5003-7003/
\*********************************************************************************************/
#include <TasmotaSerial.h>
TasmotaSerial *PmsSerial;
uint8_t pms_type = 1;
uint8_t pms_valid = 0;
struct pms5003data {
uint16_t framelen;
uint16_t pm10_standard, pm25_standard, pm100_standard;
uint16_t pm10_env, pm25_env, pm100_env;
uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
uint16_t unused;
uint16_t checksum;
} pms_data;
boolean PmsReadData()
{
if (! PmsSerial->available()) {
return false;
}
while ((PmsSerial->peek() != 0x42) && PmsSerial->available()) {
PmsSerial->read();
}
if (PmsSerial->available() < 32) {
return false;
}
uint8_t buffer[32];
uint16_t sum = 0;
PmsSerial->readBytes(buffer, 32);
PmsSerial->flush(); // Make room for another burst
// get checksum ready
for (uint8_t i = 0; i < 30; i++) {
sum += buffer[i];
}
// The data comes in endian'd, this solves it so it works on all platforms
uint16_t buffer_u16[15];
for (uint8_t i = 0; i < 15; i++) {
buffer_u16[i] = buffer[2 + i*2 + 1];
buffer_u16[i] += (buffer[2 + i*2] << 8);
}
if (sum != buffer_u16[14]) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("PMS: " D_CHECKSUM_FAILURE));
return false;
}
memcpy((void *)&pms_data, (void *)buffer_u16, 30);
pms_valid = 10;
return true;
}
/*********************************************************************************************/
void PmsSecond() // Every second
{
if (PmsReadData()) {
pms_valid = 10;
} else {
if (pms_valid) {
pms_valid--;
}
}
}
/*********************************************************************************************/
void PmsInit()
{
pms_type = 0;
if (pin[GPIO_PMS5003] < 99) {
PmsSerial = new TasmotaSerial(pin[GPIO_PMS5003], -1);
if (PmsSerial->begin()) {
pms_type = 1;
}
}
}
#ifdef USE_WEBSERVER
const char HTTP_PMS5003_SNS[] PROGMEM = "%s"
// "{s}PMS5003 " D_STANDARD_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"
// "{s}PMS5003 " D_STANDARD_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"
// "{s}PMS5003 " D_STANDARD_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"
"{s}PMS5003 " D_ENVIRONMENTAL_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"
"{s}PMS5003 " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"
"{s}PMS5003 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"
"{s}PMS5003 " D_PARTICALS_BEYOND " 0.3 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"
"{s}PMS5003 " D_PARTICALS_BEYOND " 0.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"
"{s}PMS5003 " D_PARTICALS_BEYOND " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"
"{s}PMS5003 " D_PARTICALS_BEYOND " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"
"{s}PMS5003 " D_PARTICALS_BEYOND " 5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"
"{s}PMS5003 " D_PARTICALS_BEYOND " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_WEBSERVER
void PmsShow(boolean json)
{
if (pms_valid) {
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PMS5003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d,\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,\"PB5\":%d,\"PB10\":%d}"), mqtt_data,
pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard,
pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env,
pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um, pms_data.particles_50um, pms_data.particles_100um);
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_PMS5003_SNS, mqtt_data,
// pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard,
pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env,
pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um, pms_data.particles_50um, pms_data.particles_100um);
#endif // USE_WEBSERVER
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
#define XSNS_18
boolean Xsns18(byte function)
{
boolean result = false;
if (pms_type) {
switch (function) {
case FUNC_INIT:
PmsInit();
break;
case FUNC_EVERY_SECOND:
PmsSecond();
break;
case FUNC_JSON_APPEND:
PmsShow(1);
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_APPEND:
PmsShow(0);
break;
#endif // USE_WEBSERVER
}
}
return result;
}
#endif // USE_PMS5003

View File

@ -1,5 +1,5 @@
/*
xsns_interface.ino - External sensor interface support for Sonoff-Tasmota
xsns_interface.ino - Sensor interface support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends inspired by ESPEasy
@ -17,101 +17,187 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
void XSnsInit()
{
for (byte i = 0; i < XSNS_MAX; i++) {
xsns_func_ptr[i] = NULL;
}
xsns_present = 0;
boolean (* const xsns_func_ptr[])(byte) PROGMEM = { // Sensor Function Pointers for simple implementation of sensors
#ifdef XSNS_01
xsns_func_ptr[xsns_present++] = &Xsns01;
&Xsns01,
#endif
#ifdef XSNS_02
xsns_func_ptr[xsns_present++] = &Xsns02;
&Xsns02,
#endif
#ifdef XSNS_03
xsns_func_ptr[xsns_present++] = &Xsns03;
&Xsns03,
#endif
#ifdef XSNS_04
xsns_func_ptr[xsns_present++] = &Xsns04;
&Xsns04,
#endif
#ifdef XSNS_05
xsns_func_ptr[xsns_present++] = &Xsns05;
&Xsns05,
#endif
#ifdef XSNS_06
xsns_func_ptr[xsns_present++] = &Xsns06;
&Xsns06,
#endif
#ifdef XSNS_07
xsns_func_ptr[xsns_present++] = &Xsns07;
&Xsns07,
#endif
#ifdef XSNS_08
xsns_func_ptr[xsns_present++] = &Xsns08;
&Xsns08,
#endif
#ifdef XSNS_09
xsns_func_ptr[xsns_present++] = &Xsns09;
&Xsns09,
#endif
#ifdef XSNS_10
xsns_func_ptr[xsns_present++] = &Xsns10;
&Xsns10,
#endif
#ifdef XSNS_11
xsns_func_ptr[xsns_present++] = &Xsns11;
&Xsns11,
#endif
#ifdef XSNS_12
xsns_func_ptr[xsns_present++] = &Xsns12;
&Xsns12,
#endif
#ifdef XSNS_13
xsns_func_ptr[xsns_present++] = &Xsns13;
&Xsns13,
#endif
#ifdef XSNS_14
xsns_func_ptr[xsns_present++] = &Xsns14;
&Xsns14,
#endif
#ifdef XSNS_15
xsns_func_ptr[xsns_present++] = &Xsns15;
&Xsns15,
#endif
#ifdef XSNS_16
xsns_func_ptr[xsns_present++] = &Xsns16;
&Xsns16,
#endif
#ifdef XSNS_17
xsns_func_ptr[xsns_present++] = &Xsns17;
&Xsns17,
#endif
#ifdef XSNS_18
xsns_func_ptr[xsns_present++] = &Xsns18;
&Xsns18,
#endif
#ifdef XSNS_19
xsns_func_ptr[xsns_present++] = &Xsns19;
&Xsns19,
#endif
#ifdef XSNS_20
xsns_func_ptr[xsns_present++] = &Xsns20;
&Xsns20,
#endif
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "Sensors found %d"), xsns_present);
// AddLog(LOG_LEVEL_DEBUG);
#ifdef XSNS_21
&Xsns21,
#endif
XsnsCall(FUNC_INIT);
}
#ifdef XSNS_22
&Xsns22,
#endif
#ifdef XSNS_23
&Xsns23,
#endif
#ifdef XSNS_24
&Xsns24,
#endif
#ifdef XSNS_25
&Xsns25,
#endif
#ifdef XSNS_26
&Xsns26,
#endif
#ifdef XSNS_27
&Xsns27,
#endif
#ifdef XSNS_28
&Xsns28,
#endif
#ifdef XSNS_29
&Xsns29,
#endif
#ifdef XSNS_30
&Xsns30,
#endif
#ifdef XSNS_31
&Xsns31,
#endif
#ifdef XSNS_32
&Xsns32,
#endif
// Optional user defined sensors in range 91 - 99
#ifdef XSNS_91
&Xsns91,
#endif
#ifdef XSNS_92
&Xsns92,
#endif
#ifdef XSNS_93
&Xsns93,
#endif
#ifdef XSNS_94
&Xsns94,
#endif
#ifdef XSNS_95
&Xsns95,
#endif
#ifdef XSNS_96
&Xsns96,
#endif
#ifdef XSNS_97
&Xsns97,
#endif
#ifdef XSNS_98
&Xsns98,
#endif
#ifdef XSNS_99
&Xsns99
#endif
};
const uint8_t xsns_present = sizeof(xsns_func_ptr) / sizeof(xsns_func_ptr[0]); // Number of External Sensors found
/*********************************************************************************************\
* Function call to all xsns
*
* FUNC_INIT
* FUNC_PREP_BEFORE_TELEPERIOD
* FUNC_SAVE_BEFORE_RESTART
* FUNC_JSON_APPEND
* FUNC_WEB_APPEND
* return FUNC_COMMAND
* FUNC_EVERY_SECOND
* FUNC_EVERY_50_MSECOND
\*********************************************************************************************/
boolean XsnsCall(byte Function)
@ -119,7 +205,10 @@ boolean XsnsCall(byte Function)
boolean result = false;
for (byte x = 0; x < xsns_present; x++) {
xsns_func_ptr[x](Function);
result = xsns_func_ptr[x](Function);
if (result) {
break;
}
}
return result;