Merged from upstream

This commit is contained in:
srodgers 2019-09-07 14:38:57 -07:00
commit 4a41c13738
50 changed files with 1686 additions and 604 deletions

View File

@ -53,7 +53,7 @@ public:
};
// this template method class is used to track the data being sent on the uart
// when using our own UART ISR
// when using our own UART ISR
// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes
//
class NeoEsp8266UartInterruptContext : NeoEsp8266UartContext
@ -77,12 +77,12 @@ public:
private:
volatile const uint8_t* _asyncBuff;
volatile const uint8_t* _asyncBuffEnd;
volatile static NeoEsp8266UartInterruptContext* s_uartInteruptContext[2];
volatile static NeoEsp8266UartInterruptContext* s_uartInteruptContext[2];
static void ICACHE_RAM_ATTR Isr(void* param);
};
// this template feature class is used a base for all others and contains
// this template feature class is used a base for all others and contains
// common methods
//
class UartFeatureBase
@ -129,7 +129,7 @@ public:
}
};
// this template method class is used a base for all others and contains
// this template method class is used a base for all others and contains
// common properties and methods
//
// used by NeoEsp8266Uart and NeoEsp8266AsyncUart
@ -233,14 +233,14 @@ protected:
}
// detach context, which will disable intr, may disable ISR
_context.Detach(T_UARTFEATURE::Index);
free(_pixelsSending);
}
void ICACHE_RAM_ATTR InitializeUart(uint32_t uartBaud)
{
T_UARTFEATURE::Init(uartBaud);
// attach the context, which will enable the ISR
_context.Attach(T_UARTFEATURE::Index);
}
@ -248,7 +248,7 @@ protected:
void UpdateUart(bool maintainBufferConsistency)
{
// Instruct ESP8266 hardware uart to send the pixels asynchronously
_context.StartSending(T_UARTFEATURE::Index,
_context.StartSending(T_UARTFEATURE::Index,
_pixels,
_pixels + _sizePixels);
@ -264,7 +264,10 @@ protected:
}
// swap so the user can modify without affecting the async operation
std::swap(_pixelsSending, _pixels);
// std::swap(_pixelsSending, _pixels);
uint8_t *temp = _pixelsSending;
_pixelsSending = _pixels;
_pixels = temp;
}
private:
@ -383,7 +386,7 @@ private:
};
};
// uart 0
// uart 0
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>> NeoEsp8266Uart0Ws2812xMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>> NeoEsp8266Uart0Sk6812Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>> NeoEsp8266Uart0Apa106Method;

304
lib/SENDMAIL/sendemail.cpp Executable file
View File

@ -0,0 +1,304 @@
#include "sendemail.h"
// enable serial debugging
//#define DEBUG_EMAIL_PORT Serial
SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) :
host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new WiFiClientSecure())
{
}
String SendEmail::readClient()
{
String r = client->readStringUntil('\n');
r.trim();
while (client->available()) {
delay(0);
r += client->readString();
}
return r;
}
void SetSerialBaudrate(int baudrate);
bool SendEmail::send(const String& from, const String& to, const String& subject, const String& msg)
{
if (!host.length())
{
return false;
}
client->setTimeout(timeout);
// smtp connect
#ifdef DEBUG_EMAIL_PORT
SetSerialBaudrate(115200);
DEBUG_EMAIL_PORT.print("Connecting: ");
DEBUG_EMAIL_PORT.print(host);
DEBUG_EMAIL_PORT.print(":");
DEBUG_EMAIL_PORT.println(port);
#endif
#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
#else
client->setInsecure();
bool mfln = client->probeMaxFragmentLength(host.c_str(), port, 512);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.printf("MFLN supported: %s\n", mfln ? "yes" : "no");
#endif
if (mfln) {
client->setBufferSizes(512, 512);
}
#endif
if (!client->connect(host.c_str(), port))
{
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println("Connection failed");
#endif
return false;
}
String buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("220")))
{
return false;
}
buffer = F("EHLO ");
buffer += client->localIP().toString();
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("250")))
{
return false;
}
if (user.length()>0 && passwd.length()>0 )
{
//buffer = F("STARTTLS");
//client->println(buffer);
if (auth_used==1) {
// plain
#ifdef USE_PLAIN
buffer = F("AUTH PLAIN");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("334")))
{
return false;
}
char plainAuth[100];
memset(plainAuth,sizeof(plainAuth),0);
plainAuth[0] = '\0';
strcpy(&plainAuth[1], user.c_str());
strcpy(&plainAuth[2+user.length()],passwd.c_str());
const char* pA = (const char*)&plainAuth;
char buf[100];
base64_encode(buf, pA, user.length()+passwd.length()+2);
client->println(buf);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buf);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("235")))
{
return false;
}
#endif
} else {
buffer = F("AUTH LOGIN");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("334")))
{
return false;
}
base64 b;
//buffer = user;
//buffer = b.encode(buffer);
buffer = b.encode(user);
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
//DEBUG_EMAIL_PORT.println(user);
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("334")))
{
return false;
}
//buffer = this->passwd;
//buffer = b.encode(buffer);
buffer = b.encode(passwd);
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
//DEBUG_EMAIL_PORT.println(passwd);
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("235")))
{
return false;
}
}
}
// smtp send mail
buffer = F("MAIL FROM:");
buffer += from;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("250")))
{
return false;
}
buffer = F("RCPT TO:");
buffer += to;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("250")))
{
return false;
}
buffer = F("DATA");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("354")))
{
return false;
}
buffer = F("From: ");
buffer += from;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = F("To: ");
buffer += to;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = F("Subject: ");
buffer += subject;
buffer += F("\r\n");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = msg;
client->println(buffer);
client->println('.');
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = F("QUIT");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
return true;
}
#ifdef USE_PLAIN
void SendEmail::a3_to_a4(unsigned char * a4, unsigned char * a3) {
a4[0] = (a3[0] & 0xfc) >> 2;
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
a4[3] = (a3[2] & 0x3f);
}
int SendEmail::base64_encode(char *output, const char *input, int inputLen) {
const char* _b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int i = 0, j = 0;
int encLen = 0;
unsigned char a3[3];
unsigned char a4[4];
while(inputLen--) {
a3[i++] = *(input++);
if(i == 3) {
a3_to_a4(a4, a3);
for(i = 0; i < 4; i++) {
output[encLen++] = _b64_alphabet[a4[i]];
}
i = 0;
}
}
if(i) {
for(j = i; j < 3; j++) {
a3[j] = '\0';
}
a3_to_a4(a4, a3);
for(j = 0; j < i + 1; j++) {
output[encLen++] = _b64_alphabet[a4[j]];
}
while((i++ < 3)) {
output[encLen++] = '=';
}
}
output[encLen] = '\0';
return encLen;
}
#endif

39
lib/SENDMAIL/sendemail.h Executable file
View File

@ -0,0 +1,39 @@
#ifndef __SENDEMAIL_H
#define __SENDEMAIL_H
//#define DEBUG_EMAIL_PORT
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <base64.h>
#include <core_version.h>
class SendEmail
{
private:
const String host;
const int port;
const String user;
const String passwd;
const int timeout;
const bool ssl;
const int auth_used;
#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
WiFiClient* client;
#else
// use bear ssl
// #include "WiFiClientSecureLightBearSSL.h"
// BearSSL::WiFiClientSecure_light *client;
BearSSL::WiFiClientSecure* client;
//WiFiClientSecure* client;
#endif
String readClient();
void a3_to_a4(unsigned char * a4, unsigned char * a3);
int base64_encode(char *output, const char *input, int inputLen);
public:
SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used);
bool send(const String& from, const String& to, const String& subject, const String& msg);
~SendEmail() {client->stop(); delete client;}
};
#endif

View File

