diff --git a/.gitignore b/.gitignore index 028a76667..7e89f6cd2 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ build .vscode/.browse.c_cpp.db* .vscode/c_cpp_properties.json .vscode/launch.json +*.bak diff --git a/lib/TasmotaSerial-2.2.0/README.md b/lib/TasmotaSerial-2.3.0/README.md similarity index 100% rename from lib/TasmotaSerial-2.2.0/README.md rename to lib/TasmotaSerial-2.3.0/README.md diff --git a/lib/TasmotaSerial-2.2.0/examples/swsertest/swsertest.ino b/lib/TasmotaSerial-2.3.0/examples/swsertest/swsertest.ino similarity index 100% rename from lib/TasmotaSerial-2.2.0/examples/swsertest/swsertest.ino rename to lib/TasmotaSerial-2.3.0/examples/swsertest/swsertest.ino diff --git a/lib/TasmotaSerial-2.2.0/keywords.txt b/lib/TasmotaSerial-2.3.0/keywords.txt similarity index 95% rename from lib/TasmotaSerial-2.2.0/keywords.txt rename to lib/TasmotaSerial-2.3.0/keywords.txt index 87974971e..9cf6d825c 100644 --- a/lib/TasmotaSerial-2.2.0/keywords.txt +++ b/lib/TasmotaSerial-2.3.0/keywords.txt @@ -14,6 +14,7 @@ TasmotaSerial KEYWORD1 ####################################### begin KEYWORD2 +hardwareSerial KEYWORD2 read KEYWORD2 write KEYWORD2 available KEYWORD2 diff --git a/lib/TasmotaSerial-2.2.0/library.json b/lib/TasmotaSerial-2.3.0/library.json similarity index 94% rename from lib/TasmotaSerial-2.2.0/library.json rename to lib/TasmotaSerial-2.3.0/library.json index 23a2ddab9..fad36bcc6 100644 --- a/lib/TasmotaSerial-2.2.0/library.json +++ b/lib/TasmotaSerial-2.3.0/library.json @@ -1,6 +1,6 @@ { "name": "TasmotaSerial", - "version": "2.2.0", + "version": "2.3.0", "keywords": [ "serial", "io", "TasmotaSerial" ], diff --git a/lib/TasmotaSerial-2.2.0/library.properties b/lib/TasmotaSerial-2.3.0/library.properties similarity index 94% rename from lib/TasmotaSerial-2.2.0/library.properties rename to lib/TasmotaSerial-2.3.0/library.properties index 54c79e218..095077d8e 100644 --- a/lib/TasmotaSerial-2.2.0/library.properties +++ b/lib/TasmotaSerial-2.3.0/library.properties @@ -1,5 +1,5 @@ name=TasmotaSerial -version=2.2.0 +version=2.3.0 author=Theo Arends maintainer=Theo Arends sentence=Implementation of software serial with hardware serial fallback for ESP8266. diff --git a/lib/TasmotaSerial-2.2.0/src/TasmotaSerial.cpp b/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.cpp similarity index 97% rename from lib/TasmotaSerial-2.2.0/src/TasmotaSerial.cpp rename to lib/TasmotaSerial-2.3.0/src/TasmotaSerial.cpp index 3df42f834..eecdeb124 100644 --- a/lib/TasmotaSerial-2.2.0/src/TasmotaSerial.cpp +++ b/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.cpp @@ -1,7 +1,7 @@ /* TasmotaSerial.cpp - Minimal implementation of software serial for Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -100,7 +100,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal 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; + m_bit_time = F_CPU / TM_SERIAL_BAUDRATE; pinMode(m_rx_pin, INPUT); tms_obj_list[m_rx_pin] = this; attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING); @@ -145,7 +145,7 @@ bool TasmotaSerial::begin(long speed, int stop_bits) { } } else { // Use getCycleCount() loop to get as exact timing as possible - m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed; + m_bit_time = F_CPU / speed; m_high_speed = (speed > 9600); } return m_valid; @@ -257,7 +257,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; + unsigned int next = (m_in_pos+1) % TM_SERIAL_BUFFER_SIZE; if (next != (int)m_out_pos) { m_buffer[m_in_pos] = rec; m_in_pos = next; diff --git a/lib/TasmotaSerial-2.2.0/src/TasmotaSerial.h b/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.h similarity index 96% rename from lib/TasmotaSerial-2.2.0/src/TasmotaSerial.h rename to lib/TasmotaSerial-2.3.0/src/TasmotaSerial.h index de991526a..9481ef370 100644 --- a/lib/TasmotaSerial-2.2.0/src/TasmotaSerial.h +++ b/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.h @@ -1,7 +1,7 @@ /* TasmotaSerial.h - Minimal implementation of software serial for Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,7 +22,7 @@ /*********************************************************************************************\ * TasmotaSerial supports up to 115200 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) + * Based on EspSoftwareSerial v3.4.3 by Peter Lerup (https://github.com/plerup/espsoftwareserial) \*********************************************************************************************/ #define TM_SERIAL_BAUDRATE 9600 // Default baudrate diff --git a/platformio.ini b/platformio.ini index 6b6176db0..f5d958ebf 100644 --- a/platformio.ini +++ b/platformio.ini @@ -65,7 +65,7 @@ build_flags = ${esp82xx_defaults.build_flags} -DVTABLES_IN_FLASH [core_2_5_0] -; *** Esp8266 core for Arduino version Core 2.5.0 beta3 tested for Tasmota +; *** Esp8266 core for Arduino version 2.5.0 release (still not available via platformio) platform = https://github.com/Jason2866/platform-espressif8266.git#Tasmota build_flags = ${esp82xx_defaults.build_flags} -Wl,-Teagle.flash.1m.ld @@ -130,12 +130,12 @@ board_build.flash_mode = dout platform = ${core_active.platform} build_flags = ${core_active.build_flags} -; -DUSE_CLASSIC -; -DBE_MINIMAL -; -DUSE_SENSORS -; -DUSE_BASIC -; -DUSE_KNX_NO_EMULATION -; -DUSE_DISPLAYS +; -DFIRMWARE_CLASSIC +; -DFIRMWARE_MINIMAL +; -DFIRMWARE_SENSORS +; -DFIRMWARE_BASIC +; -DFIRMWARE_KNX_NO_EMULATION +; -DFIRMWARE_DISPLAYS ; -DUSE_CONFIG_OVERRIDE ; *** Fix espressif8266@1.7.0 induced undesired all warnings @@ -184,7 +184,7 @@ board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DBE_MINIMAL +build_flags = ${common.build_flags} -DFIRMWARE_MINIMAL monitor_speed = ${common.monitor_speed} upload_port = ${common.upload_port} upload_resetmethod = ${common.upload_resetmethod} @@ -198,7 +198,7 @@ board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DUSE_BASIC +build_flags = ${common.build_flags} -DFIRMWARE_BASIC monitor_speed = ${common.monitor_speed} upload_port = ${common.upload_port} upload_resetmethod = ${common.upload_resetmethod} @@ -212,7 +212,7 @@ board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DUSE_CLASSIC +build_flags = ${common.build_flags} -DFIRMWARE_CLASSIC monitor_speed = ${common.monitor_speed} upload_port = ${common.upload_port} upload_resetmethod = ${common.upload_resetmethod} @@ -226,7 +226,7 @@ board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DUSE_KNX_NO_EMULATION +build_flags = ${common.build_flags} -DFIRMWARE_KNX_NO_EMULATION monitor_speed = ${common.monitor_speed} upload_port = ${common.upload_port} upload_resetmethod = ${common.upload_resetmethod} @@ -240,7 +240,7 @@ board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DUSE_SENSORS +build_flags = ${common.build_flags} -DFIRMWARE_SENSORS monitor_speed = ${common.monitor_speed} upload_port = ${common.upload_port} upload_resetmethod = ${common.upload_resetmethod} @@ -254,7 +254,7 @@ board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DUSE_DISPLAYS +build_flags = ${common.build_flags} -DFIRMWARE_DISPLAYS monitor_speed = ${common.monitor_speed} upload_port = ${common.upload_port} upload_resetmethod = ${common.upload_resetmethod} diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 339ae2bfe..80c79746f 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,9 +1,19 @@ -/* 6.4.1.14 20190203 +/* 6.4.1.15 20190208 + * Change image name BE_MINIMAL to FIRMWARE_MINIMAL (#5106) + * Change image names USE_xyz to FIRMWARE_xyz (#5106) + * + * 6.4.1.14 20190203 * Add SetOption32 until SetOption49 diagnostic information to Status 3 report as replacement for second property value in SetOption property name * Add Resolution property to Status 3 report providing previous SetOption second value property * Fix IR local echo * Add user configuration of HLW8012 and HJL-01/BL0937 Energy Monitoring as used in Sonoff S31, Pow Ra and many Tuya based devices * Add user configuration of MCP39F501 Energy Monitoring as used in Shelly2 + * Add support for multiple ADS1115 I2C devices (#5083) + * Add rule support for "==", "!=" ">=" and "<=" (#5122) + * Add Hass status sensor (#5139) + * Change GUI weblog solving possible empty screens (#5154) + * Change PN532 support from I2C to Serial for more stability (#5162) + * Add MHZ19 Temperature as Domoticz Temperature selection (#5128) * * 6.4.1.13 20190130 * Add command SetOption36 to control boot loop default restoration (#4645, #5063) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 3f9725772..7eace1215 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -160,6 +160,7 @@ #define D_JSON_ZERO_POINT_CALIBRATION "Zero Point Calibration" #define D_RSLT_ENERGY "ENERGY" +#define D_RSLT_HASS_STATE "HASS_STATE" #define D_RSLT_INFO "INFO" #define D_RSLT_MARGINS "MARGINS" #define D_RSLT_POWER "POWER" diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index b04271a7f..c0195039b 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Активиране на SM16716" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index caf213296..48c78ed96 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Povol SM16716" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 2c2b48d5e..c82602d0c 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 aktivieren" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index faa5f0ec2..4a711959e 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Ενεργοποίηση SM16716" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index a4acbf38d..6b4ebcbd2 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Enable SM16716" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 075c8bbf5..2e8bf6fbc 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Habilitar SM16716" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index a75205c26..59292bd44 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Activer SM16716" diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h index 031635c15..62c23386a 100644 --- a/sonoff/language/he-HE.h +++ b/sonoff/language/he-HE.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Enable SM16716" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 3d8cc8850..6a96b2501 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 engedélyezése" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index c2b3a60c3..94aac6e22 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Abilita SM16716" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index c9a0e4715..eb4ed10f7 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -554,6 +554,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 inschakelen" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 1ad8e5546..ee8de5739 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -554,6 +554,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Włącz SM16716" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index e3f61775a..c88fdd0c4 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Habilitar SM16716" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index e9b3c470e..94b5923cf 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Enable SM16716" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index a0a0953e9..d88f9e6e4 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Enable SM16716" diff --git a/sonoff/language/sk-SK.h b/sonoff/language/sk-SK.h index f1e6495c9..31d9a021e 100644 --- a/sonoff/language/sk-SK.h +++ b/sonoff/language/sk-SK.h @@ -554,6 +554,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Povoľ SM16716" diff --git a/sonoff/language/sv-SE.h b/sonoff/language/sv-SE.h index 961637b35..ea0b507b6 100644 --- a/sonoff/language/sv-SE.h +++ b/sonoff/language/sv-SE.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Aktivera SM16716" diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index 1302595cf..557b057c9 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 Aktif" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index 5a2aad11b..e227203a7 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Увімкнений SM16716" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 3f24ab2ae..3a882e424 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "启用 SM16716" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index be91648d2..b5154a03e 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "Enable SM16716" diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index d06b0c854..ea2f980e8 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -326,9 +326,6 @@ // #define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code) // #define USE_RTC_ADDR 0x68 // Default I2C address 0x68 // #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) -// #define USE_PN532_I2C // Enable PN532 - Near Field Communication (NFC) controller (+1k7 code, 164 bytes of mem) -// #define USE_PN532_DATA_FUNCTION // Enable PN532 DATA Usage using Sensor15 command (+1k6 code, 316 bytes of mem) -// #define USE_PN532_CAUSE_EVENTS // Enable PN532 driver to cause event's on card read in addition to immediate telemetry (+64 bytes code, 48 bytes mem) // #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) // #define USE_DISPLAY // Add I2C Display Support (+2k code) @@ -378,6 +375,9 @@ #define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) #define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer //#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger (+1k6 code) +//#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) +// #define USE_PN532_DATA_FUNCTION // Add sensor40 command support for erase, setting data block content (+1k7 code, 388 bytes mem) +// #define USE_PN532_DATA_RAW // Allow DATA block to be used by non-alpha-numberic data (+ 80 bytes code, 48 bytes ram) // Power monitoring sensors ----------------------- #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) @@ -431,12 +431,12 @@ * See RELEASENOTES.md for selected features \*********************************************************************************************/ -//#define USE_CLASSIC // Create sonoff-classic with initial configuration tools WPS, SmartConfig and WifiManager -//#define USE_BASIC // Create sonoff-basic with no sensors -//#define USE_SENSORS // Create sonoff-sensors with useful sensors enabled -//#define USE_KNX_NO_EMULATION // Create sonoff-knx with KNX but without Emulation -//#define USE_DISPLAYS // Create sonoff-display with display drivers enabled -//#define BE_MINIMAL // Create sonoff-minimal as intermediate firmware for OTA-MAGIC +//#define FIRMWARE_CLASSIC // Create sonoff-classic with initial configuration tools WPS, SmartConfig and WifiManager +//#define FIRMWARE_BASIC // Create sonoff-basic with no sensors +//#define FIRMWARE_SENSORS // Create sonoff-sensors with useful sensors enabled +//#define FIRMWARE_KNX_NO_EMULATION // Create sonoff-knx with KNX but without Emulation +//#define FIRMWARE_DISPLAYS // Create sonoff-display with display drivers enabled +//#define FIRMWARE_MINIMAL // Create sonoff-minimal as intermediate firmware for OTA-MAGIC /*********************************************************************************************\ * No user configurable items below diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 55a73fc56..b3192d50a 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -391,7 +391,7 @@ void SettingsSave(uint8_t rotate) * stop_flash_rotate 0 = Allow flash slot rotation (SetOption12 0) * stop_flash_rotate 1 = Allow only eeprom flash slot use (SetOption12 1) */ -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL if ((GetSettingsCrc() != settings_crc) || rotate) { if (1 == rotate) { // Use eeprom flash slot only and disable flash rotate from now on (upgrade) stop_flash_rotate = 1; @@ -441,7 +441,7 @@ void SettingsSave(uint8_t rotate) settings_crc = Settings.cfg_crc; } -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL RtcSettingsSave(); } @@ -487,12 +487,12 @@ void SettingsLoad(void) AddLog(LOG_LEVEL_DEBUG); } -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL if (!settings_location || (Settings.cfg_holder != (uint16_t)CFG_HOLDER)) { // Init defaults if cfg_holder differs from user settings in my_user_config.h SettingsDefault(); } settings_crc = GetSettingsCrc(); -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL RtcSettingsLoad(); } @@ -504,7 +504,7 @@ void SettingsErase(uint8_t type) 1 = Erase SDK parameter area at end of linker memory model (0x0FDxxx - 0x0FFFFF) solving possible wifi errors */ -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL bool result; uint32_t _sectorStart = (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 1; @@ -533,7 +533,7 @@ void SettingsErase(uint8_t type) } OsWatchLoop(); } -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL } // Copied from 2.4.0 as 2.3.0 is incomplete diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 067bc5400..17f9bdf4a 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -1957,7 +1957,7 @@ void Every250mSeconds(void) ota_retry_counter--; if (ota_retry_counter) { strlcpy(mqtt_data, GetOtaUrl(log_data, sizeof(log_data)), sizeof(mqtt_data)); -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL if (RtcSettings.ota_loader) { char *bch = strrchr(mqtt_data, '/'); // Only consider filename after last backslash prevent change of urls having "-" in it char *pch = strrchr((bch != NULL) ? bch : mqtt_data, '-'); // Change from filename-DE.bin into filename-minimal.bin @@ -1969,7 +1969,7 @@ void Every250mSeconds(void) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s-" D_JSON_MINIMAL "%s"), mqtt_data, ech); // Minimal filename must be filename-minimal } } -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "%s"), mqtt_data); AddLog(LOG_LEVEL_DEBUG); #if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) @@ -1980,14 +1980,14 @@ void Every250mSeconds(void) ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(OTAclient, mqtt_data)); #endif if (!ota_result) { -#ifndef BE_MINIMAL +#ifndef FIRMWARE_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 +#endif // FIRMWARE_MINIMAL ota_state_flag = 2; // Upgrade failed - retry } } @@ -2590,10 +2590,10 @@ void setup(void) snprintf_P(log_data, sizeof(log_data), PSTR(D_PROJECT " %s %s " D_VERSION " %s%s-" ARDUINO_ESP8266_RELEASE), PROJECT, Settings.friendlyname[0], my_version, my_image); AddLog(LOG_LEVEL_INFO); -#ifdef BE_MINIMAL +#ifdef FIRMWARE_MINIMAL snprintf_P(log_data, sizeof(log_data), PSTR(D_WARNING_MINIMAL_VERSION)); AddLog(LOG_LEVEL_INFO); -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL RtcInit(); diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index e6eb186a5..06bd3688b 100644 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -55,7 +55,7 @@ void KNX_CB_Action(message_t const &msg, void *arg); * Provide an image with useful supported sensors enabled \*********************************************************************************************/ -#ifdef USE_SENSORS +#ifdef FIRMWARE_SENSORS #undef CODE_IMAGE #define CODE_IMAGE 3 @@ -92,7 +92,6 @@ void KNX_CB_Action(message_t const &msg, void *arg); //#define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code) //#define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code) //#define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) -//#define USE_PN532_I2C // Enable PN532 - Near Field Communication (NFC) controller (+1k6 code) //#define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) #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) @@ -114,6 +113,8 @@ void KNX_CB_Action(message_t const &msg, void *arg); #define TUYA_DIMMER_ID 0 // Default dimmer Id #endif #define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer +//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger +#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) #define USE_PZEM_AC // Add support for PZEM014,016 Energy monitor (+1k1 code) #define USE_PZEM_DC // Add support for PZEM003,017 Energy monitor (+1k1 code) @@ -138,15 +139,14 @@ void KNX_CB_Action(message_t const &msg, void *arg); #define USE_RF_SENSOR // Add support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) // #define USE_THEO_V2 // Add support for decoding Theo V2 sensors as documented on https://sidweb.nl using 434MHz RF sensor receiver (+1k4 code) #define USE_ALECTO_V2 // Add support for decoding Alecto V2 sensors like ACH2010, WS3000 and DKW2012 using 868MHz RF sensor receiver (+1k7 code) -//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger -#endif // USE_SENSORS +#endif // FIRMWARE_SENSORS /*********************************************************************************************\ * [sonoff-classic.bin] * Provide an image close to version 5.12.0 but still within 499k program space to allow one time OTA \*********************************************************************************************/ -#ifdef USE_CLASSIC +#ifdef FIRMWARE_CLASSIC #undef CODE_IMAGE #define CODE_IMAGE 2 @@ -174,10 +174,6 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_SENSEAIR // Disable support for SenseAir K30, K70 and S8 CO2 sensor #undef USE_PMS5003 // Disable support for PMS5003 and PMS7003 particle concentration sensor #undef USE_NOVA_SDS // Disable support for SDS011 and SDS021 particle concentration sensor -#undef USE_PZEM004T // Disable PZEM004T energy sensor -#undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor -#undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor -#undef USE_MCP39F501 // Disable support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code) #undef USE_SERIAL_BRIDGE // Disable support for software Serial Bridge #undef USE_SDM120 // Disable support for Eastron SDM120-Modbus energy meter #undef USE_SDM630 // Disable support for Eastron SDM630-Modbus energy meter @@ -185,6 +181,12 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer +#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger +#undef USE_PN532_HSU // Disable support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) +#undef USE_PZEM004T // Disable PZEM004T energy sensor +#undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor +#undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor +#undef USE_MCP39F501 // Disable support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code) #undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI #undef USE_IR_REMOTE // Disable IR remote commands using library IRremoteESP8266 and ArduinoJson #undef USE_IR_RECEIVE // Disable support for IR receiver @@ -198,15 +200,14 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code -#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger -#endif // USE_CLASSIC +#endif // FIRMWARE_CLASSIC /*********************************************************************************************\ * [sonoff-knx.bin] * Provide a dedicated KNX image allowing enough code and memory space \*********************************************************************************************/ -#ifdef USE_KNX_NO_EMULATION +#ifdef FIRMWARE_KNX_NO_EMULATION #undef CODE_IMAGE #define CODE_IMAGE 4 @@ -215,14 +216,14 @@ void KNX_CB_Action(message_t const &msg, void *arg); #define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem) #endif #undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem) -#endif // USE_KNX_NO_EMULATION +#endif // FIRMWARE_KNX_NO_EMULATION /*********************************************************************************************\ * [sonoff-display.bin] * Provide an image with display drivers enabled \*********************************************************************************************/ -#ifdef USE_DISPLAYS +#ifdef FIRMWARE_DISPLAYS #undef CODE_IMAGE #define CODE_IMAGE 6 @@ -249,7 +250,7 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_ARILUX_RF // Remove support for Arilux RF remote controller (-0k8 code, 252 iram (non 2.3.0)) #undef USE_RF_FLASH // Remove support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (-3k code) -#endif // USE_DISPLAYS +#endif // FIRMWARE_DISPLAYS /*********************************************************************************************\ * Mandatory define for DS18x20 if changed by above image selections @@ -265,13 +266,13 @@ void KNX_CB_Action(message_t const &msg, void *arg); * Provide an image without sensors \*********************************************************************************************/ -#ifdef USE_BASIC +#ifdef FIRMWARE_BASIC #undef CODE_IMAGE #define CODE_IMAGE 5 #undef APP_SLEEP -#define APP_SLEEP 1 // Default to sleep = 1 for USE_BASIC +#define APP_SLEEP 1 // Default to sleep = 1 for FIRMWARE_BASIC //#undef USE_ENERGY_SENSOR // Disable energy sensors #undef USE_ARDUINO_OTA // Disable support for Arduino OTA @@ -307,6 +308,8 @@ void KNX_CB_Action(message_t const &msg, void *arg); //#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer +#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger +#undef USE_PN532_HSU // Disable support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) #undef USE_PZEM004T // Disable PZEM004T energy sensor #undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor #undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor @@ -324,15 +327,14 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code -#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger -#endif // USE_BASIC +#endif // FIRMWARE_BASIC /*********************************************************************************************\ * [sonoff-minimal.bin] * Provide the smallest image possible while still enabling a webserver for intermediate image load \*********************************************************************************************/ -#ifdef BE_MINIMAL +#ifdef FIRMWARE_MINIMAL #undef CODE_IMAGE #define CODE_IMAGE 1 @@ -371,6 +373,8 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer +#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger +#undef USE_PN532_HSU // Disable support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) #undef USE_PZEM004T // Disable PZEM004T energy sensor #undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor #undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor @@ -388,8 +392,7 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code -#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL /*********************************************************************************************\ * Mandatory defines satisfying possible disabled defines diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 12f9a9241..a400d2afd 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -162,6 +162,8 @@ enum UserSelectablePins { GPIO_MCP39F5_TX, // MCP39F501 Serial interface (Shelly2) GPIO_MCP39F5_RX, // MCP39F501 Serial interface (Shelly2) GPIO_MCP39F5_RST, // MCP39F501 Reset (Shelly2) + GPIO_PN532_TXD, // PN532 NFC Serial Tx + GPIO_PN532_RXD, // PN532 NFC Serial Rx GPIO_SM16716_CLK, // SM16716 CLOCK GPIO_SM16716_DAT, // SM16716 DATA GPIO_SM16716_SEL, // SM16716 SELECT @@ -230,6 +232,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_BUTTON "1in|" D_SENSOR_BUTTON "2in|" D_SENSOR_BUTTON "3in|" D_SENSOR_BUTTON "4in|" D_SENSOR_NRG_SEL "|" D_SENSOR_NRG_SEL "i|" D_SENSOR_NRG_CF1 "|" D_SENSOR_HLW_CF "|" D_SENSOR_HJL_CF "|" D_SENSOR_MCP39F5_TX "|" D_SENSOR_MCP39F5_RX "|" D_SENSOR_MCP39F5_RST "|" + D_SENSOR_PN532_TX "|" D_SENSOR_PN532_RX "|" D_SENSOR_SM16716_CLK "|" D_SENSOR_SM16716_DAT "|" D_SENSOR_SM16716_POWER ; @@ -538,14 +541,18 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_TUYA_TX, // Tuya Serial interface GPIO_TUYA_RX, // Tuya Serial interface #endif -#ifdef USE_MGC3130 - GPIO_MGC3130_XFER, - GPIO_MGC3130_RESET, -#endif #ifdef USE_AZ7798 GPIO_AZ_TXD, // AZ-Instrument 7798 CO2 datalogger Serial interface GPIO_AZ_RXD, // AZ-Instrument 7798 CO2 datalogger Serial interface #endif +#ifdef USE_PN532_HSU + GPIO_PN532_TXD, // PN532 HSU Tx + GPIO_PN532_RXD, // PN532 HSU Rx +#endif +#ifdef USE_MGC3130 + GPIO_MGC3130_XFER, + GPIO_MGC3130_RESET, +#endif #ifdef USE_MAX31855 GPIO_MAX31855CS, // MAX31855 Serial interface GPIO_MAX31855CLK, // MAX31855 Serial interface @@ -1072,9 +1079,10 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, // GPIO09 0, // GPIO10 // GPIO11 (SD_CMD Flash) - 0, + GPIO_USER, // GPIO12 Optional sensor GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status - 0, 0, 0, 0 + GPIO_USER, // GPIO14 Optional sensor + 0, 0, 0 }, { "Sonoff B1", // Sonoff B1 (ESP8285 - my9231) GPIO_KEY1, // GPIO00 Pad diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 5aaa62872..9afa3f2b2 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x0604010E +#define VERSION 0x0604010F #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/support_features.ino b/sonoff/support_features.ino index 1dc19e172..31c449531 100644 --- a/sonoff/support_features.ino +++ b/sonoff/support_features.ino @@ -126,16 +126,16 @@ void GetFeatures(void) #ifdef USE_CONFIG_OVERRIDE feature_drv2 |= 0x00000001; // user_config(_override).h #endif -#ifdef BE_MINIMAL +#ifdef FIRMWARE_MINIMAL feature_drv2 |= 0x00000002; // user_config(_override).h #endif -#ifdef USE_SENSORS +#ifdef FIRMWARE_SENSORS feature_drv2 |= 0x00000004; // user_config(_override).h #endif -#ifdef USE_CLASSIC +#ifdef FIRMWARE_CLASSIC feature_drv2 |= 0x00000008; // user_config(_override).h #endif -#ifdef USE_KNX_NO_EMULATION +#ifdef FIRMWARE_KNX_NO_EMULATION feature_drv2 |= 0x00000010; // user_config(_override).h #endif #ifdef USE_DISPLAY_MODES1TO5 @@ -378,8 +378,8 @@ void GetFeatures(void) #ifdef USE_MAX31855 feature_sns2 |= 0x00080000; // xsns_39_max31855.ino #endif -#ifdef USE_PN532_I2C - feature_sns2 |= 0x00100000; // xsns_40_pn532_i2c.ino +#ifdef USE_PN532_HSU + feature_sns2 |= 0x00100000; // xsns_40_pn532.ino #endif #ifdef USE_MAX44009 feature_sns2 |= 0x00200000; diff --git a/sonoff/support_wifi.ino b/sonoff/support_wifi.ino index 730ac595f..90f0584b7 100644 --- a/sonoff/support_wifi.ino +++ b/sonoff/support_wifi.ino @@ -501,12 +501,12 @@ void WifiCheck(uint8_t param) } } -#ifdef BE_MINIMAL +#ifdef FIRMWARE_MINIMAL if (1 == RtcSettings.ota_loader) { RtcSettings.ota_loader = 0; ota_state_flag = 3; } -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL #ifdef USE_DISCOVERY if (Settings.flag3.mdns_enabled) { diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index 51498abb4..449ae6e35 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -129,11 +129,11 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM = "x.onreadystatechange=function(){" "if(x.readyState==4&&x.status==200){" "var z,d;" - "d=x.responseXML;" - "id=d.getElementsByTagName('i')[0].childNodes[0].nodeValue;" - "if(d.getElementsByTagName('j')[0].childNodes[0].nodeValue==0){t.value='';}" - "z=d.getElementsByTagName('l')[0].childNodes;" - "if(z.length>0){t.value+=decodeURIComponent(z[0].nodeValue);}" + "d=x.responseText.split(/\1/);" + "id=d.shift();" + "if(d.shift()==0){t.value='';}" + "z=d.shift();" + "if(z.length>0){t.value+=z;}" "t.scrollTop=99999;" "sn=t.scrollTop;" "}" @@ -208,7 +208,7 @@ const char HTTP_HEAD_STYLE[] PROGMEM = "" "" "
" -#ifdef BE_MINIMAL +#ifdef FIRMWARE_MINIMAL "

" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "

" #endif "
" @@ -227,7 +227,7 @@ const char HTTP_MSG_SLIDER2[] PROGMEM = const char HTTP_MSG_RSTRT[] PROGMEM = "
" D_DEVICE_WILL_RESTART "

"; const char HTTP_BTN_MENU1[] PROGMEM = -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL "
" "
" #endif @@ -401,7 +401,7 @@ void StartWebserver(int type, IPAddress ipweb) WebServer->on("/ay", HandleAjaxStatusRefresh); WebServer->on("/cm", HandleHttpCommand); WebServer->onNotFound(HandleNotFound); -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL WebServer->on("/cn", HandleConfiguration); WebServer->on("/md", HandleModuleConfiguration); WebServer->on("/wi", HandleWifiConfiguration); @@ -416,7 +416,7 @@ void StartWebserver(int type, IPAddress ipweb) #endif // USE_EMULATION XdrvCall(FUNC_WEB_ADD_HANDLER); XsnsCall(FUNC_WEB_ADD_HANDLER); -#endif // Not BE_MINIMAL +#endif // Not FIRMWARE_MINIMAL } reset_web_log_flag = false; WebServer->begin(); // Web server start @@ -601,7 +601,7 @@ void HandleRoot(void) } if (HTTP_MANAGER == webserver_state) { -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL if ((Settings.web_password[0] != 0) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1"))) { HandleWifiLogin(); } else { @@ -619,7 +619,7 @@ void HandleRoot(void) HandleWifiLogin(); } } -#endif // Not BE_MINIMAL +#endif // Not FIRMWARE_MINIMAL } else { char stemp[10]; String page = FPSTR(HTTP_HEAD); @@ -673,12 +673,12 @@ void HandleRoot(void) page += F(""); } -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL mqtt_data[0] = '\0'; XdrvCall(FUNC_WEB_ADD_MAIN_BUTTON); XsnsCall(FUNC_WEB_ADD_MAIN_BUTTON); page += String(mqtt_data); -#endif // Not BE_MINIMAL +#endif // Not FIRMWARE_MINIMAL if (HTTP_ADMIN == webserver_state) { page += FPSTR(HTTP_BTN_MENU1); @@ -773,7 +773,7 @@ bool HttpCheckPriviledgedAccess(bool autorequestauth = true) /*-------------------------------------------------------------------------------------------*/ -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL void HandleConfiguration(void) { @@ -1407,7 +1407,7 @@ void HandleInformation(void) page += FPSTR(HTTP_BTN_MAIN); ShowPage(page); } -#endif // Not BE_MINIMAL +#endif // Not FIRMWARE_MINIMAL /*-------------------------------------------------------------------------------------------*/ @@ -1813,7 +1813,9 @@ void HandleAjaxConsoleRefresh(void) if (strlen(svalue)) { counter = atoi(svalue); } bool 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 + // mqtt_data used as scratch space + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%d\1%d\1"), web_log_index, last_reset_web_log_flag); + String message = mqtt_data; if (!reset_web_log_flag) { counter = 0; reset_web_log_flag = true; @@ -1834,20 +1836,13 @@ void HandleAjaxConsoleRefresh(void) cflg = true; } strlcpy(mqtt_data, tmp, len); - message += mqtt_data; + message += mqtt_data; // mqtt_data used as scratch space } counter++; - if (!counter) { counter++; } // Skip 0 as it is not allowed + if (!counter) { counter++; } // Skip log index 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("%d%d"), web_log_index, last_reset_web_log_flag); - message.replace(F("}9"), mqtt_data); // Save to load here - message += F(""); + message += F("\1"); WebServer->send(200, FPSTR(HDR_CTYPE_XML), message); } diff --git a/sonoff/xdrv_08_serial_bridge.ino b/sonoff/xdrv_08_serial_bridge.ino index bb2abab63..74915935c 100644 --- a/sonoff/xdrv_08_serial_bridge.ino +++ b/sonoff/xdrv_08_serial_bridge.ino @@ -42,7 +42,7 @@ void SerialBridgeInput(void) { while (SerialBridgeSerial->available()) { yield(); - uint8_t serial_in_uint8_t = SerialBridgeSerial->read(); + uint8_t serial_in_byte = SerialBridgeSerial->read(); if (serial_in_byte > 127) { // binary data... serial_bridge_in_byte_counter = 0; diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 0ea47c369..327c128dc 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -78,6 +78,18 @@ #define D_JSON_INITIATED "Initiated" +#define COMPARE_OPERATOR_NONE -1 +#define COMPARE_OPERATOR_EQUAL 0 +#define COMPARE_OPERATOR_BIGGER 1 +#define COMPARE_OPERATOR_SMALLER 2 +#define COMPARE_OPERATOR_EXACT_DIVISION 3 +#define COMPARE_OPERATOR_NUMBER_EQUAL 4 +#define COMPARE_OPERATOR_NOT_EQUAL 5 +#define COMPARE_OPERATOR_BIGGER_EQUAL 6 +#define COMPARE_OPERATOR_SMALLER_EQUAL 7 +#define MAXIMUM_COMPARE_OPERATOR COMPARE_OPERATOR_SMALLER_EQUAL +const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<="; + enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM, CMND_ADD, CMND_SUB, CMND_MULT, CMND_SCALE, CMND_CALC_RESOLUTION }; const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE "|" D_CMND_CALC_RESOLUTION ; @@ -128,31 +140,20 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule) String rule_name = rule.substring(pos +1); // "CURRENT>0.100" or "BOOT" or "%var1%" or "MINUTE|5" - char compare = ' '; - pos = rule_name.indexOf(">"); - if (pos > 0) { - compare = '>'; - } else { - pos = rule_name.indexOf("<"); - if (pos > 0) { - compare = '<'; - } else { - pos = rule_name.indexOf("="); - if (pos > 0) { - compare = '='; - } else { - pos = rule_name.indexOf("|"); // Modulo, cannot use % easily as it is used for variable detection - if (pos > 0) { - compare = '%'; - } - } + char compare_operator[3]; + int8_t compare = COMPARE_OPERATOR_NONE; + for (int8_t i = MAXIMUM_COMPARE_OPERATOR; i >= 0; i--) { + snprintf_P(compare_operator, sizeof(compare_operator), kCompareOperators + (i *2)); + if ((pos = rule_name.indexOf(compare_operator)) > 0) { + compare = i; + break; } } char rule_svalue[CMDSZ] = { 0 }; double rule_value = 0; - if (pos > 0) { - String rule_param = rule_name.substring(pos + 1); + if (compare != COMPARE_OPERATOR_NONE) { + String rule_param = rule_name.substring(pos + strlen(compare_operator)); for (uint8_t i = 0; i < MAX_RULE_VARS; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%%VAR%d%%"), i +1); if (rule_param.startsWith(stemp)) { @@ -224,24 +225,32 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule) int int_value = int(value); int int_rule_value = int(rule_value); switch (compare) { - case '%': - if ((int_value > 0) && (int_rule_value > 0)) { - if ((int_value % int_rule_value) == 0) { match = true; } - } + case COMPARE_OPERATOR_EXACT_DIVISION: + match = (int_rule_value && (int_value % int_rule_value) == 0); break; - case '>': - if (value > rule_value) { match = true; } + case COMPARE_OPERATOR_EQUAL: + match = (!strcasecmp(str_value, rule_svalue)); // Compare strings - this also works for hexadecimals break; - case '<': - if (value < rule_value) { match = true; } + case COMPARE_OPERATOR_BIGGER: + match = (value > rule_value); break; - case '=': -// if (value == rule_value) { match = true; } // Compare values - only decimals or partly hexadecimals - if (!strcasecmp(str_value, rule_svalue)) { match = true; } // Compare strings - this also works for hexadecimals + case COMPARE_OPERATOR_SMALLER: + match = (value < rule_value); break; - case ' ': - match = true; // Json value but not needed + case COMPARE_OPERATOR_NUMBER_EQUAL: + match = (value == rule_value); break; + case COMPARE_OPERATOR_NOT_EQUAL: + match = (value != rule_value); + break; + case COMPARE_OPERATOR_BIGGER_EQUAL: + match = (value >= rule_value); + break; + case COMPARE_OPERATOR_SMALLER_EQUAL: + match = (value <= rule_value); + break; + default: + match = true; } } else match = true; diff --git a/sonoff/xdrv_12_home_assistant.ino b/sonoff/xdrv_12_home_assistant.ino index 6b6d1bff3..b6e6af299 100644 --- a/sonoff/xdrv_12_home_assistant.ino +++ b/sonoff/xdrv_12_home_assistant.ino @@ -122,6 +122,11 @@ const char HASS_DISCOVER_SENSOR_ANY[] PROGMEM = "%s,\"unit_of_meas\":\" \"," // " " As unit of measurement to get a value graph in Hass "\"val_tpl\":\"{{value_json['%s'].%s}}\""; // "COUNTER":{"C1":0} -> {{ value_json['COUNTER'].C1 }} +const char HASS_DISCOVER_SENSOR_HASS_STATUS[] PROGMEM = + "%s,\"json_attributes_topic\":\"%s\"," + "\"unit_of_meas\":\" \"," // " " As unit of measurement to get a value graph in Hass + "\"val_tpl\":\"{{value_json['" D_JSON_RSSI "']}}\"";// "COUNTER":{"C1":0} -> {{ value_json['COUNTER'].C1 }} + const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM = "%s,\"uniq_id\":\"%s\"," "\"device\":{\"identifiers\":[\"%06X\"]," @@ -130,11 +135,16 @@ const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM = "\"sw_version\":\"%s%s\"," "\"manufacturer\":\"Tasmota\"}"; +const char HASS_DISCOVER_DEVICE_INFO_SHORT[] PROGMEM = + "%s,\"uniq_id\":\"%s\"," + "\"device\":{\"identifiers\":[\"%06X\"]}"; + const char HASS_DISCOVER_TOPIC_PREFIX[] PROGMEM = "%s, \"~\":\"%s\""; uint8_t hass_init_step = 0; uint8_t hass_mode = 0; +int hass_tele_period = 0; static void FindPrefix(char* s1, char* s2, char* out) { @@ -156,6 +166,26 @@ static void Shorten(char** s, char *prefix) } } +int try_snprintf_P(char *s, size_t n, const char *format, ... ) +{ + va_list args; + va_start(args, format); + int len = vsnprintf_P(NULL, 0, format, args); + if (len >= n) { + snprintf_P(log_data, sizeof(log_data), + PSTR("ERROR: MQTT discovery failed due to too long topic or friendly name. " + "Please shorten topic and friendly name. Failed to format(%u/%u):"), len, n); + AddLog(LOG_LEVEL_ERROR); + va_start(args, format); + vsnprintf_P(log_data, sizeof(log_data), format, args); + AddLog(LOG_LEVEL_ERROR); + } else { + va_start(args, format); + vsnprintf_P(s, n, format, args); + } + va_end(args); +} + void HAssAnnounceRelayLight(void) { char stopic[TOPSZ]; @@ -174,14 +204,16 @@ void HAssAnnounceRelayLight(void) // Clear "other" topic first in case the device has been reconfigured from ligth to switch or vice versa snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%d"), ESP.getChipId(), (is_topic_light) ? "RL" : "LI", i); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), (is_topic_light) ? "switch" : "light", unique_id); + snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), + (is_topic_light) ? "switch" : "light", unique_id); MqttPublish(stopic, true); // Clear or Set topic snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%d"), ESP.getChipId(), (is_topic_light) ? "LI" : "RL", i); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), (is_topic_light) ? "light" : "switch", unique_id); + snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), + (is_topic_light) ? "light" : "switch", unique_id); if (Settings.flag.hass_discovery && (i <= devices_present)) { - char name[33]; + char name[33+2]; // friendlyname(33) + " " + index char value_template[33]; char prefix[TOPSZ]; char *command_topic = stemp1; @@ -202,27 +234,30 @@ void HAssAnnounceRelayLight(void) Shorten(&command_topic, prefix); Shorten(&state_topic, prefix); Shorten(&availability_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_RELAY, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_RELAY, name, command_topic, state_topic, value_template, Settings.state_text[0], Settings.state_text[1], availability_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_DEVICE_INFO_SHORT, mqtt_data, + unique_id, ESP.getChipId()); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); if (is_light) { char *brightness_command_topic = stemp1; GetTopic_P(brightness_command_topic, CMND, mqtt_topic, D_CMND_DIMMER); Shorten(&brightness_command_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_DIMMER, mqtt_data, brightness_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_DIMMER, mqtt_data, brightness_command_topic, state_topic); if (light_subtype >= LST_RGB) { char *rgb_command_topic = stemp1; GetTopic_P(rgb_command_topic, CMND, mqtt_topic, D_CMND_COLOR); Shorten(&rgb_command_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_COLOR, mqtt_data, rgb_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_COLOR, mqtt_data, rgb_command_topic, state_topic); char *effect_command_topic = stemp1; GetTopic_P(effect_command_topic, CMND, mqtt_topic, D_CMND_SCHEME); Shorten(&effect_command_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_SCHEME, mqtt_data, effect_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_SCHEME, mqtt_data, effect_command_topic, state_topic); } if (LST_RGBW == light_subtype) { @@ -230,21 +265,17 @@ void HAssAnnounceRelayLight(void) GetTopic_P(white_temp_command_topic, CMND, mqtt_topic, D_CMND_WHITE); Shorten(&white_temp_command_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_WHITE, mqtt_data, white_temp_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_WHITE, mqtt_data, white_temp_command_topic, state_topic); } if ((LST_COLDWARM == light_subtype) || (LST_RGBWC == light_subtype)) { char *color_temp_command_topic = stemp1; GetTopic_P(color_temp_command_topic, CMND, mqtt_topic, D_CMND_COLORTEMPERATURE); Shorten(&color_temp_command_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_CT, mqtt_data, color_temp_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_CT, mqtt_data, color_temp_command_topic, state_topic); } } - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_DEVICE_INFO, mqtt_data, - unique_id, ESP.getChipId(), - Settings.friendlyname[0], ModuleName().c_str(), my_version, my_image); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); } MqttPublish(stopic, true); } @@ -266,7 +297,7 @@ void HAssAnnounceButtonSwitch(uint8_t device, char* topic, uint8_t present, uint snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/binary_sensor/%s/config"), unique_id); if (Settings.flag.hass_discovery && present) { - char name[33]; + char name[33+6]; // friendlyname(33) + " " + "BTN" + " " + index char value_template[33]; char prefix[TOPSZ]; char *state_topic = stemp1; @@ -284,16 +315,15 @@ void HAssAnnounceButtonSwitch(uint8_t device, char* topic, uint8_t present, uint FindPrefix(state_topic, availability_topic, prefix); Shorten(&state_topic, prefix); Shorten(&availability_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_BUTTON_SWITCH, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_BUTTON_SWITCH, name, state_topic, Settings.state_text[toggle?2:1], availability_topic); - if (toggle) snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_BUTTON_SWITCH_TOGGLE, mqtt_data); - else snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_BUTTON_SWITCH_ONOFF, mqtt_data, Settings.state_text[0]); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_DEVICE_INFO_SHORT, mqtt_data, + unique_id, ESP.getChipId()); + if (strlen(prefix) > 0 ) try_snprintf_P(mqtt_data-1, sizeof(mqtt_data), HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); + if (toggle) try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_BUTTON_SWITCH_TOGGLE, mqtt_data); + else try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_BUTTON_SWITCH_ONOFF, mqtt_data, Settings.state_text[0]); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_DEVICE_INFO, mqtt_data, - unique_id, ESP.getChipId(), - Settings.friendlyname[0], ModuleName().c_str(), my_version, my_image); - if (strlen(prefix) > 0 ) snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); } MqttPublish(stopic, true); } @@ -374,7 +404,7 @@ void HAssAnnounceSensor(const char* sensorname, const char* subsensortype) snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s/config"), unique_id); if (Settings.flag.hass_discovery) { - char name[33]; + char name[33+42]; // friendlyname(33) + " " + sensorname(20?) + " " + sensortype(20?) char prefix[TOPSZ]; char *state_topic = stemp1; char *availability_topic = stemp2; @@ -386,39 +416,40 @@ void HAssAnnounceSensor(const char* sensorname, const char* subsensortype) Shorten(&state_topic, prefix); Shorten(&availability_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR, name, state_topic, availability_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_DEVICE_INFO_SHORT, mqtt_data, + unique_id, ESP.getChipId()); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); if (!strcmp_P(subsensortype, PSTR(D_JSON_TEMPERATURE))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_TEMP, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_TEMP, mqtt_data, TempUnit(), sensorname); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_HUMIDITY))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_HUM, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_HUM, mqtt_data, sensorname); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_PRESSURE))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_PRESS, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_PRESS, mqtt_data, PressureUnit().c_str(), sensorname); - } else if (!strcmp_P(subsensortype, PSTR(D_JSON_TOTAL)) || !strcmp_P(subsensortype, PSTR(D_JSON_TODAY)) || !strcmp_P(subsensortype, PSTR(D_JSON_YESTERDAY))){ - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_KWH, + } else if (!strcmp_P(subsensortype, PSTR(D_JSON_TOTAL)) + || !strcmp_P(subsensortype, PSTR(D_JSON_TODAY)) + || !strcmp_P(subsensortype, PSTR(D_JSON_YESTERDAY))){ + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_KWH, mqtt_data, sensorname, subsensortype); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_POWERUSAGE))){ - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_WATT, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_WATT, mqtt_data, sensorname, subsensortype); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_VOLTAGE))){ - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_VOLTAGE, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_VOLTAGE, mqtt_data, sensorname, subsensortype); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_CURRENT))){ - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_AMPERE, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_AMPERE, mqtt_data, sensorname, subsensortype); } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_ANY, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_ANY, mqtt_data, sensorname, subsensortype); } - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_DEVICE_INFO, mqtt_data, - unique_id, ESP.getChipId(), - Settings.friendlyname[0], ModuleName().c_str(), my_version, my_image); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); } MqttPublish(stopic, true); } @@ -469,6 +500,57 @@ void HAssAnnounceSensors(void) } while (hass_xsns_index != 0); } +void HAssAnnounceStatusSensor(void) +{ + char stopic[TOPSZ]; + char stemp1[TOPSZ]; + char stemp2[TOPSZ]; + char unique_id[30]; + + // Announce sensor + mqtt_data[0] = '\0'; // Clear retained message + + // Clear or Set topic + snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s"), ESP.getChipId(), "status"); + snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s/config"), unique_id); + + if (Settings.flag.hass_discovery) { + char name[33+7]; // friendlyname(33) + " " + "status" + char prefix[TOPSZ]; + char *state_topic = stemp1; + char *availability_topic = stemp2; + + snprintf_P(name, sizeof(name), PSTR("%s %s"), Settings.friendlyname[0], "status"); + GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_HASS_STATE)); + GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); + FindPrefix(state_topic, availability_topic, prefix); + Shorten(&state_topic, prefix); + Shorten(&availability_topic, prefix); + + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR, + name, state_topic, availability_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_HASS_STATUS, + mqtt_data, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_DEVICE_INFO, mqtt_data, + unique_id, ESP.getChipId(), + Settings.friendlyname[0], ModuleName().c_str(), my_version, my_image); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); + try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + } + MqttPublish(stopic, true); +} + +void HAssPublishStatus(void) +{ + snprintf_P(mqtt_data, sizeof(mqtt_data), + PSTR("{\"" D_JSON_VERSION "\":\"%s%s\",\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_RESTARTREASON "\":\"%s\",\"" + D_JSON_UPTIME "\":\"%s\",\"" D_JSON_BOOTCOUNT "\":%d,\"" D_JSON_SAVECOUNT "\":%d,\"" + D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_RSSI "\":\"%d\",\"LoadAvg\":%lu}"), + my_version, my_image, ModuleName().c_str(), GetResetReason().c_str(), GetUptime().c_str(), Settings.bootcount, + Settings.save_flag, WiFi.localIP().toString().c_str(), WifiGetRssiAsQuality(WiFi.RSSI()), loop_load_avg); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_HASS_STATE)); +} + void HAssDiscovery(void) { // Configure Tasmota for default Home Assistant parameters to keep discovery message as short as possible @@ -496,6 +578,9 @@ void HAssDiscovery(void) // Send info about sensors HAssAnnounceSensors(); + + // Send info about status sensor + HAssAnnounceStatusSensor(); } } @@ -525,6 +610,14 @@ bool Xdrv12(uint8_t function) if (!hass_init_step) { HAssDiscovery(); // Scheduled discovery using available resources } + } else if (Settings.flag.hass_discovery && Settings.tele_period) { + hass_tele_period++; + if (hass_tele_period >= Settings.tele_period) { + hass_tele_period = 0; + + mqtt_data[0] = '\0'; + HAssPublishStatus(); + } } break; } diff --git a/sonoff/xnrg_03_pzem004t.ino b/sonoff/xnrg_03_pzem004t.ino index e0b6327bd..a15d61ba1 100644 --- a/sonoff/xnrg_03_pzem004t.ino +++ b/sonoff/xnrg_03_pzem004t.ino @@ -32,7 +32,7 @@ #include -TasmotaSerial *PzemSerial; +TasmotaSerial *PzemSerial = NULL; #define PZEM_VOLTAGE (uint8_t)0xB0 #define RESP_VOLTAGE (uint8_t)0xA0 @@ -239,7 +239,7 @@ int Xnrg03(uint8_t function) PzemSnsInit(); break; case FUNC_EVERY_200_MSECOND: - PzemEvery200ms(); + if (PzemSerial) { PzemEvery200ms(); } break; } } diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index 53034a73c..d878d9e8b 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -28,6 +28,7 @@ #define XNRG_04 4 +#define MCP_BAUDRATE 4800 #define MCP_TIMEOUT 4 #define MCP_CALIBRATION_TIMEOUT 2 @@ -66,7 +67,7 @@ #define MCP_BUFFER_SIZE 60 #include -TasmotaSerial *McpSerial; +TasmotaSerial *McpSerial = NULL; typedef struct mcp_cal_registers_type { uint16_t gain_current_rms; @@ -91,9 +92,8 @@ typedef struct mcp_cal_registers_type { uint16_t accumulation_interval; } mcp_cal_registers_type; -char *mcp_buffer = NULL; // Serial receive buffer -int mcp_byte_counter = 0; // Index in serial receive buffer - +char *mcp_buffer = NULL; +unsigned long mcp_window = 0; unsigned long mcp_kWhcounter = 0; uint32_t mcp_system_configuration = 0x03000000; uint32_t mcp_active_power; @@ -108,6 +108,7 @@ uint8_t mcp_calibration_active = 0; uint8_t mcp_init = 0; uint8_t mcp_timeout = 0; uint8_t mcp_calibrate = 0; +uint8_t mcp_byte_counter = 0; /*********************************************************************************************\ * Olimex tools @@ -474,19 +475,20 @@ void McpParseData(void) void McpSerialInput(void) { - if (McpSerial->available()) { - unsigned long start = millis(); - while (millis() - start < 20) { - yield(); - if (McpSerial->available()) { - mcp_buffer[mcp_byte_counter++] = McpSerial->read(); - start = millis(); - } - } + while ((McpSerial->available()) && (mcp_byte_counter < MCP_BUFFER_SIZE)) { + yield(); + mcp_buffer[mcp_byte_counter++] = McpSerial->read(); + mcp_window = millis(); + } + // Ignore until non received after 2 chars (= 12 bits/char) time + if ((mcp_byte_counter) && (millis() - mcp_window > (24000 / MCP_BAUDRATE) +1)) { AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)mcp_buffer, mcp_byte_counter); - if (1 == mcp_byte_counter) { + if (MCP_BUFFER_SIZE == mcp_byte_counter) { +// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: Overflow")); + } + else if (1 == mcp_byte_counter) { if (MCP_ERROR_CRC == mcp_buffer[0]) { // AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: Send " D_CHECKSUM_FAILURE)); mcp_timeout = 0; @@ -556,8 +558,13 @@ void McpSnsInit(void) { // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions McpSerial = new TasmotaSerial(pin[GPIO_MCP39F5_RX], pin[GPIO_MCP39F5_TX], 1); - if (McpSerial->begin(4800)) { - if (McpSerial->hardwareSerial()) { ClaimSerial(); } + if (McpSerial->begin(MCP_BAUDRATE)) { + if (McpSerial->hardwareSerial()) { + ClaimSerial(); + mcp_buffer = serial_in_buffer; // Use idle serial buffer to save RAM + } else { + mcp_buffer = (char*)(malloc(MCP_BUFFER_SIZE)); + } if (pin[GPIO_MCP39F5_RST] < 99) { digitalWrite(pin[GPIO_MCP39F5_RST], 1); // MCP enable } @@ -570,17 +577,14 @@ void McpDrvInit(void) { if (!energy_flg) { if ((pin[GPIO_MCP39F5_RX] < 99) && (pin[GPIO_MCP39F5_TX] < 99)) { - mcp_buffer = (char*)(malloc(MCP_BUFFER_SIZE)); - if (mcp_buffer != NULL) { - if (pin[GPIO_MCP39F5_RST] < 99) { - pinMode(pin[GPIO_MCP39F5_RST], OUTPUT); - digitalWrite(pin[GPIO_MCP39F5_RST], 0); // MCP disable - Reset Delta Sigma ADC's - } - mcp_calibrate = 0; - mcp_timeout = 2; // Initial wait - mcp_init = 2; // Initial setup steps - energy_flg = XNRG_04; + if (pin[GPIO_MCP39F5_RST] < 99) { + pinMode(pin[GPIO_MCP39F5_RST], OUTPUT); + digitalWrite(pin[GPIO_MCP39F5_RST], 0); // MCP disable - Reset Delta Sigma ADC's } + mcp_calibrate = 0; + mcp_timeout = 2; // Initial wait + mcp_init = 2; // Initial setup steps + energy_flg = XNRG_04; } } } @@ -652,10 +656,10 @@ int Xnrg04(uint8_t function) McpSnsInit(); break; case FUNC_LOOP: - McpSerialInput(); + if (McpSerial) { McpSerialInput(); } break; case FUNC_EVERY_SECOND: - McpEverySecond(); + if (McpSerial) { McpEverySecond(); } break; case FUNC_COMMAND: result = McpCommand(); diff --git a/sonoff/xsns_12_ads1115.ino b/sonoff/xsns_12_ads1115.ino index f75baa3e8..51cbb6c43 100644 --- a/sonoff/xsns_12_ads1115.ino +++ b/sonoff/xsns_12_ads1115.ino @@ -119,7 +119,8 @@ CONFIG REGISTER uint8_t ads1115_type = 0; uint8_t ads1115_address; uint8_t ads1115_addresses[] = { ADS1115_ADDRESS_ADDR_GND, ADS1115_ADDRESS_ADDR_VDD, ADS1115_ADDRESS_ADDR_SDA, ADS1115_ADDRESS_ADDR_SCL }; - +uint8_t ads1115_found[] = {false,false,false,false}; +int16_t ads1115_values[4]; //Ads1115StartComparator(channel, ADS1115_REG_CONFIG_MODE_SINGLE); //Ads1115StartComparator(channel, ADS1115_REG_CONFIG_MODE_CONTIN); void Ads1115StartComparator(uint8_t channel, uint16_t mode) @@ -160,52 +161,84 @@ int16_t Ads1115GetConversion(uint8_t channel) void Ads1115Detect(void) { uint16_t buffer; - - if (ads1115_type) { - return; - } - for (uint8_t i = 0; i < sizeof(ads1115_addresses); i++) { - ads1115_address = ads1115_addresses[i]; - if (I2cValidRead16(&buffer, ads1115_address, ADS1115_REG_POINTER_CONVERT)) { - Ads1115StartComparator(i, ADS1115_REG_CONFIG_MODE_CONTIN); - ads1115_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "ADS1115", ads1115_address); - AddLog(LOG_LEVEL_DEBUG); - break; + if (!ads1115_found[i]) { + ads1115_address = ads1115_addresses[i]; + if (I2cValidRead16(&buffer, ads1115_address, ADS1115_REG_POINTER_CONVERT) && + I2cValidRead16(&buffer, ads1115_address, ADS1115_REG_POINTER_CONFIG)) { + Ads1115StartComparator(i, ADS1115_REG_CONFIG_MODE_CONTIN); + ads1115_type = 1; + ads1115_found[i] = 1; + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "ADS1115", ads1115_address); + AddLog(LOG_LEVEL_DEBUG); + } } } } +void Ads1115GetValues(uint8_t address) +{ + uint8_t old_address = ads1115_address; + ads1115_address = address; + for (uint8_t i = 0; i < 4; i++) { + ads1115_values[i] = Ads1115GetConversion(i); + //snprintf_P(log_data, sizeof(log_data), "Logging ADS1115 %02x (%i) = %i", address, i, ads1115_values[i] ); + //AddLog(LOG_LEVEL_INFO); + } + ads1115_address = old_address; +} + +void Ads1115toJSON(char *comma_j) +{ + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s{"), mqtt_data,comma_j); + char *comma = (char*)""; + for (uint8_t i = 0; i < 4; i++) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"A%d\":%d"), mqtt_data, comma, i, ads1115_values[i]); + comma = (char*)","; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); +} + +void Ads1115toString(uint8_t address) +{ + char label[15]; + snprintf_P(label, sizeof(label), "ADS1115(%02x)", address); + + for (uint8_t i = 0; i < 4; i++) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ANALOG, mqtt_data, label, i, ads1115_values[i]); + } +} + void Ads1115Show(bool json) { - if (ads1115_type) { - char stemp[10]; + if (!ads1115_type) { return; } - uint8_t dsxflg = 0; - for (uint8_t i = 0; i < 4; i++) { - int16_t adc_value = Ads1115GetConversion(i); + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"ADS1115\":["), mqtt_data); + } + char *comma = (char*)""; + + for (uint8_t t = 0; t < sizeof(ads1115_addresses); t++) { + //snprintf_P(log_data, sizeof(log_data), "Logging ADS1115 %02x", ads1115_addresses[t]); + //AddLog(LOG_LEVEL_INFO); + if (ads1115_found[t]) { + Ads1115GetValues(ads1115_addresses[t]); if (json) { - if (!dsxflg ) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"ADS1115\":{"), mqtt_data); - stemp[0] = '\0'; - } - dsxflg++; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"A%d\":%d"), mqtt_data, stemp, i, adc_value); - strlcpy(stemp, ",", sizeof(stemp)); + Ads1115toJSON(comma); + comma = (char*)","; + } #ifdef USE_WEBSERVER - } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ANALOG, mqtt_data, "ADS1115", i, adc_value); + else { + Ads1115toString(ads1115_addresses[t]); + } #endif // USE_WEBSERVER - } - } - if (json) { - if (dsxflg) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); - } } } + + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]"), mqtt_data); + } } /*********************************************************************************************\ diff --git a/sonoff/xsns_15_mhz19.ino b/sonoff/xsns_15_mhz19.ino index 747a8125f..8558a9cd9 100644 --- a/sonoff/xsns_15_mhz19.ino +++ b/sonoff/xsns_15_mhz19.ino @@ -345,7 +345,10 @@ void MhzShow(bool json) if (json) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_MODEL "\":\"%s\",\"" D_JSON_CO2 "\":%d,\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, types, model, mhz_last_ppm, temperature); #ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, mhz_last_ppm); + if (0 == tele_period) { + DomoticzSensor(DZ_AIRQUALITY, mhz_last_ppm); + DomoticzSensor(DZ_TEMP, temperature); + } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { diff --git a/sonoff/xsns_16_tsl2561.ino b/sonoff/xsns_16_tsl2561.ino index 0dbaf7141..f7777cf18 100644 --- a/sonoff/xsns_16_tsl2561.ino +++ b/sonoff/xsns_16_tsl2561.ino @@ -64,12 +64,14 @@ bool Tsl2561Read(void) void Tsl2561Detect(void) { if (tsl2561_type) { return; } + uint8_t id; if (I2cDevice(0x29) || I2cDevice(0x39) || I2cDevice(0x49)) { + if (!Tsl.id(id)) return; Tsl.begin(); if (Tsl.on()) { tsl2561_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, tsl2561_types, Tsl.address()); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, tsl2561_types, Tsl.address(), id); AddLog(LOG_LEVEL_DEBUG); } } diff --git a/sonoff/xsns_40_pn532.ino b/sonoff/xsns_40_pn532.ino new file mode 100644 index 000000000..c1daef96e --- /dev/null +++ b/sonoff/xsns_40_pn532.ino @@ -0,0 +1,615 @@ +/* + xsns_40_pn532.ino - Support for PN532 (HSU) NFC Tag Reader + + Copyright (C) 2019 Andre Thomas and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + 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 . +*/ + +#ifdef USE_PN532_HSU + +#define XSNS_40 40 + +#include + +TasmotaSerial *PN532_Serial; + +#define PN532_INVALID_ACK -1 +#define PN532_TIMEOUT -2 +#define PN532_INVALID_FRAME -3 +#define PN532_NO_SPACE -4 + +#define PN532_PREAMBLE 0x00 +#define PN532_STARTCODE1 0x00 +#define PN532_STARTCODE2 0xFF +#define PN532_POSTAMBLE 0x00 + +#define PN532_HOSTTOPN532 0xD4 +#define PN532_PN532TOHOST 0xD5 + +#define PN532_ACK_WAIT_TIME 0x0A + +#define PN532_COMMAND_GETFIRMWAREVERSION 0x02 +#define PN532_COMMAND_SAMCONFIGURATION 0x14 +#define PN532_COMMAND_RFCONFIGURATION 0x32 +#define PN532_COMMAND_INDATAEXCHANGE 0x40 +#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A + +#define PN532_MIFARE_ISO14443A 0x00 +#define MIFARE_CMD_READ 0x30 +#define MIFARE_CMD_AUTH_A 0x60 +#define MIFARE_CMD_AUTH_B 0x61 +#define MIFARE_CMD_WRITE 0xA0 + +uint8_t pn532_model = 0; // Used to maintain detection flag +uint8_t pn532_command = 0; // Used to carry command code between functions +uint8_t pn532_scantimer = 0; // Used to prevent multiple successful reads within 2 second window + +uint8_t pn532_packetbuffer[64]; // Global buffer used to store packet + +#ifdef USE_PN532_DATA_FUNCTION +uint8_t pn532_function = 0; +uint8_t pn532_newdata[16]; +uint8_t pn532_newdata_len = 0; +#endif // USE_PN532_DATA_FUNCTION + +void PN532_Init(void) +{ + if ((pin[GPIO_PN532_RXD] < 99) && (pin[GPIO_PN532_TXD] < 99)) { + PN532_Serial = new TasmotaSerial(pin[GPIO_PN532_RXD], pin[GPIO_PN532_TXD], 1); + if (PN532_Serial->begin(115200)) { + if (PN532_Serial->hardwareSerial()) { ClaimSerial(); } + PN532_wakeup(); + uint32_t ver = PN532_getFirmwareVersion(); + if (ver) { + PN532_setPassiveActivationRetries(0xFF); + PN532_SAMConfig(); + pn532_model = 1; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC Reader detected (V%u.%u)",(ver>>16) & 0xFF, (ver>>8) & 0xFF); + AddLog(LOG_LEVEL_INFO); + } + } + } +} + +int8_t PN532_receive(uint8_t *buf, int len, uint16_t timeout) +{ + int read_bytes = 0; + int ret; + unsigned long start_millis; + while (read_bytes < len) { + start_millis = millis(); + do { + ret = PN532_Serial->read(); + if (ret >= 0) { + break; + } + } while((timeout == 0) || ((millis()- start_millis ) < timeout)); + + if (ret < 0) { + if (read_bytes) { + return read_bytes; + } else { + return PN532_TIMEOUT; + } + } + buf[read_bytes] = (uint8_t)ret; + read_bytes++; + } + return read_bytes; +} + +int8_t PN532_readAckFrame(void) +{ + const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; + uint8_t ackBuf[sizeof(PN532_ACK)]; + + if (PN532_receive(ackBuf, sizeof(PN532_ACK), PN532_ACK_WAIT_TIME) <= 0) { + return PN532_TIMEOUT; + } + + if (memcmp(&ackBuf, &PN532_ACK, sizeof(PN532_ACK))) { + return PN532_INVALID_ACK; + } + return 0; +} + +int8_t PN532_writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) +{ + // Clear the serial buffer just in case + PN532_Serial->flush(); + + pn532_command = header[0]; + PN532_Serial->write((uint8_t)PN532_PREAMBLE); + PN532_Serial->write((uint8_t)PN532_STARTCODE1); + PN532_Serial->write(PN532_STARTCODE2); + + uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA + PN532_Serial->write(length); + PN532_Serial->write(~length + 1); // checksum of length + + PN532_Serial->write(PN532_HOSTTOPN532); + uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA + + PN532_Serial->write(header, hlen); + for (uint8_t i = 0; i < hlen; i++) { + sum += header[i]; + } + + PN532_Serial->write(body, blen); + for (uint8_t i = 0; i < blen; i++) { + sum += body[i]; + } + + uint8_t checksum = ~sum + 1; // checksum of TFI + DATA + PN532_Serial->write(checksum); + PN532_Serial->write((uint8_t)PN532_POSTAMBLE); + + return PN532_readAckFrame(); +} + +int16_t PN532_readResponse(uint8_t buf[], uint8_t len, uint16_t timeout = 50) +{ + uint8_t tmp[3]; + + // Read preamble and start code + if (PN532_receive(tmp, 3, timeout)<=0) { + return PN532_TIMEOUT; + } + if (0 != tmp[0] || 0!= tmp[1] || 0xFF != tmp[2]) { + return PN532_INVALID_FRAME; + } + + // Get length of data to be received + uint8_t length[2]; + if (PN532_receive(length, 2, timeout) <= 0) { + return PN532_TIMEOUT; + } + // Validate that frame is valid + if (0 != (uint8_t)(length[0] + length[1])) { + return PN532_INVALID_FRAME; + } + length[0] -= 2; + if (length[0] > len) { // If this happens, then pn532_packetbuffer is not large enough + return PN532_NO_SPACE; + } + + // Get the command byte + uint8_t cmd = pn532_command + 1; + if (PN532_receive(tmp, 2, timeout) <= 0) { // Time out while receiving + return PN532_TIMEOUT; + } + if (PN532_PN532TOHOST != tmp[0] || cmd != tmp[1]) { // Invalid frame received + return PN532_INVALID_FRAME; + } + + if (PN532_receive(buf, length[0], timeout) != length[0]) { // Timed out + return PN532_TIMEOUT; + } + + uint8_t sum = PN532_PN532TOHOST + cmd; + for (uint8_t i=0; i status) { + return 0; + } + + response = pn532_packetbuffer[0]; + response <<= 8; + response |= pn532_packetbuffer[1]; + response <<= 8; + response |= pn532_packetbuffer[2]; + response <<= 8; + response |= pn532_packetbuffer[3]; + + return response; +} + +void PN532_wakeup(void) +{ + uint8_t wakeup[5] = {0x55, 0x55, 0, 0, 0 }; + PN532_Serial->write(wakeup,sizeof(wakeup)); + + // Flush the serial buffer just in case there's garbage in there + PN532_Serial->flush(); +} + +bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout = 50) +{ + pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; + pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later) + pn532_packetbuffer[2] = cardbaudrate; + if (PN532_writeCommand(pn532_packetbuffer, 3)) { + return 0x0; // command failed + } + // read data packet + if (PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) { + return 0x0; + } + + /* Check some basic stuff + b0 Tags Found + b1 Tag Number (only one used in this example) + b2..3 SENS_RES + b4 SEL_RES + b5 NFCID Length + b6..NFCIDLen NFCID + */ + + if (pn532_packetbuffer[0] != 1) { + return 0; + } + + uint16_t sens_res = pn532_packetbuffer[2]; + sens_res <<= 8; + sens_res |= pn532_packetbuffer[3]; + + /* Card appears to be Mifare Classic */ + *uidLength = pn532_packetbuffer[5]; + + for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) { + uid[i] = pn532_packetbuffer[6 + i]; + } + + return 1; +} + +bool PN532_setPassiveActivationRetries(uint8_t maxRetries) +{ + pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION; + pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries) + pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF) + pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01) + pn532_packetbuffer[4] = maxRetries; + if (PN532_writeCommand(pn532_packetbuffer, 5)) { + return 0; // no ACK + } + return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); +} + +bool PN532_SAMConfig(void) +{ + pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION; + pn532_packetbuffer[1] = 0x01; // normal mode + pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second + pn532_packetbuffer[3] = 0x00; // we don't need the external IRQ pin + if (PN532_writeCommand(pn532_packetbuffer, 4)) { + return false; + } + return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); +} + +#ifdef USE_PN532_DATA_FUNCTION + +uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) +{ + uint8_t i; + uint8_t _key[6]; + uint8_t _uid[7]; + uint8_t _uidLen; + + // Hang on to the key and uid data + memcpy(&_key, keyData, 6); + memcpy(&_uid, uid, uidLen); + _uidLen = uidLen; + + // Prepare the authentication command // + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */ + pn532_packetbuffer[1] = 1; /* Max card numbers */ + pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A; + pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */ + memcpy(&pn532_packetbuffer[4], &_key, 6); + for (i = 0; i < _uidLen; i++) { + pn532_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */ + } + + if (PN532_writeCommand(pn532_packetbuffer, 10 + _uidLen)) { return 0; } + + // Read the response packet + PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer)); + + // Check if the response is valid and we are authenticated??? + // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00 + // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good + if (pn532_packetbuffer[0] != 0x00) { + // Authentification failed + return 0; + } + + return 1; +} + +uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) +{ + /* Prepare the command */ + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = 1; /* Card number */ + pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ + + /* Send the command */ + if (PN532_writeCommand(pn532_packetbuffer, 4)) { + return 0; + } + + /* Read the response packet */ + PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer)); + + /* If byte 8 isn't 0x00 we probably have an error */ + if (pn532_packetbuffer[0] != 0x00) { + return 0; + } + + /* Copy the 16 data bytes to the output buffer */ + /* Block content starts at byte 9 of a valid response */ + memcpy (data, &pn532_packetbuffer[1], 16); + + return 1; +} + +uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) +{ + /* Prepare the first command */ + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = 1; /* Card number */ + pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */ + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ + memcpy(&pn532_packetbuffer[4], data, 16); /* Data Payload */ + + /* Send the command */ + if (PN532_writeCommand(pn532_packetbuffer, 20)) { + return 0; + } + + /* Read the response packet */ + return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); +} + +#endif // USE_PN532_DATA_FUNCTION + +void PN532_ScanForTag(void) +{ + if (!pn532_model) { return; } + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; + uint8_t uid_len = 0; + uint8_t card_data[16]; + bool erase_success = false; + bool set_success = false; + if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uid_len)) { + char uids[15]; + +#ifdef USE_PN532_DATA_FUNCTION + char card_datas[34]; +#endif // USE_PN532_DATA_FUNCTION + + sprintf(uids,""); + for (uint8_t i = 0;i < uid_len;i++) { + sprintf(uids,"%s%02X",uids,uid[i]); + } + +#ifdef USE_PN532_DATA_FUNCTION + if (uid_len == 4) { // Lets try to read block 1 of the mifare classic card for more information + uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + if (mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) { + if (mifareclassic_ReadDataBlock(1, card_data)) { +#ifdef USE_PN532_DATA_RAW + memcpy(&card_datas,&card_data,sizeof(card_data)); +#else + for (uint8_t i = 0;i < sizeof(card_data);i++) { + if ((isalpha(card_data[i])) || ((isdigit(card_data[i])))) { + card_datas[i] = char(card_data[i]); + } else { + card_datas[i] = '\0'; + } + } +#endif // USE_PN532_DATA_RAW + } + if (pn532_function == 1) { // erase block 1 of card + for (uint8_t i = 0;i<16;i++) { + card_data[i] = 0x00; + } + if (mifareclassic_WriteDataBlock(1, card_data)) { + erase_success = true; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Erase success"); + AddLog(LOG_LEVEL_INFO); + memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string + } + } + if (pn532_function == 2) { +#ifdef USE_PN532_DATA_RAW + memcpy(&card_data,&pn532_newdata,sizeof(card_data)); + if (mifareclassic_WriteDataBlock(1, card_data)) { + set_success = true; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Data write successful"); + AddLog(LOG_LEVEL_INFO); + memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string + } +#else + bool IsAlphaNumeric = true; + for (uint8_t i = 0;i < pn532_newdata_len;i++) { + if ((!isalpha(pn532_newdata[i])) && (!isdigit(pn532_newdata[i]))) { + IsAlphaNumeric = false; + } + } + if (IsAlphaNumeric) { + memcpy(&card_data,&pn532_newdata,pn532_newdata_len); + card_data[pn532_newdata_len] = '\0'; // Enforce null termination + if (mifareclassic_WriteDataBlock(1, card_data)) { + set_success = true; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Data write successful"); + AddLog(LOG_LEVEL_INFO); + memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string + } + } else { + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Data must be alphanumeric"); + AddLog(LOG_LEVEL_INFO); + } +#endif // USE_PN532_DATA_RAW + } + } else { + sprintf(card_datas,"AUTHFAIL"); + } + } + switch (pn532_function) { + case 0x01: + if (!erase_success) { + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Erase fail - exiting erase mode"); + AddLog(LOG_LEVEL_INFO); + } + break; + case 0x02: + if (!set_success) { + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Write failed - exiting set mode"); + AddLog(LOG_LEVEL_INFO); + } + default: + break; + } + pn532_function = 0; +#endif // USE_PN532_DATA_FUNCTION + + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); + +#ifdef USE_PN532_DATA_FUNCTION + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\", \"DATA\":\"%s\"}}"), mqtt_data, uids, card_datas); +#else + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\"}}"), mqtt_data, uids); +#endif // USE_PN532_DATA_FUNCTION + + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); + +#ifdef USE_PN532_CAUSE_EVENTS + + char command[71]; +#ifdef USE_PN532_DATA_FUNCTION + sprintf(command,"backlog event PN532_UID=%s;event PN532_DATA=%s",uids,card_datas); +#else + sprintf(command,"event PN532_UID=%s",uids); +#endif // USE_PN532_DATA_FUNCTION + ExecuteCommand(command, SRC_RULE); +#endif // USE_PN532_CAUSE_EVENTS + + pn532_scantimer = 7; // Ignore tags found for two seconds + } +} + +#ifdef USE_PN532_DATA_FUNCTION + +bool PN532_Command(void) +{ + bool serviced = true; + uint8_t paramcount = 0; + if (XdrvMailbox.data_len > 0) { + paramcount=1; + } else { + serviced = false; + return serviced; + } + char sub_string[XdrvMailbox.data_len]; + char sub_string_tmp[XdrvMailbox.data_len]; + for (uint8_t ca=0;ca 1) { + if (XdrvMailbox.data[XdrvMailbox.data_len-1] == ',') { + serviced = false; + return serviced; + } + sprintf(sub_string_tmp,subStr(sub_string, XdrvMailbox.data, ",", 2)); + pn532_newdata_len = strlen(sub_string_tmp); + if (pn532_newdata_len > 15) { pn532_newdata_len = 15; } + memcpy(&pn532_newdata,&sub_string_tmp,pn532_newdata_len); + pn532_newdata[pn532_newdata_len] = 0x00; // Null terminate the string + pn532_function = 2; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Next scanned tag data block 1 will be set to '%s'",pn532_newdata); + AddLog(LOG_LEVEL_INFO); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"COMMAND\":\"S\"\"}}"), mqtt_data); + return serviced; + } + } +} + +#endif // USE_PN532_DATA_FUNCTION + +bool Xsns40(uint8_t function) +{ + bool result = false; + + switch (function) { + case FUNC_INIT: + PN532_Init(); + result = true; + break; + case FUNC_EVERY_50_MSECOND: + break; + case FUNC_EVERY_100_MSECOND: + break; + case FUNC_EVERY_250_MSECOND: + if (pn532_scantimer > 0) { + pn532_scantimer--; + } else { + PN532_ScanForTag(); + } + break; + case FUNC_EVERY_SECOND: + break; +#ifdef USE_PN532_DATA_FUNCTION + case FUNC_COMMAND: + if (XSNS_40 == XdrvMailbox.index) { + result = PN532_Command(); + } + break; +#endif + } + return result; +} + +#endif // USE_PN532_HSU diff --git a/sonoff/xsns_40_pn532_i2c.ino b/sonoff/xsns_40_pn532_i2c.ino deleted file mode 100644 index 640e21c6e..000000000 --- a/sonoff/xsns_40_pn532_i2c.ino +++ /dev/null @@ -1,606 +0,0 @@ -/* - xsns_40_pn532.ino - Support for PN532 (I2C) NFC Tag Reader - - Copyright (C) 2019 Andre Thomas and Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - 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 . -*/ - -#ifdef USE_I2C -#ifdef USE_PN532_I2C - -/*********************************************************************************************\ - * PN532 - Near Field Communication (NFC) controller - * - * Datasheet at https://www.nxp.com/docs/en/nxp/data-sheets/PN532_C1.pdf - * - * I2C Address: 0x24 -\*********************************************************************************************/ - -#define XSNS_40 40 - -#define PN532_I2C_ADDRESS 0x24 - -#define PN532_COMMAND_GETFIRMWAREVERSION 0x02 -#define PN532_COMMAND_SAMCONFIGURATION 0x14 -#define PN532_COMMAND_INDATAEXCHANGE 0x40 -#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A - -#define MIFARE_CMD_READ 0x30 -#define MIFARE_CMD_AUTH_A 0x60 -#define MIFARE_CMD_AUTH_B 0x61 -#define MIFARE_CMD_WRITE 0xA0 - -#define PN532_PREAMBLE 0x00 -#define PN532_STARTCODE1 0x00 -#define PN532_STARTCODE2 0xFF -#define PN532_POSTAMBLE 0x00 - -#define PN532_HOSTTOPN532 0xD4 -#define PN532_PN532TOHOST 0xD5 - -#define PN532_INVALID_ACK -1 -#define PN532_TIMEOUT -2 -#define PN532_INVALID_FRAME -3 -#define PN532_NO_SPACE -4 - -#define PN532_MIFARE_ISO14443A 0x00 - -uint8_t pn532_i2c_detected = 0; -uint8_t pn532_i2c_packetbuffer[64]; -uint8_t pn532_i2c_scan_defer_report = 0; // If a valid card was found we will not scan for one again in the same two seconds so we set this to 19 if a card was found -uint8_t pn532_i2c_command = 0; - -uint8_t pn532_i2c_disable = 0; - -#ifdef USE_PN532_DATA_FUNCTION -uint8_t pn532_i2c_function = 0; -uint8_t pn532_i2c_newdata[16]; -uint8_t pn532_i2c_newdata_len = 0; -#endif // USE_PN532_DATA_FUNCTION - -const uint8_t PROGMEM pn532_global_timeout = 10; - -int16_t PN532_getResponseLength(uint8_t buf[], uint8_t len) { - const uint8_t PN532_NACK[] = {0, 0, 0xFF, 0xFF, 0, 0}; - uint8_t time = 0; - do { - if (Wire.requestFrom(PN532_I2C_ADDRESS, 6)) { - if (Wire.read() & 1) { // check first byte --- status - break; // PN532 is ready - } - } - delay(1); - time++; - if (time > pn532_global_timeout) { - return -1; - } - } while (1); - - if ((0x00 != Wire.read()) || (0x00 != Wire.read()) || (0xFF != Wire.read())) { // PREAMBLE || STARTCODE1 || STARTCODE2 - return PN532_INVALID_FRAME; - } - - uint8_t length = Wire.read(); - - // request for last respond msg again - Wire.beginTransmission(PN532_I2C_ADDRESS); - for (uint16_t i = 0;i < sizeof(PN532_NACK); ++i) { - Wire.write(PN532_NACK[i]); - } - Wire.endTransmission(); - return length; -} - - -int16_t PN532_readResponse(uint8_t buf[], uint8_t len) -{ - uint8_t time = 0; - uint8_t length; - - length = PN532_getResponseLength(buf, len); - - // [RDY] 00 00 FF LEN LCS (TFI PD0 ... PDn) DCS 00 - - do { - if (Wire.requestFrom(PN532_I2C_ADDRESS, 6 + length + 2)) { - if (Wire.read() & 1) { // check first byte --- status - break; // PN532 is ready - } - } - delay(1); - time++; - if (time > pn532_global_timeout) { - return -1; - } - } while (1); - - if ((0x00 != Wire.read()) || (0x00 != Wire.read()) || (0xFF != Wire.read())) { // PREAMBLE || STARTCODE1 || STARTCODE2 - return PN532_INVALID_FRAME; - } - - length = Wire.read(); - - if (0 != (uint8_t)(length + Wire.read())) { // checksum of length - return PN532_INVALID_FRAME; - } - - uint8_t cmd = pn532_i2c_command + 1; // response command - if ((PN532_PN532TOHOST != Wire.read()) || ((cmd) != Wire.read())) { - return PN532_INVALID_FRAME; - } - length -= 2; - if (length > len) { - return PN532_NO_SPACE; // not enough space - } - uint8_t sum = PN532_PN532TOHOST + cmd; - for (uint8_t i = 0; i < length; i++) { - buf[i] = Wire.read(); - sum += buf[i]; - } - uint8_t checksum = Wire.read(); - if (0 != (uint8_t)(sum + checksum)) { - return PN532_INVALID_FRAME; - } - Wire.read(); // POSTAMBLE - return length; -} - - -int8_t PN532_readAckFrame(void) -{ - const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; - uint8_t ackBuf[sizeof(PN532_ACK)]; - - uint8_t time = 0; - - do { - if (Wire.requestFrom(PN532_I2C_ADDRESS, sizeof(PN532_ACK) + 1)) { - if (Wire.read() & 1) { // check first byte --- status - break; // PN532 is ready - } - } - delay(1); - time++; - if (time > pn532_global_timeout) { // We time out after 10ms - return PN532_TIMEOUT; - } - } while (1); - - for (uint8_t i = 0; i < sizeof(PN532_ACK); i++) { - ackBuf[i] = Wire.read(); - } - - if (memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK))) { - return PN532_INVALID_ACK; - } - - return 0; -} - -int8_t PN532_writeCommand(const uint8_t *header, uint8_t hlen) -{ - pn532_i2c_command = header[0]; - Wire.beginTransmission(PN532_I2C_ADDRESS); - Wire.write(PN532_PREAMBLE); - Wire.write(PN532_STARTCODE1); - Wire.write(PN532_STARTCODE2); - uint8_t length = hlen + 1; // TFI + DATA - Wire.write(length); - Wire.write(~length + 1); // checksum of length - Wire.write(PN532_HOSTTOPN532); - uint8_t sum = PN532_HOSTTOPN532; // Sum of TFI + DATA - for (uint8_t i = 0; i < hlen; i++) { - if (Wire.write(header[i])) { - sum += header[i]; - } else { - return PN532_INVALID_FRAME; - } - } - uint8_t checksum = ~sum + 1; // Checksum of TFI + DATA - Wire.write(checksum); - Wire.write(PN532_POSTAMBLE); - Wire.endTransmission(); - return PN532_readAckFrame(); -} - -uint32_t PN532_getFirmwareVersion(void) -{ - uint32_t response; - pn532_i2c_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION; - if (PN532_writeCommand(pn532_i2c_packetbuffer, 1)) { - return 0; - } - int16_t status = PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer)); - if (0 > status) { - return 0; - } - response = pn532_i2c_packetbuffer[0]; - response <<= 8; - response |= pn532_i2c_packetbuffer[1]; - response <<= 8; - response |= pn532_i2c_packetbuffer[2]; - response <<= 8; - response |= pn532_i2c_packetbuffer[3]; - return response; -} - -bool PN532_SAMConfig(void) -{ - pn532_i2c_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION; - pn532_i2c_packetbuffer[1] = 0x01; // normal mode; - pn532_i2c_packetbuffer[2] = 0x01; // timeout 50ms * 1 = 50ms - pn532_i2c_packetbuffer[3] = 0x00; // Disable IRQ pin - - if (PN532_writeCommand(pn532_i2c_packetbuffer, 4)) - return false; - - return (0 < PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer))); -} - -void PN532_Detect(void) -{ - if ((pn532_i2c_detected) || (pn532_i2c_disable)) { return; } - - Wire.setClockStretchLimit(1000); // Enable 1ms clock stretch as per datasheet Table 12.25 (Timing for the I2C interface) - - uint32_t ver = PN532_getFirmwareVersion(); - if (ver) { - pn532_i2c_detected = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "PN532 NFC Reader (V%u.%u)", PN532_I2C_ADDRESS); - snprintf_P(log_data, sizeof(log_data), log_data, (ver>>16) & 0xFF, (ver>>8) & 0xFF); - AddLog(LOG_LEVEL_DEBUG); - PN532_SAMConfig(); - } -} - -bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength) -{ - pn532_i2c_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; - pn532_i2c_packetbuffer[1] = 1; - pn532_i2c_packetbuffer[2] = cardbaudrate; - - if (PN532_writeCommand(pn532_i2c_packetbuffer, 3)) { - return false; // command failed - } - - if (PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer)) < 0) { // No data packet so no tag was found - Wire.beginTransmission(PN532_I2C_ADDRESS); - Wire.endTransmission(); - return false; - } - - if (pn532_i2c_packetbuffer[0] != 1) { return false; } // Not a valid tag - - *uidLength = pn532_i2c_packetbuffer[5]; - for (uint8_t i = 0;i < pn532_i2c_packetbuffer[5]; i++) { - uid[i] = pn532_i2c_packetbuffer[6 + i]; - } - return true; -} - -#ifdef USE_PN532_DATA_FUNCTION - -uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) -{ - uint8_t i; - uint8_t _key[6]; - uint8_t _uid[7]; - uint8_t _uidLen; - - // Hang on to the key and uid data - memcpy (_key, keyData, 6); - memcpy (_uid, uid, uidLen); - _uidLen = uidLen; - - // Prepare the authentication command // - pn532_i2c_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */ - pn532_i2c_packetbuffer[1] = 1; /* Max card numbers */ - pn532_i2c_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A; - pn532_i2c_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */ - memcpy (&pn532_i2c_packetbuffer[4], _key, 6); - for (i = 0; i < _uidLen; i++) { - pn532_i2c_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */ - } - - if (PN532_writeCommand(pn532_i2c_packetbuffer, 10 + _uidLen)) - return 0; - - // Read the response packet - PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer)); - - // Check if the response is valid and we are authenticated??? - // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00 - // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good - if (pn532_i2c_packetbuffer[0] != 0x00) { - // Authentification failed - return 0; - } - - return 1; -} - -uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) -{ - /* Prepare the command */ - pn532_i2c_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; - pn532_i2c_packetbuffer[1] = 1; /* Card number */ - pn532_i2c_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ - pn532_i2c_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ - - /* Send the command */ - if (PN532_writeCommand(pn532_i2c_packetbuffer, 4)) { - return 0; - } - - /* Read the response packet */ - PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer)); - - /* If byte 8 isn't 0x00 we probably have an error */ - if (pn532_i2c_packetbuffer[0] != 0x00) { - return 0; - } - - /* Copy the 16 data bytes to the output buffer */ - /* Block content starts at byte 9 of a valid response */ - memcpy (data, &pn532_i2c_packetbuffer[1], 16); - - return 1; -} - -uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) -{ - /* Prepare the first command */ - pn532_i2c_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; - pn532_i2c_packetbuffer[1] = 1; /* Card number */ - pn532_i2c_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */ - pn532_i2c_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ - memcpy(&pn532_i2c_packetbuffer[4], data, 16); /* Data Payload */ - - /* Send the command */ - if (PN532_writeCommand(pn532_i2c_packetbuffer, 20)) { - return 0; - } - - /* Read the response packet */ - return (0 < PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer))); -} - -#endif // USE_PN532_DATA_FUNCTION - -void PN532_ScanForTag(void) -{ - if (pn532_i2c_disable) { return; } - uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; - uint8_t uid_len = 0; - uint8_t card_data[16]; - bool erase_success = false; - bool set_success = false; - if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uid_len)) { - if (pn532_i2c_scan_defer_report > 0) { - pn532_i2c_scan_defer_report--; - } else { - char uids[15]; - -#ifdef USE_PN532_DATA_FUNCTION - char card_datas[34]; -#endif // USE_PN532_DATA_FUNCTION - - sprintf(uids,""); - for (uint8_t i = 0;i < uid_len;i++) { - sprintf(uids,"%s%02X",uids,uid[i]); - } - -#ifdef USE_PN532_DATA_FUNCTION - if (uid_len == 4) { // Lets try to read block 0 of the mifare classic card for more information - uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - if (mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) { - if (mifareclassic_ReadDataBlock(1, card_data)) { -#ifdef USE_PN532_DATA_RAW - memcpy(&card_datas,&card_data,sizeof(card_data)); -#else - for (uint8_t i = 0;i < sizeof(card_data);i++) { - if ((isalpha(card_data[i])) || ((isdigit(card_data[i])))) { - card_datas[i] = char(card_data[i]); - } else { - card_datas[i] = '\0'; - } - } -#endif // USE_PN532_DATA_RAW - } - if (pn532_i2c_function == 1) { // erase block 1 of card - for (uint8_t i = 0;i<16;i++) { - card_data[i] = 0x00; - } - if (mifareclassic_WriteDataBlock(1, card_data)) { - erase_success = true; - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Erase success"); - AddLog(LOG_LEVEL_INFO); - memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string - } - } - if (pn532_i2c_function == 2) { -#ifdef USE_PN532_DATA_RAW - memcpy(&card_data,&pn532_i2c_newdata,sizeof(card_data)); - if (mifareclassic_WriteDataBlock(1, card_data)) { - set_success = true; - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Data write successful"); - AddLog(LOG_LEVEL_INFO); - memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string - } -#else - bool IsAlphaNumeric = true; - for (uint8_t i = 0;i < pn532_i2c_newdata_len;i++) { - if ((!isalpha(pn532_i2c_newdata[i])) && (!isdigit(pn532_i2c_newdata[i]))) { - IsAlphaNumeric = false; - } - } - if (IsAlphaNumeric) { - memcpy(&card_data,&pn532_i2c_newdata,pn532_i2c_newdata_len); - card_data[pn532_i2c_newdata_len] = '\0'; // Enforce null termination - if (mifareclassic_WriteDataBlock(1, card_data)) { - set_success = true; - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Data write successful"); - AddLog(LOG_LEVEL_INFO); - memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string - } - } else { - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Data must be alphanumeric"); - AddLog(LOG_LEVEL_INFO); - } -#endif // USE_PN532_DATA_RAW - } - } else { - sprintf(card_datas,"AUTHFAIL"); - } - } - switch (pn532_i2c_function) { - case 0x01: - if (!erase_success) { - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Erase fail - exiting erase mode"); - AddLog(LOG_LEVEL_INFO); - } - break; - case 0x02: - if (!set_success) { - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Write failed - exiting set mode"); - AddLog(LOG_LEVEL_INFO); - } - default: - break; - } - pn532_i2c_function = 0; -#endif // USE_PN532_DATA_FUNCTION - - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); - -#ifdef USE_PN532_DATA_FUNCTION - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\", \"DATA\":\"%s\"}}"), mqtt_data, uids, card_datas); -#else - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\"}}"), mqtt_data, uids); -#endif // USE_PN532_DATA_FUNCTION - - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); - -#ifdef USE_PN532_CAUSE_EVENTS - - char command[71]; -#ifdef USE_PN532_DATA_FUNCTION - sprintf(command,"backlog event PN532_UID=%s;event PN532_DATA=%s",uids,card_datas); -#else - sprintf(command,"event PN532_UID=%s",uids); -#endif // USE_PN532_DATA_FUNCTION - ExecuteCommand(command, SRC_RULE); -#endif // USE_PN532_CAUSE_EVENTS - - pn532_i2c_scan_defer_report = 7; // Ignore tags found for two seconds - } - } else { - if (pn532_i2c_scan_defer_report > 0) { pn532_i2c_scan_defer_report--; } - } -} - -#ifdef USE_PN532_DATA_FUNCTION - -bool PN532_Command(void) -{ - bool serviced = true; - uint8_t paramcount = 0; - if (XdrvMailbox.data_len > 0) { - paramcount=1; - } else { - serviced = false; - return serviced; - } - char sub_string[XdrvMailbox.data_len]; - char sub_string_tmp[XdrvMailbox.data_len]; - for (uint8_t ca=0;ca 1) { - if (XdrvMailbox.data[XdrvMailbox.data_len-1] == ',') { - serviced = false; - return serviced; - } - sprintf(sub_string_tmp,subStr(sub_string, XdrvMailbox.data, ",", 2)); - pn532_i2c_newdata_len = strlen(sub_string_tmp); - if (pn532_i2c_newdata_len > 15) { pn532_i2c_newdata_len = 15; } - memcpy(&pn532_i2c_newdata,&sub_string_tmp,pn532_i2c_newdata_len); - pn532_i2c_newdata[pn532_i2c_newdata_len] = 0x00; // Null terminate the string - pn532_i2c_function = 2; - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Next scanned tag data block 1 will be set to '%s'",pn532_i2c_newdata); - AddLog(LOG_LEVEL_INFO); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"COMMAND\":\"S\"\"}}"), mqtt_data); - return serviced; - } - } -} - -#endif // USE_PN532_DATA_FUNCTION - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xsns40(uint8_t function) -{ - bool result = false; - - if (i2c_flg) { - switch (function) { - case FUNC_EVERY_250_MSECOND: - if (pn532_i2c_detected) { - PN532_ScanForTag(); - } - break; - case FUNC_EVERY_SECOND: - PN532_Detect(); - break; - -#ifdef USE_PN532_DATA_FUNCTION - case FUNC_COMMAND: - if (XSNS_40 == XdrvMailbox.index) { - result = PN532_Command(); - } - break; -#endif // USE_PN532_DATA_FUNCTION - - case FUNC_SAVE_BEFORE_RESTART: - if (!pn532_i2c_disable) { - pn532_i2c_disable = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "PN532 NFC Reader - Disabling for reboot", PN532_I2C_ADDRESS); - AddLog(LOG_LEVEL_DEBUG); - } - break; - default: - break; - } - } - return result; -} - -#endif // USE_PN532_I2C -#endif // USE_I2C diff --git a/tools/decode-status.py b/tools/decode-status.py index 2d105bc96..dd90d1669 100644 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -123,8 +123,8 @@ a_features = [[ "USE_TIMERS","USE_SUNRISE","USE_TIMERS_WEB","USE_RULES", "USE_KNX","USE_WPS","USE_SMARTCONFIG","MQTT_ARDUINOMQTT" ],[ - "USE_CONFIG_OVERRIDE","BE_MINIMAL","USE_SENSORS","USE_CLASSIC", - "USE_KNX_NO_EMULATION","USE_DISPLAY_MODES1TO5","USE_DISPLAY_GRAPH","USE_DISPLAY_LCD", + "USE_CONFIG_OVERRIDE","FIRMWARE_MINIMAL","FIRMWARE_SENSORS","FIRMWARE_CLASSIC", + "FIRMWARE_KNX_NO_EMULATION","USE_DISPLAY_MODES1TO5","USE_DISPLAY_GRAPH","USE_DISPLAY_LCD", "USE_DISPLAY_SSD1306","USE_DISPLAY_MATRIX","USE_DISPLAY_ILI9341","USE_DISPLAY_EPAPER", "USE_DISPLAY_SH1106","USE_MP3_PLAYER","USE_PCA9685","USE_TUYA_DIMMER", "USE_RC_SWITCH","USE_ARMTRONIX_DIMMERS","","",