mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-30 14:16:32 +00:00
Merged from upstream
This commit is contained in:
commit
4a41c13738
@ -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:
|
||||
|
304
lib/SENDMAIL/sendemail.cpp
Executable file
304
lib/SENDMAIL/sendemail.cpp
Executable 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
39
lib/SENDMAIL/sendemail.h
Executable 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
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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_
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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_
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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 "\":["));
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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++) {
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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++;
|
||||
|
@ -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);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
Loading…
x
Reference in New Issue
Block a user