@ -1,4 +1,12 @@
/*********************************************************************************************\
* 6.6.0.11 20190907
* Change Settings crc calculation allowing short term backward compatibility
*
* 6.6.0.10 20190905
* Redesign Tuya support by Shantur Rathore (#6353)
* Add command Reset 99 to reset bootcount to zero (#684, #6351)
* Change command Time 1/2/3 to select JSON time format ISO, ISO + Epoch or Epoch for legacy reason
*
* 6.6.0.9 20190828
* Change theoretical baudrate range to 300..19660500 bps in 300 increments (#6294)
* Add Full support of all protocols in IRremoteESP8266, to be used on dedicated-IR Tasmota version. Warning: +81k Flash when compiling with USE_IR_REMOTE_FULL
@ -6,6 +14,9 @@
* Add 'sonoff-ir' pre-packaged IR-dedicated firmware and 'sonoff-ircustom' to customize firmware with IR Full protocol support
* Add Zigbee support phase 2 - cc2530 initialization and basic ZCL decoding
* Add driver USE_SDM120_2 with Domoticz P1 Smart Meter functionality as future replacement for USE_SDM120 - Pls test and report
* Add command Power0 0/1/2/Off/On/Toggle to control all power outputs at once (#6340)
* Add time to more events (#6337)
* Add command Time 1/2/3 to select JSON time format ISO + Epoch, ISO or Epoch
*
* 6.6.0.8 20190827
* Add Tuya Energy monitoring by Shantur Rathore

View File

@ -96,6 +96,7 @@
#define D_JSON_LOW "Low"
#define D_JSON_MAC "Mac"
#define D_JSON_MASK "Mask"
#define D_JSON_MEMORY_ERROR "Memory error"
#define D_JSON_MINIMAL "minimal"
#define D_JSON_MODEL "Model"
#define D_JSON_MQTT_COUNT "MqttCount"
@ -326,6 +327,7 @@
#define D_CMND_WEBCOLOR "WebColor"
#define D_CMND_WEBSENSOR "WebSensor"
#define D_CMND_EMULATION "Emulation"
#define D_CMND_SENDMAIL "Sendmail"
// Commands xdrv_03_energy.ino
#define D_CMND_POWERLOW "PowerLow"
@ -444,6 +446,10 @@
#define D_CMND_LATITUDE "Latitude"
#define D_CMND_LONGITUDE "Longitude"
// Commands xdrv_16_tuyadimmer.ino
#define D_CMND_TUYA_MCU "TuyaMCU"
// Commands xdrv_23_zigbee.ino
#define D_CMND_ZIGBEEZNPSEND "ZigbeeZNPSend"
#define D_JSON_ZIGBEEZNPRECEIVED "ZigbeeZNPReceived"

View File

@ -147,9 +147,9 @@
#define D_START "Start"
#define D_STD_TIME "STD"
#define D_STOP "Stop"
#define D_SUBNET_MASK "Maschera sottorete"
#define D_SUBNET_MASK "Maschera Subnet"
#define D_SUBSCRIBE_TO "Sottoscrivi a"
#define D_UNSUBSCRIBE_FROM "Unsubscribe from"
#define D_UNSUBSCRIBE_FROM "Cancella da"
#define D_SUCCESSFUL "Riuscito"
#define D_SUNRISE "Alba"
#define D_SUNSET "Tramonto"
@ -161,16 +161,16 @@
#define D_TRANSMIT "Trasmesso"
#define D_TRUE "Vero"
#define D_TVOC "TVOC"
#define D_UPGRADE "aggiornamento"
#define D_UPGRADE "Aggiornamento"
#define D_UPLOAD "Invio"
#define D_UPTIME "Uptime"
#define D_USER "Utente"
#define D_UTC_TIME "UTC"
#define D_UV_INDEX "Indice UV"
#define D_UV_INDEX_1 "Low"
#define D_UV_INDEX_2 "Mid"
#define D_UV_INDEX_3 "High"
#define D_UV_INDEX_4 "Danger"
#define D_UV_INDEX_1 "Basso"
#define D_UV_INDEX_2 "Medio"
#define D_UV_INDEX_3 "Alto"
#define D_UV_INDEX_4 "Pericolo"
#define D_UV_INDEX_5 "BurnL1/2"
#define D_UV_INDEX_6 "BurnL3"
#define D_UV_INDEX_7 "OoR"
@ -186,7 +186,7 @@
#define D_WARNING_MINIMAL_VERSION "ATTENZIONE Questa versione non supporta il salvataggio delle impostazioni"
#define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1"
#define D_SERIAL_LOGGING_DISABLED "Log seriale disabilitato"
#define D_SERIAL_LOGGING_DISABLED "Log Seriale disabilitato"
#define D_SYSLOG_LOGGING_REENABLED "Syslog ri-abilitato"
#define D_SET_BAUDRATE_TO "Baudrate impostato a"
@ -198,11 +198,11 @@
#define D_OSWATCH "osWatch"
#define D_BLOCKED_LOOP "Ciclo Bloccato"
#define D_WPS_FAILED_WITH_STATUS "WPSconfig Fallito con stato"
#define D_ACTIVE_FOR_3_MINUTES "attivo per 3 minuti"
#define D_ACTIVE_FOR_3_MINUTES "Attivo per 3 minuti"
#define D_FAILED_TO_START "partenza fallita"
#define D_PATCH_ISSUE_2186 "Patch issue 2186"
#define D_CONNECTING_TO_AP "Connessione ad AP"
#define D_IN_MODE "in modalità"
#define D_IN_MODE "In modalità"
#define D_CONNECT_FAILED_NO_IP_ADDRESS "Connessione fallita, indirizzo IP non ricevuto"
#define D_CONNECT_FAILED_AP_NOT_REACHED "Connessione fallita, AP non raggiungibile"
#define D_CONNECT_FAILED_WRONG_PASSWORD "Connessione fallita, password AP non corretta"
@ -259,8 +259,8 @@
#define D_PULLUP_ENABLE "No Button/Switch pull-up"
#define D_ADC "ADC"
#define D_GPIO "GPIO"
#define D_SERIAL_IN "Serial In"
#define D_SERIAL_OUT "Serial Out"
#define D_SERIAL_IN "Seriale In"
#define D_SERIAL_OUT "Seriale Out"
#define D_WIFI_PARAMETERS "Parametri Wifi"
#define D_SCAN_FOR_WIFI_NETWORKS "Scansione delle reti wifi"
@ -283,30 +283,30 @@
#define D_FULL_TOPIC "Full Topic"
#define D_LOGGING_PARAMETERS "Parametri Logging"
#define D_SERIAL_LOG_LEVEL "Seriale livello di log"
#define D_WEB_LOG_LEVEL "Web livello di log"
#define D_SYS_LOG_LEVEL "Sys livello di log"
#define D_SERIAL_LOG_LEVEL "Livello di log Seriale"
#define D_WEB_LOG_LEVEL "livello di log Web"
#define D_SYS_LOG_LEVEL "livello di log Sys"
#define D_MORE_DEBUG "Debug aggiuntivo"
#define D_SYSLOG_HOST "Syslog host"
#define D_SYSLOG_PORT "Syslog porta"
#define D_TELEMETRY_PERIOD "Periodo Telemetria"
#define D_OTHER_PARAMETERS "Altri parametri"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_TEMPLATE "Modello"
#define D_ACTIVATE "Attivare"
#define D_WEB_ADMIN_PASSWORD "Password Amministratore Web"
#define D_MQTT_ENABLE "Abilita MQTT"
#define D_FRIENDLY_NAME "Nome confidenziale"
#define D_FRIENDLY_NAME "Nome amichevole"
#define D_BELKIN_WEMO "Belkin WeMo"
#define D_HUE_BRIDGE "Hue Bridge"
#define D_SINGLE_DEVICE "dispositivo singolo"
#define D_MULTI_DEVICE "dispositivo multiplo"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_CONFIGURE_TEMPLATE "Configurare Modello"
#define D_TEMPLATE_PARAMETERS "Parametri Modello"
#define D_TEMPLATE_NAME "Nome"
#define D_BASE_TYPE "Baseto nel"
#define D_TEMPLATE_FLAGS "Opzioni"
#define D_SAVE_CONFIGURATION "Salva configurazione"
#define D_CONFIGURATION_SAVED "Configurazione salvata"
@ -464,12 +464,12 @@
#define D_PARTICALS_BEYOND "Particelle"
// xsns_32_mpu6050.ino
#define D_AX_AXIS "Accel. X-Axis"
#define D_AY_AXIS "Accel. Y-Axis"
#define D_AZ_AXIS "Accel. Z-Axis"
#define D_GX_AXIS "Gyro X-Axis"
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
#define D_AX_AXIS "Accel. Asse-X"
#define D_AY_AXIS "Accel. Asse-Y"
#define D_AZ_AXIS "Accel. Asse-Z"
#define D_GX_AXIS "Gyro Asse-X"
#define D_GY_AXIS "Gyro Asse-Y"
#define D_GZ_AXIS "Gyro Asse-Z"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Rimuovere peso"

View File

@ -65,8 +65,8 @@
#define D_BY "por" // Write by me
#define D_BYTES "Bytes"
#define D_CELSIUS "Celsius"
#define D_CHANNEL "Channel"
#define D_CO2 "Dióxido de carbono"
#define D_CHANNEL "Canal"
#define D_CO2 "CO2"
#define D_CODE "Código" // Button code
#define D_COLDLIGHT "Luz fria"
#define D_COMMAND "Comando"
@ -93,14 +93,14 @@
#define D_FALLBACK_TOPIC "Tópico para retornar"
#define D_FALSE "Falso"
#define D_FILE "Arquivo"
#define D_FLOW_RATE "Flow rate"
#define D_FLOW_RATE "Quociente de vazão"
#define D_FREE_MEMORY "Memória livre"
#define D_FREQUENCY "Frequência"
#define D_GAS "Gás"
#define D_GATEWAY "Gateway"
#define D_GROUP "Grupo"
#define D_HOST "Anfitrião"
#define D_HOSTNAME "Nome do anfitrião"
#define D_HOST "Host"
#define D_HOSTNAME "Nome do Host"
#define D_HUMIDITY "Umidade"
#define D_ILLUMINANCE "Luminância"
#define D_IMMEDIATE "Imediato" // Button immediate
@ -167,10 +167,10 @@
#define D_USER "Usuário"
#define D_UTC_TIME "UTC"
#define D_UV_INDEX "Índice UV"
#define D_UV_INDEX_1 "Low"
#define D_UV_INDEX_2 "Mid"
#define D_UV_INDEX_3 "High"
#define D_UV_INDEX_4 "Danger"
#define D_UV_INDEX_1 "Baixo"
#define D_UV_INDEX_2 "Médio"
#define D_UV_INDEX_3 "Alto"
#define D_UV_INDEX_4 "Perigro"
#define D_UV_INDEX_5 "BurnL1/2"
#define D_UV_INDEX_6 "BurnL3"
#define D_UV_INDEX_7 "OoR"
@ -178,7 +178,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Versão"
#define D_VOLTAGE "Voltagem"
#define D_WEIGHT "Weight"
#define D_WEIGHT "Peso"
#define D_WARMLIGHT "Luz quente"
#define D_WEB_SERVER "Servidor WEB"
@ -186,7 +186,7 @@
#define D_WARNING_MINIMAL_VERSION "AVISO: esta versão não supporta configurações persistentes"
#define D_LEVEL_10 "nível 1-0"
#define D_LEVEL_01 "nível 0-1"
#define D_SERIAL_LOGGING_DISABLED "Registro em série desabilitado"
#define D_SERIAL_LOGGING_DISABLED "Registro Serial desabilitado"
#define D_SYSLOG_LOGGING_REENABLED "Registro do Syslog reativado"
#define D_SET_BAUDRATE_TO "Ajuste da velocidade para"
@ -292,7 +292,7 @@
#define D_TELEMETRY_PERIOD "Período de telemetria"
#define D_OTHER_PARAMETERS "Outros parâmetros"
#define D_TEMPLATE "Template"
#define D_TEMPLATE "Modelo"
#define D_ACTIVATE "Activate"
#define D_WEB_ADMIN_PASSWORD "Senha de WEB Admin"
#define D_MQTT_ENABLE "MQTT habilitado"
@ -302,11 +302,11 @@
#define D_SINGLE_DEVICE "Dispositivo único"
#define D_MULTI_DEVICE "Múltiplos dispositivos"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_CONFIGURE_TEMPLATE "Configurar Modelo"
#define D_TEMPLATE_PARAMETERS "Parâmetros Modelo"
#define D_TEMPLATE_NAME "Nome"
#define D_BASE_TYPE "Baseado em"
#define D_TEMPLATE_FLAGS "Opções"
#define D_SAVE_CONFIGURATION "Gravar configuração"
#define D_CONFIGURATION_SAVED "Configuração gravada"
@ -347,10 +347,10 @@
#define D_UPLOAD_ERR_7 "Envio cancelado"
#define D_UPLOAD_ERR_8 "Arquivo inválido"
#define D_UPLOAD_ERR_9 "Arquivo muito grande"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERR_10 "Falha ao iniciar chip RF"
#define D_UPLOAD_ERR_11 "Falha ao apagar o chip RF"
#define D_UPLOAD_ERR_12 "Falha ao escrever o chip RF"
#define D_UPLOAD_ERR_13 "Falha ao decodificar o firmware de RF"
#define D_UPLOAD_ERROR_CODE "Código de erro do envio"
#define D_ENTER_COMMAND "Inserir comando"
@ -472,27 +472,27 @@
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
#define D_RESET_HX711 "Reset Scale"
#define D_CONFIGURE_HX711 "Configure Scale"
#define D_HX711_PARAMETERS "Scale parameters"
#define D_ITEM_WEIGHT "Item weight"
#define D_REFERENCE_WEIGHT "Reference weigth"
#define D_CALIBRATE "Calibrate"
#define D_CALIBRATION "Calibration"
#define D_HX_CAL_REMOVE "Remover peso"
#define D_HX_CAL_REFERENCE "Peso de referência de carga"
#define D_HX_CAL_DONE "Calibrado"
#define D_HX_CAL_FAIL "Falha na calibração"
#define D_RESET_HX711 "Redefinir escala"
#define D_CONFIGURE_HX711 "Configurar escala"
#define D_HX711_PARAMETERS "Parâmetros de escala"
#define D_ITEM_WEIGHT "Peso do Item"
#define D_REFERENCE_WEIGHT "Peso de referência"
#define D_CALIBRATE "Calibrar"
#define D_CALIBRATION "Calibração"
//xsns_35_tx20.ino
#define D_TX20_WIND_DIRECTION "Wind Direction"
#define D_TX20_WIND_SPEED "Wind Speed"
#define D_TX20_WIND_SPEED_AVG "Wind Speed Avg"
#define D_TX20_WIND_SPEED_MAX "Wind Speed Max"
#define D_TX20_WIND_DIRECTION "Direção do vento"
#define D_TX20_WIND_SPEED "Velocidade do vento"
#define D_TX20_WIND_SPEED_AVG "Velocidade média do vento"
#define D_TX20_WIND_SPEED_MAX "Velocidade do vento Máxima"
#define D_TX20_NORTH "N"
#define D_TX20_EAST "E"
#define D_TX20_EAST "L"
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
#define D_TX20_WEST "O"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
@ -657,37 +657,37 @@
#define D_LOG_WIFI "WIF: " // Wifi
//SDM220
#define D_PHASE_ANGLE "Phase Angle"
#define D_IMPORT_ACTIVE "Import Active"
#define D_EXPORT_ACTIVE "Export Active"
#define D_IMPORT_REACTIVE "Import Reactive"
#define D_EXPORT_REACTIVE "Export Reactive"
#define D_TOTAL_REACTIVE "Total Reactive"
#define D_PHASE_ANGLE "Ângulo de Fase"
#define D_IMPORT_ACTIVE "Importar Ativo"
#define D_EXPORT_ACTIVE "Exportar Ativo"
#define D_IMPORT_REACTIVE "Importar Reativo"
#define D_EXPORT_REACTIVE "Exportar Reativo"
#define D_TOTAL_REACTIVE "Reativo total"
#define D_UNIT_KWARH "kVArh"
#define D_UNIT_ANGLE "Deg"
//SOLAXX1
#define D_PV1_VOLTAGE "PV1 Voltage"
#define D_PV1_CURRENT "PV1 Current"
#define D_PV1_POWER "PV1 Power"
#define D_PV2_VOLTAGE "PV2 Voltage"
#define D_PV2_CURRENT "PV2 Current"
#define D_PV2_POWER "PV2 Power"
#define D_SOLAR_POWER "Solar Power"
#define D_INVERTER_POWER "Inverter Power"
#define D_PV1_VOLTAGE "PV1 Voltagem"
#define D_PV1_CURRENT "PV1 Corrente"
#define D_PV1_POWER "PV1 Energia"
#define D_PV2_VOLTAGE "PV2 Voltagem"
#define D_PV2_CURRENT "PV2 Corrente"
#define D_PV2_POWER "PV2 Energia"
#define D_SOLAR_POWER "Energia Solar"
#define D_INVERTER_POWER "Potência do Inversor"
#define D_STATUS "Status"
#define D_WAITING "Waiting"
#define D_CHECKING "Checking"
#define D_WORKING "Working"
#define D_FAILURE "Failure"
#define D_SOLAX_ERROR_0 "No Error Code"
#define D_SOLAX_ERROR_1 "Grid Lost Fault"
#define D_SOLAX_ERROR_2 "Grid Voltage Fault"
#define D_SOLAX_ERROR_3 "Grid Frequency Fault"
#define D_SOLAX_ERROR_4 "Pv Voltage Fault"
#define D_SOLAX_ERROR_5 "Isolation Fault"
#define D_SOLAX_ERROR_6 "Over Temperature Fault"
#define D_SOLAX_ERROR_7 "Fan Fault"
#define D_SOLAX_ERROR_8 "Other Device Fault"
#define D_WAITING "Esperando"
#define D_CHECKING "Verificando"
#define D_WORKING "Trabalhando"
#define D_FAILURE "Falha"
#define D_SOLAX_ERROR_0 "Nenhum código de erro"
#define D_SOLAX_ERROR_1 "Erro Grid Perdida"
#define D_SOLAX_ERROR_2 "Falha na Tensão da rede"
#define D_SOLAX_ERROR_3 "Falha na Frequência do Grid"
#define D_SOLAX_ERROR_4 "Pv Falha de Tensão"
#define D_SOLAX_ERROR_5 "Falha de Isolamento"
#define D_SOLAX_ERROR_6 "Falha de Temperatura excessiva"
#define D_SOLAX_ERROR_7 "Falha no Ventilador"
#define D_SOLAX_ERROR_8 "Outra falha do dispositivo"
#endif // _LANGUAGE_PT_BR_H_

View File

@ -307,7 +307,7 @@
// -- Optional modules ----------------------------
#define USE_BUZZER // Add support for a buzzer (+0k6 code)
#define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code)
#define USE_TUYA_DIMMER // Add support for Tuya Serial Dimmer
#define USE_TUYA_MCU // Add support for Tuya Serial MCU
#define TUYA_DIMMER_ID 0 // Default dimmer Id
#define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code)
#define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer and Sonoff L1 (+2k code)

View File

@ -78,7 +78,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t no_hold_retain : 1; // bit 12 (v6.4.1.19) - SetOption62 - Don't use retain flag on HOLD messages
uint32_t no_power_feedback : 1; // bit 13 (v6.5.0.9) - SetOption63 - Don't scan relay power state at restart
uint32_t use_underscore : 1; // bit 14 (v6.5.0.12) - SetOption64 - Enable "_" instead of "-" as sensor index separator
uint32_t tuya_disable_dimmer : 1; // bit 15 (v6.5.0.15) - SetOption65 - Enable or Disable Tuya Serial Dimmer control
uint32_t ex_tuya_disable_dimmer : 1; // bit 15 (v6.5.0.15) - SetOption65 - (Enable or Disable Tuya Serial Dimmer control) - free since 6.6.0.10
uint32_t tuya_dimmer_range_255 : 1; // bit 16 (v6.6.0.1) - SetOption66 - Enable or Disable Dimmer range 255 slider control
uint32_t buzzer_enable : 1; // bit 17 (v6.6.0.1) - SetOption67 - Enable buzzer when available
uint32_t pwm_multi_channels : 1; // bit 18 (v6.6.0.3) - SetOption68 - Enable multi-channels PWM instead of Color PWM
@ -105,8 +105,7 @@ typedef union {
uint32_t spare01 : 1;
uint32_t spare02 : 1;
uint32_t spare03 : 1;
uint32_t spare04 : 1;
uint32_t spare05 : 1;
uint32_t time_format : 2; // (v6.6.0.9) - CMND_TIME
uint32_t calc_resolution : 3;
uint32_t weight_resolution : 2;
uint32_t frequency_resolution : 2;
@ -186,6 +185,14 @@ typedef struct {
uint32_t last_return_kWhtotal;
} EnergyUsage;
typedef struct {
uint8_t fnid = 0;
uint8_t dpid = 0;
} TuyaFnidDpidMap;
const uint8_t MAX_TUYA_FUNCTIONS = 16;
/*
struct SYSCFG {
unsigned long cfg_holder; // 000 Pre v6 header
@ -364,6 +371,7 @@ struct SYSCFG {
unsigned long energy_frequency_calibration; // 7C8 also used by HX711 to save last weight
uint16_t web_refresh; // 7CC
char mems[MAX_RULE_MEMS][10]; // 7CE
<<<<<<< HEAD
char rules[MAX_RULE_SETS][MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m, 3 x 512 bytes in v5.14.0b
uint8_t data8[32]; // E00
uint16_t data16[16]; // E20
@ -372,8 +380,15 @@ struct SYSCFG {
uint8_t free_e20[432]; // E50
=======
char rules[MAX_RULE_SETS][MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m, 3 x 512 bytes in v5.14.0b
TuyaFnidDpidMap tuya_fnid_map[MAX_TUYA_FUNCTIONS]; // E00 32 bytes
// FFF last location
uint8_t free_e20[472]; // E20
>>>>>>> upstream/development
uint32_t cfg_timestamp; // FF8
uint32_t cfg_crc32; // FFC
} Settings;
struct RTCRBT {

View File

@ -273,8 +273,8 @@ const uint32_t SETTINGS_LOCATION = SPIFFS_END; // No need for SPIFFS as it uses
// Version 5.2 allow for more flash space
const uint8_t CFG_ROTATES = 8; // Number of flash sectors used (handles uploads)
uint16_t settings_crc = 0;
uint32_t settings_location = SETTINGS_LOCATION;
uint32_t settings_crc32 = 0;
uint8_t *settings_buffer = nullptr;
/********************************************************************************************/
@ -318,19 +318,42 @@ bool SettingsBufferAlloc(void)
return true;
}
uint16_t GetSettingsCrc(void)
uint16_t GetCfgCrc16(uint8_t *bytes, uint32_t size)
{
uint16_t crc = 0;
uint8_t *bytes = (uint8_t*)&Settings;
// Fix miscalculation if previous Settings was 3584 and current Settings is 4096 as of 0x06060007
uint32_t size = (Settings.version < 0x06060007) ? 3584 : sizeof(SYSCFG);
for (uint32_t i = 0; i < size; i++) {
if ((i < 14) || (i > 15)) { crc += bytes[i]*(i+1); } // Skip crc
}
return crc;
}
uint16_t GetSettingsCrc(void)
{
// Fix miscalculation if previous Settings was 3584 and current Settings is 4096 between 0x06060007 and 0x0606000A
uint32_t size = ((Settings.version < 0x06060007) || (Settings.version > 0x0606000A)) ? 3584 : sizeof(SYSCFG);
return GetCfgCrc16((uint8_t*)&Settings, size);
}
uint32_t GetCfgCrc32(uint8_t *bytes, uint32_t size)
{
// https://create.stephan-brumme.com/crc32/#bitwise
uint32_t crc = 0;
while (size--) {
crc ^= *bytes++;
for (uint32_t j = 0; j < 8; j++) {
crc = (crc >> 1) ^ (-int(crc & 1) & 0xEDB88320);
}
}
return ~crc;
}
uint32_t GetSettingsCrc32(void)
{
return GetCfgCrc32((uint8_t*)&Settings, sizeof(SYSCFG) -4); // Skip crc32
}
void SettingsSaveAll(void)
{
if (Settings.flag.save_state) {
@ -340,9 +363,6 @@ void SettingsSaveAll(void)
}
XsnsCall(FUNC_SAVE_BEFORE_RESTART);
XdrvCall(FUNC_SAVE_BEFORE_RESTART);
#ifdef USE_EEPROM
EepromCommit();
#endif
SettingsSave(0);
}
@ -366,7 +386,7 @@ void SettingsSave(uint8_t rotate)
* stop_flash_rotate 1 = Allow only eeprom flash slot use (SetOption12 1)
*/
#ifndef FIRMWARE_MINIMAL
if ((GetSettingsCrc() != settings_crc) || rotate) {
if ((GetSettingsCrc32() != settings_crc32) || rotate) {
if (1 == rotate) { // Use eeprom flash slot only and disable flash rotate from now on (upgrade)
stop_flash_rotate = 1;
}
@ -381,32 +401,19 @@ void SettingsSave(uint8_t rotate)
settings_location = SETTINGS_LOCATION;
}
}
Settings.save_flag++;
Settings.cfg_size = sizeof(SYSCFG);
Settings.cfg_crc = GetSettingsCrc();
#ifdef USE_EEPROM
if (SPIFFS_END == settings_location) {
uint8_t* flash_buffer;
flash_buffer = new uint8_t[SPI_FLASH_SEC_SIZE];
if (eeprom_data && eeprom_size) {
size_t flash_offset = SPI_FLASH_SEC_SIZE - eeprom_size;
memcpy(flash_buffer + flash_offset, eeprom_data, eeprom_size); // Write dirty EEPROM data
} else {
ESP.flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)flash_buffer, SPI_FLASH_SEC_SIZE); // Read EEPROM area
}
memcpy(flash_buffer, &Settings, sizeof(Settings));
ESP.flashEraseSector(settings_location);
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)flash_buffer, SPI_FLASH_SEC_SIZE);
delete[] flash_buffer;
Settings.save_flag++;
if (UtcTime() > START_VALID_TIME) {
Settings.cfg_timestamp = UtcTime();
} else {
ESP.flashEraseSector(settings_location);
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG));
Settings.cfg_timestamp++;
}
#else
Settings.cfg_size = sizeof(SYSCFG);
Settings.cfg_crc = GetSettingsCrc(); // Keep for backward compatibility in case of fall-back just after upgrade
Settings.cfg_crc32 = GetSettingsCrc32();
ESP.flashEraseSector(settings_location);
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG));
#endif // USE_EEPROM
if (!stop_flash_rotate && rotate) {
for (uint32_t i = 1; i < CFG_ROTATES; i++) {
@ -417,7 +424,7 @@ void SettingsSave(uint8_t rotate)
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG D_SAVED_TO_FLASH_AT " %X, " D_COUNT " %d, " D_BYTES " %d"), settings_location, Settings.save_flag, sizeof(SYSCFG));
settings_crc = Settings.cfg_crc;
settings_crc32 = Settings.cfg_crc32;
}
#endif // FIRMWARE_MINIMAL
RtcSettingsSave();
@ -442,7 +449,10 @@ void SettingsLoad(void)
bool valid = false;
if (Settings.version > 0x06000000) {
bool almost_valid = (Settings.cfg_crc == GetSettingsCrc());
bool almost_valid = (Settings.cfg_crc32 == GetSettingsCrc32());
if (Settings.version < 0x0606000B) {
almost_valid = (Settings.cfg_crc == GetSettingsCrc());
}
// Sometimes CRC on pages below FB, overwritten by OTA, is fine but Settings are still invalid. So check cfg_holder too
if (almost_valid && (0 == cfg_holder)) { cfg_holder = Settings.cfg_holder; } // At FB always active cfg_holder
valid = (cfg_holder == Settings.cfg_holder);
@ -471,7 +481,7 @@ void SettingsLoad(void)
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();
settings_crc32 = GetSettingsCrc32();
#endif // FIRMWARE_MINIMAL
RtcSettingsLoad();
@ -1096,6 +1106,41 @@ void SettingsDelta(void)
Settings.sbaudrate = Settings.ex_sbaudrate * 4;
}
if (Settings.version < 0x0606000A) {
uint8_t tuyaindex = 0;
if (Settings.param[P_ex_TUYA_DIMMER_ID] > 0) { // ex SetOption34
Settings.tuya_fnid_map[tuyaindex].fnid = 21; // TUYA_MCU_FUNC_DIMMER - Move Tuya Dimmer Id to Map
Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_ex_TUYA_DIMMER_ID];
tuyaindex++;
} else if (Settings.flag3.ex_tuya_disable_dimmer == 1) { // ex SetOption65
Settings.tuya_fnid_map[tuyaindex].fnid = 11; // TUYA_MCU_FUNC_REL1 - Create FnID for Switches
Settings.tuya_fnid_map[tuyaindex].dpid = 1;
tuyaindex++;
}
if (Settings.param[P_ex_TUYA_RELAYS] > 0) {
for (uint8_t i = 0 ; i < Settings.param[P_ex_TUYA_RELAYS]; i++) { // ex SetOption41
Settings.tuya_fnid_map[tuyaindex].fnid = 12 + i; // TUYA_MCU_FUNC_REL2 - Create FnID for Switches
Settings.tuya_fnid_map[tuyaindex].dpid = i + 2;
tuyaindex++;
}
}
if (Settings.param[P_ex_TUYA_POWER_ID] > 0) { // ex SetOption46
Settings.tuya_fnid_map[tuyaindex].fnid = 31; // TUYA_MCU_FUNC_POWER - Move Tuya Power Id to Map
Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_ex_TUYA_POWER_ID];
tuyaindex++;
}
if (Settings.param[P_ex_TUYA_VOLTAGE_ID] > 0) { // ex SetOption44
Settings.tuya_fnid_map[tuyaindex].fnid = 33; // TUYA_MCU_FUNC_VOLTAGE - Move Tuya Voltage Id to Map
Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_ex_TUYA_VOLTAGE_ID];
tuyaindex++;
}
if (Settings.param[P_ex_TUYA_CURRENT_ID] > 0) { // ex SetOption45
Settings.tuya_fnid_map[tuyaindex].fnid = 32; // TUYA_MCU_FUNC_CURRENT - Move Tuya Current Id to Map
Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_ex_TUYA_CURRENT_ID];
tuyaindex++;
}
}
Settings.version = VERSION;
SettingsSave(1);
}

View File

@ -130,6 +130,8 @@ const uint32_t SERIAL_POLLING = 100; // Serial receive polling in ms
const uint32_t ZIGBEE_POLLING = 100; // Serial receive polling in ms
const uint8_t MAX_STATUS = 11; // Max number of status lines
const uint32_t START_VALID_TIME = 1451602800; // Time is synced and after 2016-01-01
const uint32_t DRIVER_BOOT_DELAY = 1; // Number of milliseconds to retard driver cycles during boot-up time to reduce overall CPU load whilst Wifi is connecting
const uint32_t LOOP_SLEEP_DELAY = 50; // Lowest number of milliseconds to go through the main loop using delay when needed
@ -231,7 +233,11 @@ enum EmulationOptions {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
enum TopicOptions { CMND, STAT, TELE, nu1, RESULT_OR_CMND, RESULT_OR_STAT, RESULT_OR_TELE };
enum ExecuteCommandPowerOptions { POWER_OFF, POWER_ON, POWER_TOGGLE, POWER_BLINK, POWER_BLINK_STOP, power_nu1, POWER_OFF_NO_STATE, POWER_ON_NO_STATE, power_nu2, POWER_SHOW_STATE };
enum ExecuteCommandPowerOptions { POWER_OFF, POWER_ON, POWER_TOGGLE, POWER_BLINK, POWER_BLINK_STOP,
POWER_OFF_NO_STATE = 8, POWER_ON_NO_STATE, POWER_TOGGLE_NO_STATE,
POWER_SHOW_STATE = 16 };
enum SendKeyPowerOptions { POWER_HOLD = 3, CLEAR_RETAIN = 9 };
enum SendKeyOptions { KEY_BUTTON, KEY_SWITCH };
enum PowerOnStateOptions { POWER_ALL_OFF, POWER_ALL_ON, POWER_ALL_SAVED_TOGGLE, POWER_ALL_SAVED, POWER_ALL_ALWAYS_ON, POWER_ALL_OFF_PULSETIME_ON };
@ -239,9 +245,9 @@ enum ButtonStates { PRESSED, NOT_PRESSED };
enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER };
enum SettingsParamIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_IR_UNKNOW_THRESHOLD, // SetOption32 .. SetOption38
P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_TUYA_RELAYS, P_OVER_TEMP, // SetOption39 .. SetOption42
P_TUYA_DIMMER_MAX, P_TUYA_VOLTAGE_ID, P_TUYA_CURRENT_ID, P_TUYA_POWER_ID, // SetOption43 .. SetOption46
enum SettingsParamIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_ex_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_IR_UNKNOW_THRESHOLD, // SetOption32 .. SetOption38
P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_ex_TUYA_RELAYS, P_OVER_TEMP, // SetOption39 .. SetOption42
P_TUYA_DIMMER_MAX, P_ex_TUYA_VOLTAGE_ID, P_ex_TUYA_CURRENT_ID, P_ex_TUYA_POWER_ID, // SetOption43 .. SetOption46
P_ENERGY_TARIFF1, P_ENERGY_TARIFF2, // SetOption47 .. SetOption48
P_MAX_PARAM8}; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49
@ -257,7 +263,7 @@ enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT
enum LightSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX};
enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT,
FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND,
FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_300_MSECOND, FUNC_EVERY_SECOND,
FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART,
FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER,
FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA,

