Merge branch 'development' into sm16716

This commit is contained in:
Gabor Simon 2019-02-08 20:00:53 +04:00 committed by GitHub
commit 7b93df4978
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 1066 additions and 852 deletions

1
.gitignore vendored
View File

@ -15,3 +15,4 @@ build
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
*.bak

View File

@ -14,6 +14,7 @@ TasmotaSerial KEYWORD1
#######################################
begin KEYWORD2
hardwareSerial KEYWORD2
read KEYWORD2
write KEYWORD2
available KEYWORD2

View File

@ -1,6 +1,6 @@
{
"name": "TasmotaSerial",
"version": "2.2.0",
"version": "2.3.0",
"keywords": [
"serial", "io", "TasmotaSerial"
],

View File

@ -1,5 +1,5 @@
name=TasmotaSerial
version=2.2.0
version=2.3.0
author=Theo Arends
maintainer=Theo Arends <theo@arends.com>
sentence=Implementation of software serial with hardware serial fallback for ESP8266.

View File

@ -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;

View File

@ -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

View File

@ -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}

View File

@ -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)

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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) {

View File

@ -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 =
"</head>"
"<body>"
"<div style='text-align:left;display:inline-block;min-width:340px;'>"
#ifdef BE_MINIMAL
#ifdef FIRMWARE_MINIMAL
"<div style='text-align:center;color:red;'><h3>" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "</h3></div>"
#endif
"<div style='text-align:center;'><noscript>" D_NOSCRIPT "<br/></noscript>"
@ -227,7 +227,7 @@ const char HTTP_MSG_SLIDER2[] PROGMEM =
const char HTTP_MSG_RSTRT[] PROGMEM =
"<br/><div style='text-align:center;'>" D_DEVICE_WILL_RESTART "</div><br/>";
const char HTTP_BTN_MENU1[] PROGMEM =
#ifndef BE_MINIMAL
#ifndef FIRMWARE_MINIMAL
"<br/><form action='cn' method='get'><button>" D_CONFIGURATION "</button></form>"
"<br/><form action='in' method='get'><button>" D_INFORMATION "</button></form>"
#endif
@ -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("</tr></table>");
}
#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("<r><i>%d</i><j>%d</j><l>"), web_log_index, last_reset_web_log_flag);
message.replace(F("}9"), mqtt_data); // Save to load here
message += F("</l></r>");
message += F("\1");
WebServer->send(200, FPSTR(HDR_CTYPE_XML), message);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -32,7 +32,7 @@
#include <TasmotaSerial.h>
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;
}
}

View File

@ -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.h>
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();

View File

@ -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);
}
}
/*********************************************************************************************\

View File

@ -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 {

View File

@ -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);
}
}

615
sonoff/xsns_40_pn532.ino Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifdef USE_PN532_HSU
#define XSNS_40 40
#include <TasmotaSerial.h>
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<length[0]; i++) {
sum += buf[i];
}
// Checksum & postamble
if (PN532_receive(tmp, 2, timeout) <= 0) {
return PN532_TIMEOUT;
}
if (0 != (uint8_t)(sum + tmp[0]) || 0 != tmp[1]) { // Checksum fail, so frame must be invalid
return PN532_INVALID_FRAME;
}
return length[0];
}
uint32_t PN532_getFirmwareVersion(void)
{
uint32_t response;
pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
if (PN532_writeCommand(pn532_packetbuffer, 1)) {
return 0;
}
// Read data packet
int16_t status = PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer));
if (0 > 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<XdrvMailbox.data_len;ca++) {
if ((' ' == XdrvMailbox.data[ca]) || ('=' == XdrvMailbox.data[ca])) { XdrvMailbox.data[ca] = ','; }
if (',' == XdrvMailbox.data[ca]) { paramcount++; }
}
UpperCase(XdrvMailbox.data,XdrvMailbox.data);
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"E")) {
pn532_function = 1; // Block 1 of next card/tag will be reset to 0x00...
snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Next scanned tag data block 1 will be erased");
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\":\"E\"\"}}"), mqtt_data);
return serviced;
}
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"S")) {
if (paramcount > 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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<XdrvMailbox.data_len;ca++) {
if ((' ' == XdrvMailbox.data[ca]) || ('=' == XdrvMailbox.data[ca])) { XdrvMailbox.data[ca] = ','; }
if (',' == XdrvMailbox.data[ca]) { paramcount++; }
}
UpperCase(XdrvMailbox.data,XdrvMailbox.data);
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"E")) {
pn532_i2c_function = 1; // Block 0 of next card/tag will be reset to 0x00...
snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Next scanned tag data block 1 will be erased");
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\":\"E\"\"}}"), mqtt_data);
return serviced;
}
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"S")) {
if (paramcount > 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

View File

@ -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","","",