View File

@ -90,6 +90,7 @@ unsigned long pulse_timer[MAX_PULSETIMERS] = { 0 }; // Power off timer
unsigned long blink_timer = 0; // Power cycle timer
unsigned long backlog_delay = 0; // Command backlog delay
power_t power = 0; // Current copy of Settings.power
power_t last_power = 0; // Last power set state
power_t blink_power; // Blink power state
power_t blink_mask = 0; // Blink relay active mask
power_t blink_powersave; // Blink start power save state
@ -172,7 +173,7 @@ String backlog[MAX_BACKLOG]; // Command backlog
char* Format(char* output, const char* input, int size)
{
char *token;
uint8_t digits = 0;
uint32_t digits = 0;
if (strstr(input, "%") != nullptr) {
strlcpy(output, input, size);
@ -201,7 +202,9 @@ char* Format(char* output, const char* input, int size)
}
}
}
if (!digits) { strlcpy(output, input, size); }
if (!digits) {
strlcpy(output, input, size);
}
return output;
}
@ -219,7 +222,7 @@ char* GetOtaUrl(char *otaurl, size_t otaurl_size)
return otaurl;
}
char* GetTopic_P(char *stopic, uint8_t prefix, char *topic, const char* subtopic)
char* GetTopic_P(char *stopic, uint32_t prefix, char *topic, const char* subtopic)
{
/* prefix 0 = Cmnd
prefix 1 = Stat
@ -258,25 +261,29 @@ char* GetTopic_P(char *stopic, uint8_t prefix, char *topic, const char* subtopic
}
fulltopic.replace(F("#"), "");
fulltopic.replace(F("//"), "/");
if (!fulltopic.endsWith("/")) fulltopic += "/";
if (!fulltopic.endsWith("/")) {
fulltopic += "/";
}
snprintf_P(stopic, TOPSZ, PSTR("%s%s"), fulltopic.c_str(), romram);
return stopic;
}
char* GetFallbackTopic_P(char *stopic, uint8_t prefix, const char* subtopic)
char* GetFallbackTopic_P(char *stopic, uint32_t prefix, const char* subtopic)
{
return GetTopic_P(stopic, prefix +4, nullptr, subtopic);
}
char* GetStateText(uint8_t state)
char* GetStateText(uint32_t state)
{
if (state > 3) { state = 1; }
if (state > 3) {
state = 1;
}
return Settings.state_text[state];
}
/********************************************************************************************/
void SetLatchingRelay(power_t lpower, uint8_t state)
void SetLatchingRelay(power_t lpower, uint32_t state)
{
// power xx00 - toggle REL1 (Off) and REL3 (Off) - device 1 Off, device 2 Off
// power xx01 - toggle REL2 (On) and REL3 (Off) - device 1 On, device 2 Off
@ -289,17 +296,15 @@ void SetLatchingRelay(power_t lpower, uint8_t state)
}
for (uint32_t i = 0; i < devices_present; i++) {
uint8_t port = (i << 1) + ((latching_power >> i) &1);
uint32_t port = (i << 1) + ((latching_power >> i) &1);
if (pin[GPIO_REL1 +port] < 99) {
digitalWrite(pin[GPIO_REL1 +port], bitRead(rel_inverted, port) ? !state : state);
}
}
}
void SetDevicePower(power_t rpower, int source)
void SetDevicePower(power_t rpower, uint32_t source)
{
uint8_t state;
ShowSource(source);
if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { // All on and stay on
@ -310,9 +315,11 @@ void SetDevicePower(power_t rpower, int source)
if (Settings.flag.interlock) { // Allow only one or no relay set
for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) {
power_t mask = 1;
uint8_t count = 0;
uint32_t count = 0;
for (uint32_t j = 0; j < devices_present; j++) {
if ((Settings.interlock[i] & mask) && (rpower & mask)) { count++; }
if ((Settings.interlock[i] & mask) && (rpower & mask)) {
count++;
}
mask <<= 1;
}
if (count > 1) {
@ -323,6 +330,10 @@ void SetDevicePower(power_t rpower, int source)
}
}
if (rpower) { // Any power set
last_power = rpower;
}
XdrvMailbox.index = rpower;
XdrvCall(FUNC_SET_POWER); // Signal power state
@ -344,7 +355,7 @@ void SetDevicePower(power_t rpower, int source)
}
else {
for (uint32_t i = 0; i < devices_present; i++) {
state = rpower &1;
power_t state = rpower &1;
if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) {
digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? !state : state);
}
@ -353,13 +364,59 @@ void SetDevicePower(power_t rpower, int source)
}
}
void SetLedPowerIdx(uint8_t led, uint8_t state)
void RestorePower(bool publish_power, uint32_t source)
{
if ((99 == pin[GPIO_LEDLNK]) && (0 == led)) { // Legacy - LED1 is link led only if LED2 is present
if (pin[GPIO_LED2] < 99) { led = 1; }
if (power != last_power) {
SetDevicePower(last_power, source);
if (publish_power) {
MqttPublishAllPowerState();
}
}
}
void SetAllPower(uint32_t state, uint32_t source)
{
// state 0 = POWER_OFF = Relay Off
// state 1 = POWER_ON = Relay On (turn off after Settings.pulse_timer * 100 mSec if enabled)
// state 2 = POWER_TOGGLE = Toggle relay
// state 8 = POWER_OFF_NO_STATE = Relay Off and no publishPowerState
// state 9 = POWER_ON_NO_STATE = Relay On and no publishPowerState
// state 10 = POWER_TOGGLE_NO_STATE = Toggle relay and no publishPowerState
// state 16 = POWER_SHOW_STATE = Show power state
bool publish_power = true;
if ((state >= POWER_OFF_NO_STATE) && (state <= POWER_TOGGLE_NO_STATE)) {
state &= 3; // POWER_OFF, POWER_ON or POWER_TOGGLE
publish_power = false;
}
if ((state >= POWER_OFF) && (state <= POWER_TOGGLE)) {
power_t all_on = (1 << devices_present) -1;
switch (state) {
case POWER_OFF:
power = 0;
break;
case POWER_ON:
power = all_on;
break;
case POWER_TOGGLE:
power ^= all_on; // Complement current state
}
SetDevicePower(power, source);
}
if (publish_power) {
MqttPublishAllPowerState();
}
}
void SetLedPowerIdx(uint32_t led, uint32_t state)
{
if ((99 == pin[GPIO_LEDLNK]) && (0 == led)) { // Legacy - LED1 is link led only if LED2 is present
if (pin[GPIO_LED2] < 99) {
led = 1;
}
}
if (pin[GPIO_LED1 + led] < 99) {
uint8_t mask = 1 << led;
uint32_t mask = 1 << led;
if (state) {
state = 1;
led_power |= mask;
@ -370,13 +427,13 @@ void SetLedPowerIdx(uint8_t led, uint8_t state)
}
}
void SetLedPower(uint8_t state)
void SetLedPower(uint32_t state)
{
if (99 == pin[GPIO_LEDLNK]) { // Legacy - Only use LED1 and/or LED2
if (99 == pin[GPIO_LEDLNK]) { // Legacy - Only use LED1 and/or LED2
SetLedPowerIdx(0, state);
} else {
power_t mask = 1;
for (uint32_t i = 0; i < leds_present; i++) { // Map leds to power
for (uint32_t i = 0; i < leds_present; i++) { // Map leds to power
bool tstate = (power & mask);
SetLedPowerIdx(i, tstate);
mask <<= 1;
@ -384,18 +441,18 @@ void SetLedPower(uint8_t state)
}
}
void SetLedPowerAll(uint8_t state)
void SetLedPowerAll(uint32_t state)
{
for (uint32_t i = 0; i < leds_present; i++) {
SetLedPowerIdx(i, state);
}
}
void SetLedLink(uint8_t state)
void SetLedLink(uint32_t state)
{
uint8_t led_pin = pin[GPIO_LEDLNK];
uint8_t led_inv = ledlnk_inverted;
if (99 == led_pin) { // Legacy - LED1 is status
uint32_t led_pin = pin[GPIO_LEDLNK];
uint32_t led_inv = ledlnk_inverted;
if (99 == led_pin) { // Legacy - LED1 is status
led_pin = pin[GPIO_LED1];
led_inv = bitRead(led_inverted, 0);
}
@ -405,34 +462,32 @@ void SetLedLink(uint8_t state)
}
}
void SetPulseTimer(uint8_t index, uint16_t time)
void SetPulseTimer(uint32_t index, uint32_t time)
{
pulse_timer[index] = (time > 111) ? millis() + (1000 * (time - 100)) : (time > 0) ? millis() + (100 * time) : 0L;
}
uint16_t GetPulseTimer(uint8_t index)
uint32_t GetPulseTimer(uint32_t index)
{
uint16_t result = 0;
long time = TimePassedSince(pulse_timer[index]);
if (time < 0) {
time *= -1;
result = (time > 11100) ? (time / 1000) + 100 : (time > 0) ? time / 100 : 0;
return (time > 11100) ? (time / 1000) + 100 : (time > 0) ? time / 100 : 0;
}
return result;
return 0;
}
/********************************************************************************************/
bool SendKey(uint8_t key, uint8_t device, uint8_t state)
bool SendKey(uint32_t key, uint32_t device, uint32_t state)
{
// key 0 = button_topic
// key 1 = switch_topic
// state 0 = off
// state 1 = on
// state 2 = toggle
// state 3 = hold
// state 9 = clear retain flag
// key 0 = KEY_BUTTON = button_topic
// key 1 = KEY_SWITCH = switch_topic
// state 0 = POWER_OFF = off
// state 1 = POWER_ON = on
// state 2 = POWER_TOGGLE = toggle
// state 3 = POWER_HOLD = hold
// state 9 = CLEAR_RETAIN = clear retain flag
char stopic[TOPSZ];
char scommand[CMDSZ];
@ -442,23 +497,25 @@ bool SendKey(uint8_t key, uint8_t device, uint8_t state)
char *tmp = (key) ? Settings.switch_topic : Settings.button_topic;
Format(key_topic, tmp, sizeof(key_topic));
if (Settings.flag.mqtt_enabled && MqttIsConnected() && (strlen(key_topic) != 0) && strcmp(key_topic, "0")) {
if (!key && (device > devices_present)) { device = 1; } // Only allow number of buttons up to number of devices
if (!key && (device > devices_present)) {
device = 1; // Only allow number of buttons up to number of devices
}
GetTopic_P(stopic, CMND, key_topic,
GetPowerDevice(scommand, device, sizeof(scommand), (key + Settings.flag.device_index_enable))); // cmnd/switchtopic/POWERx
if (9 == state) {
if (CLEAR_RETAIN == state) {
mqtt_data[0] = '\0';
} else {
if ((Settings.flag3.button_switch_force_local || !strcmp(mqtt_topic, key_topic) || !strcmp(Settings.mqtt_grptopic, key_topic)) && (2 == state)) {
state = ~(power >> (device -1)) &1;
if ((Settings.flag3.button_switch_force_local || !strcmp(mqtt_topic, key_topic) || !strcmp(Settings.mqtt_grptopic, key_topic)) && (POWER_TOGGLE == state)) {
state = ~(power >> (device -1)) &1; // POWER_OFF or POWER_ON
}
snprintf_P(mqtt_data, sizeof(mqtt_data), GetStateText(state));
}
#ifdef USE_DOMOTICZ
if (!(DomoticzSendKey(key, device, state, strlen(mqtt_data)))) {
MqttPublishDirect(stopic, ((key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain) && (state != 3 || !Settings.flag3.no_hold_retain));
MqttPublishDirect(stopic, ((key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain) && (state != POWER_HOLD || !Settings.flag3.no_hold_retain));
}
#else
MqttPublishDirect(stopic, ((key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain) && (state != 3 || !Settings.flag3.no_hold_retain));
MqttPublishDirect(stopic, ((key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain) && (state != POWER_HOLD || !Settings.flag3.no_hold_retain));
#endif // USE_DOMOTICZ
result = !Settings.flag3.button_switch_force_local;
} else {
@ -471,17 +528,18 @@ bool SendKey(uint8_t key, uint8_t device, uint8_t state)
return result;
}
void ExecuteCommandPower(uint8_t device, uint8_t state, int source)
void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
{
// device = Relay number 1 and up
// state 0 = Relay Off
// state 1 = Relay On (turn off after Settings.pulse_timer * 100 mSec if enabled)
// state 2 = Toggle relay
// state 3 = Blink relay
// state 4 = Stop blinking relay
// state 6 = Relay Off and no publishPowerState
// state 7 = Relay On and no publishPowerState
// state 9 = Show power state
// state 0 = POWER_OFF = Relay Off
// state 1 = POWER_ON = Relay On (turn off after Settings.pulse_timer * 100 mSec if enabled)
// state 2 = POWER_TOGGLE = Toggle relay
// state 3 = POWER_BLINK = Blink relay
// state 4 = POWER_BLINK_STOP = Stop blinking relay
// state 8 = POWER_OFF_NO_STATE = Relay Off and no publishPowerState
// state 9 = POWER_ON_NO_STATE = Relay On and no publishPowerState
// state 10 = POWER_TOGGLE_NO_STATE = Toggle relay and no publishPowerState
// state 16 = POWER_SHOW_STATE = Show power state
// ShowSource(source);
@ -495,16 +553,20 @@ void ExecuteCommandPower(uint8_t device, uint8_t state, int source)
}
#endif // USE_SONOFF_IFAN
uint8_t publish_power = 1;
if ((POWER_OFF_NO_STATE == state) || (POWER_ON_NO_STATE == state)) {
state &= 1;
publish_power = 0;
bool publish_power = true;
if ((state >= POWER_OFF_NO_STATE) && (state <= POWER_TOGGLE_NO_STATE)) {
state &= 3; // POWER_OFF, POWER_ON or POWER_TOGGLE
publish_power = false;
}
if ((device < 1) || (device > devices_present)) device = 1;
if ((device < 1) || (device > devices_present)) {
device = 1;
}
active_device = device;
if (device <= MAX_PULSETIMERS) { SetPulseTimer(device -1, 0); }
if (device <= MAX_PULSETIMERS) {
SetPulseTimer(device -1, 0);
}
power_t mask = 1 << (device -1); // Device to control
if (state <= POWER_TOGGLE) {
if ((blink_mask & mask)) {
@ -546,7 +608,9 @@ void ExecuteCommandPower(uint8_t device, uint8_t state, int source)
#ifdef USE_KNX
KnxUpdatePowerState(device, power);
#endif // USE_KNX
if (publish_power && Settings.flag3.hass_tele_on_power) { MqttPublishTeleState(); }
if (publish_power && Settings.flag3.hass_tele_on_power) {
MqttPublishTeleState();
}
if (device <= MAX_PULSETIMERS) { // Restart PulseTime if powered On
SetPulseTimer(device -1, (((POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate) ? ~power : power) & mask) ? Settings.pulse_timer[device -1] : 0);
}
@ -563,13 +627,17 @@ void ExecuteCommandPower(uint8_t device, uint8_t state, int source)
return;
}
else if (POWER_BLINK_STOP == state) {
uint8_t flag = (blink_mask & mask);
bool flag = (blink_mask & mask);
blink_mask &= (POWER_MASK ^ mask); // Clear device mask
MqttPublishPowerBlinkState(device);
if (flag) ExecuteCommandPower(device, (blink_powersave >> (device -1))&1, SRC_IGNORE); // Restore state
if (flag) {
ExecuteCommandPower(device, (blink_powersave >> (device -1))&1, SRC_IGNORE); // Restore state
}
return;
}
if (publish_power) MqttPublishPowerState(device);
if (publish_power) {
MqttPublishPowerState(device);
}
}
void StopAllPowerBlink(void)
@ -586,18 +654,6 @@ void StopAllPowerBlink(void)
}
}
void SetAllPower(uint8_t state, int source)
{
if ((POWER_ALL_OFF == state) || (POWER_ALL_ON == state)) {
power = 0;
if (POWER_ALL_ON == state) {
power = (1 << devices_present) -1;
}
SetDevicePower(power, source);
MqttPublishAllPowerState();
}
}
void MqttShowPWMState(void)
{
ResponseAppend_P(PSTR("\"" D_CMND_PWM "\":{"));
@ -824,7 +880,7 @@ void Every250mSeconds(void)
{
// As the max amount of sleep = 250 mSec this loop should always be taken...
uint8_t blinkinterval = 1;
uint32_t blinkinterval = 1;
state_250mS++;
state_250mS &= 0x3;
@ -1178,7 +1234,7 @@ void SerialInput(void)
if (Settings.flag.mqtt_serial && serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) {
serial_in_buffer[serial_in_byte_counter] = 0; // Serial data completed
char hex_char[(serial_in_byte_counter * 2) + 2];
Response_P(PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"),
ResponseTime_P(PSTR(",\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"),
(Settings.flag.mqtt_serial_raw) ? ToHex_P((unsigned char*)serial_in_buffer, serial_in_byte_counter, hex_char, sizeof(hex_char)) : serial_in_buffer);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
XdrvRulesProcess();
@ -1190,10 +1246,10 @@ void SerialInput(void)
void GpioInit(void)
{
uint8_t mpin;
uint32_t mpin;
if (!ValidModule(Settings.module)) {
uint8_t module = MODULE;
uint32_t module = MODULE;
if (!ValidModule(MODULE)) { module = SONOFF_BASIC; }
Settings.module = module;
Settings.last_module = module;
@ -1230,7 +1286,7 @@ void GpioInit(void)
my_adc0 = Settings.my_adc0; // Set User selected Module sensors
}
my_module_flag = ModuleFlag();
uint8_t template_adc0 = my_module_flag.data &15;
uint32_t template_adc0 = my_module_flag.data &15;
if ((template_adc0 > ADC0_NONE) && (template_adc0 < ADC0_USER)) {
my_adc0 = template_adc0; // Force Template override
}
@ -1604,8 +1660,6 @@ void setup(void)
XsnsCall(FUNC_INIT);
}
uint32_t _counter = 0;
void loop(void)
{
uint32_t my_sleep = millis();

View File

@ -85,7 +85,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
// -- Optional modules -------------------------
#define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code)
#define USE_TUYA_DIMMER // Add support for Tuya Serial Dimmer
#define USE_TUYA_MCU // Add support for Tuya Serial MCU
#ifndef TUYA_DIMMER_ID
#define TUYA_DIMMER_ID 0 // Default dimmer Id
#endif
@ -217,7 +217,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
//#ifndef USE_SONOFF_IFAN
#define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code)
//#endif
#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer
#undef USE_TUYA_MCU // Disable support for Tuya Serial MCU
#undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code)
#undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer and Sonoff L1 (+2k code)
#undef ROTARY_V1 // Disable support for MI Desk Lamp
@ -345,7 +345,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
// -- Optional modules -------------------------
#undef USE_BUZZER // Disable support for a buzzer (+0k6 code)
#undef USE_SONOFF_IFAN // Disable support for Sonoff iFan02 and iFan03 (+2k code)
#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer
#undef USE_TUYA_MCU // Disable support for Tuya Serial MCU
#undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code)
#undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer and Sonoff L1 (+2k code)
#undef USE_DS18x20 // Disable Optional for more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code)
@ -436,7 +436,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
// -- Optional modules -------------------------
#define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code)
//#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer
//#undef USE_TUYA_MCU // Disable support for Tuya Serial MCU
#undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code)
#undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer and Sonoff L1 (+2k code)
#undef ROTARY_V1 // Disable support for MI Desk Lamp
@ -517,7 +517,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
// -- Optional modules -------------------------
#undef USE_SONOFF_IFAN // Disable support for Sonoff iFan02 and iFan03 (+2k code)
#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer
#undef USE_TUYA_MCU // Disable support for Tuya Serial MCU
#undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code)
#undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer and Sonoff L1 (+2k code)
#undef ROTARY_V1 // Disable support for MI Desk Lamp

View File

@ -541,7 +541,7 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_SM16716_DAT, // SM16716 DATA
GPIO_SM16716_SEL, // SM16716 SELECT
#endif // USE_SM16716
#ifdef USE_TUYA_DIMMER
#ifdef USE_TUYA_MCU
GPIO_TUYA_TX, // Tuya Serial interface
GPIO_TUYA_RX, // Tuya Serial interface
#endif
@ -749,7 +749,7 @@ const uint8_t kModuleNiceList[] PROGMEM = {
OBI2,
MANZOKU_EU_4,
ESP_SWITCH, // Switch Devices
#ifdef USE_TUYA_DIMMER
#ifdef USE_TUYA_MCU
TUYA_DIMMER, // Dimmer Devices
#endif
#ifdef USE_ARMTRONIX_DIMMERS
@ -1728,7 +1728,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0 = Off, 1 = On )
0, 0, 0
},
{ "Tuya Dimmer", // Tuya Dimmer (ESP8266 w/ separate MCU dimmer)
{ "Tuya MCU", // Tuya MCU device (ESP8266 w/ separate MCU)
// https://www.amazon.com/gp/product/B07CTNSZZ8/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1
GPIO_USER, // Virtual Button (controlled by MCU)
GPIO_USER, // GPIO01 MCU serial control

View File

@ -20,6 +20,6 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_
const uint32_t VERSION = 0x06060009;
const uint32_t VERSION = 0x0606000B;
#endif // _SONOFF_VERSION_H_

View File

@ -870,7 +870,24 @@ uint32_t WebColor(uint32_t i)
* Response data handling
\*********************************************************************************************/
int Response_P(const char* format, ...) // Content send snprintf_P char data
const uint16_t TIMESZ = 100; // Max number of characters in time string
char* ResponseGetTime(uint32_t format, char* time_str)
{
switch (format) {
case 1:
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\",\"Epoch\":%u"), GetDateAndTime(DT_LOCAL).c_str(), UtcTime());
break;
case 2:
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":%u"), UtcTime());
break;
default:
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
}
return time_str;
}
int Response_P(const char* format, ...) // Content send snprintf_P char data
{
// This uses char strings. Be aware of sending %% if % is needed
va_list args;
@ -880,6 +897,20 @@ int Response_P(const char* format, ...) // Content send snprintf_P char data
return len;
}
int ResponseTime_P(const char* format, ...) // Content send snprintf_P char data
{
// This uses char strings. Be aware of sending %% if % is needed
va_list args;
va_start(args, format);
ResponseGetTime(Settings.flag2.time_format, mqtt_data);
int mlen = strlen(mqtt_data);
int len = vsnprintf_P(mqtt_data + mlen, sizeof(mqtt_data) - mlen, format, args);
va_end(args);
return len + mlen;
}
int ResponseAppend_P(const char* format, ...) // Content send snprintf_P char data
{
// This uses char strings. Be aware of sending %% if % is needed
@ -891,15 +922,15 @@ int ResponseAppend_P(const char* format, ...) // Content send snprintf_P char d
return len + mlen;
}
int ResponseAppendTime(void)
int ResponseAppendTimeFormat(uint32_t format)
{
return ResponseAppend_P(PSTR("{\"" D_JSON_TIME "\":\"%s\",\"Epoch\":%u"), GetDateAndTime(DT_LOCAL).c_str(), UtcTime());
char time_str[TIMESZ];
return ResponseAppend_P(ResponseGetTime(format, time_str));
}
int ResponseBeginTime(void)
int ResponseAppendTime(void)
{
mqtt_data[0] = '\0';
return ResponseAppendTime();
return ResponseAppendTimeFormat(Settings.flag2.time_format);
}
int ResponseJsonEnd(void)

View File

@ -165,7 +165,7 @@ void ButtonHandler(void)
if (!Button.hold_timer[button_index]) { button_pressed = true; } // Do not allow within 1 second
}
if (button_pressed) {
if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
}
}
@ -174,7 +174,7 @@ void ButtonHandler(void)
if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) {
if (Settings.flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1);
if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
}
} else {
@ -199,14 +199,14 @@ void ButtonHandler(void)
if (Settings.flag.button_restrict) { // SetOption1 (0) - Button restriction
if (Settings.param[P_HOLD_IGNORE] > 0) { // SetOption40 (0) - Do not ignore button hold
if (Button.hold_timer[button_index] > loops_per_second * Settings.param[P_HOLD_IGNORE] / 10) {
Button.hold_timer[button_index] = 0; // Reset button hold counter to stay below hold trigger
Button.press_counter[button_index] = 0; // Discard button press to disable functionality
Button.hold_timer[button_index] = 0; // Reset button hold counter to stay below hold trigger
Button.press_counter[button_index] = 0; // Discard button press to disable functionality
DEBUG_CORE_LOG(PSTR("BTN: " D_BUTTON "%d cancel by " D_CMND_SETOPTION "40 %d"), button_index +1, Settings.param[P_HOLD_IGNORE]);
}
}
if (Button.hold_timer[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button hold
Button.press_counter[button_index] = 0;
SendKey(0, button_index +1, 3); // Execute Hold command via MQTT if ButtonTopic is set
SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); // Execute Hold command via MQTT if ButtonTopic is set
}
} else {
if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button held for factor times longer
@ -241,7 +241,7 @@ void ButtonHandler(void)
#if defined(USE_LIGHT) && defined(ROTARY_V1)
if (!((0 == button_index) && RotaryButtonPressed())) {
#endif
if (single_press && SendKey(0, button_index + Button.press_counter[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
if (single_press && SendKey(KEY_BUTTON, button_index + Button.press_counter[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
// Success
} else {
if (Button.press_counter[button_index] < 3) { // Single or Double press

View File

@ -257,11 +257,20 @@ void CmndDelay(void)
void CmndPower(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= devices_present)) {
if ((XdrvMailbox.payload < 0) || (XdrvMailbox.payload > 4)) { XdrvMailbox.payload = 9; }
// Settings.flag.device_index_enable = user_index;
if ((XdrvMailbox.payload < POWER_OFF) || (XdrvMailbox.payload > POWER_BLINK_STOP)) {
XdrvMailbox.payload = POWER_SHOW_STATE;
}
// Settings.flag.device_index_enable = XdrvMailbox.usridx;
ExecuteCommandPower(XdrvMailbox.index, XdrvMailbox.payload, SRC_IGNORE);
mqtt_data[0] = '\0';
}
else if (0 == XdrvMailbox.index) {
if ((XdrvMailbox.payload < POWER_OFF) || (XdrvMailbox.payload > POWER_TOGGLE)) {
XdrvMailbox.payload = POWER_SHOW_STATE;
}
SetAllPower(XdrvMailbox.payload, SRC_IGNORE);
mqtt_data[0] = '\0';
}
}
void CmndStatus(void)
@ -607,26 +616,23 @@ void CmndSetoption(void)
#endif // USE_HOME_ASSISTANT
}
}
else if (1 == ptype) { // SetOption50 .. 81
else if (1 == ptype) { // SetOption50 .. 81
if (XdrvMailbox.payload <= 1) {
bitWrite(Settings.flag3.data, pindex, XdrvMailbox.payload);
if (5 == pindex) { // SetOption55
if (5 == pindex) { // SetOption55
if (0 == XdrvMailbox.payload) {
restart_flag = 2; // Disable mDNS needs restart
}
}
if (10 == pindex) { // SetOption60 enable or disable traditional sleep
if (10 == pindex) { // SetOption60 enable or disable traditional sleep
WiFiSetSleepMode(); // Update WiFi sleep mode accordingly
}
if (18 == pindex) { // SetOption68 for multi-channel PWM, requires a reboot
restart_flag = 2;
}
if (15 == pindex) { // SetOption65 for tuya_disable_dimmer requires a reboot
if (18 == pindex) { // SetOption68 for multi-channel PWM, requires a reboot
restart_flag = 2;
}
}
}
else { // SetOption32 .. 49
else { // SetOption32 .. 49
uint32_t param_low = 0;
uint32_t param_high = 255;
switch (pindex) {
@ -635,9 +641,6 @@ void CmndSetoption(void)
param_low = 1;
param_high = 250;
break;
case P_TUYA_RELAYS:
param_high = 8;
break;
}
if ((XdrvMailbox.payload >= param_low) && (XdrvMailbox.payload <= param_high)) {
Settings.param[pindex] = XdrvMailbox.payload;
@ -652,11 +655,7 @@ void CmndSetoption(void)
IrReceiveUpdateThreshold();
break;
#endif
#ifdef USE_TUYA_DIMMER
case P_TUYA_RELAYS:
case P_TUYA_POWER_ID:
case P_TUYA_CURRENT_ID:
case P_TUYA_VOLTAGE_ID:
#ifdef USE_TUYA_MCU
case P_TUYA_DIMMER_MAX:
restart_flag = 2; // Need a restart to update GUI
break;
@ -1260,6 +1259,10 @@ void CmndReset(void)
restart_flag = 210 + XdrvMailbox.payload;
Response_P(PSTR("{\"" D_CMND_RESET "\":\"" D_JSON_ERASE ", " D_JSON_RESET_AND_RESTARTING "\"}"));
break;
case 99:
Settings.bootcount = 0;
ResponseCmndDone();
break;
default:
ResponseCmndChar(D_JSON_ONE_TO_RESET);
}
@ -1267,10 +1270,25 @@ void CmndReset(void)
void CmndTime(void)
{
// payload 0 = (re-)enable NTP
// payload 1 = Time format {"Time":"2019-09-04T14:31:29"}
// payload 2 = Time format {"Time":"2019-09-04T14:31:29","Epoch":1567600289}
// payload 3 = Time format {"Time":1567600289}
// payload 4 = reserved
// payload 1451602800 - disable NTP and set time to epoch
uint32_t format = Settings.flag2.time_format;
if (XdrvMailbox.data_len > 0) {
RtcSetTime(XdrvMailbox.payload);
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4)) {
Settings.flag2.time_format = XdrvMailbox.payload -1;
format = Settings.flag2.time_format;
} else {
format = 1; // {"Time":"2019-09-04T14:31:29","Epoch":1567600289}
RtcSetTime(XdrvMailbox.payload);
}
}
ResponseBeginTime();
mqtt_data[0] = '\0';
ResponseAppendTimeFormat(format);
ResponseJsonEnd();
}

View File

@ -171,7 +171,7 @@ void GetFeatures(void)
#ifdef USE_PCA9685
feature_drv2 |= 0x00004000; // xdrv_15_pca9685.ino
#endif
#if defined(USE_LIGHT) && defined(USE_TUYA_DIMMER)
#if defined(USE_LIGHT) && defined(USE_TUYA_MCU)
feature_drv2 |= 0x00008000; // xdrv_16_tuyadimmer.ino
#endif
#ifdef USE_RC_SWITCH

View File

@ -143,7 +143,7 @@ void SwitchHandler(uint8_t mode)
if (Switch.hold_timer[i]) {
Switch.hold_timer[i]--;
if (0 == Switch.hold_timer[i]) {
SendKey(1, i +1, 3); // Execute command via MQTT
SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT
}
}
@ -152,10 +152,10 @@ void SwitchHandler(uint8_t mode)
// enum SwitchModeOptions {TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, MAX_SWITCH_OPTION};
if (button != Switch.last_state[i]) {
switchflag = 3;
switchflag = POWER_TOGGLE +1;
switch (Settings.switchmode[i]) {
case TOGGLE:
switchflag = 2; // Toggle
switchflag = POWER_TOGGLE; // Toggle
break;
case FOLLOW:
switchflag = button &1; // Follow wall switch state
@ -165,17 +165,17 @@ void SwitchHandler(uint8_t mode)
break;
case PUSHBUTTON:
if ((PRESSED == button) && (NOT_PRESSED == Switch.last_state[i])) {
switchflag = 2; // Toggle with pushbutton to Gnd
switchflag = POWER_TOGGLE; // Toggle with pushbutton to Gnd
}
break;
case PUSHBUTTON_INV:
if ((NOT_PRESSED == button) && (PRESSED == Switch.last_state[i])) {
switchflag = 2; // Toggle with releasing pushbutton from Gnd
switchflag = POWER_TOGGLE; // Toggle with releasing pushbutton from Gnd
}
break;
case PUSHBUTTON_TOGGLE:
if (button != Switch.last_state[i]) {
switchflag = 2; // Toggle with any pushbutton change
switchflag = POWER_TOGGLE; // Toggle with any pushbutton change
}
break;
case PUSHBUTTONHOLD:
@ -184,7 +184,7 @@ void SwitchHandler(uint8_t mode)
}
if ((NOT_PRESSED == button) && (PRESSED == Switch.last_state[i]) && (Switch.hold_timer[i])) {
Switch.hold_timer[i] = 0;
switchflag = 2; // Toggle with pushbutton to Gnd
switchflag = POWER_TOGGLE; // Toggle with pushbutton to Gnd
}
break;
case PUSHBUTTONHOLD_INV:
@ -193,13 +193,13 @@ void SwitchHandler(uint8_t mode)
}
if ((PRESSED == button) && (NOT_PRESSED == Switch.last_state[i]) && (Switch.hold_timer[i])) {
Switch.hold_timer[i] = 0;
switchflag = 2; // Toggle with pushbutton to Gnd
switchflag = POWER_TOGGLE; // Toggle with pushbutton to Gnd
}
break;
}
if (switchflag < 3) {
if (!SendKey(1, i +1, switchflag)) { // Execute command via MQTT
if (switchflag <= POWER_TOGGLE) {
if (!SendKey(KEY_SWITCH, i +1, switchflag)) { // Execute command via MQTT
ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < devices_present)
}
}

View File

@ -500,7 +500,7 @@ static bool WifiIsInManagerMode(){
return (HTTP_MANAGER == Web.state || HTTP_MANAGER_RESET_ONLY == Web.state);
}
void ShowWebSource(int source)
void ShowWebSource(uint32_t source)
{
if ((source > 0) && (source < SRC_MAX)) {
char stemp1[20];
@ -508,7 +508,7 @@ void ShowWebSource(int source)
}
}
void ExecuteWebCommand(char* svalue, int source)
void ExecuteWebCommand(char* svalue, uint32_t source)
{
ShowWebSource(source);
ExecuteCommand(svalue, SRC_IGNORE);
@ -1053,6 +1053,7 @@ bool HandleRootStatusRefresh(void)
#ifdef USE_SCRIPT_WEB_DISPLAY
XdrvCall(FUNC_WEB_SENSOR);
#endif
WSContentSend_P(PSTR("</table>"));
if (devices_present) {
@ -1686,8 +1687,8 @@ void HandleBackupConfiguration(void)
WSSend(200, CT_STREAM, "");
uint16_t cfg_crc = Settings.cfg_crc;
Settings.cfg_crc = GetSettingsCrc(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918)
uint32_t cfg_crc32 = Settings.cfg_crc32;
Settings.cfg_crc32 = GetSettingsCrc32(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918)
memcpy(settings_buffer, &Settings, sizeof(Settings));
if (Web.config_xor_on_set) {
@ -1707,7 +1708,7 @@ void HandleBackupConfiguration(void)
SettingsBufferFree();
Settings.cfg_crc = cfg_crc; // Restore crc in case savedata = 0 to make sure settings will be noted as changed
Settings.cfg_crc32 = cfg_crc32; // Restore crc in case savedata = 0 to make sure settings will be noted as changed
}
/*-------------------------------------------------------------------------------------------*/
@ -2092,12 +2093,13 @@ void HandleUploadLoop(void)
unsigned long buffer_version = settings_buffer[11] << 24 | settings_buffer[10] << 16 | settings_buffer[9] << 8 | settings_buffer[8];
if (buffer_version > 0x06000000) {
uint32_t buffer_size = settings_buffer[3] << 8 | settings_buffer[2];
uint16_t buffer_crc = settings_buffer[15] << 8 | settings_buffer[14];
uint16_t crc = 0;
for (uint32_t i = 0; i < buffer_size; i++) {
if ((i < 14) || (i > 15)) { crc += settings_buffer[i]*(i+1); } // Skip crc
if (buffer_version > 0x0606000A) {
uint32_t buffer_crc32 = settings_buffer[4095] << 24 | settings_buffer[4094] << 16 | settings_buffer[4093] << 8 | settings_buffer[4092];
valid_settings = (GetCfgCrc32(settings_buffer, buffer_size -4) == buffer_crc32);
} else {
uint16_t buffer_crc16 = settings_buffer[15] << 8 | settings_buffer[14];
valid_settings = (GetCfgCrc16(settings_buffer, buffer_size) == buffer_crc16);
}
valid_settings = (buffer_crc == crc);
} else {
valid_settings = (settings_buffer[0] == CONFIG_FILE_SIGN);
}
@ -2350,6 +2352,151 @@ String UrlEncode(const String& text)
return encoded;
}
#ifdef USE_SENDMAIL
#include "sendemail.h"
//SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const bool ssl);
//SendEmail::send(const String& from, const String& to, const String& subject, const String& msg)
// sendmail [server:port:user:passwd:from:to:subject] data
// sendmail [*:*:*:*:*:to:subject] data uses defines from user_config
// sendmail currently only works with core 2.4.2
#define SEND_MAIL_MINRAM 19*1024
uint16_t SendMail(char *buffer) {
uint16_t count;
char *params,*oparams;
char *mserv;
uint16_t port;
char *user;
char *pstr;
char *passwd;
char *from;
char *to;
char *subject;
char *cmd;
char secure=0,auth=0;
uint16_t status=1;
SendEmail *mail=0;
//DebugFreeMem();
// return if not enough memory
uint16_t mem=ESP.getFreeHeap();
if (mem<SEND_MAIL_MINRAM) {
return 4;
}
while (*buffer==' ') buffer++;
// copy params
oparams=(char*)calloc(strlen(buffer)+2,1);
if (!oparams) return 4;
params=oparams;
strcpy(params,buffer);
if (*params=='p') {
auth=1;
params++;
}
if (*params!='[') {
goto exit;
}
params++;
mserv=strtok(params,":");
if (!mserv) {
goto exit;
}
// port
pstr=strtok(NULL,":");
if (!pstr) {
goto exit;
}
#ifdef EMAIL_PORT
if (*pstr=='*') {
port=EMAIL_PORT;
} else {
port=atoi(pstr);
}
#else
port=atoi(pstr);
#endif
user=strtok(NULL,":");
if (!user) {
goto exit;
}
passwd=strtok(NULL,":");
if (!passwd) {
goto exit;
}
from=strtok(NULL,":");
if (!from) {
goto exit;
}
to=strtok(NULL,":");
if (!to) {
goto exit;
}
subject=strtok(NULL,"]");
if (!subject) {
goto exit;
}
cmd=subject+strlen(subject)+1;
#ifdef EMAIL_USER
if (*user=='*') {
user=(char*)EMAIL_USER;
}
#endif
#ifdef EMAIL_PASSWORD
if (*passwd=='*') {
passwd=(char*)EMAIL_PASSWORD;
}
#endif
#ifdef EMAIL_SERVER
if (*mserv=='*') {
mserv=(char*)EMAIL_SERVER;
}
#endif //USE_SENDMAIL
// auth = 0 => AUTH LOGIN 1 => PLAIN LOGIN
// 2 seconds timeout
#define MAIL_TIMEOUT 2000
mail = new SendEmail(mserv, port,user,passwd, MAIL_TIMEOUT, auth);
#ifdef EMAIL_FROM
if (*from=='*') {
from=(char*)EMAIL_FROM;
}
#endif
exit:
if (mail) {
bool result=mail->send(from,to,subject,cmd);
delete mail;
if (result==true) status=0;
}
if (oparams) free(oparams);
return status;
}
#endif
int WebSend(char *buffer)
{
// [sonoff] POWER1 ON --> Sends http://sonoff/cm?cmnd=POWER1 ON
@ -2462,17 +2609,23 @@ bool JsonWebColor(const char* dataBuf)
return true;
}
const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND ;
const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND "|" D_JSON_MEMORY_ERROR;
const char kWebCommands[] PROGMEM = "|" // No prefix
#ifdef USE_EMULATION
D_CMND_EMULATION "|"
#endif
#ifdef USE_SENDMAIL
D_CMND_SENDMAIL "|"
#endif
D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_WEBCOLOR "|" D_CMND_WEBSENSOR;
void (* const WebCommand[])(void) PROGMEM = {
#ifdef USE_EMULATION
&CmndEmulation,
#endif
#ifdef USE_SENDMAIL
&CmndSendmail,
#endif
&CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor, &CmndWebSensor };
@ -2500,6 +2653,18 @@ void CmndEmulation(void)
}
#endif // USE_EMULATION
#ifdef USE_SENDMAIL
void CmndSendmail(void)
{
if (XdrvMailbox.data_len > 0) {
uint8_t result = SendMail(XdrvMailbox.data);
char stemp1[20];
ResponseCmndChar(GetTextIndexed(stemp1, sizeof(stemp1), result, kWebSendStatus));
}
}
#endif // USE_SENDMAIL
void CmndWebServer(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {

View File

@ -894,7 +894,7 @@ void CmndButtonRetain(void)
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
if (!XdrvMailbox.payload) {
for (uint32_t i = 1; i <= MAX_KEYS; i++) {
SendKey(0, i, 9); // Clear MQTT retain in broker
SendKey(KEY_BUTTON, i, CLEAR_RETAIN); // Clear MQTT retain in broker
}
}
Settings.flag.mqtt_button_retain = XdrvMailbox.payload;
@ -907,7 +907,7 @@ void CmndSwitchRetain(void)
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
if (!XdrvMailbox.payload) {
for (uint32_t i = 1; i <= MAX_SWITCHES; i++) {
SendKey(1, i, 9); // Clear MQTT retain in broker
SendKey(KEY_SWITCH, i, CLEAR_RETAIN); // Clear MQTT retain in broker
}
}
Settings.flag.mqtt_switch_retain = XdrvMailbox.payload;

View File

@ -83,9 +83,9 @@ struct ENERGY {
float total = 0; // 12345.12345 kWh tariff 1 + 2
float total1 = 0; // 12345.12345 kWh tariff 1 - off-peak
unsigned long kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only)
unsigned long kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only)
unsigned long kWhtoday_offset = 0; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily
unsigned long kWhtoday; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily
unsigned long kWhtoday1; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily
unsigned long period = 0; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily
uint8_t fifth_second = 0;
@ -129,23 +129,40 @@ void EnergyUpdateToday(void)
Energy.kWhtoday_delta -= (delta * 1000);
Energy.kWhtoday += delta;
}
uint32_t energy_diff = Energy.kWhtoday - RtcSettings.energy_kWhtoday;
RtcSettings.energy_kWhtoday = Energy.kWhtoday;
Energy.daily = (float)Energy.kWhtoday / 100000;
Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday) / 100000;
uint32_t energy_diff = Energy.kWhtoday_offset + Energy.kWhtoday - RtcSettings.energy_kWhtoday;
RtcSettings.energy_kWhtoday = Energy.kWhtoday_offset + Energy.kWhtoday;
Energy.daily = (float)(RtcSettings.energy_kWhtoday) / 100000;
Energy.total = (float)(RtcSettings.energy_kWhtotal + RtcSettings.energy_kWhtoday) / 100000;
if ((RtcTime.hour < Settings.param[P_ENERGY_TARIFF2]) || // Tarrif1 = Off-Peak
(RtcTime.hour >= Settings.param[P_ENERGY_TARIFF1]) ||
(Settings.flag3.energy_weekend && ((RtcTime.day_of_week == 1) ||
(RtcTime.day_of_week == 7)))
) {
Energy.kWhtoday1 += energy_diff;
RtcSettings.energy_usage.usage1_kWhtoday = Energy.kWhtoday1;
Energy.total1 = (float)(RtcSettings.energy_usage.usage1_kWhtotal + Energy.kWhtoday1) / 100000;
RtcSettings.energy_usage.usage1_kWhtoday += energy_diff;
Energy.total1 = (float)(RtcSettings.energy_usage.usage1_kWhtotal + RtcSettings.energy_usage.usage1_kWhtoday) / 100000;
}
}
void EnergyUpdateTotal(float value, bool kwh)
{
char energy_total_chr[FLOATSZ];
dtostrfd(value, 4, energy_total_chr);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NRG: Energy Total %s %sWh"), energy_total_chr, (kwh) ? "k" : "");
uint32_t multiplier = (kwh) ? 100000 : 100; // kWh or Wh to deca milli Wh
if (0 == Energy.start_energy || (value < Energy.start_energy)) {
Energy.start_energy = value; // Init after restart and handle roll-over if any
}
else if (value != Energy.start_energy) {
Energy.kWhtoday = (unsigned long)((value - Energy.start_energy) * multiplier);
}
EnergyUpdateToday();
}
/*********************************************************************************************/
void Energy200ms(void)
@ -160,16 +177,17 @@ void Energy200ms(void)
if (RtcTime.valid) {
if (LocalTime() == Midnight()) {
Settings.energy_kWhyesterday = Energy.kWhtoday;
Settings.energy_kWhyesterday = RtcSettings.energy_kWhtoday;
Settings.energy_kWhtotal += Energy.kWhtoday;
RtcSettings.energy_kWhtotal = Settings.energy_kWhtotal;
RtcSettings.energy_kWhtotal += RtcSettings.energy_kWhtoday;
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
Energy.kWhtoday = 0;
Energy.kWhtoday_offset = 0;
RtcSettings.energy_kWhtoday = 0;
Energy.start_energy = 0;
Settings.energy_usage.usage1_kWhtotal += Energy.kWhtoday1;
RtcSettings.energy_usage.usage1_kWhtotal = Settings.energy_usage.usage1_kWhtotal;
Energy.kWhtoday1 = 0;
RtcSettings.energy_usage.usage1_kWhtotal += RtcSettings.energy_usage.usage1_kWhtoday;
Settings.energy_usage.usage1_kWhtotal = RtcSettings.energy_usage.usage1_kWhtotal;
RtcSettings.energy_usage.usage1_kWhtoday = 0;
Energy.kWhtoday_delta = 0;
@ -195,12 +213,10 @@ void EnergySaveState(void)
{
Settings.energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0;
Settings.energy_kWhtoday = Energy.kWhtoday;
RtcSettings.energy_kWhtoday = Energy.kWhtoday;
Settings.energy_kWhtoday = RtcSettings.energy_kWhtoday;
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
Settings.energy_usage.usage1_kWhtoday = Energy.kWhtoday1;
RtcSettings.energy_usage.usage1_kWhtoday = Energy.kWhtoday1;
Settings.energy_usage.usage1_kWhtoday = RtcSettings.energy_usage.usage1_kWhtoday;
Settings.energy_usage.usage1_kWhtotal = RtcSettings.energy_usage.usage1_kWhtotal;
}
@ -297,10 +313,10 @@ void EnergyMarginCheck(void)
} else {
Energy.mplh_counter--;
if (!Energy.mplh_counter) {
Response_P(PSTR("{\"" D_JSON_MAXPOWERREACHED "\":\"%d%s\"}"), energy_power_u, (Settings.flag.value_units) ? " " D_UNIT_WATT : "");
ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHED "\":\"%d%s\"}"), energy_power_u, (Settings.flag.value_units) ? " " D_UNIT_WATT : "");
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow();
ExecuteCommandPower(1, POWER_OFF, SRC_MAXPOWER);
SetAllPower(POWER_ALL_OFF, SRC_MAXPOWER);
if (!Energy.mplr_counter) {
Energy.mplr_counter = Settings.param[P_MAX_POWER_RETRY] +1;
}
@ -320,11 +336,11 @@ void EnergyMarginCheck(void)
if (Energy.mplr_counter) {
Energy.mplr_counter--;
if (Energy.mplr_counter) {
Response_P(PSTR("{\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1));
ResponseTime_P(PSTR(",\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR));
ExecuteCommandPower(1, POWER_ON, SRC_MAXPOWER);
RestorePower(true, SRC_MAXPOWER);
} else {
Response_P(PSTR("{\"" D_JSON_MAXPOWERREACHEDRETRY "\":\"%s\"}"), GetStateText(0));
ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHEDRETRY "\":\"%s\"}"), GetStateText(0));
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow();
}
@ -338,17 +354,17 @@ void EnergyMarginCheck(void)
energy_daily_u = (uint16_t)(Energy.daily * 1000);
if (!Energy.max_energy_state && (RtcTime.hour == Settings.energy_max_energy_start)) {
Energy.max_energy_state = 1;
Response_P(PSTR("{\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1));
ResponseTime_P(PSTR(",\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR));
ExecuteCommandPower(1, POWER_ON, SRC_MAXENERGY);
RestorePower(true, SRC_MAXENERGY);
}
else if ((1 == Energy.max_energy_state ) && (energy_daily_u >= Settings.energy_max_energy)) {
Energy.max_energy_state = 2;
dtostrfd(Energy.daily, 3, mqtt_data);
Response_P(PSTR("{\"" D_JSON_MAXENERGYREACHED "\":\"%s%s\"}"), mqtt_data, (Settings.flag.value_units) ? " " D_UNIT_KILOWATTHOUR : "");
ResponseTime_P(PSTR(",\"" D_JSON_MAXENERGYREACHED "\":\"%s%s\"}"), mqtt_data, (Settings.flag.value_units) ? " " D_UNIT_KILOWATTHOUR : "");
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow();
ExecuteCommandPower(1, POWER_OFF, SRC_MAXENERGY);
SetAllPower(POWER_ALL_OFF, SRC_MAXENERGY);
}
}
#endif // USE_ENERGY_POWER_LIMIT
@ -359,9 +375,10 @@ void EnergyMarginCheck(void)
void EnergyMqttShow(void)
{
// {"Time":"2017-12-16T11:48:55","ENERGY":{"Total":0.212,"Yesterday":0.000,"Today":0.014,"Period":2.0,"Power":22.0,"Factor":1.00,"Voltage":213.6,"Current":0.100}}
ResponseBeginTime();
int tele_period_save = tele_period;
tele_period = 2;
mqtt_data[0] = '\0';
ResponseAppendTime();
EnergyShow(true);
tele_period = tele_period_save;
ResponseJsonEnd();
@ -422,13 +439,14 @@ void CmndEnergyReset(void)
if (p != XdrvMailbox.data) {
switch (XdrvMailbox.index) {
case 1:
Energy.kWhtoday = lnum *100;
Energy.kWhtoday_offset = lnum *100;
Energy.kWhtoday = 0;
Energy.kWhtoday_delta = 0;
Energy.period = Energy.kWhtoday;
Settings.energy_kWhtoday = Energy.kWhtoday;
RtcSettings.energy_kWhtoday = Energy.kWhtoday;
Energy.daily = (float)Energy.kWhtoday / 100000;
if (!RtcSettings.energy_kWhtotal && !Energy.kWhtoday) {
Energy.period = Energy.kWhtoday_offset;
Settings.energy_kWhtoday = Energy.kWhtoday_offset;
RtcSettings.energy_kWhtoday = Energy.kWhtoday_offset;
Energy.daily = (float)Energy.kWhtoday_offset / 100000;
if (!RtcSettings.energy_kWhtotal && !Energy.kWhtoday_offset) {
Settings.energy_kWhtotal_time = LocalTime();
}
break;
@ -438,14 +456,14 @@ void CmndEnergyReset(void)
case 3:
RtcSettings.energy_kWhtotal = lnum *100;
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday) / 100000;
Settings.energy_kWhtotal_time = (!Energy.kWhtoday) ? LocalTime() : Midnight();
Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday_offset + Energy.kWhtoday) / 100000;
Settings.energy_kWhtotal_time = (!Energy.kWhtoday_offset) ? LocalTime() : Midnight();
break;
}
}
if (Energy.kWhtoday1 > Energy.kWhtoday) {
Energy.kWhtoday1 = Energy.kWhtoday;
if (RtcSettings.energy_usage.usage1_kWhtoday > (Energy.kWhtoday_offset + Energy.kWhtoday)) {
RtcSettings.energy_usage.usage1_kWhtoday = Energy.kWhtoday_offset + Energy.kWhtoday;
}
if (Settings.energy_usage.usage1_kWhtoday > Settings.energy_kWhtoday) {
Settings.energy_usage.usage1_kWhtoday = Settings.energy_kWhtoday;
@ -686,10 +704,20 @@ void EnergySnsInit(void)
XnrgCall(FUNC_INIT);
if (energy_flg) {
Energy.kWhtoday = (RtcSettingsValid()) ? RtcSettings.energy_kWhtoday : (RtcTime.day_of_year == Settings.energy_kWhdoy) ? Settings.energy_kWhtoday : 0;
Energy.kWhtoday1 = (RtcSettingsValid()) ? RtcSettings.energy_usage.usage1_kWhtoday : (RtcTime.day_of_year == Settings.energy_kWhdoy) ? Settings.energy_usage.usage1_kWhtoday : 0;
if (RtcSettingsValid()) {
Energy.kWhtoday_offset = RtcSettings.energy_kWhtoday;
}
else if (RtcTime.day_of_year == Settings.energy_kWhdoy) {
Energy.kWhtoday_offset = Settings.energy_kWhtoday;
RtcSettings.energy_usage.usage1_kWhtoday = Settings.energy_usage.usage1_kWhtoday;
}
else {
Energy.kWhtoday_offset = 0;
RtcSettings.energy_usage.usage1_kWhtoday = 0;
}
Energy.kWhtoday = 0;
Energy.kWhtoday_delta = 0;
Energy.period = Energy.kWhtoday;
Energy.period = Energy.kWhtoday_offset;
EnergyUpdateToday();
ticker_energy.attach_ms(200, Energy200ms);
}
@ -770,8 +798,8 @@ void EnergyShow(bool json)
float energy = 0;
char energy_period_chr[FLOATSZ];
if (show_energy_period) {
if (Energy.period) energy = (float)(Energy.kWhtoday - Energy.period) / 100;
Energy.period = Energy.kWhtoday;
if (Energy.period) energy = (float)(RtcSettings.energy_kWhtoday - Energy.period) / 100;
Energy.period = RtcSettings.energy_kWhtoday;
dtostrfd(energy, Settings.flag2.wattage_resolution, energy_period_chr);
snprintf_P(speriod, sizeof(speriod), PSTR(",\"" D_JSON_PERIOD "\":%s"), energy_period_chr);
}
@ -806,7 +834,7 @@ void EnergyShow(bool json)
char energy_total1_chr[FLOATSZ];
dtostrfd(Energy.total1 * 1000, 1, energy_total1_chr); // Tariff1
char energy_non[2] = "0";
DomoticzSensorP1SmartMeter(energy_total1_chr, energy_total_chr, energy_non, energy_non, (int)Energy.active_power, 0);
DomoticzSensorP1SmartMeter(energy_total1_chr, energy_total_chr, energy_non, energy_non, (int)Energy.active_power);
if (Energy.voltage_available) {
DomoticzSensor(DZ_VOLTAGE, voltage_chr); // Voltage
@ -870,6 +898,9 @@ bool Xdrv03(uint8_t function)
case FUNC_LOOP:
XnrgCall(FUNC_LOOP);
break;
case FUNC_EVERY_250_MSECOND:
XnrgCall(FUNC_EVERY_250_MSECOND);
break;
#ifdef USE_ENERGY_MARGIN_DETECTION
case FUNC_SET_POWER:
Energy.power_steady_counter = 2;

View File

@ -154,7 +154,7 @@ void IrReceiveCheck(void)
} else {
snprintf_P(svalue, sizeof(svalue), PSTR("\"0x%s\""), hvalue);
}
Response_P(PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":%s"),
ResponseTime_P(PSTR(",\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":%s"),
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, svalue);
if (Settings.flag3.receive_raw) {

View File

@ -220,7 +220,7 @@ void IrReceiveCheck(void)
// if ((now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) && (UNKNOWN != results.decode_type) && (results.bits > 0)) {
if (!irsend_active && (now - ir_lasttime > IR_TIME_AVOID_DUPLICATE)) {
ir_lasttime = now;
Response_P(PSTR("{\"" D_JSON_IRRECEIVED "\":%s"), sendIRJsonState(results).c_str());
ResponseTime_P(PSTR(",\"" D_JSON_IRRECEIVED "\":%s"), sendIRJsonState(results).c_str());
if (Settings.flag3.receive_raw) {
ResponseAppend_P(PSTR(",\"" D_JSON_IR_RAWDATA "\":["));

View File

@ -214,7 +214,7 @@ void SonoffBridgeReceivedRaw(void)
if (0xB1 == serial_in_buffer[1]) { buckets = serial_in_buffer[2] << 1; } // Bucket sniffing
Response_P(PSTR("{\"" D_CMND_RFRAW "\":{\"" D_JSON_DATA "\":\""));
ResponseTime_P(PSTR(",\"" D_CMND_RFRAW "\":{\"" D_JSON_DATA "\":\""));
for (uint32_t i = 0; i < serial_in_byte_counter; i++) {
ResponseAppend_P(PSTR("%02X"), serial_in_buffer[i]);
if (0xB1 == serial_in_buffer[1]) {
@ -226,6 +226,7 @@ void SonoffBridgeReceivedRaw(void)
}
ResponseAppend_P(PSTR("\"}}"));
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_CMND_RFRAW));
XdrvRulesProcess();
}
@ -294,7 +295,7 @@ void SonoffBridgeReceived(void)
} else {
snprintf_P(stemp, sizeof(stemp), PSTR("\"%06X\""), received_id);
}
Response_P(PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":%s,\"" D_CMND_RFKEY "\":%s}}"),
ResponseTime_P(PSTR(",\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":%s,\"" D_CMND_RFKEY "\":%s}}"),
sync_time, low_time, high_time, stemp, rfkey);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED));
XdrvRulesProcess();

View File

@ -306,7 +306,7 @@ bool DomoticzSendKey(uint8_t key, uint8_t device, uint8_t state, uint8_t svalflg
if (device <= MAX_DOMOTICZ_IDX) {
if ((Settings.domoticz_key_idx[device -1] || Settings.domoticz_switch_idx[device -1]) && (svalflg)) {
Response_P(PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"),
(key) ? Settings.domoticz_switch_idx[device -1] : Settings.domoticz_key_idx[device -1], (state) ? (2 == state) ? "Toggle" : "On" : "Off");
(key) ? Settings.domoticz_switch_idx[device -1] : Settings.domoticz_key_idx[device -1], (state) ? (POWER_TOGGLE == state) ? "Toggle" : "On" : "Off");
MqttPublish(domoticz_in_topic);
result = true;
}
@ -383,14 +383,19 @@ void DomoticzSensorPowerEnergy(int power, char *energy)
DomoticzSensor(DZ_POWER_ENERGY, data);
}
void DomoticzSensorP1SmartMeter(char *usage1, char *usage2, char *return1, char *return2, int consumed, int produced)
void DomoticzSensorP1SmartMeter(char *usage1, char *usage2, char *return1, char *return2, int power)
{
//usage1 = energy usage meter tariff 1, This is an incrementing counter
//usage2 = energy usage meter tariff 2, This is an incrementing counter
//return1 = energy return meter tariff 1, This is an incrementing counter
//return2 = energy return meter tariff 2, This is an incrementing counter
//consumed = actual usage power (Watt)
//produced = actual return power (Watt)
//power = if >= 0 actual usage power. if < 0 actual return power (Watt)
int consumed = power;
int produced = 0;
if (power < 0) {
consumed = 0;
produced = -power;
}
char data[64];
snprintf_P(data, sizeof(data), PSTR("%s;%s;%s;%s;%d;%d"), usage1, usage2, return1, return2, consumed, produced);
DomoticzSensor(DZ_P1_SMART_METER, data);

View File

@ -71,7 +71,7 @@ void SerialBridgeInput(void)
if (serial_bridge_in_byte_counter && (millis() > (serial_bridge_polling_window + SERIAL_POLLING))) {
serial_bridge_buffer[serial_bridge_in_byte_counter] = 0; // Serial data completed
char hex_char[(serial_bridge_in_byte_counter * 2) + 2];
Response_P(PSTR("{\"" D_JSON_SSERIALRECEIVED "\":\"%s\"}"),
ResponseTime_P(PSTR(",\"" D_JSON_SSERIALRECEIVED "\":\"%s\"}"),
(serial_bridge_raw) ? ToHex_P((unsigned char*)serial_bridge_buffer, serial_bridge_in_byte_counter, hex_char, sizeof(hex_char)) : serial_bridge_buffer);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED));
XdrvRulesProcess();

View File

@ -296,7 +296,7 @@ void TimerEverySecond(void)
if (xtimer.days & days) {
Settings.timer[i].arm = xtimer.repeat;
#if defined(USE_RULES) || defined(USE_SCRIPT)
if (3 == xtimer.power) { // Blink becomes Rule disregarding device and allowing use of Backlog commands
if (POWER_BLINK == xtimer.power) { // Blink becomes Rule disregarding device and allowing use of Backlog commands
Response_P(PSTR("{\"Clock\":{\"Timer\":%d}}"), i +1);
XdrvRulesProcess();
} else

View File

@ -575,7 +575,7 @@ void KNX_CB_Action(message_t const &msg, void *arg)
else if (chan->type < 17) // Toggle Relays
{
if (!toggle_inhibit) {
ExecuteCommandPower((chan->type) -8, 2, SRC_KNX);
ExecuteCommandPower((chan->type) -8, POWER_TOGGLE, SRC_KNX);
if (Settings.flag.knx_enable_enhancement) {
toggle_inhibit = TOGGLE_INHIBIT_TIME;
}

View File

@ -1247,6 +1247,12 @@ void DisplayInitDriver(void)
{
XdspCall(FUNC_DISPLAY_INIT_DRIVER);
if (renderer) {
renderer->setTextFont(Settings.display_font);
renderer->setTextSize(Settings.display_size);
}
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings.display_model);
if (Settings.display_model) {
@ -1376,14 +1382,18 @@ void CmndDisplaySize(void)
{
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) {
Settings.display_size = XdrvMailbox.payload;
if (renderer) renderer->setTextSize(Settings.display_size);
else DisplaySetSize(Settings.display_size);
}
ResponseCmndNumber(Settings.display_size);
}
void CmndDisplayFont(void)
{
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) {
if ((XdrvMailbox.payload >=0) && (XdrvMailbox.payload <= 4)) {
Settings.display_font = XdrvMailbox.payload;
if (renderer) renderer->setTextFont(Settings.display_font);
else DisplaySetFont(Settings.display_font);
}
ResponseCmndNumber(Settings.display_font);
}
@ -1804,7 +1814,7 @@ void Restore_graph(uint8_t num, char *path) {
if (!fp) return;
char vbuff[32];
char *cp=vbuff;
char buf[2];
uint8_t buf[2];
uint8_t findex=0;
for (uint32_t count=0;count<=gp->xs+4;count++) {

View File

@ -166,8 +166,7 @@ bool PCA9685_Command(void)
void PCA9685_OutputTelemetry(bool telemetry) {
if (0 == pca9685_detected) { return; } // We do not do this if the PCA9685 has not been detected
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"PCA9685\":{\"PWM_FREQ\":%i,"),pca9685_freq);
ResponseTime_P(PSTR(",\"PCA9685\":{\"PWM_FREQ\":%i,"),pca9685_freq);
for (uint32_t pin=0;pin<16;pin++) {
ResponseAppend_P(PSTR("\"PWM%i\":%i,"),pin,pca9685_pin_pwm_value[pin]);
}

View File

@ -1,5 +1,5 @@
/*
xdrv_16_tuyadimmer.ino - Tuya dimmer support for Sonoff-Tasmota
xdrv_16_tuyamcu.ino - Tuya MCU support for Sonoff-Tasmota
Copyright (C) 2019 digiblur, Joel Stein and Theo Arends
@ -18,7 +18,7 @@
*/
#ifdef USE_LIGHT
#ifdef USE_TUYA_DIMMER
#ifdef USE_TUYA_MCU
#define XDRV_16 16
#define XNRG_08 8
@ -61,10 +61,156 @@ struct TUYA {
int byte_counter = 0; // Index in serial receive buffer
} Tuya;
enum TuyaSupportedFunctions {
TUYA_MCU_FUNC_NONE,
TUYA_MCU_FUNC_SWT1 = 1, // Buttons
TUYA_MCU_FUNC_SWT2,
TUYA_MCU_FUNC_SWT3,
TUYA_MCU_FUNC_SWT4,
TUYA_MCU_FUNC_REL1 = 11, // Relays
TUYA_MCU_FUNC_REL2,
TUYA_MCU_FUNC_REL3,
TUYA_MCU_FUNC_REL4,
TUYA_MCU_FUNC_REL5,
TUYA_MCU_FUNC_REL6,
TUYA_MCU_FUNC_REL7,
TUYA_MCU_FUNC_REL8,
TUYA_MCU_FUNC_DIMMER = 21,
TUYA_MCU_FUNC_POWER = 31,
TUYA_MCU_FUNC_CURRENT,
TUYA_MCU_FUNC_VOLTAGE,
TUYA_MCU_FUNC_REL1_INV = 41, // Inverted Relays
TUYA_MCU_FUNC_REL2_INV,
TUYA_MCU_FUNC_REL3_INV,
TUYA_MCU_FUNC_REL4_INV,
TUYA_MCU_FUNC_REL5_INV,
TUYA_MCU_FUNC_REL6_INV,
TUYA_MCU_FUNC_REL7_INV,
TUYA_MCU_FUNC_REL8_INV,
TUYA_MCU_FUNC_LAST = 255
};
const char kTuyaCommand[] PROGMEM = "|" // No prefix
D_CMND_TUYA_MCU;
void (* const TuyaCommand[])(void) PROGMEM = {
&CmndTuyaMcu
};
/*
TuyaMcu fnid,dpid
*/
void CmndTuyaMcu(void) {
if (XdrvMailbox.data_len > 0) {
char *p;
uint8_t i = 0;
uint8_t parm[3] = { 0 };
for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 2; str = strtok_r(nullptr, ", ", &p)) {
parm[i] = strtoul(str, nullptr, 0);
i++;
}
if (TuyaFuncIdValid(parm[0])) {
TuyaAddMcuFunc(parm[0], parm[1]);
restart_flag = 2;
} else {
AddLog_P2(LOG_LEVEL_ERROR, PSTR("TYA: TuyaMcu Invalid function id=%d"), parm[0]);
}
}
Response_P(PSTR("["));
bool added = false;
for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
if (Settings.tuya_fnid_map[i].fnid != 0) {
if (added) {
ResponseAppend_P(PSTR(","));
}
ResponseAppend_P(PSTR("{\"fnId\":%d, \"dpId\":%d}" ), Settings.tuya_fnid_map[i].fnid, Settings.tuya_fnid_map[i].dpid);
added = true;
}
}
ResponseAppend_P(PSTR("]"));
}
/*********************************************************************************************\
* Internal Functions
\*********************************************************************************************/
void TuyaAddMcuFunc(uint8_t fnId, uint8_t dpId) {
bool added = false;
if (fnId == 0 || dpId == 0) { // Delete entry
for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
if ((dpId > 0 && Settings.tuya_fnid_map[i].dpid == dpId) || (fnId > TUYA_MCU_FUNC_NONE && Settings.tuya_fnid_map[i].fnid == fnId)) {
Settings.tuya_fnid_map[i].fnid = TUYA_MCU_FUNC_NONE;
Settings.tuya_fnid_map[i].dpid = 0;
break;
}
}
} else { // Add or update
for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
if (Settings.tuya_fnid_map[i].dpid == dpId || Settings.tuya_fnid_map[i].dpid == 0 || Settings.tuya_fnid_map[i].fnid == fnId || Settings.tuya_fnid_map[i].fnid == 0) {
if (!added) { // Update entry if exisiting entry or add
Settings.tuya_fnid_map[i].fnid = fnId;
Settings.tuya_fnid_map[i].dpid = dpId;
added = true;
} else if (Settings.tuya_fnid_map[i].dpid == dpId || Settings.tuya_fnid_map[i].fnid == fnId) { // Remove existing entry if added to empty place
Settings.tuya_fnid_map[i].fnid = TUYA_MCU_FUNC_NONE;
Settings.tuya_fnid_map[i].dpid = 0;
}
}
}
}
UpdateDevices();
}
void UpdateDevices() {
for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
uint8_t fnId = Settings.tuya_fnid_map[i].fnid;
if (fnId > TUYA_MCU_FUNC_NONE && Settings.tuya_fnid_map[i].dpid > 0) {
if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) { //Relay
bitClear(rel_inverted, fnId - TUYA_MCU_FUNC_REL1);
} else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { // Inverted Relay
bitSet(rel_inverted, fnId - TUYA_MCU_FUNC_REL1_INV);
}
}
}
}
inline bool TuyaFuncIdValid(uint8_t fnId) {
return (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) ||
(fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) ||
fnId == TUYA_MCU_FUNC_DIMMER ||
(fnId >= TUYA_MCU_FUNC_POWER && fnId <= TUYA_MCU_FUNC_VOLTAGE) ||
(fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV);
}
uint8_t TuyaGetFuncId(uint8_t dpid) {
for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
if (Settings.tuya_fnid_map[i].dpid == dpid) {
return Settings.tuya_fnid_map[i].fnid;
}
}
return TUYA_MCU_FUNC_NONE;
}
uint8_t TuyaGetDpId(uint8_t fnId) {
for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
if (Settings.tuya_fnid_map[i].fnid == fnId) {
return Settings.tuya_fnid_map[i].dpid;
}
}
return 0;
}
void TuyaSendCmd(uint8_t cmd, uint8_t payload[] = nullptr, uint16_t payload_len = 0)
{
uint8_t checksum = (0xFF + cmd + (payload_len >> 8) + (payload_len & 0xFF));
@ -131,7 +277,7 @@ bool TuyaSetPower(void)
int16_t source = XdrvMailbox.payload;
if (source != SRC_SWITCH && TuyaSerial) { // ignore to prevent loop from pushing state from faceplate interaction
TuyaSendBool(active_device, bitRead(rpower, active_device-1));
TuyaSendBool(active_device, bitRead(rpower, active_device-1) ^ bitRead(rel_inverted, active_device-1));
status = true;
}
return status;
@ -146,24 +292,22 @@ bool TuyaSetChannels(void)
void LightSerialDuty(uint8_t duty)
{
if (duty > 0 && !Tuya.ignore_dim && TuyaSerial) {
uint8_t dpid = TuyaGetDpId(TUYA_MCU_FUNC_DIMMER);
if (duty > 0 && !Tuya.ignore_dim && TuyaSerial && dpid > 0) {
if (Settings.flag3.tuya_dimmer_min_limit) { // Enable dimming limit SetOption69: Enabled by default
if (duty < 25) { duty = 25; } // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself
}
if (Settings.flag3.tuya_disable_dimmer == 0) {
duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_TUYA_DIMMER_MAX]);
if (Tuya.new_dim != duty) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim value=%d (id=%d)"), duty, Settings.param[P_TUYA_DIMMER_ID]);
TuyaSendValue(Settings.param[P_TUYA_DIMMER_ID], duty);
}
duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_TUYA_DIMMER_MAX]);
if (Tuya.new_dim != duty) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim value=%d (id=%d)"), duty, dpid);
TuyaSendValue(dpid, duty);
}
} else {
} else if (dpid > 0) {
Tuya.ignore_dim = false; // reset flag
if (Settings.flag3.tuya_disable_dimmer == 0) {
duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_TUYA_DIMMER_MAX]);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim skipped value=%d"), duty); // due to 0 or already set
}
duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_TUYA_DIMMER_MAX]);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim skipped value=%d"), duty); // due to 0 or already set
} else {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Cannot set dimmer. Dimmer Id unknown")); //
}
}
@ -189,6 +333,7 @@ void TuyaResetWifi(void)
void TuyaPacketProcess(void)
{
char scmnd[20];
uint8_t fnId = TUYA_MCU_FUNC_NONE;
switch (Tuya.buffer[3]) {
@ -201,24 +346,33 @@ void TuyaPacketProcess(void)
break;
case TUYA_CMD_STATE:
if (Tuya.buffer[5] == 5) { // on/off packet
fnId = TuyaGetFuncId(Tuya.buffer[6]);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: FnId=%d is set for dpId=%d"), fnId, Tuya.buffer[6]);
// if (TuyaFuncIdValid(fnId)) {
if (Tuya.buffer[5] == 5) { // on/off packet
/*if ((power || Settings.light_dimmer > 0) && (power != Tuya.buffer[10])) {
ExecuteCommandPower(1, Tuya.buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
}*/
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Device-%d --> MCU State: %s Current State:%s"),Tuya.buffer[6],Tuya.buffer[10]?"On":"Off",bitRead(power, Tuya.buffer[6]-1)?"On":"Off");
if ((power || Settings.light_dimmer > 0) && (Tuya.buffer[10] != bitRead(power, Tuya.buffer[6]-1))) {
ExecuteCommandPower(Tuya.buffer[6], Tuya.buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
}
}
else if (Tuya.buffer[5] == 8) { // Long value packet
if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[10]?"On":"Off",bitRead(power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off");
if ((power || Settings.light_dimmer > 0) && (Tuya.buffer[10] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1))) {
ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
}
} else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d-Inverted --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[10]?"Off":"On",bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1?"Off":"On");
if (Tuya.buffer[10] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1) {
ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[10] ^ 1, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
}
} else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Switch-%d --> MCU State: %d Current State:%d"),fnId - TUYA_MCU_FUNC_SWT1 + 1,Tuya.buffer[10], SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1));
if (Settings.flag3.tuya_disable_dimmer == 0) {
if (!Settings.param[P_TUYA_DIMMER_ID]) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Autoconfiguring Dimmer ID %d"), Tuya.buffer[6]);
Settings.param[P_TUYA_DIMMER_ID] = Tuya.buffer[6];
if (SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1) != Tuya.buffer[10]) {
SwitchSetVirtual(fnId - TUYA_MCU_FUNC_SWT1, Tuya.buffer[10]);
SwitchHandler(1);
}
}
if (Settings.param[P_TUYA_DIMMER_ID] == Tuya.buffer[6]) {
}
else if (Tuya.buffer[5] == 8) { // Long value packet
if (fnId == TUYA_MCU_FUNC_DIMMER) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Dim State=%d"), Tuya.buffer[13]);
Tuya.new_dim = changeUIntScale((uint8_t) Tuya.buffer[13], 0, Settings.param[P_TUYA_DIMMER_MAX], 0, 100);
if ((power || Settings.flag3.tuya_apply_o20) && (Tuya.new_dim > 0) && (abs(Tuya.new_dim - Settings.light_dimmer) > 1)) {
@ -228,30 +382,30 @@ void TuyaPacketProcess(void)
ExecuteCommand(scmnd, SRC_SWITCH);
}
}
}
#ifdef USE_ENERGY_SENSOR
if (Settings.param[P_TUYA_VOLTAGE_ID] == Tuya.buffer[6]) {
Energy.voltage = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 10;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Settings.param[P_TUYA_VOLTAGE_ID], (Tuya.buffer[12] << 8 | Tuya.buffer[13]));
} else if (Settings.param[P_TUYA_CURRENT_ID] == Tuya.buffer[6]) {
Energy.current = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 1000;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Settings.param[P_TUYA_CURRENT_ID], (Tuya.buffer[12] << 8 | Tuya.buffer[13]));
} else if (Settings.param[P_TUYA_POWER_ID] == Tuya.buffer[6]) {
Energy.active_power = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 10;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Settings.param[P_TUYA_POWER_ID], (Tuya.buffer[12] << 8 | Tuya.buffer[13]));
#ifdef USE_ENERGY_SENSOR
else if (fnId == TUYA_MCU_FUNC_VOLTAGE) {
Energy.voltage = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 10;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Tuya.buffer[6], (Tuya.buffer[12] << 8 | Tuya.buffer[13]));
} else if (fnId == TUYA_MCU_FUNC_CURRENT) {
Energy.current = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 1000;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Tuya.buffer[6], (Tuya.buffer[12] << 8 | Tuya.buffer[13]));
} else if (fnId == TUYA_MCU_FUNC_POWER) {
Energy.active_power = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 10;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Tuya.buffer[6], (Tuya.buffer[12] << 8 | Tuya.buffer[13]));
if (Tuya.lastPowerCheckTime != 0 && Energy.active_power > 0) {
Energy.kWhtoday += (float)Energy.active_power * (Rtc.utc_time - Tuya.lastPowerCheckTime) / 36;
EnergyUpdateToday();
if (Tuya.lastPowerCheckTime != 0 && Energy.active_power > 0) {
Energy.kWhtoday += (float)Energy.active_power * (Rtc.utc_time - Tuya.lastPowerCheckTime) / 36;
EnergyUpdateToday();
}
Tuya.lastPowerCheckTime = Rtc.utc_time;
}
Tuya.lastPowerCheckTime = Rtc.utc_time;
} else if (Settings.param[P_TUYA_DIMMER_ID] != Tuya.buffer[6]){
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Unknown ID=%d"), Tuya.buffer[6]);
}
#endif // USE_ENERGY_SENSOR
#endif // USE_ENERGY_SENSOR
}
}
// } else {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Unknown FnId=%s for dpId=%s"), fnId, Tuya.buffer[6]);
// }
break;
case TUYA_CMD_WIFI_RESET:
@ -266,9 +420,9 @@ void TuyaPacketProcess(void)
break;
case TUYA_CMD_MCU_CONF:
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: RX MCU configuration"));
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX MCU configuration Mode=%d"), Tuya.buffer[5]);
if (Tuya.buffer[5] == 2) {
if (Tuya.buffer[5] == 2) { // Processing by ESP module mode
uint8_t led1_gpio = Tuya.buffer[6];
uint8_t key1_gpio = Tuya.buffer[7];
bool key1_set = false;
@ -307,21 +461,41 @@ bool TuyaModuleSelected(void)
Settings.my_gp.io[3] = GPIO_TUYA_RX;
restart_flag = 2;
}
if (Settings.flag3.tuya_disable_dimmer == 0) {
if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER) == 0 && TUYA_DIMMER_ID > 0) {
TuyaAddMcuFunc(TUYA_MCU_FUNC_DIMMER, TUYA_DIMMER_ID);
}
bool relaySet = false;
devices_present--;
for (uint8_t i = 0 ; i < MAX_TUYA_FUNCTIONS; i++) {
if ((Settings.tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1 && Settings.tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8 ) ||
(Settings.tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1_INV && Settings.tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8_INV )) {
relaySet = true;
devices_present++;
}
}
if (!relaySet) {
TuyaAddMcuFunc(TUYA_MCU_FUNC_REL1, 1);
devices_present++;
SettingsSaveAll();
}
if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER) != 0) {
light_type = LT_SERIAL1;
} else {
light_type = LT_BASIC;
}
UpdateDevices();
return true;
}
void TuyaInit(void)
{
devices_present += Settings.param[P_TUYA_RELAYS]; // SetOption41 - Add virtual relays if present
if (!Settings.param[P_TUYA_DIMMER_ID]) {
Settings.param[P_TUYA_DIMMER_ID] = TUYA_DIMMER_ID;
}
Tuya.buffer = (char*)(malloc(TUYA_BUFFER_SIZE));
if (Tuya.buffer != nullptr) {
TuyaSerial = new TasmotaSerial(pin[GPIO_TUYA_RX], pin[GPIO_TUYA_TX], 2);
@ -434,11 +608,11 @@ int Xnrg08(uint8_t function)
if (TUYA_DIMMER == my_module_type) {
if (FUNC_PRE_INIT == function) {
if (!energy_flg) {
if (Settings.param[P_TUYA_POWER_ID] != 0) {
if (Settings.param[P_TUYA_CURRENT_ID] == 0) {
if (TuyaGetDpId(TUYA_MCU_FUNC_POWER) != 0) {
if (TuyaGetDpId(TUYA_MCU_FUNC_CURRENT) == 0) {
Energy.current_available = false;
}
if (Settings.param[P_TUYA_VOLTAGE_ID] == 0) {
if (TuyaGetDpId(TUYA_MCU_FUNC_VOLTAGE) == 0) {
Energy.voltage_available = false;
}
energy_flg = XNRG_08;
@ -486,10 +660,13 @@ bool Xdrv16(uint8_t function)
case FUNC_SET_CHANNELS:
result = TuyaSetChannels();
break;
case FUNC_COMMAND:
result = DecodeCommand(kTuyaCommand, TuyaCommand);
break;
}
}
return result;
}
#endif // USE_TUYA_DIMMER
#endif // USE_TUYA_MCU
#endif // USE_LIGHT

View File

@ -67,7 +67,7 @@ void RfReceiveCheck(void)
} else {
snprintf_P(stemp, sizeof(stemp), PSTR("\"0x%lX\""), (uint32_t)data);
}
Response_P(PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_RF_DATA "\":%s,\"" D_JSON_RF_BITS "\":%d,\"" D_JSON_RF_PROTOCOL "\":%d,\"" D_JSON_RF_PULSE "\":%d}}"),
ResponseTime_P(PSTR(",\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_RF_DATA "\":%s,\"" D_JSON_RF_BITS "\":%d,\"" D_JSON_RF_PROTOCOL "\":%d,\"" D_JSON_RF_PULSE "\":%d}}"),
stemp, bits, protocol, delay);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED));
XdrvRulesProcess();

View File

@ -96,7 +96,7 @@ void SonoffIFanSetFanspeed(uint8_t fanspeed, bool sequence)
fans = kIFan03Speed[fanspeed];
}
for (uint32_t i = 2; i < 5; i++) {
uint8_t state = (fans &1) + 6; // Add no publishPowerState
uint8_t state = (fans &1) + POWER_OFF_NO_STATE; // Add no publishPowerState
ExecuteCommandPower(i, state, SRC_IGNORE); // Use relay 2, 3 and 4
fans >>= 1;
}

View File

@ -156,10 +156,10 @@ public:
void publishMQTTReceived(void) {
char hex_char[_payload.len()*2+2];
ToHex_P((unsigned char*)_payload.getBuffer(), _payload.len(), hex_char, sizeof(hex_char));
Response_P(PSTR("{\"" D_JSON_ZIGBEEZCLRECEIVED "\":{\"fc\":\"0x%02X\",\"manuf\":\"0x%04X\",\"transact\":%d,"
"\"cmdid\":\"0x%02X\",\"payload\":\"%s\"}}"),
_frame_control, _manuf_code, _transact_seq, _cmd_id,
hex_char);
ResponseTime_P(PSTR(",\"" D_JSON_ZIGBEEZCLRECEIVED "\":{\"fc\":\"0x%02X\",\"manuf\":\"0x%04X\",\"transact\":%d,"
"\"cmdid\":\"0x%02X\",\"payload\":\"%s\"}}"),
_frame_control, _manuf_code, _transact_seq, _cmd_id,
hex_char);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLSENT));
XdrvRulesProcess();
}
@ -834,7 +834,7 @@ void ZigbeeInput(void)
SBuffer znp_buffer = zigbee_buffer->subBuffer(2, zigbee_frame_len - 3); // remove SOF, LEN and FCS
ToHex_P((unsigned char*)znp_buffer.getBuffer(), znp_buffer.len(), hex_char, sizeof(hex_char));
Response_P(PSTR("{\"" D_JSON_ZIGBEEZNPRECEIVED "\":\"%s\"}"), hex_char);
ResponseTime_P(PSTR(",\"" D_JSON_ZIGBEEZNPRECEIVED "\":\"%s\"}"), hex_char);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZNPRECEIVED));
XdrvRulesProcess();

View File

@ -145,13 +145,13 @@ void SH1106Refresh(void) // Every second
if (Settings.display_mode) { // Mode 0 is User text
switch (Settings.display_mode) {
case 1: // Time
Ssd1306Time();
SH1106Time();
break;
case 2: // Local
case 3: // Local
case 4: // Mqtt
case 5: // Mqtt
Ssd1306PrintLog();
SH1106PrintLog();
break;
}
}

View File

@ -124,13 +124,19 @@ void ILI9488_InitDriver()
#ifdef USE_TOUCH_BUTTONS
void ILI9488_MQTT(uint8_t count,const char *cp) {
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,\"RA8876\":{\"%s%d\":\"%d\"}}"), mqtt_data,cp,count+1,(buttons[count]->vpower&0x80)>>7);
ResponseTime_P(PSTR(",\"RA8876\":{\"%s%d\":\"%d\"}}"), cp,count+1,(buttons[count]->vpower&0x80)>>7);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
}
void ILI9488_RDW_BUTT(uint32_t count,uint32_t pwr) {
buttons[count]->xdrawButton(pwr);
if (pwr) buttons[count]->vpower|=0x80;
else buttons[count]->vpower&=0x7f;
}
// check digitizer hit
void FT6236Check() {
uint16_t temp;
uint8_t rbutt=0,vbutt=0;
ili9488_ctouch_counter++;
if (2 == ili9488_ctouch_counter) {
// every 100 ms should be enough
@ -158,17 +164,17 @@ if (2 == ili9488_ctouch_counter) {
// now must compare with defined buttons
for (uint8_t count=0; count<MAXBUTTONS; count++) {
if (buttons[count]) {
uint8_t bflags=buttons[count]->vpower&0x7f;
if (buttons[count]->contains(ili9488_pLoc.x,ili9488_pLoc.y)) {
// did hit
buttons[count]->press(true);
if (buttons[count]->justPressed()) {
uint8_t bflags=buttons[count]->vpower&0x7f;
if (!bflags) {
// real button
if (!SendKey(0, count+1, POWER_TOGGLE)) {
ExecuteCommandPower(count+1, POWER_TOGGLE, SRC_BUTTON);
uint8_t pwr=bitRead(power,rbutt);
if (!SendKey(KEY_BUTTON, rbutt+1, POWER_TOGGLE)) {
ExecuteCommandPower(rbutt+1, POWER_TOGGLE, SRC_BUTTON);
ILI9488_RDW_BUTT(count,!pwr);
}
buttons[count]->xdrawButton(bitRead(power,count));
} else {
// virtual button
const char *cp;
@ -186,6 +192,11 @@ if (2 == ili9488_ctouch_counter) {
}
}
}
if (!bflags) {
rbutt++;
} else {
vbutt++;
}
}
}
}
@ -193,15 +204,27 @@ if (2 == ili9488_ctouch_counter) {
// no hit
for (uint8_t count=0; count<MAXBUTTONS; count++) {
if (buttons[count]) {
uint8_t bflags=buttons[count]->vpower&0x7f;
buttons[count]->press(false);
if (buttons[count]->justReleased()) {
uint8_t bflags=buttons[count]->vpower&0x7f;
if (bflags>1) {
// push button
buttons[count]->vpower&=0x7f;
ILI9488_MQTT(count,"PBT");
if (bflags>0) {
if (bflags>1) {
// push button
buttons[count]->vpower&=0x7f;
ILI9488_MQTT(count,"PBT");
}
buttons[count]->xdrawButton(buttons[count]->vpower&0x80);
}
buttons[count]->xdrawButton(buttons[count]->vpower&0x80);
}
if (!bflags) {
// check if power button stage changed
uint8_t pwr=bitRead(power,rbutt);
uint8_t vpwr=(buttons[count]->vpower&0x80)>>7;
if (pwr!=vpwr) {
ILI9488_RDW_BUTT(count,pwr);
}
rbutt++;
}
}
}

View File

@ -109,14 +109,20 @@ void RA8876_InitDriver()
#ifdef USE_TOUCH_BUTTONS
void RA8876_MQTT(uint8_t count,const char *cp) {
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,\"RA8876\":{\"%s%d\":\"%d\"}}"), mqtt_data,cp,count+1,(buttons[count]->vpower&0x80)>>7);
ResponseTime_P(PSTR(",\"RA8876\":{\"%s%d\":\"%d\"}}"), cp,count+1,(buttons[count]->vpower&0x80)>>7);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
}
void RA8876_RDW_BUTT(uint32_t count,uint32_t pwr) {
buttons[count]->xdrawButton(pwr);
if (pwr) buttons[count]->vpower|=0x80;
else buttons[count]->vpower&=0x7f;
}
// check digitizer hit
void FT5316Check() {
uint16_t temp;
uint8_t rbutt=0,vbutt=0;
ra8876_ctouch_counter++;
if (2 == ra8876_ctouch_counter) {
// every 100 ms should be enough
@ -153,23 +159,26 @@ if (2 == ra8876_ctouch_counter) {
break;
}
*/
//AddLog_P2(LOG_LEVEL_INFO, PSTR(">> %d,%d"),ra8876_pLoc.x,ra8876_pLoc.y);
//Serial.printf("loc x: %d , loc y: %d\n",pLoc.x,pLoc.y);
// now must compare with defined buttons
for (uint8_t count=0; count<MAXBUTTONS; count++) {
if (buttons[count]) {
uint8_t bflags=buttons[count]->vpower&0x7f;
if (buttons[count]->contains(ra8876_pLoc.x,ra8876_pLoc.y)) {
// did hit
buttons[count]->press(true);
if (buttons[count]->justPressed()) {
uint8_t bflags=buttons[count]->vpower&0x7f;
if (!bflags) {
// real button
if (!SendKey(0, count+1, POWER_TOGGLE)) {
ExecuteCommandPower(count+1, POWER_TOGGLE, SRC_BUTTON);
uint8_t pwr=bitRead(power,rbutt);
if (!SendKey(KEY_BUTTON, rbutt+1, POWER_TOGGLE)) {
ExecuteCommandPower(rbutt+1, POWER_TOGGLE, SRC_BUTTON);
RA8876_RDW_BUTT(count,!pwr);
}
buttons[count]->xdrawButton(bitRead(power,count));
} else {
// virtual button
const char *cp;
@ -187,6 +196,11 @@ if (2 == ra8876_ctouch_counter) {
}
}
}
if (!bflags) {
rbutt++;
} else {
vbutt++;
}
}
}
}
@ -194,15 +208,26 @@ if (2 == ra8876_ctouch_counter) {
// no hit
for (uint8_t count=0; count<MAXBUTTONS; count++) {
if (buttons[count]) {
uint8_t bflags=buttons[count]->vpower&0x7f;
buttons[count]->press(false);
if (buttons[count]->justReleased()) {
uint8_t bflags=buttons[count]->vpower&0x7f;
if (bflags>1) {
// push button
buttons[count]->vpower&=0x7f;
RA8876_MQTT(count,"PBT");
if (bflags>0) {
if (bflags>1) {
// push button
buttons[count]->vpower&=0x7f;
RA8876_MQTT(count,"PBT");
}
buttons[count]->xdrawButton(buttons[count]->vpower&0x80);
}
buttons[count]->xdrawButton(buttons[count]->vpower&0x80);
}
if (!bflags) {
// check if power button stage changed
uint8_t pwr=bitRead(power,rbutt);
uint8_t vpwr=(buttons[count]->vpower&0x80)>>7;
if (pwr!=vpwr) {
RA8876_RDW_BUTT(count,pwr);
}
rbutt++;
}
}
}

View File

@ -181,12 +181,7 @@ void PzemEvery200ms(void)
Energy.active_power = value;
break;
case 4: // Total energy as 99999Wh
if (!Energy.start_energy || (value < Energy.start_energy)) Energy.start_energy = value; // Init after restart and hanlde roll-over if any
if (value != Energy.start_energy) {
Energy.kWhtoday += (unsigned long)((value - Energy.start_energy) * 100);
Energy.start_energy = value;
}
EnergyUpdateToday();
EnergyUpdateTotal(value, false);
break;
}
pzem_read_state++;

View File

@ -64,7 +64,7 @@ void PzemAcEverySecond(void)
uint8_t buffer[26];
uint8_t error = PzemAcModbus->ReceiveBuffer(buffer, 10);
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, (buffer[2]) ? buffer[2] +5 : sizeof(buffer));
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, sizeof(buffer));
if (error) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemAc response error %d"), error);
@ -82,12 +82,7 @@ void PzemAcEverySecond(void)
Energy.power_factor = (float)((buffer[19] << 8) + buffer[20]) / 100.0; // 1.00
float energy = (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]); // 4294967295 Wh
if (!Energy.start_energy || (energy < Energy.start_energy)) { Energy.start_energy = energy; } // Init after restart and handle roll-over if any
if (energy != Energy.start_energy) {
Energy.kWhtoday += (unsigned long)((energy - Energy.start_energy) * 100);
Energy.start_energy = energy;
}
EnergyUpdateToday();
EnergyUpdateTotal(energy, false);
// }
}
}

View File

@ -46,7 +46,7 @@ void PzemDcEverySecond(void)
uint8_t buffer[22];
uint8_t error = PzemDcModbus->ReceiveBuffer(buffer, 8);
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, (buffer[2]) ? buffer[2] +5 : sizeof(buffer));
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, sizeof(buffer));
if (error) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemDc response error %d"), error);
@ -61,12 +61,7 @@ void PzemDcEverySecond(void)
Energy.active_power = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0; // 429496729.0 W
float energy = (float)((buffer[13] << 24) + (buffer[14] << 16) + (buffer[11] << 8) + buffer[12]); // 4294967295 Wh
if (!Energy.start_energy || (energy < Energy.start_energy)) { Energy.start_energy = energy; } // Init after restart and handle roll-over if any
if (energy != Energy.start_energy) {
Energy.kWhtoday += (unsigned long)((energy - Energy.start_energy) * 100);
Energy.start_energy = energy;
}
EnergyUpdateToday();
EnergyUpdateTotal(energy, false);
}
}

View File

@ -78,7 +78,7 @@ struct SDM220 {
/*********************************************************************************************/
void SDM120Every200ms(void)
void SDM120Every250ms(void)
{
bool data_ready = Sdm120Modbus->ReceiveReady();
@ -86,15 +86,18 @@ void SDM120Every200ms(void)
uint8_t buffer[9];
uint32_t error = Sdm120Modbus->ReceiveBuffer(buffer, 2);
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, (buffer[2]) ? buffer[2] +5 : sizeof(buffer));
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, sizeof(buffer));
if (error) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SDM120 response error %d"), error);
} else {
Energy.data_valid = 0;
// 0 1 2 3 4 5 6 7 8
// SA FC BC Fh Fl Sh Sl Cl Ch
// 01 04 04 43 66 33 34 1B 38 = 230.2 Volt
float value;
((uint8_t*)&value)[3] = buffer[3]; // Get float values
((uint8_t*)&value)[3] = buffer[3]; // Get float values
((uint8_t*)&value)[2] = buffer[4];
((uint8_t*)&value)[1] = buffer[5];
((uint8_t*)&value)[0] = buffer[6];
@ -129,14 +132,7 @@ void SDM120Every200ms(void)
break;
case 7:
if (!Energy.start_energy || (value < Energy.start_energy)) { // 484.708 kWh
Energy.start_energy = value; // Init after restart and hanlde roll-over if any
}
if (value != Energy.start_energy) {
Energy.kWhtoday += (unsigned long)((value - Energy.start_energy) * 100000); // kWh to deca milli Wh
Energy.start_energy = value;
}
EnergyUpdateToday();
EnergyUpdateTotal(value, true); // 484.708 kWh
break;
#ifdef USE_SDM220
@ -266,8 +262,8 @@ int Xnrg09(uint8_t function)
case FUNC_INIT:
Sdm120SnsInit();
break;
case FUNC_EVERY_200_MSECOND:
if (uptime > 4) { SDM120Every200ms(); }
case FUNC_EVERY_250_MSECOND:
if (uptime > 4) { SDM120Every250ms(); }
break;
#ifdef USE_SDM220

View File

@ -303,8 +303,7 @@ void MCP230xx_CheckForInterrupt(void) {
break;
}
if (int_tele) {
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"MCP230XX_INT\":{\"D%i\":%i,\"MS\":%lu}}"),
ResponseTime_P(PSTR(",\"MCP230XX_INT\":{\"D%i\":%i,\"MS\":%lu}}"),
intp+(mcp230xx_port*8), ((mcp230xx_intcap >> intp) & 0x01),millis_since_last_int);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("MCP230XX_INT"));
}
@ -730,8 +729,7 @@ void MCP230xx_OutputTelemetry(void) {
}
if (outputcount) {
char stt[7];
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"MCP230_OUT\":{"));
ResponseTime_P(PSTR(",\"MCP230_OUT\":{"));
for (uint32_t pinx = 0;pinx < mcp230xx_pincount;pinx++) {
if (Settings.mcp230xx_config[pinx].pinmode >= 5) {
sprintf(stt,ConvertNumTxt(((gpiototal>>pinx)&1),Settings.mcp230xx_config[pinx].pinmode));
@ -746,8 +744,7 @@ void MCP230xx_OutputTelemetry(void) {
#endif // USE_MCP230xx_OUTPUT
void MCP230xx_Interrupt_Counter_Report(void) {
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"MCP230_INTTIMER\":{"));
ResponseTime_P(PSTR(",\"MCP230_INTTIMER\":{"));
for (uint32_t pinx = 0;pinx < mcp230xx_pincount;pinx++) {
if (Settings.mcp230xx_config[pinx].int_count_en) { // Counting is enabled for this pin so we add to report
ResponseAppend_P(PSTR("\"INTCNT_D%i\":%i,"),pinx,mcp230xx_int_counter[pinx]);
@ -761,8 +758,7 @@ void MCP230xx_Interrupt_Counter_Report(void) {
void MCP230xx_Interrupt_Retain_Report(void) {
uint16_t retainresult = 0;
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"MCP_INTRETAIN\":{"));
ResponseTime_P(PSTR(",\"MCP_INTRETAIN\":{"));
for (uint32_t pinx = 0;pinx < mcp230xx_pincount;pinx++) {
if (Settings.mcp230xx_config[pinx].int_retain_flag) {
ResponseAppend_P(PSTR("\"D%i\":%i,"),pinx,mcp230xx_int_retainer[pinx]);

View File

@ -494,12 +494,10 @@ void PN532_ScanForTag(void)
pn532_function = 0;
#endif // USE_PN532_DATA_FUNCTION
ResponseBeginTime();
#ifdef USE_PN532_DATA_FUNCTION
ResponseAppend_P(PSTR(",\"PN532\":{\"UID\":\"%s\", \"DATA\":\"%s\"}}"), uids, card_datas);
ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\", \"DATA\":\"%s\"}}"), uids, card_datas);
#else
ResponseAppend_P(PSTR(",\"PN532\":{\"UID\":\"%s\"}}"), uids);
ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\"}}"), uids);
#endif // USE_PN532_DATA_FUNCTION
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
@ -541,8 +539,7 @@ bool PN532_Command(void)
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"E")) {
pn532_function = 1; // Block 1 of next card/tag will be reset to 0x00...
AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Next scanned tag data block 1 will be erased"));
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"PN532\":{\"COMMAND\":\"E\"}}"));
ResponseTime_P(PSTR(",\"PN532\":{\"COMMAND\":\"E\"}}"));
return serviced;
}
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"S")) {
@ -558,8 +555,7 @@ bool PN532_Command(void)
pn532_newdata[pn532_newdata_len] = 0x00; // Null terminate the string
pn532_function = 2;
AddLog_P2(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Next scanned tag data block 1 will be set to '%s'"), pn532_newdata);
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"PN532\":{\"COMMAND\":\"S\"}}"));
ResponseTime_P(PSTR(",\"PN532\":{\"COMMAND\":\"S\"}}"));
return serviced;
}
}

View File

@ -253,8 +253,7 @@ void SPS30_Show(bool json) {
void CmdClean(void) {
sps30_cmd(SPS_CMD_CLEAN);
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"SPS30\":{\"CFAN\":\"true\"}}"));
ResponseTime_P(PSTR(",\"SPS30\":{\"CFAN\":\"true\"}}"));
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
}

View File

@ -106,8 +106,7 @@ void RDM6300_ScanForTag() {
memcpy(rdm_uid_str,&rdm_buffer[2],8);
rdm_uid_str[9]=0;
Response_P(PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
ResponseAppend_P(PSTR(",\"RDM6300\":{\"UID\":\"%s\"}}"), rdm_uid_str);
ResponseTime_P(PSTR(",\"RDM6300\":{\"UID\":\"%s\"}}"), rdm_uid_str);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
/*
char command[24];

View File

@ -547,8 +547,7 @@ void ibeacon_mqtt(const char *mac,const char *rssi) {
memcpy(s_rssi,rssi,4);
s_rssi[4]=0;
int16_t n_rssi=atoi(s_rssi);
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"" D_CMND_IBEACON "_%s\":{\"RSSI\":%d}}"),s_mac,n_rssi);
ResponseTime_P(PSTR(",\"" D_CMND_IBEACON "_%s\":{\"RSSI\":%d}}"),s_mac,n_rssi);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
}

View File

@ -140,6 +140,11 @@ struct METER_DESC {
uint16_t flag;
int32_t params;
char prefix[8];
int8_t trxpin;
uint8_t tsecs;
char *txmem;
uint8_t index;
uint8_t max_index;
};
// meter list , enter new meters here
@ -167,7 +172,7 @@ struct METER_DESC {
#undef METERS_USED
#define METERS_USED 1
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'o',0,SML_BAUDRATE,"OBIS"}};
[0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}};
const uint8_t meter[]=
"1,1-0:1.8.0*255(@1," D_TPWRIN ",KWh," DJ_TPWRIN ",4|"
"1,1-0:2.8.0*255(@1," D_TPWROUT ",KWh," DJ_TPWROUT ",4|"
@ -185,7 +190,7 @@ const uint8_t meter[]=
#undef METERS_USED
#define METERS_USED 1
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'o',0,SML_BAUDRATE,"OBIS"}};
[0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}};
const uint8_t meter[]=
"1,1-0:1.8.1*255(@1," D_TPWRIN ",KWh," DJ_TPWRIN ",4|"
"1,1-0:2.8.1*255(@1," D_TPWROUT ",KWh," DJ_TPWROUT ",4|"
@ -199,7 +204,7 @@ const uint8_t meter[]=
#undef METERS_USED
#define METERS_USED 1
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'s',0,SML_BAUDRATE,"SML"}};
[0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}};
// 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär
const uint8_t meter[]=
//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff
@ -218,7 +223,7 @@ const uint8_t meter[]=
#undef METERS_USED
#define METERS_USED 1
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'s',0,SML_BAUDRATE,"SML"}};
[0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}};
// 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär
// verbrauch total
const uint8_t meter[]=
@ -236,7 +241,7 @@ const uint8_t meter[]=
#undef METERS_USED
#define METERS_USED 1
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'s',0,SML_BAUDRATE,"SML"}};
[0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}};
// 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär
// verbrauch total
const uint8_t meter[]=
@ -252,7 +257,7 @@ const uint8_t meter[]=
#undef METERS_USED
#define METERS_USED 1
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'s',0,SML_BAUDRATE,"strom"}};
[0]={3,'s',0,SML_BAUDRATE,"strom",-1,1,0}};
const uint8_t meter[]=
//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff
"1,77070100010800ff@1000," D_TPWRIN ",KWh," DJ_TPWRIN ",4|"
@ -275,7 +280,7 @@ const uint8_t meter[]=
#undef METERS_USED
#define METERS_USED 1
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'s',0,SML_BAUDRATE,"SML"}};
[0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}};
const uint8_t meter[]=
//0x77,0x07,0x01,0x00,0x01,0x08,0x01,0xff
"1,77070100010800ff@1000," D_TPWRIN ",KWh," DJ_TPWRIN ",4|"
@ -291,9 +296,9 @@ const uint8_t meter[]=
#define METERS_USED 3
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'o',0,SML_BAUDRATE,"OBIS"}, // harware serial RX pin
[1]={14,'s',0,SML_BAUDRATE,"SML"}, // GPIO14 software serial
[2]={4,'o',0,SML_BAUDRATE,"OBIS2"}}; // GPIO4 software serial
[0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}, // harware serial RX pin
[1]={14,'s',0,SML_BAUDRATE,"SML",-1,1,0}, // GPIO14 software serial
[2]={4,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}}; // GPIO4 software serial
// 3 Zähler definiert
const uint8_t meter[]=
@ -320,8 +325,8 @@ const uint8_t meter[]=
#define METERS_USED 2
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'o',0,SML_BAUDRATE,"OBIS1"}, // harware serial RX pin
[1]={14,'o',0,SML_BAUDRATE,"OBIS2"}}; // GPIO14 software serial
[0]={3,'o',0,SML_BAUDRATE,"OBIS1",-1,1,0}, // harware serial RX pin
[1]={14,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}}; // GPIO14 software serial
// 2 Zähler definiert
const uint8_t meter[]=
@ -342,9 +347,9 @@ const uint8_t meter[]=
#define METERS_USED 3
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'o',0,SML_BAUDRATE,"OBIS1"}, // harware serial RX pin
[1]={14,'o',0,SML_BAUDRATE,"OBIS2"},
[2]={1,'o',0,SML_BAUDRATE,"OBIS3"}};
[0]={3,'o',0,SML_BAUDRATE,"OBIS1",-1,1,0}, // harware serial RX pin
[1]={14,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0},
[2]={1,'o',0,SML_BAUDRATE,"OBIS3",-1,1,0}};
// 3 Zähler definiert
const uint8_t meter[]=
@ -372,7 +377,7 @@ const uint8_t meter[]=
#undef METERS_USED
#define METERS_USED 1
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'o',0,SML_BAUDRATE,"OBIS"}};
[0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}};
const uint8_t meter[]=
"1,1-0:1.8.1*255(@1," D_TPWRIN ",KWh," DJ_TPWRIN ",4|"
"1,=d 1 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|"
@ -385,7 +390,7 @@ const uint8_t meter[]=
#undef METERS_USED
#define METERS_USED 1
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'s',0,SML_BAUDRATE,"SML"}};
[0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}};
// 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär
const uint8_t meter[]=
//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff
@ -407,7 +412,7 @@ const uint8_t meter[]=
#undef METERS_USED
#define METERS_USED 3
struct METER_DESC const meter_desc[METERS_USED]={
[0]={3,'o',0,SML_BAUDRATE,"OBIS"}, // harware serial RX pin
[0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}, // harware serial RX pin
[1]={14,'c',0,50,"Gas"}, // GPIO14 gas counter
[2]={1,'c',0,10,"Wasser"}}; // water counter
@ -430,9 +435,9 @@ const uint8_t meter[]=
#define METERS_USED 3
struct METER_DESC const meter_desc[METERS_USED]={
[0]={1,'c',0,10,"H20"}, // GPIO1 Wasser Zähler
[1]={4,'c',0,50,"GAS"}, // GPIO4 gas Zähler
[2]={3,'s',0,SML_BAUDRATE,"SML"}}; // SML harware serial RX pin
[0]={1,'c',0,10,"H20",-1,1,0}, // GPIO1 Wasser Zähler
[1]={4,'c',0,50,"GAS",-1,1,0}, // GPIO4 gas Zähler
[2]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; // SML harware serial RX pin
const uint8_t meter[]=
//----------------------------Wasserzähler--sensor53 c1------------------------------------
@ -516,7 +521,7 @@ char meter_id[MAX_METERS][METER_ID_SIZE];
#define EBUS_SYNC 0xaa
#define EBUS_ESC 0xa9
uint8_t ebus_pos;
uint8_t mbus_pos;
#ifdef USE_MEDIAN_FILTER
// median filter, should be odd size
@ -786,32 +791,20 @@ uint8_t dump2log=0;
bool Serial_available() {
uint8_t num=dump2log&7;
if (num<1 || num>meters_used) return Serial.available();
if (num==1) {
return Serial.available();
} else {
return meter_ss[num-1]->available();
}
if (num<1 || num>meters_used) num=1;
return meter_ss[num-1]->available();
}
uint8_t Serial_read() {
uint8_t num=dump2log&7;
if (num<1 || num>meters_used) return Serial.read();
if (num==1) {
return Serial.read();
} else {
return meter_ss[num-1]->read();
}
if (num<1 || num>meters_used) num=1;
return meter_ss[num-1]->read();
}
uint8_t Serial_peek() {
uint8_t num=dump2log&7;
if (num<1 || num>meters_used) return Serial.peek();
if (num==1) {
return Serial.peek();
} else {
return meter_ss[num-1]->peek();
}
if (num<1 || num>meters_used) num=1;
return meter_ss[num-1]->peek();
}
void Dump2log(void) {
@ -1154,15 +1147,13 @@ uint8_t ebus_CalculateCRC( uint8_t *Data, uint16_t DataLen ) {
void sml_shift_in(uint32_t meters,uint32_t shard) {
uint32_t count;
if (meter_desc_p[meters].type!='e') {
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m') {
// shift in
for (count=0; count<SML_BSIZ-1; count++) {
smltbuf[meters][count]=smltbuf[meters][count+1];
}
}
uint8_t iob;
if (shard) iob=(uint8_t)Serial.read();
else iob=(uint8_t)meter_ss[meters]->read();
uint8_t iob=(uint8_t)meter_ss[meters]->read();
if (meter_desc_p[meters].type=='o') {
smltbuf[meters][SML_BSIZ-1]=iob&0x7f;
@ -1170,6 +1161,13 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
smltbuf[meters][SML_BSIZ-1]=iob;
} else if (meter_desc_p[meters].type=='r') {
smltbuf[meters][SML_BSIZ-1]=iob;
} else if (meter_desc_p[meters].type=='m') {
smltbuf[meters][mbus_pos] = iob;
mbus_pos++;
if (mbus_pos>=9) {
SML_Decode(meters);
mbus_pos=0;
}
} else {
if (iob==EBUS_SYNC) {
// should be end of telegramm
@ -1200,7 +1198,7 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
}
}
sb_counter++;
if (meter_desc_p[meters].type!='e') SML_Decode(meters);
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m') SML_Decode(meters);
}
@ -1211,14 +1209,8 @@ uint32_t meters;
for (meters=0; meters<meters_used; meters++) {
if (meter_desc_p[meters].type!='c') {
// poll for serial input
if (meter_desc_p[meters].srcpin==3) {
while (Serial.available()) {
sml_shift_in(meters,1);
}
} else {
while (meter_ss[meters]->available()) {
sml_shift_in(meters,0);
}
while (meter_ss[meters]->available()) {
sml_shift_in(meters,0);
}
}
}
@ -1348,7 +1340,8 @@ void SML_Decode(uint8_t index) {
} else {
// compare value
uint8_t found=1;
int32_t ebus_dval=99;
uint32_t ebus_dval=99;
float mbus_dval=99;
while (*mp!='@') {
if (meter_desc_p[mindex].type=='o' || meter_desc_p[mindex].type=='c') {
if (*mp++!=*cp++) {
@ -1363,7 +1356,7 @@ void SML_Decode(uint8_t index) {
found=0;
}
} else {
// ebus or raw
// ebus mbus or raw
// XXHHHHSSUU
if (*mp=='x' && *(mp+1)=='x') {
//ignore
@ -1379,7 +1372,7 @@ void SML_Decode(uint8_t index) {
ebus_dval=val;
mp+=2;
}
else if (*mp=='s' && *(mp+1)=='s' && *(mp+2)=='s' && *(mp+3)=='s'){
else if (*mp=='s' && *(mp+1)=='s' && *(mp+2)=='s' && *(mp+3)=='s') {
int16_t val = *cp|(*(cp+1)<<8);
ebus_dval=val;
mp+=4;
@ -1389,7 +1382,15 @@ void SML_Decode(uint8_t index) {
int8_t val = *cp++;
ebus_dval=val;
mp+=2;
} else {
}
else if (*mp=='f' && *(mp+1)=='f' && *(mp+2)=='f' && *(mp+3)=='f' && *(mp+4)=='f' && *(mp+5)=='f' && *(mp+6)=='f' && *(mp+7)=='f') {
uint32_t val= (*(cp+0)<<24)|(*(cp+1)<<16)|(*(cp+2)<<8)|(*(cp+3)<<0);
float *fp=(float*)&val;
mbus_dval=*fp;
mp+=8;
cp+=4;
}
else {
uint8_t val = hexnibble(*mp++) << 4;
val |= hexnibble(*mp++);
if (val!=*cp++) {
@ -1418,7 +1419,7 @@ void SML_Decode(uint8_t index) {
}
} else {
double dval;
if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r') {
if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r' && meter_desc_p[mindex].type!='m') {
// get numeric values
if (meter_desc_p[mindex].type=='o' || meter_desc_p[mindex].type=='c') {
dval=xCharToDouble((char*)cp);
@ -1426,7 +1427,7 @@ void SML_Decode(uint8_t index) {
dval=sml_getvalue(cp,mindex);
}
} else {
// ebus
// ebus or mbus
if (*mp=='b') {
mp++;
uint8_t shift=*mp&7;
@ -1434,7 +1435,23 @@ void SML_Decode(uint8_t index) {
ebus_dval&=1;
mp+=2;
}
dval=ebus_dval;
if (*mp=='i') {
// mbus index
mp++;
uint8_t mb_index=strtol((char*)mp,(char**)&mp,10);
if (mb_index!=meter_desc_p[mindex].index) {
goto nextsect;
}
uint16_t crc = MBUS_calculateCRC(&smltbuf[mindex][0],7);
if (lowByte(crc)!=smltbuf[mindex][7]) goto nextsect;
if (highByte(crc)!=smltbuf[mindex][8]) goto nextsect;
dval=mbus_dval;
//AddLog_P2(LOG_LEVEL_INFO, PSTR(">> %s"),mp);
mp++;
} else {
dval=ebus_dval;
}
}
#ifdef USE_MEDIAN_FILTER
meter_vars[vindex]=median(&sml_mf[vindex],dval);
@ -1488,8 +1505,7 @@ void SML_Immediate_MQTT(const char *mp,uint8_t index,uint8_t mindex) {
if (dp&0x10) {
// immediate mqtt
dtostrfd(meter_vars[index],dp&0xf,tpowstr);
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s}}"),meter_desc_p[mindex].prefix,jname,tpowstr);
ResponseTime_P(PSTR(",\"%s\":{\"%s\":%s}}"),meter_desc_p[mindex].prefix,jname,tpowstr);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
}
}
@ -1723,6 +1739,14 @@ void SML_Init(void) {
#ifdef USE_SCRIPT
for (uint32_t cnt=0;cnt<MAX_METERS;cnt++) {
if (script_meter_desc[cnt].txmem) {
free(script_meter_desc[cnt].txmem);
script_meter_desc[cnt].txmem=0;
}
}
uint8_t meter_script=Run_Scripter(">M",-2,0);
if (meter_script==99) {
// use script definition
@ -1782,13 +1806,42 @@ void SML_Init(void) {
lp++;
script_meter_desc[index].prefix[7]=0;
for (uint32_t cnt=0; cnt<8; cnt++) {
if (*lp==SCRIPT_EOL) {
if (*lp==SCRIPT_EOL || *lp==',') {
script_meter_desc[index].prefix[cnt]=0;
lp--;
break;
}
script_meter_desc[index].prefix[cnt]=*lp++;
}
if (*lp==',') {
lp++;
script_meter_desc[index].trxpin=strtol(lp,&lp,10);
if (*lp!=',') goto next_line;
lp++;
script_meter_desc[index].tsecs=strtol(lp,&lp,10);
if (*lp==',') {
lp++;
char txbuff[256];
uint32_t txlen=0,tx_entries=1;
for (uint32_t cnt=0; cnt<sizeof(txbuff); cnt++) {
if (*lp==SCRIPT_EOL) {
txbuff[cnt]=0;
txlen=cnt;
break;
}
if (*lp==',') tx_entries++;
txbuff[cnt]=*lp++;
}
if (txlen) {
script_meter_desc[index].txmem=(char*)calloc(txlen+2,1);
if (script_meter_desc[index].txmem) {
strcpy(script_meter_desc[index].txmem,txbuff);
}
script_meter_desc[index].index=0;
script_meter_desc[index].max_index=tx_entries;
}
}
}
if (*lp==SCRIPT_EOL) lp--;
goto next_line;
}
@ -1862,19 +1915,20 @@ next_line:
}
} else {
// serial input, init
if (meter_desc_p[meters].srcpin==3) {
ClaimSerial();
SetSerialBaudrate(meter_desc_p[meters].params);
} else {
#ifdef SPECIAL_SS
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,-1,0,1);
if (meter_desc_p[meters].type=='m') {
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1);
} else {
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1,1);
}
#else
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,-1);
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1);
#endif
if (meter_ss[meters]->begin(meter_desc_p[meters].params)) {
meter_ss[meters]->flush();
}
}
if (meter_ss[meters]->hardwareSerial()) { ClaimSerial(); }
}
}
@ -1958,25 +2012,102 @@ uint32_t ctime=millis();
}
}
#ifdef SML_SEND_SEQ
#define SML_SEQ_PERIOD 5
uint8_t sml_seq_cnt;
void SendSeq(void) {
sml_seq_cnt++;
if (sml_seq_cnt>SML_SEQ_PERIOD) {
sml_seq_cnt=0;
// send sequence every N Seconds
uint8_t sequence[]={0x2F,0x3F,0x21,0x0D,0x0A,0};
uint8_t *ucp=sequence;
while (*ucp) {
uint8_t iob=*ucp++;
// for no parity disable next line
iob|=(CalcEvenParity(iob)<<7);
Serial.write(iob);
#ifdef USE_SCRIPT
char *SML_Get_Sequence(char *cp,uint32_t index) {
if (!index) return cp;
uint32_t cindex=0;
while (cp) {
cp=strchr(cp,',');
if (cp) {
cp++;
cindex++;
if (cindex==index) {
return cp;
}
}
}
}
uint8_t sml_250ms_cnt;
void SML_Check_Send(void) {
sml_250ms_cnt++;
for (uint32_t cnt=0; cnt<meters_used; cnt++) {
if (script_meter_desc[cnt].trxpin>=0 && script_meter_desc[cnt].txmem) {
if ((sml_250ms_cnt%script_meter_desc[cnt].tsecs)==0) {
if (script_meter_desc[cnt].max_index>1) {
script_meter_desc[cnt].index++;
if (script_meter_desc[cnt].index>=script_meter_desc[cnt].max_index) {
script_meter_desc[cnt].index=0;
}
char *cp=SML_Get_Sequence(script_meter_desc[cnt].txmem,script_meter_desc[cnt].index);
SML_Send_Seq(cnt,cp);
//AddLog_P2(LOG_LEVEL_INFO, PSTR(">> %s"),cp);
} else {
SML_Send_Seq(cnt,script_meter_desc[cnt].txmem);
}
}
}
}
}
uint8_t sml_hexnibble(char chr) {
uint8_t rVal = 0;
if (isdigit(chr)) {
rVal = chr - '0';
} else {
if (chr >= 'A' && chr <= 'F') rVal = chr + 10 - 'A';
if (chr >= 'a' && chr <= 'f') rVal = chr + 10 - 'a';
}
return rVal;
}
// send sequence every N Seconds
void SML_Send_Seq(uint32_t meter,char *seq) {
uint8_t sbuff[32];
uint8_t *ucp=sbuff,slen;
char *cp=seq;
while (*cp) {
if (!*cp || !*(cp+1)) break;
if (*cp==',') break;
uint8_t iob=(sml_hexnibble(*cp) << 4) | sml_hexnibble(*(cp+1));
cp+=2;
*ucp++=iob;
slen++;
if (slen>=sizeof(sbuff)) break;
}
if (script_meter_desc[meter].type=='m') {
*ucp++=0;
*ucp++=2;
// append crc
uint16_t crc = MBUS_calculateCRC(sbuff,6);
*ucp++=lowByte(crc);
*ucp++=highByte(crc);
slen+=4;
}
meter_ss[meter]->write(sbuff,slen);
}
#endif // USE_SCRIPT
uint16_t MBUS_calculateCRC(uint8_t *frame, uint8_t num) {
uint16_t crc, flag;
crc = 0xFFFF;
for (uint32_t i = 0; i < num; i++) {
crc ^= frame[i];
for (uint32_t j = 8; j; j--) {
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001
crc ^= 0xA001;
} else { // Else LSB is not set
crc >>= 1; // Just shift right
}
}
}
return crc;
}
/*
// for odd parity init with 1
uint8_t CalcEvenParity(uint8_t data) {
uint8_t parity=0;
@ -1987,7 +2118,7 @@ uint8_t parity=0;
}
return parity;
}
#endif
*/
// dump to log shows serial data on console
@ -2004,8 +2135,7 @@ bool XSNS_53_cmd(void) {
// set dump mode
cp++;
dump2log=atoi(cp);
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"SML\":{\"CMD\":\"dump: %d\"}}"),dump2log);
ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"dump: %d\"}}"),dump2log);
} else if (*cp=='c') {
// set ounter
cp++;
@ -2025,12 +2155,10 @@ bool XSNS_53_cmd(void) {
}
}
}
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"SML\":{\"CMD\":\"counter%d: %d\"}}"),index,RtcSettings.pulse_counter[index-1]);
ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"counter%d: %d\"}}"),index,RtcSettings.pulse_counter[index-1]);
} else if (*cp=='r') {
// restart
ResponseBeginTime();
ResponseAppend_P(PSTR(",\"SML\":{\"CMD\":\"restart\"}}"));
ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"restart\"}}"));
SML_CounterSaveState();
SML_Init();
} else {
@ -2053,6 +2181,7 @@ void SML_CounterSaveState(void) {
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
@ -2070,11 +2199,11 @@ bool Xsns53(byte function) {
if (dump2log) Dump2log();
else SML_Poll();
break;
#ifdef SML_SEND_SEQ
case FUNC_EVERY_SECOND:
SendSeq();
#ifdef USE_SCRIPT
case FUNC_EVERY_250_MSECOND:
SML_Check_Send();
break;
#endif
#endif // USE_SCRIPT
case FUNC_JSON_APPEND:
SML_Show(1);
break;

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
VER = '2.3.0032'
VER = '2.3.0033'
"""
decode-config.py - Backup/Restore Sonoff-Tasmota configuration data
@ -984,7 +984,22 @@ Setting_6_6_0_9.update ({
'sbaudrate': ('<H', 0x77A, (None, None, ('Serial', '"SBaudrate {}".format($)')), ('$ * 1200','$ / 1200') ),
})
# ======================================================================
Setting_6_6_0_10 = copy.deepcopy(Setting_6_6_0_9)
Setting_6_6_0_10.update ({
'cfg_timestamp': ('<L', 0xFF8, (None, None, (INTERNAL, None)) ),
'cfg_crc32': ('<L', 0xFFC, (None, None, (INTERNAL, None)), '"0x{:08x}".format($)' ),
'tuya_fnid_map': ({
'fnid': ('B', 0xE00, (None, None, ('Management', '"TuyaMCU {},{}".format($,@["tuya_fnid_map"][#-1]["dpid"]) if ($!=0 or @["tuya_fnid_map"][#-1]["dpid"]!=0) else None')) ),
'dpid': ('B', 0xE01, (None, None, ('Management', None)) ),
}, 0xE00, ([16], None, ('Management', None)), (None, None) ),
})
Setting_6_6_0_10['flag2'][0].update ({
'time_format': ('<L', (0x5BC,2, 4), (None, None, ('Management', '"Time {}".format($+1)')) ),
})
Setting_6_6_0_10['flag3'][0].pop('tuya_show_dimmer',None)
# ======================================================================
Settings = [
(0x606000A,0x1000, Setting_6_6_0_10),
(0x6060009,0x1000, Setting_6_6_0_9),
(0x6060008,0x1000, Setting_6_6_0_8),
(0x6060007,0x1000, Setting_6_6_0_7),