mirror of
https://github.com/arendst/Tasmota.git
synced 2025-04-24 23:07:17 +00:00

* When setting PWM values, updates all the LEDs (instant response). Uses led_power values. * If LEDLINK not set, but LED1 is, LED1 is the status led. When turning on/off, setledlink uses digitalwrite (which does not respect the new pwm operation). In this case only, we will use the setledpoweridx instead of digitalwrite - costly (every 250ms this runs), but edge case / legacy. Allows more intuitive operation - if we blink an LED with the max and min PWM limits, we'd expect it to respect these. In this case, blink will also now update the led_power status, which keeps this accurate e.g. if ledpower 1 cmnd was sent, then blink occurred, led_state would read a 1 for that bit but the led would be off (but nothing was reading it for status so it didn't cause any trouble). Leaving digitalwrite when LEDLINK is defined as this is more efficient and the use case for pwm leds is to find buttons - link indicator would become more ambiguous for no benefit.
1923 lines
70 KiB
C++
1923 lines
70 KiB
C++
/*
|
|
support_command.ino - command support for Tasmota
|
|
|
|
Copyright (C) 2020 Theo Arends
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
const char kTasmotaCommands[] PROGMEM = "|" // No prefix
|
|
D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|"
|
|
D_CMND_SERIALLOG "|" D_CMND_RESTART "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|" D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SAVEDATA "|"
|
|
D_CMND_SO "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|" D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|"
|
|
D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_FREQUENCY_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_WEIGHT_RESOLUTION "|"
|
|
D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_TEMPLATE "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|"
|
|
D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SYSLOG "|" D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALCONFIG "|"
|
|
D_CMND_SERIALDELIMITER "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|"
|
|
D_CMND_DEVICENAME "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TELEPERIOD "|" D_CMND_RESET "|" D_CMND_TIME "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|"
|
|
D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_LEDMASK "|" D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|"
|
|
D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|" D_CMND_SETLEDPWMON "|" D_CMND_SETLEDPWMOFF "|"
|
|
#ifdef USE_I2C
|
|
D_CMND_I2CSCAN "|" D_CMND_I2CDRIVER "|"
|
|
#endif
|
|
#ifdef USE_DEVICE_GROUPS
|
|
D_CMND_DEVGROUP_NAME "|"
|
|
#ifdef USE_DEVICE_GROUPS_SEND
|
|
D_CMND_DEVGROUP_SEND "|"
|
|
#endif // USE_DEVICE_GROUPS_SEND
|
|
D_CMND_DEVGROUP_SHARE "|" D_CMND_DEVGROUPSTATUS "|"
|
|
#endif // USE_DEVICE_GROUPS
|
|
D_CMND_SENSOR "|" D_CMND_DRIVER;
|
|
|
|
void (* const TasmotaCommand[])(void) PROGMEM = {
|
|
&CmndBacklog, &CmndDelay, &CmndPower, &CmndStatus, &CmndState, &CmndSleep, &CmndUpgrade, &CmndUpgrade, &CmndOtaUrl,
|
|
&CmndSeriallog, &CmndRestart, &CmndPowerOnState, &CmndPulsetime, &CmndBlinktime, &CmndBlinkcount, &CmndSavedata,
|
|
&CmndSetoption, &CmndSetoption, &CmndTemperatureResolution, &CmndHumidityResolution, &CmndPressureResolution, &CmndPowerResolution,
|
|
&CmndVoltageResolution, &CmndFrequencyResolution, &CmndCurrentResolution, &CmndEnergyResolution, &CmndWeightResolution,
|
|
&CmndModule, &CmndModules, &CmndGpio, &CmndGpios, &CmndTemplate, &CmndPwm, &CmndPwmfrequency, &CmndPwmrange,
|
|
&CmndButtonDebounce, &CmndSwitchDebounce, &CmndSyslog, &CmndLoghost, &CmndLogport, &CmndSerialSend, &CmndBaudrate, &CmndSerialConfig,
|
|
&CmndSerialDelimiter, &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig,
|
|
&CmndDevicename, &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd,
|
|
&CmndTimeDst, &CmndAltitude, &CmndLedPower, &CmndLedState, &CmndLedMask, &CmndWifiPower, &CmndTempOffset, &CmndHumOffset,
|
|
&CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, &CmndSetLedPwmOn, &CmndSetLedPwmOff,
|
|
#ifdef USE_I2C
|
|
&CmndI2cScan, CmndI2cDriver,
|
|
#endif
|
|
#ifdef USE_DEVICE_GROUPS
|
|
&CmndDevGroupName,
|
|
#ifdef USE_DEVICE_GROUPS_SEND
|
|
&CmndDevGroupSend,
|
|
#endif // USE_DEVICE_GROUPS_SEND
|
|
&CmndDevGroupShare, &CmndDevGroupStatus,
|
|
#endif // USE_DEVICE_GROUPS
|
|
&CmndSensor, &CmndDriver };
|
|
|
|
const char kWifiConfig[] PROGMEM =
|
|
D_WCFG_0_RESTART "||" D_WCFG_2_WIFIMANAGER "||" D_WCFG_4_RETRY "|" D_WCFG_5_WAIT "|" D_WCFG_6_SERIAL "|" D_WCFG_7_WIFIMANAGER_RESET_ONLY;
|
|
|
|
/********************************************************************************************/
|
|
|
|
void ResponseCmndNumber(int value)
|
|
{
|
|
Response_P(S_JSON_COMMAND_NVALUE, XdrvMailbox.command, value);
|
|
}
|
|
|
|
void ResponseCmndFloat(float value, uint32_t decimals)
|
|
{
|
|
char stemp1[TOPSZ];
|
|
dtostrfd(value, decimals, stemp1);
|
|
Response_P(S_JSON_COMMAND_XVALUE, XdrvMailbox.command, stemp1); // Return float value without quotes
|
|
}
|
|
|
|
void ResponseCmndIdxNumber(int value)
|
|
{
|
|
Response_P(S_JSON_COMMAND_INDEX_NVALUE, XdrvMailbox.command, XdrvMailbox.index, value);
|
|
}
|
|
|
|
void ResponseCmndChar_P(const char* value)
|
|
{
|
|
Response_P(S_JSON_COMMAND_SVALUE, XdrvMailbox.command, value);
|
|
}
|
|
|
|
void ResponseCmndChar(const char* value)
|
|
{
|
|
Response_P(S_JSON_COMMAND_SVALUE, XdrvMailbox.command, value);
|
|
}
|
|
|
|
void ResponseCmndStateText(uint32_t value)
|
|
{
|
|
ResponseCmndChar(GetStateText(value));
|
|
}
|
|
|
|
void ResponseCmndDone(void)
|
|
{
|
|
ResponseCmndChar(D_JSON_DONE);
|
|
}
|
|
|
|
void ResponseCmndIdxChar(const char* value)
|
|
{
|
|
Response_P(S_JSON_COMMAND_INDEX_SVALUE, XdrvMailbox.command, XdrvMailbox.index, value);
|
|
}
|
|
|
|
void ResponseCmndAll(uint32_t text_index, uint32_t count)
|
|
{
|
|
uint32_t real_index = text_index;
|
|
mqtt_data[0] = '\0';
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
if ((SET_MQTT_GRP_TOPIC == text_index) && (1 == i)) { real_index = SET_MQTT_GRP_TOPIC2 -1; }
|
|
ResponseAppend_P(PSTR("%c\"%s%d\":\"%s\""), (i) ? ',' : '{', XdrvMailbox.command, i +1, SettingsText(real_index +i));
|
|
}
|
|
ResponseJsonEnd();
|
|
}
|
|
|
|
/********************************************************************************************/
|
|
|
|
void ExecuteCommand(const char *cmnd, uint32_t source)
|
|
{
|
|
// cmnd: "status 0" = stopic "status" and svalue " 0"
|
|
// cmnd: "var1 =1" = stopic "var1" and svalue " =1"
|
|
// cmnd: "var1=1" = stopic "var1" and svalue "=1"
|
|
#ifdef USE_DEBUG_DRIVER
|
|
ShowFreeMem(PSTR("ExecuteCommand"));
|
|
#endif
|
|
ShowSource(source);
|
|
|
|
const char *pos = cmnd;
|
|
while (*pos && isspace(*pos)) {
|
|
pos++; // Skip all spaces
|
|
}
|
|
|
|
const char *start = pos;
|
|
// Get a command. Commands can only use letters, digits and underscores
|
|
while (*pos && (isalpha(*pos) || isdigit(*pos) || '_' == *pos || '/' == *pos)) {
|
|
if ('/' == *pos) { // Skip possible cmnd/tasmota/ preamble
|
|
start = pos + 1;
|
|
}
|
|
pos++;
|
|
}
|
|
if ('\0' == *start || pos <= start) {
|
|
return; // Did not find any command to execute
|
|
}
|
|
|
|
uint32_t size = pos - start;
|
|
char stopic[size + 2]; // with leader '/' and end '\0'
|
|
stopic[0] = '/';
|
|
memcpy(stopic+1, start, size);
|
|
stopic[size+1] = '\0';
|
|
|
|
char svalue[strlen(pos) +1]; // pos point to the start of parameters
|
|
strlcpy(svalue, pos, sizeof(svalue));
|
|
CommandHandler(stopic, svalue, strlen(svalue));
|
|
}
|
|
|
|
/********************************************************************************************/
|
|
|
|
// topicBuf: /power1 dataBuf: toggle = Console command
|
|
// topicBuf: cmnd/tasmota/power1 dataBuf: toggle = Mqtt command using topic
|
|
// topicBuf: cmnd/tasmotas/power1 dataBuf: toggle = Mqtt command using a group topic
|
|
// topicBuf: cmnd/DVES_83BB10_fb/power1 dataBuf: toggle = Mqtt command using fallback topic
|
|
|
|
void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len)
|
|
{
|
|
#ifdef USE_DEBUG_DRIVER
|
|
ShowFreeMem(PSTR("CommandHandler"));
|
|
#endif
|
|
|
|
while (*dataBuf && isspace(*dataBuf)) {
|
|
dataBuf++; // Skip leading spaces in data
|
|
data_len--;
|
|
}
|
|
|
|
bool grpflg = false;
|
|
uint32_t real_index = SET_MQTT_GRP_TOPIC;
|
|
for (uint32_t i = 0; i < MAX_GROUP_TOPICS; i++) {
|
|
if (1 == i) { real_index = SET_MQTT_GRP_TOPIC2 -1; }
|
|
char *group_topic = SettingsText(real_index +i);
|
|
if (*group_topic && strstr(topicBuf, group_topic) != nullptr) {
|
|
grpflg = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
char stemp1[TOPSZ];
|
|
GetFallbackTopic_P(stemp1, ""); // Full Fallback topic = cmnd/DVES_xxxxxxxx_fb/
|
|
fallback_topic_flag = (!strncmp(topicBuf, stemp1, strlen(stemp1)));
|
|
|
|
char *type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type)
|
|
|
|
uint32_t index = 1;
|
|
bool user_index = false;
|
|
if (type != nullptr) {
|
|
type++;
|
|
uint32_t i;
|
|
int nLen; // strlen(type)
|
|
char *s = type;
|
|
for (nLen = 0; *s; s++, nLen++) {
|
|
*s=toupper(*s);
|
|
}
|
|
i = nLen;
|
|
if (i > 0) { // may be 0
|
|
while (isdigit(type[i-1])) {
|
|
i--;
|
|
}
|
|
}
|
|
if (i < nLen) {
|
|
index = atoi(type + i);
|
|
user_index = true;
|
|
}
|
|
type[i] = '\0';
|
|
}
|
|
|
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf);
|
|
|
|
if (type != nullptr) {
|
|
Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}"));
|
|
|
|
if (Settings.ledstate &0x02) { blinks++; }
|
|
|
|
if (!strcmp(dataBuf,"?")) { data_len = 0; }
|
|
|
|
char *p;
|
|
int32_t payload = strtol(dataBuf, &p, 0); // decimal, octal (0) or hex (0x)
|
|
if (p == dataBuf) { payload = -99; }
|
|
int temp_payload = GetStateNumber(dataBuf);
|
|
if (temp_payload > -1) { payload = temp_payload; }
|
|
|
|
DEBUG_CORE_LOG(PSTR("CMD: Payload %d"), payload);
|
|
|
|
// backlog_delay = millis() + (100 * MIN_BACKLOG_DELAY);
|
|
backlog_delay = millis() + Settings.param[P_BACKLOG_DELAY];
|
|
|
|
char command[CMDSZ] = { 0 };
|
|
XdrvMailbox.command = command;
|
|
XdrvMailbox.index = index;
|
|
XdrvMailbox.data_len = data_len;
|
|
XdrvMailbox.payload = payload;
|
|
XdrvMailbox.grpflg = grpflg;
|
|
XdrvMailbox.usridx = user_index;
|
|
XdrvMailbox.topic = type;
|
|
XdrvMailbox.data = dataBuf;
|
|
|
|
#ifdef USE_SCRIPT_SUB_COMMAND
|
|
// allow overwrite tasmota cmds
|
|
if (!Script_SubCmd()) {
|
|
if (!DecodeCommand(kTasmotaCommands, TasmotaCommand)) {
|
|
if (!XdrvCall(FUNC_COMMAND)) {
|
|
if (!XsnsCall(FUNC_COMMAND)) {
|
|
type = nullptr; // Unknown command
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else //USE_SCRIPT_SUB_COMMAND
|
|
if (!DecodeCommand(kTasmotaCommands, TasmotaCommand)) {
|
|
if (!XdrvCall(FUNC_COMMAND)) {
|
|
if (!XsnsCall(FUNC_COMMAND)) {
|
|
type = nullptr; // Unknown command
|
|
}
|
|
}
|
|
}
|
|
#endif //USE_SCRIPT_SUB_COMMAND
|
|
|
|
}
|
|
|
|
if (type == nullptr) {
|
|
blinks = 201;
|
|
snprintf_P(stemp1, sizeof(stemp1), PSTR(D_JSON_COMMAND));
|
|
Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_UNKNOWN "\"}"));
|
|
type = (char*)stemp1;
|
|
}
|
|
|
|
if (mqtt_data[0] != '\0') {
|
|
MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
|
|
XdrvRulesProcess();
|
|
}
|
|
fallback_topic_flag = false;
|
|
}
|
|
|
|
/********************************************************************************************/
|
|
|
|
void CmndBacklog(void)
|
|
{
|
|
if (XdrvMailbox.data_len) {
|
|
|
|
#ifdef SUPPORT_IF_STATEMENT
|
|
char *blcommand = strtok(XdrvMailbox.data, ";");
|
|
while ((blcommand != nullptr) && (backlog.size() < MAX_BACKLOG))
|
|
#else
|
|
uint32_t bl_pointer = (!backlog_pointer) ? MAX_BACKLOG -1 : backlog_pointer;
|
|
bl_pointer--;
|
|
char *blcommand = strtok(XdrvMailbox.data, ";");
|
|
while ((blcommand != nullptr) && (backlog_index != bl_pointer))
|
|
#endif
|
|
{
|
|
while(true) {
|
|
blcommand = Trim(blcommand);
|
|
if (!strncasecmp_P(blcommand, PSTR(D_CMND_BACKLOG), strlen(D_CMND_BACKLOG))) {
|
|
blcommand += strlen(D_CMND_BACKLOG); // Skip unnecessary command Backlog
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (*blcommand != '\0') {
|
|
#ifdef SUPPORT_IF_STATEMENT
|
|
if (backlog.size() < MAX_BACKLOG) {
|
|
backlog.add(blcommand);
|
|
}
|
|
#else
|
|
backlog[backlog_index] = String(blcommand);
|
|
backlog_index++;
|
|
if (backlog_index >= MAX_BACKLOG) backlog_index = 0;
|
|
#endif
|
|
}
|
|
blcommand = strtok(nullptr, ";");
|
|
}
|
|
// ResponseCmndChar(D_JSON_APPENDED);
|
|
mqtt_data[0] = '\0';
|
|
} else {
|
|
bool blflag = BACKLOG_EMPTY;
|
|
#ifdef SUPPORT_IF_STATEMENT
|
|
backlog.clear();
|
|
#else
|
|
backlog_pointer = backlog_index;
|
|
#endif
|
|
ResponseCmndChar(blflag ? D_JSON_EMPTY : D_JSON_ABORTED);
|
|
}
|
|
}
|
|
|
|
void CmndDelay(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= (MIN_BACKLOG_DELAY / 100)) && (XdrvMailbox.payload <= 3600)) {
|
|
backlog_delay = millis() + (100 * XdrvMailbox.payload);
|
|
}
|
|
uint32_t bl_delay = 0;
|
|
long bl_delta = TimePassedSince(backlog_delay);
|
|
if (bl_delta < 0) { bl_delay = (bl_delta *-1) / 100; }
|
|
ResponseCmndNumber(bl_delay);
|
|
}
|
|
|
|
void CmndPower(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= devices_present)) {
|
|
if ((XdrvMailbox.payload < POWER_OFF) || (XdrvMailbox.payload > POWER_BLINK_STOP)) {
|
|
XdrvMailbox.payload = POWER_SHOW_STATE;
|
|
}
|
|
// Settings.flag.device_index_enable = XdrvMailbox.usridx; // SetOption26 - Switch between POWER or POWER1
|
|
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)
|
|
{
|
|
uint32_t payload = ((XdrvMailbox.payload < 0) || (XdrvMailbox.payload > MAX_STATUS)) ? 99 : XdrvMailbox.payload;
|
|
|
|
uint32_t option = STAT;
|
|
char stemp[200];
|
|
char stemp2[TOPSZ];
|
|
|
|
// Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX
|
|
// Commented on 20200118 as it seems to be no longer needed
|
|
// if (!strcmp(SettingsText(SET_MQTTPREFIX1), SettingsText(SET_MQTTPREFIX2)) && (!payload)) { option++; } // TELE
|
|
|
|
if ((!Settings.flag.mqtt_enabled) && (6 == payload)) { payload = 99; } // SetOption3 - Enable MQTT
|
|
if (!energy_flg && (9 == payload)) { payload = 99; }
|
|
if (!CrashFlag() && (12 == payload)) { payload = 99; }
|
|
|
|
if ((0 == payload) || (99 == payload)) {
|
|
uint32_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present;
|
|
#ifdef USE_SONOFF_IFAN
|
|
if (IsModuleIfan()) { maxfn = 1; }
|
|
#endif // USE_SONOFF_IFAN
|
|
stemp[0] = '\0';
|
|
for (uint32_t i = 0; i < maxfn; i++) {
|
|
snprintf_P(stemp, sizeof(stemp), PSTR("%s%s\"%s\"" ), stemp, (i > 0 ? "," : ""), SettingsText(SET_FRIENDLYNAME1 +i));
|
|
}
|
|
stemp2[0] = '\0';
|
|
for (uint32_t i = 0; i < MAX_SWITCHES; i++) {
|
|
snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]);
|
|
}
|
|
Response_P(PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_DEVICENAME "\":\"%s\",\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\""
|
|
D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\""
|
|
D_CMND_LEDMASK "\":\"%04X\",\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\""
|
|
D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"),
|
|
ModuleNr(), SettingsText(SET_DEVICENAME), stemp, mqtt_topic,
|
|
SettingsText(SET_MQTT_BUTTON_TOPIC), power, Settings.poweronstate, Settings.ledstate,
|
|
Settings.ledmask, Settings.save_data,
|
|
Settings.flag.save_state, // SetOption0 - Save power state and use after restart
|
|
SettingsText(SET_MQTT_SWITCH_TOPIC),
|
|
stemp2,
|
|
Settings.flag.mqtt_button_retain, // CMND_BUTTONRETAIN
|
|
Settings.flag.mqtt_switch_retain, // CMND_SWITCHRETAIN
|
|
Settings.flag.mqtt_sensor_retain, // CMND_SENSORRETAIN
|
|
Settings.flag.mqtt_power_retain); // CMND_POWERRETAIN
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS));
|
|
}
|
|
|
|
if ((0 == payload) || (1 == payload)) {
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_JSON_BAUDRATE "\":%d,\"" D_CMND_SERIALCONFIG "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\",\"" D_CMND_OTAURL "\":\"%s\",\""
|
|
D_JSON_RESTARTREASON "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\",\"" D_JSON_STARTUPUTC "\":\"%s\",\"" D_CMND_SLEEP "\":%d,\""
|
|
D_JSON_CONFIG_HOLDER "\":%d,\"" D_JSON_BOOTCOUNT "\":%d,\"BCResetTime\":\"%s\",\"" D_JSON_SAVECOUNT "\":%d"
|
|
#ifdef ESP8266
|
|
",\"" D_JSON_SAVEADDRESS "\":\"%X\""
|
|
#endif
|
|
"}}"),
|
|
Settings.baudrate * 300, GetSerialConfig().c_str(), SettingsText(SET_MQTT_GRP_TOPIC), SettingsText(SET_OTAURL),
|
|
GetResetReason().c_str(), GetUptime().c_str(), GetDateAndTime(DT_RESTART).c_str(), Settings.sleep,
|
|
Settings.cfg_holder, Settings.bootcount, GetDateAndTime(DT_BOOTCOUNT).c_str(), Settings.save_flag
|
|
#ifdef ESP8266
|
|
, GetSettingsAddress()
|
|
#endif
|
|
);
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "1"));
|
|
}
|
|
|
|
if ((0 == payload) || (2 == payload)) {
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS2_FIRMWARE "\":{\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_BUILDDATETIME "\":\"%s\""
|
|
#ifdef ESP8266
|
|
",\"" D_JSON_BOOTVERSION "\":%d"
|
|
#endif
|
|
",\"" D_JSON_COREVERSION "\":\"" ARDUINO_CORE_RELEASE "\",\"" D_JSON_SDKVERSION "\":\"%s\","
|
|
"\"Hardware\":\"%s\""
|
|
"%s}}"),
|
|
my_version, my_image, GetBuildDateAndTime().c_str()
|
|
#ifdef ESP8266
|
|
, ESP.getBootVersion()
|
|
#endif
|
|
, ESP.getSdkVersion(),
|
|
GetDeviceHardware().c_str(),
|
|
GetStatistics().c_str());
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "2"));
|
|
}
|
|
|
|
if ((0 == payload) || (3 == payload)) {
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_MQTTLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\""
|
|
D_CMND_LOGHOST "\":\"%s\",\"" D_CMND_LOGPORT "\":%d,\"" D_CMND_SSID "\":[\"%s\",\"%s\"],\"" D_CMND_TELEPERIOD "\":%d,\""
|
|
D_JSON_RESOLUTION "\":\"%08X\",\"" D_CMND_SETOPTION "\":[\"%08X\",\"%s\",\"%08X\",\"%08X\"]}}"),
|
|
Settings.seriallog_level, Settings.weblog_level, Settings.mqttlog_level, Settings.syslog_level,
|
|
SettingsText(SET_SYSLOG_HOST), Settings.syslog_port, SettingsText(SET_STASSID1), SettingsText(SET_STASSID2), Settings.tele_period,
|
|
Settings.flag2.data, Settings.flag.data, ToHex_P((unsigned char*)Settings.param, PARAM8_SIZE, stemp2, sizeof(stemp2)),
|
|
Settings.flag3.data, Settings.flag4.data);
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "3"));
|
|
}
|
|
|
|
if ((0 == payload) || (4 == payload)) {
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_JSON_PROGRAMSIZE "\":%d,\"" D_JSON_FREEMEMORY "\":%d,\"" D_JSON_HEAPSIZE "\":%d,\""
|
|
#ifdef ESP32
|
|
D_JSON_PSRMAXMEMORY "\":%d,\"" D_JSON_PSRFREEMEMORY "\":%d,"
|
|
#endif
|
|
D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d"
|
|
#ifdef ESP8266
|
|
",\"" D_JSON_FLASHCHIPID "\":\"%06X\""
|
|
#endif
|
|
",\"" D_JSON_FLASHMODE "\":%d,\""
|
|
D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"]"),
|
|
ESP_getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP_getFreeHeap()/1024,
|
|
#ifdef ESP32
|
|
ESP.getPsramSize()/1024, ESP.getFreePsram()/1024,
|
|
#endif
|
|
ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024
|
|
#ifdef ESP8266
|
|
, ESP.getFlashChipId()
|
|
#endif
|
|
, ESP.getFlashChipMode(),
|
|
LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5, feature6);
|
|
XsnsDriverState();
|
|
ResponseAppend_P(PSTR(",\"Sensors\":"));
|
|
XsnsSensorState();
|
|
ResponseJsonEndEnd();
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "4"));
|
|
}
|
|
|
|
if ((0 == payload) || (5 == payload)) {
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_GATEWAY "\":\"%s\",\""
|
|
D_JSON_SUBNETMASK "\":\"%s\",\"" D_JSON_DNSSERVER "\":\"%s\",\"" D_JSON_MAC "\":\"%s\",\""
|
|
D_CMND_WEBSERVER "\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"),
|
|
my_hostname, WiFi.localIP().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(),
|
|
IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(), WiFi.macAddress().c_str(),
|
|
Settings.webserver, Settings.sta_config, WifiGetOutputPower().c_str());
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "5"));
|
|
}
|
|
|
|
if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\""
|
|
D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"),
|
|
SettingsText(SET_MQTT_HOST), Settings.mqtt_port, SettingsText(SET_MQTT_CLIENT),
|
|
mqtt_client, SettingsText(SET_MQTT_USER), MqttConnectCount(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6"));
|
|
}
|
|
|
|
if ((0 == payload) || (7 == payload)) {
|
|
if (99 == Settings.timezone) {
|
|
snprintf_P(stemp, sizeof(stemp), PSTR("%d" ), Settings.timezone);
|
|
} else {
|
|
snprintf_P(stemp, sizeof(stemp), PSTR("\"%s\"" ), GetTimeZone().c_str());
|
|
}
|
|
#if defined(USE_TIMERS) && defined(USE_SUNRISE)
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_JSON_UTC_TIME "\":\"%s\",\"" D_JSON_LOCAL_TIME "\":\"%s\",\"" D_JSON_STARTDST "\":\"%s\",\""
|
|
D_JSON_ENDDST "\":\"%s\",\"" D_CMND_TIMEZONE "\":%s,\"" D_JSON_SUNRISE "\":\"%s\",\"" D_JSON_SUNSET "\":\"%s\"}}"),
|
|
GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_LOCALNOTZ).c_str(), GetDateAndTime(DT_DST).c_str(),
|
|
GetDateAndTime(DT_STD).c_str(), stemp, GetSun(0).c_str(), GetSun(1).c_str());
|
|
#else
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_JSON_UTC_TIME "\":\"%s\",\"" D_JSON_LOCAL_TIME "\":\"%s\",\"" D_JSON_STARTDST "\":\"%s\",\""
|
|
D_JSON_ENDDST "\":\"%s\",\"" D_CMND_TIMEZONE "\":%s}}"),
|
|
GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_LOCALNOTZ).c_str(), GetDateAndTime(DT_DST).c_str(),
|
|
GetDateAndTime(DT_STD).c_str(), stemp);
|
|
#endif // USE_TIMERS and USE_SUNRISE
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "7"));
|
|
}
|
|
|
|
#if defined(USE_ENERGY_SENSOR) && defined(USE_ENERGY_MARGIN_DETECTION)
|
|
if (energy_flg) {
|
|
if ((0 == payload) || (9 == payload)) {
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERDELTA "\":%d,\"" D_CMND_POWERLOW "\":%d,\"" D_CMND_POWERHIGH "\":%d,\""
|
|
D_CMND_VOLTAGELOW "\":%d,\"" D_CMND_VOLTAGEHIGH "\":%d,\"" D_CMND_CURRENTLOW "\":%d,\"" D_CMND_CURRENTHIGH "\":%d}}"),
|
|
Settings.energy_power_delta, Settings.energy_min_power, Settings.energy_max_power,
|
|
Settings.energy_min_voltage, Settings.energy_max_voltage, Settings.energy_min_current, Settings.energy_max_current);
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "9"));
|
|
}
|
|
}
|
|
#endif // USE_ENERGY_MARGIN_DETECTION
|
|
|
|
if ((0 == payload) || (8 == payload) || (10 == payload)) {
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS10_SENSOR "\":"));
|
|
MqttShowSensor();
|
|
ResponseJsonEnd();
|
|
if (8 == payload) {
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "8"));
|
|
} else {
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "10"));
|
|
}
|
|
}
|
|
|
|
if ((0 == payload) || (11 == payload)) {
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS11_STATUS "\":"));
|
|
MqttShowState();
|
|
ResponseJsonEnd();
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "11"));
|
|
}
|
|
|
|
if (CrashFlag()) {
|
|
if ((0 == payload) || (12 == payload)) {
|
|
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS12_STATUS "\":"));
|
|
CrashDump();
|
|
ResponseJsonEnd();
|
|
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "12"));
|
|
}
|
|
}
|
|
|
|
#ifdef USE_SCRIPT_STATUS
|
|
if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">U",2,mqtt_data);
|
|
#endif
|
|
|
|
if (payload) {
|
|
XdrvRulesProcess(); // Allow rule processing on single Status command only
|
|
}
|
|
|
|
mqtt_data[0] = '\0';
|
|
}
|
|
|
|
void CmndState(void)
|
|
{
|
|
mqtt_data[0] = '\0';
|
|
MqttShowState();
|
|
if (Settings.flag3.hass_tele_on_power) { // SetOption59 - Send tele/%topic%/STATE in addition to stat/%topic%/RESULT
|
|
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN);
|
|
}
|
|
#ifdef USE_HOME_ASSISTANT
|
|
if (Settings.flag.hass_discovery) { // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
|
|
HAssPublishStatus();
|
|
}
|
|
#endif // USE_HOME_ASSISTANT
|
|
}
|
|
|
|
void CmndTempOffset(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
int value = (int)(CharToFloat(XdrvMailbox.data) * 10);
|
|
if ((value > -127) && (value < 127)) {
|
|
Settings.temp_comp = value;
|
|
}
|
|
}
|
|
ResponseCmndFloat((float)(Settings.temp_comp) / 10, 1);
|
|
}
|
|
|
|
void CmndHumOffset(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
int value = (int)(CharToFloat(XdrvMailbox.data) * 10);
|
|
if ((value > -101) && (value < 101)) {
|
|
Settings.hum_comp = value;
|
|
}
|
|
}
|
|
ResponseCmndFloat((float)(Settings.hum_comp) / 10, 1);
|
|
}
|
|
|
|
void CmndGlobalTemp(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
float temperature = CharToFloat(XdrvMailbox.data);
|
|
if (!isnan(temperature) && Settings.flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit
|
|
temperature = (temperature - 32) / 1.8; // Celsius
|
|
}
|
|
if ((temperature >= -50.0) && (temperature <= 100.0)) {
|
|
ConvertTemp(temperature);
|
|
global_update = 1; // Keep global values just entered valid
|
|
}
|
|
}
|
|
ResponseCmndFloat(global_temperature, 1);
|
|
}
|
|
|
|
void CmndGlobalHum(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
float humidity = CharToFloat(XdrvMailbox.data);
|
|
if ((humidity >= 0.0) && (humidity <= 100.0)) {
|
|
ConvertHumidity(humidity);
|
|
global_update = 1; // Keep global values just entered valid
|
|
}
|
|
}
|
|
ResponseCmndFloat(global_humidity, 1);
|
|
}
|
|
|
|
void CmndSleep(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 251)) {
|
|
Settings.sleep = XdrvMailbox.payload;
|
|
ssleep = XdrvMailbox.payload;
|
|
WiFiSetSleepMode();
|
|
}
|
|
Response_P(S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, XdrvMailbox.command, Settings.sleep, ssleep);
|
|
|
|
}
|
|
|
|
void CmndUpgrade(void)
|
|
{
|
|
// Check if the payload is numerically 1, and had no trailing chars.
|
|
// e.g. "1foo" or "1.2.3" could fool us.
|
|
// Check if the version we have been asked to upgrade to is higher than our current version.
|
|
// We also need at least 3 chars to make a valid version number string.
|
|
if (((1 == XdrvMailbox.data_len) && (1 == XdrvMailbox.payload)) || ((XdrvMailbox.data_len >= 3) && NewerVersion(XdrvMailbox.data))) {
|
|
ota_state_flag = 3;
|
|
char stemp1[TOPSZ];
|
|
Response_P(PSTR("{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}"), XdrvMailbox.command, my_version, GetOtaUrl(stemp1, sizeof(stemp1)));
|
|
} else {
|
|
Response_P(PSTR("{\"%s\":\"" D_JSON_ONE_OR_GT "\"}"), XdrvMailbox.command, my_version);
|
|
}
|
|
}
|
|
|
|
void CmndOtaUrl(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
SettingsUpdateText(SET_OTAURL, (SC_DEFAULT == Shortcut()) ? PSTR(OTA_URL) : XdrvMailbox.data);
|
|
}
|
|
ResponseCmndChar(SettingsText(SET_OTAURL));
|
|
}
|
|
|
|
void CmndSeriallog(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) {
|
|
Settings.flag.mqtt_serial = 0; // CMND_SERIALSEND and CMND_SERIALLOG
|
|
SetSeriallog(XdrvMailbox.payload);
|
|
}
|
|
Response_P(S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, XdrvMailbox.command, Settings.seriallog_level, seriallog_level);
|
|
}
|
|
|
|
void CmndRestart(void)
|
|
{
|
|
switch (XdrvMailbox.payload) {
|
|
case 1:
|
|
restart_flag = 2;
|
|
ResponseCmndChar(D_JSON_RESTARTING);
|
|
break;
|
|
case -1:
|
|
CmndCrash(); // force a crash
|
|
break;
|
|
case -2:
|
|
CmndWDT();
|
|
break;
|
|
case -3:
|
|
CmndBlockedLoop();
|
|
break;
|
|
case 99:
|
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING));
|
|
EspRestart();
|
|
break;
|
|
default:
|
|
ResponseCmndChar_P(PSTR(D_JSON_ONE_TO_RESTART));
|
|
}
|
|
}
|
|
|
|
void CmndPowerOnState(void)
|
|
{
|
|
#ifdef ESP8266
|
|
if (my_module_type != MOTOR)
|
|
#endif // ESP8266
|
|
{
|
|
/* 0 = Keep relays off after power on
|
|
* 1 = Turn relays on after power on, if PulseTime set wait for PulseTime seconds, and turn relays off
|
|
* 2 = Toggle relays after power on
|
|
* 3 = Set relays to last saved state after power on
|
|
* 4 = Turn relays on and disable any relay control (used for Sonoff Pow to always measure power)
|
|
* 5 = Keep relays off after power on, if PulseTime set wait for PulseTime seconds, and turn relays on
|
|
*/
|
|
if ((XdrvMailbox.payload >= POWER_ALL_OFF) && (XdrvMailbox.payload <= POWER_ALL_OFF_PULSETIME_ON)) {
|
|
Settings.poweronstate = XdrvMailbox.payload;
|
|
if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) {
|
|
for (uint32_t i = 1; i <= devices_present; i++) {
|
|
ExecuteCommandPower(i, POWER_ON, SRC_IGNORE);
|
|
}
|
|
}
|
|
}
|
|
ResponseCmndNumber(Settings.poweronstate);
|
|
}
|
|
}
|
|
|
|
void CmndPulsetime(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PULSETIMERS)) {
|
|
uint32_t items = 1;
|
|
if (!XdrvMailbox.usridx && !XdrvMailbox.data_len) {
|
|
items = MAX_PULSETIMERS;
|
|
} else {
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 65536)) {
|
|
Settings.pulse_timer[XdrvMailbox.index -1] = XdrvMailbox.payload; // 0 - 65535
|
|
SetPulseTimer(XdrvMailbox.index -1, XdrvMailbox.payload);
|
|
}
|
|
}
|
|
mqtt_data[0] = '\0';
|
|
for (uint32_t i = 0; i < items; i++) {
|
|
uint32_t index = (1 == items) ? XdrvMailbox.index : i +1;
|
|
ResponseAppend_P(PSTR("%c\"%s%d\":{\"" D_JSON_SET "\":%d,\"" D_JSON_REMAINING "\":%d}"),
|
|
(i) ? ',' : '{',
|
|
XdrvMailbox.command, index,
|
|
Settings.pulse_timer[index -1], GetPulseTimer(index -1));
|
|
}
|
|
ResponseJsonEnd();
|
|
}
|
|
}
|
|
|
|
void CmndBlinktime(void)
|
|
{
|
|
if ((XdrvMailbox.payload > 1) && (XdrvMailbox.payload <= 3600)) {
|
|
Settings.blinktime = XdrvMailbox.payload;
|
|
if (blink_timer > 0) { blink_timer = millis() + (100 * XdrvMailbox.payload); }
|
|
}
|
|
ResponseCmndNumber(Settings.blinktime);
|
|
}
|
|
|
|
void CmndBlinkcount(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 65536)) {
|
|
Settings.blinkcount = XdrvMailbox.payload; // 0 - 65535
|
|
if (blink_counter) { blink_counter = Settings.blinkcount *2; }
|
|
}
|
|
ResponseCmndNumber(Settings.blinkcount);
|
|
}
|
|
|
|
void CmndSavedata(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3600)) {
|
|
Settings.save_data = XdrvMailbox.payload;
|
|
save_data_counter = Settings.save_data;
|
|
}
|
|
SettingsSaveAll();
|
|
char stemp1[TOPSZ];
|
|
if (Settings.save_data > 1) {
|
|
snprintf_P(stemp1, sizeof(stemp1), PSTR(D_JSON_EVERY " %d " D_UNIT_SECOND), Settings.save_data);
|
|
}
|
|
ResponseCmndChar((Settings.save_data > 1) ? stemp1 : GetStateText(Settings.save_data));
|
|
}
|
|
|
|
void CmndSetoption(void)
|
|
{
|
|
snprintf_P(XdrvMailbox.command, CMDSZ, PSTR(D_CMND_SETOPTION)); // Rename result shortcut command SO to SetOption
|
|
|
|
if (XdrvMailbox.index < 114) {
|
|
uint32_t ptype;
|
|
uint32_t pindex;
|
|
if (XdrvMailbox.index <= 31) { // SetOption0 .. 31 = Settings.flag
|
|
ptype = 2;
|
|
pindex = XdrvMailbox.index; // 0 .. 31
|
|
}
|
|
else if (XdrvMailbox.index <= 49) { // SetOption32 .. 49 = Settings.param
|
|
ptype = 1;
|
|
pindex = XdrvMailbox.index -32; // 0 .. 17 (= PARAM8_SIZE -1)
|
|
}
|
|
else if (XdrvMailbox.index <= 81) { // SetOption50 .. 81 = Settings.flag3
|
|
ptype = 3;
|
|
pindex = XdrvMailbox.index -50; // 0 .. 31
|
|
}
|
|
else { // SetOption82 .. 113 = Settings.flag4
|
|
ptype = 4;
|
|
pindex = XdrvMailbox.index -82; // 0 .. 31
|
|
}
|
|
|
|
if (XdrvMailbox.payload >= 0) {
|
|
if (1 == ptype) { // SetOption32 .. 49
|
|
uint32_t param_low = 0;
|
|
uint32_t param_high = 255;
|
|
switch (pindex) {
|
|
case P_HOLD_TIME:
|
|
case P_MAX_POWER_RETRY:
|
|
param_low = 1;
|
|
param_high = 250;
|
|
break;
|
|
}
|
|
if ((XdrvMailbox.payload >= param_low) && (XdrvMailbox.payload <= param_high)) {
|
|
Settings.param[pindex] = XdrvMailbox.payload;
|
|
#ifdef USE_LIGHT
|
|
if (P_RGB_REMAP == pindex) {
|
|
LightUpdateColorMapping();
|
|
restart_flag = 2; // SetOption37 needs a reboot in most cases
|
|
}
|
|
#endif
|
|
#if (defined(USE_IR_REMOTE) && defined(USE_IR_RECEIVE)) || defined(USE_IR_REMOTE_FULL)
|
|
if (P_IR_UNKNOW_THRESHOLD == pindex) {
|
|
IrReceiveUpdateThreshold();
|
|
}
|
|
#endif
|
|
} else {
|
|
ptype = 99; // Command Error
|
|
}
|
|
} else {
|
|
if (XdrvMailbox.payload <= 1) {
|
|
if (2 == ptype) { // SetOption0 .. 31
|
|
switch (pindex) {
|
|
case 5: // mqtt_power_retain (CMND_POWERRETAIN)
|
|
case 6: // mqtt_button_retain (CMND_BUTTONRETAIN)
|
|
case 7: // mqtt_switch_retain (CMND_SWITCHRETAIN)
|
|
case 9: // mqtt_sensor_retain (CMND_SENSORRETAIN)
|
|
case 14: // interlock (CMND_INTERLOCK)
|
|
case 22: // mqtt_serial (SerialSend and SerialLog)
|
|
case 23: // mqtt_serial_raw (SerialSend)
|
|
case 25: // knx_enabled (Web config)
|
|
case 27: // knx_enable_enhancement (Web config)
|
|
ptype = 99; // Command Error
|
|
break; // Ignore command SetOption
|
|
case 3: // mqtt
|
|
case 15: // pwm_control
|
|
restart_flag = 2;
|
|
default:
|
|
bitWrite(Settings.flag.data, pindex, XdrvMailbox.payload);
|
|
}
|
|
if (12 == pindex) { // stop_flash_rotate
|
|
stop_flash_rotate = XdrvMailbox.payload;
|
|
SettingsSave(2);
|
|
}
|
|
#ifdef USE_HOME_ASSISTANT
|
|
if ((19 == pindex) || (30 == pindex)) {
|
|
HAssDiscover(); // Delayed execution to provide enough resources during hass_discovery or hass_light
|
|
}
|
|
#endif // USE_HOME_ASSISTANT
|
|
}
|
|
else if (3 == ptype) { // SetOption50 .. 81
|
|
bitWrite(Settings.flag3.data, pindex, XdrvMailbox.payload);
|
|
switch (pindex) {
|
|
case 5: // SetOption55
|
|
if (0 == XdrvMailbox.payload) {
|
|
restart_flag = 2; // Disable mDNS needs restart
|
|
}
|
|
break;
|
|
case 10: // SetOption60 enable or disable traditional sleep
|
|
WiFiSetSleepMode(); // Update WiFi sleep mode accordingly
|
|
break;
|
|
case 18: // SetOption68 for multi-channel PWM, requires a reboot
|
|
case 25: // SetOption75 grouptopic change
|
|
restart_flag = 2;
|
|
break;
|
|
}
|
|
}
|
|
else if (4 == ptype) { // SetOption82 .. 113
|
|
bitWrite(Settings.flag4.data, pindex, XdrvMailbox.payload);
|
|
switch (pindex) {
|
|
case 3: // SetOption85 - Enable Device Groups
|
|
case 6: // SetOption88 - PWM Dimmer Buttons control remote devices
|
|
restart_flag = 2;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
ptype = 99; // Command Error
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ptype < 99) {
|
|
if (1 == ptype) {
|
|
ResponseCmndIdxNumber(Settings.param[pindex]);
|
|
} else {
|
|
uint32_t flag = Settings.flag.data;
|
|
if (3 == ptype) {
|
|
flag = Settings.flag3.data;
|
|
}
|
|
else if (4 == ptype) {
|
|
flag = Settings.flag4.data;
|
|
}
|
|
ResponseCmndIdxChar(GetStateText(bitRead(flag, pindex)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmndTemperatureResolution(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
|
|
Settings.flag2.temperature_resolution = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.temperature_resolution);
|
|
}
|
|
|
|
void CmndHumidityResolution(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
|
|
Settings.flag2.humidity_resolution = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.humidity_resolution);
|
|
}
|
|
|
|
void CmndPressureResolution(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
|
|
Settings.flag2.pressure_resolution = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.pressure_resolution);
|
|
}
|
|
|
|
void CmndPowerResolution(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
|
|
Settings.flag2.wattage_resolution = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.wattage_resolution);
|
|
}
|
|
|
|
void CmndVoltageResolution(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
|
|
Settings.flag2.voltage_resolution = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.voltage_resolution);
|
|
}
|
|
|
|
void CmndFrequencyResolution(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
|
|
Settings.flag2.frequency_resolution = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.frequency_resolution);
|
|
}
|
|
|
|
void CmndCurrentResolution(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
|
|
Settings.flag2.current_resolution = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.current_resolution);
|
|
}
|
|
|
|
void CmndEnergyResolution(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 5)) {
|
|
Settings.flag2.energy_resolution = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.energy_resolution);
|
|
}
|
|
|
|
void CmndWeightResolution(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
|
|
Settings.flag2.weight_resolution = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.weight_resolution);
|
|
}
|
|
|
|
void CmndSpeedUnit(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6)) {
|
|
Settings.flag2.speed_conversion = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.flag2.speed_conversion);
|
|
}
|
|
|
|
void CmndModule(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= MAXMODULE)) {
|
|
bool present = false;
|
|
if (0 == XdrvMailbox.payload) {
|
|
XdrvMailbox.payload = USER_MODULE;
|
|
present = true;
|
|
} else {
|
|
XdrvMailbox.payload--;
|
|
present = ValidTemplateModule(XdrvMailbox.payload);
|
|
}
|
|
if (present) {
|
|
Settings.last_module = Settings.module;
|
|
Settings.module = XdrvMailbox.payload;
|
|
SetModuleType();
|
|
if (Settings.last_module != XdrvMailbox.payload) {
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
|
|
Settings.my_gp.io[i] = GPIO_NONE;
|
|
}
|
|
}
|
|
restart_flag = 2;
|
|
}
|
|
}
|
|
Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, ModuleNr(), ModuleName().c_str());
|
|
}
|
|
|
|
void CmndModules(void)
|
|
{
|
|
uint32_t midx = USER_MODULE;
|
|
uint32_t lines = 1;
|
|
bool jsflg = false;
|
|
for (uint32_t i = 0; i <= sizeof(kModuleNiceList); i++) {
|
|
if (i > 0) { midx = pgm_read_byte(kModuleNiceList + i -1); }
|
|
if (!jsflg) {
|
|
Response_P(PSTR("{\"" D_CMND_MODULES "%d\":{"), lines);
|
|
} else {
|
|
ResponseAppend_P(PSTR(","));
|
|
}
|
|
jsflg = true;
|
|
uint32_t j = i ? midx +1 : 0;
|
|
if ((ResponseAppend_P(PSTR("\"%d\":\"%s\""), j, AnyModuleName(midx).c_str()) > (LOGSZ - TOPSZ)) || (i == sizeof(kModuleNiceList))) {
|
|
ResponseJsonEndEnd();
|
|
MqttPublishPrefixTopic_P(RESULT_OR_STAT, XdrvMailbox.command);
|
|
jsflg = false;
|
|
lines++;
|
|
}
|
|
}
|
|
mqtt_data[0] = '\0';
|
|
}
|
|
|
|
void CmndGpio(void)
|
|
{
|
|
if (XdrvMailbox.index < ARRAY_SIZE(Settings.my_gp.io)) {
|
|
myio cmodule;
|
|
ModuleGpios(&cmodule);
|
|
if (ValidGPIO(XdrvMailbox.index, cmodule.io[XdrvMailbox.index]) && (XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < AGPIO(GPIO_SENSOR_END))) {
|
|
bool present = false;
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(kGpioNiceList); i++) {
|
|
#ifdef ESP8266
|
|
uint32_t midx = pgm_read_byte(kGpioNiceList + i);
|
|
if (midx == XdrvMailbox.payload) {
|
|
present = true;
|
|
break;
|
|
}
|
|
#else // ESP32
|
|
uint32_t midx = pgm_read_word(kGpioNiceList + i);
|
|
if ((XdrvMailbox.payload >= (midx & 0xFFE0)) && (XdrvMailbox.payload < midx)) {
|
|
present = true;
|
|
break;
|
|
}
|
|
#endif // ESP8266 - ESP32
|
|
}
|
|
if (present) {
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
|
|
if (ValidGPIO(i, cmodule.io[i]) && (Settings.my_gp.io[i] == XdrvMailbox.payload)) {
|
|
Settings.my_gp.io[i] = GPIO_NONE;
|
|
}
|
|
}
|
|
Settings.my_gp.io[XdrvMailbox.index] = XdrvMailbox.payload;
|
|
restart_flag = 2;
|
|
}
|
|
}
|
|
Response_P(PSTR("{"));
|
|
bool jsflg = false;
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
|
|
if (ValidGPIO(i, cmodule.io[i]) || ((AGPIO(GPIO_USER) == XdrvMailbox.payload) && !FlashPin(i))) {
|
|
if (jsflg) { ResponseAppend_P(PSTR(",")); }
|
|
jsflg = true;
|
|
uint32_t sensor_type = Settings.my_gp.io[i];
|
|
if (!ValidGPIO(i, cmodule.io[i])) {
|
|
sensor_type = cmodule.io[i];
|
|
if (AGPIO(GPIO_USER) == sensor_type) { // A user GPIO equals a not connected (=GPIO_NONE) GPIO here
|
|
sensor_type = GPIO_NONE;
|
|
}
|
|
}
|
|
char sindex[4] = { 0 };
|
|
#ifdef ESP8266
|
|
uint32_t sensor_name_idx = sensor_type;
|
|
#else // ESP32
|
|
uint32_t sensor_name_idx = sensor_type >> 5;
|
|
uint32_t nice_list_search = sensor_type & 0xFFE0;
|
|
for (uint32_t j = 0; j < ARRAY_SIZE(kGpioNiceList); j++) {
|
|
uint32_t nls_idx = pgm_read_word(kGpioNiceList + j);
|
|
if (((nls_idx & 0xFFE0) == nice_list_search) && ((nls_idx & 0x001F) > 0)) {
|
|
snprintf_P(sindex, sizeof(sindex), PSTR("%d"), (sensor_type & 0x001F) +1);
|
|
break;
|
|
}
|
|
}
|
|
#endif // ESP8266 - ESP32
|
|
const char *sensor_names = kSensorNames;
|
|
if (sensor_name_idx > GPIO_FIX_START) {
|
|
sensor_name_idx = sensor_name_idx - GPIO_FIX_START -1;
|
|
sensor_names = kSensorNamesFixed;
|
|
}
|
|
char stemp1[TOPSZ];
|
|
ResponseAppend_P(PSTR("\"" D_CMND_GPIO "%d\":{\"%d\":\"%s%s\"}"),
|
|
i, sensor_type, GetTextIndexed(stemp1, sizeof(stemp1), sensor_name_idx, sensor_names), sindex);
|
|
}
|
|
}
|
|
if (jsflg) {
|
|
ResponseJsonEnd();
|
|
} else {
|
|
ResponseCmndChar(D_JSON_NOT_SUPPORTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmndGpios(void)
|
|
{
|
|
myio cmodule;
|
|
ModuleGpios(&cmodule);
|
|
uint32_t lines = 1;
|
|
bool jsflg = false;
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(kGpioNiceList); i++) {
|
|
#ifdef ESP8266
|
|
uint32_t midx = pgm_read_byte(kGpioNiceList + i);
|
|
uint32_t ridx = midx;
|
|
#else // ESP32
|
|
uint32_t ridx = pgm_read_word(kGpioNiceList + i) & 0xFFE0;
|
|
uint32_t midx = ridx >> 5;
|
|
#endif // ESP8266 - ESP32
|
|
if ((XdrvMailbox.payload != 255) && GetUsedInModule(midx, cmodule.io)) { continue; }
|
|
if (!jsflg) {
|
|
Response_P(PSTR("{\"" D_CMND_GPIOS "%d\":{"), lines);
|
|
} else {
|
|
ResponseAppend_P(PSTR(","));
|
|
}
|
|
jsflg = true;
|
|
char stemp1[TOPSZ];
|
|
if ((ResponseAppend_P(PSTR("\"%d\":\"%s\""), ridx, GetTextIndexed(stemp1, sizeof(stemp1), midx, kSensorNames)) > (LOGSZ - TOPSZ)) || (i == ARRAY_SIZE(kGpioNiceList) -1)) {
|
|
ResponseJsonEndEnd();
|
|
MqttPublishPrefixTopic_P(RESULT_OR_STAT, XdrvMailbox.command);
|
|
jsflg = false;
|
|
lines++;
|
|
}
|
|
}
|
|
mqtt_data[0] = '\0';
|
|
}
|
|
|
|
void CmndTemplate(void)
|
|
{
|
|
// {"NAME":"Generic","GPIO":[17,254,29,254,7,254,254,254,138,254,139,254,254],"FLAG":1,"BASE":255}
|
|
bool error = false;
|
|
|
|
if (strstr(XdrvMailbox.data, "{") == nullptr) { // If no JSON it must be parameter
|
|
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= MAXMODULE)) {
|
|
XdrvMailbox.payload--;
|
|
if (ValidTemplateModule(XdrvMailbox.payload)) {
|
|
ModuleDefault(XdrvMailbox.payload); // Copy template module
|
|
if (USER_MODULE == Settings.module) { restart_flag = 2; }
|
|
}
|
|
}
|
|
else if (0 == XdrvMailbox.payload) { // Copy current template to user template
|
|
if (Settings.module != USER_MODULE) {
|
|
ModuleDefault(Settings.module);
|
|
}
|
|
}
|
|
else if (255 == XdrvMailbox.payload) { // Copy current module with user configured GPIO
|
|
if (Settings.module != USER_MODULE) {
|
|
ModuleDefault(Settings.module);
|
|
}
|
|
SettingsUpdateText(SET_TEMPLATE_NAME, "Merged");
|
|
uint32_t j = 0;
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
|
|
if (6 == i) { j = 9; }
|
|
if (8 == i) { j = 12; }
|
|
if (my_module.io[j] > GPIO_NONE) {
|
|
Settings.user_template.gp.io[i] = my_module.io[j];
|
|
}
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (JsonTemplate(XdrvMailbox.data)) { // Free 336 bytes StaticJsonBuffer stack space by moving code to function
|
|
if (USER_MODULE == Settings.module) { restart_flag = 2; }
|
|
} else {
|
|
ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON));
|
|
error = true;
|
|
}
|
|
}
|
|
if (!error) { TemplateJson(); }
|
|
}
|
|
|
|
void CmndPwm(void)
|
|
{
|
|
if (pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings.pwm_range) && PinUsed(GPIO_PWM1, XdrvMailbox.index -1)) {
|
|
Settings.pwm_value[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
|
analogWrite(Pin(GPIO_PWM1, XdrvMailbox.index -1), bitRead(pwm_inverted, XdrvMailbox.index -1) ? Settings.pwm_range - XdrvMailbox.payload : XdrvMailbox.payload);
|
|
}
|
|
Response_P(PSTR("{"));
|
|
MqttShowPWMState(); // Render the PWM status to MQTT
|
|
ResponseJsonEnd();
|
|
}
|
|
}
|
|
|
|
void CmndPwmfrequency(void)
|
|
{
|
|
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload >= PWM_MIN) && (XdrvMailbox.payload <= PWM_MAX))) {
|
|
Settings.pwm_frequency = (1 == XdrvMailbox.payload) ? PWM_FREQ : XdrvMailbox.payload;
|
|
#ifdef ESP8266
|
|
analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
|
|
#else
|
|
analogWriteFreqRange(0,Settings.pwm_frequency,Settings.pwm_range);
|
|
#endif
|
|
}
|
|
ResponseCmndNumber(Settings.pwm_frequency);
|
|
}
|
|
|
|
void CmndPwmrange(void)
|
|
{
|
|
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload > 254) && (XdrvMailbox.payload < 1024))) {
|
|
Settings.pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : XdrvMailbox.payload;
|
|
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
|
if (Settings.pwm_value[i] > Settings.pwm_range) {
|
|
Settings.pwm_value[i] = Settings.pwm_range;
|
|
}
|
|
}
|
|
#ifdef ESP8266
|
|
analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h)
|
|
#else
|
|
analogWriteFreqRange(0,Settings.pwm_frequency,Settings.pwm_range);
|
|
#endif
|
|
}
|
|
ResponseCmndNumber(Settings.pwm_range);
|
|
}
|
|
|
|
void CmndButtonDebounce(void)
|
|
{
|
|
if ((XdrvMailbox.payload > 39) && (XdrvMailbox.payload < 1001)) {
|
|
Settings.button_debounce = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.button_debounce);
|
|
}
|
|
|
|
void CmndSwitchDebounce(void)
|
|
{
|
|
if ((XdrvMailbox.payload > 39) && (XdrvMailbox.payload < 1001)) {
|
|
Settings.switch_debounce = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.switch_debounce);
|
|
}
|
|
|
|
void CmndBaudrate(void)
|
|
{
|
|
if (XdrvMailbox.payload >= 300) {
|
|
XdrvMailbox.payload /= 300; // Make it a valid baudrate
|
|
uint32_t baudrate = (XdrvMailbox.payload & 0xFFFF) * 300;
|
|
SetSerialBaudrate(baudrate);
|
|
}
|
|
ResponseCmndNumber(Settings.baudrate * 300);
|
|
}
|
|
|
|
void CmndSerialConfig(void)
|
|
{
|
|
// See TasmotaSerialConfig for possible options
|
|
// SerialConfig 0..23 where 3 equals 8N1
|
|
// SerialConfig 8N1
|
|
|
|
if (XdrvMailbox.data_len > 0) {
|
|
if (XdrvMailbox.data_len < 3) { // Use 0..23 as serial config option
|
|
if ((XdrvMailbox.payload >= TS_SERIAL_5N1) && (XdrvMailbox.payload <= TS_SERIAL_8O2)) {
|
|
SetSerialConfig(XdrvMailbox.payload);
|
|
}
|
|
}
|
|
else if ((XdrvMailbox.payload >= 5) && (XdrvMailbox.payload <= 8)) {
|
|
uint8_t serial_config = XdrvMailbox.payload -5; // Data bits 5, 6, 7 or 8, No parity and 1 stop bit
|
|
|
|
bool valid = true;
|
|
char parity = (XdrvMailbox.data[1] & 0xdf);
|
|
if ('E' == parity) {
|
|
serial_config += 0x08; // Even parity
|
|
}
|
|
else if ('O' == parity) {
|
|
serial_config += 0x10; // Odd parity
|
|
}
|
|
else if ('N' != parity) {
|
|
valid = false;
|
|
}
|
|
|
|
if ('2' == XdrvMailbox.data[2]) {
|
|
serial_config += 0x04; // Stop bits 2
|
|
}
|
|
else if ('1' != XdrvMailbox.data[2]) {
|
|
valid = false;
|
|
}
|
|
|
|
if (valid) {
|
|
SetSerialConfig(serial_config);
|
|
}
|
|
}
|
|
}
|
|
ResponseCmndChar(GetSerialConfig().c_str());
|
|
}
|
|
|
|
void CmndSerialSend(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) {
|
|
SetSeriallog(LOG_LEVEL_NONE);
|
|
Settings.flag.mqtt_serial = 1; // CMND_SERIALSEND and CMND_SERIALLOG
|
|
Settings.flag.mqtt_serial_raw = (XdrvMailbox.index > 3) ? 1 : 0; // CMND_SERIALSEND3
|
|
if (XdrvMailbox.data_len > 0) {
|
|
if (1 == XdrvMailbox.index) {
|
|
Serial.printf("%s\n", XdrvMailbox.data); // "Hello Tiger\n"
|
|
}
|
|
else if (2 == XdrvMailbox.index || 4 == XdrvMailbox.index) {
|
|
for (uint32_t i = 0; i < XdrvMailbox.data_len; i++) {
|
|
Serial.write(XdrvMailbox.data[i]); // "Hello Tiger" or "A0"
|
|
}
|
|
}
|
|
else if (3 == XdrvMailbox.index) {
|
|
uint32_t dat_len = XdrvMailbox.data_len;
|
|
Serial.printf("%s", Unescape(XdrvMailbox.data, &dat_len)); // "Hello\f"
|
|
}
|
|
else if (5 == XdrvMailbox.index) {
|
|
SerialSendRaw(RemoveSpace(XdrvMailbox.data)); // "AA004566" as hex values
|
|
}
|
|
ResponseCmndDone();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmndSerialDelimiter(void)
|
|
{
|
|
if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.payload < 256)) {
|
|
if (XdrvMailbox.payload > 0) {
|
|
Settings.serial_delimiter = XdrvMailbox.payload;
|
|
} else {
|
|
uint32_t dat_len = XdrvMailbox.data_len;
|
|
Unescape(XdrvMailbox.data, &dat_len);
|
|
Settings.serial_delimiter = XdrvMailbox.data[0];
|
|
}
|
|
}
|
|
ResponseCmndNumber(Settings.serial_delimiter);
|
|
}
|
|
|
|
void CmndSyslog(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) {
|
|
SetSyslog(XdrvMailbox.payload);
|
|
}
|
|
Response_P(S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, XdrvMailbox.command, Settings.syslog_level, syslog_level);
|
|
}
|
|
|
|
void CmndLoghost(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
SettingsUpdateText(SET_SYSLOG_HOST, (SC_DEFAULT == Shortcut()) ? SYS_LOG_HOST : XdrvMailbox.data);
|
|
}
|
|
ResponseCmndChar(SettingsText(SET_SYSLOG_HOST));
|
|
}
|
|
|
|
void CmndLogport(void)
|
|
{
|
|
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 65536)) {
|
|
Settings.syslog_port = (1 == XdrvMailbox.payload) ? SYS_LOG_PORT : XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.syslog_port);
|
|
}
|
|
|
|
void CmndIpAddress(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 4)) {
|
|
uint32_t address;
|
|
if (ParseIp(&address, XdrvMailbox.data)) {
|
|
Settings.ip_address[XdrvMailbox.index -1] = address;
|
|
// restart_flag = 2;
|
|
}
|
|
char stemp1[TOPSZ];
|
|
snprintf_P(stemp1, sizeof(stemp1), PSTR(" (%s)"), WiFi.localIP().toString().c_str());
|
|
Response_P(S_JSON_COMMAND_INDEX_SVALUE_SVALUE, XdrvMailbox.command, XdrvMailbox.index, IPAddress(Settings.ip_address[XdrvMailbox.index -1]).toString().c_str(), (1 == XdrvMailbox.index) ? stemp1:"");
|
|
}
|
|
}
|
|
|
|
void CmndNtpServer(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_NTP_SERVERS)) {
|
|
if (!XdrvMailbox.usridx) {
|
|
ResponseCmndAll(SET_NTPSERVER1, MAX_NTP_SERVERS);
|
|
} else {
|
|
uint32_t ntp_server = SET_NTPSERVER1 + XdrvMailbox.index -1;
|
|
if (XdrvMailbox.data_len > 0) {
|
|
SettingsUpdateText(ntp_server,
|
|
(SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? (1 == XdrvMailbox.index) ? PSTR(NTP_SERVER1) : (2 == XdrvMailbox.index) ? PSTR(NTP_SERVER2) : PSTR(NTP_SERVER3) : XdrvMailbox.data);
|
|
SettingsUpdateText(ntp_server, ReplaceCommaWithDot(SettingsText(ntp_server)));
|
|
// restart_flag = 2; // Issue #3890
|
|
ntp_force_sync = true;
|
|
}
|
|
ResponseCmndIdxChar(SettingsText(ntp_server));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmndAp(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {
|
|
switch (XdrvMailbox.payload) {
|
|
case 0: // Toggle
|
|
Settings.sta_active ^= 1;
|
|
break;
|
|
case 1: // AP1
|
|
case 2: // AP2
|
|
Settings.sta_active = XdrvMailbox.payload -1;
|
|
}
|
|
restart_flag = 2;
|
|
}
|
|
Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active));
|
|
}
|
|
|
|
void CmndSsid(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SSIDS)) {
|
|
if (!XdrvMailbox.usridx) {
|
|
ResponseCmndAll(SET_STASSID1, MAX_SSIDS);
|
|
} else {
|
|
if (XdrvMailbox.data_len > 0) {
|
|
SettingsUpdateText(SET_STASSID1 + XdrvMailbox.index -1,
|
|
(SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? (1 == XdrvMailbox.index) ? STA_SSID1 : STA_SSID2 : XdrvMailbox.data);
|
|
Settings.sta_active = XdrvMailbox.index -1;
|
|
restart_flag = 2;
|
|
}
|
|
ResponseCmndIdxChar(SettingsText(SET_STASSID1 + XdrvMailbox.index -1));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmndPassword(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) {
|
|
if ((XdrvMailbox.data_len > 4) || (SC_CLEAR == Shortcut()) || (SC_DEFAULT == Shortcut())) {
|
|
SettingsUpdateText(SET_STAPWD1 + XdrvMailbox.index -1,
|
|
(SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? (1 == XdrvMailbox.index) ? STA_PASS1 : STA_PASS2 : XdrvMailbox.data);
|
|
Settings.sta_active = XdrvMailbox.index -1;
|
|
restart_flag = 2;
|
|
ResponseCmndIdxChar(SettingsText(SET_STAPWD1 + XdrvMailbox.index -1));
|
|
} else {
|
|
Response_P(S_JSON_COMMAND_INDEX_ASTERISK, XdrvMailbox.command, XdrvMailbox.index);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmndHostname(void)
|
|
{
|
|
if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) {
|
|
SettingsUpdateText(SET_HOSTNAME, (SC_DEFAULT == Shortcut()) ? WIFI_HOSTNAME : XdrvMailbox.data);
|
|
if (strstr(SettingsText(SET_HOSTNAME), "%") != nullptr) {
|
|
SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME);
|
|
}
|
|
restart_flag = 2;
|
|
}
|
|
ResponseCmndChar(SettingsText(SET_HOSTNAME));
|
|
}
|
|
|
|
void CmndWifiConfig(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= WIFI_RESTART) && (XdrvMailbox.payload < MAX_WIFI_OPTION)) {
|
|
if ((EX_WIFI_SMARTCONFIG == XdrvMailbox.payload) || (EX_WIFI_WPSCONFIG == XdrvMailbox.payload)) {
|
|
XdrvMailbox.payload = WIFI_MANAGER;
|
|
}
|
|
Settings.sta_config = XdrvMailbox.payload;
|
|
wifi_state_flag = Settings.sta_config;
|
|
if (WifiState() > WIFI_RESTART) {
|
|
restart_flag = 2;
|
|
}
|
|
}
|
|
char stemp1[TOPSZ];
|
|
Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, Settings.sta_config, GetTextIndexed(stemp1, sizeof(stemp1), Settings.sta_config, kWifiConfig));
|
|
}
|
|
|
|
void CmndDevicename(void)
|
|
{
|
|
if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) {
|
|
SettingsUpdateText(SET_DEVICENAME, ('"' == XdrvMailbox.data[0]) ? "" : (SC_DEFAULT == Shortcut()) ? SettingsText(SET_FRIENDLYNAME1) : XdrvMailbox.data);
|
|
}
|
|
ResponseCmndChar(SettingsText(SET_DEVICENAME));
|
|
}
|
|
|
|
void CmndFriendlyname(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_FRIENDLYNAMES)) {
|
|
if (!XdrvMailbox.usridx && !XdrvMailbox.data_len) {
|
|
ResponseCmndAll(SET_FRIENDLYNAME1, MAX_FRIENDLYNAMES);
|
|
} else {
|
|
if (XdrvMailbox.data_len > 0) {
|
|
char stemp1[TOPSZ];
|
|
if (1 == XdrvMailbox.index) {
|
|
snprintf_P(stemp1, sizeof(stemp1), PSTR(FRIENDLY_NAME));
|
|
} else {
|
|
snprintf_P(stemp1, sizeof(stemp1), PSTR(FRIENDLY_NAME "%d"), XdrvMailbox.index);
|
|
}
|
|
SettingsUpdateText(SET_FRIENDLYNAME1 + XdrvMailbox.index -1, ('"' == XdrvMailbox.data[0]) ? "" : (SC_DEFAULT == Shortcut()) ? stemp1 : XdrvMailbox.data);
|
|
}
|
|
ResponseCmndIdxChar(SettingsText(SET_FRIENDLYNAME1 + XdrvMailbox.index -1));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmndSwitchMode(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SWITCHES)) {
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < MAX_SWITCH_OPTION)) {
|
|
Settings.switchmode[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndIdxNumber(Settings.switchmode[XdrvMailbox.index-1]);
|
|
}
|
|
}
|
|
|
|
void CmndInterlock(void)
|
|
{
|
|
// Interlock 0 - Off, Interlock 1 - On, Interlock 1,2 3,4 5,6,7
|
|
uint32_t max_relays = devices_present;
|
|
if (light_type) { max_relays--; }
|
|
if (max_relays > sizeof(Settings.interlock[0]) * 8) { max_relays = sizeof(Settings.interlock[0]) * 8; }
|
|
if (max_relays > 1) { // Only interlock with more than 1 relay
|
|
if (XdrvMailbox.data_len > 0) {
|
|
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Interlock entry
|
|
for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) { Settings.interlock[i] = 0; } // Reset current interlocks
|
|
char *group;
|
|
char *q;
|
|
uint32_t group_index = 0;
|
|
power_t relay_mask = 0;
|
|
for (group = strtok_r(XdrvMailbox.data, " ", &q); group && group_index < MAX_INTERLOCKS; group = strtok_r(nullptr, " ", &q)) {
|
|
char *str;
|
|
char *p;
|
|
for (str = strtok_r(group, ",", &p); str; str = strtok_r(nullptr, ",", &p)) {
|
|
int pbit = atoi(str);
|
|
if ((pbit > 0) && (pbit <= max_relays)) { // Only valid relays
|
|
pbit--;
|
|
if (!bitRead(relay_mask, pbit)) { // Only relay once
|
|
bitSet(relay_mask, pbit);
|
|
bitSet(Settings.interlock[group_index], pbit);
|
|
}
|
|
}
|
|
}
|
|
group_index++;
|
|
}
|
|
for (uint32_t i = 0; i < group_index; i++) {
|
|
uint32_t minimal_bits = 0;
|
|
for (uint32_t j = 0; j < max_relays; j++) {
|
|
if (bitRead(Settings.interlock[i], j)) { minimal_bits++; }
|
|
}
|
|
if (minimal_bits < 2) { Settings.interlock[i] = 0; } // Discard single relay as interlock
|
|
}
|
|
} else {
|
|
Settings.flag.interlock = XdrvMailbox.payload &1; // CMND_INTERLOCK - Enable/disable interlock
|
|
if (Settings.flag.interlock) {
|
|
SetDevicePower(power, SRC_IGNORE); // Remove multiple relays if set
|
|
}
|
|
}
|
|
#ifdef USE_SHUTTER
|
|
if (Settings.flag3.shutter_mode) { // SetOption80 - Enable shutter support
|
|
ShutterInit(); // to update shutter mode
|
|
}
|
|
#endif // USE_SHUTTER
|
|
}
|
|
Response_P(PSTR("{\"" D_CMND_INTERLOCK "\":\"%s\",\"" D_JSON_GROUPS "\":\""), GetStateText(Settings.flag.interlock));
|
|
uint32_t anygroup = 0;
|
|
for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) {
|
|
if (Settings.interlock[i]) {
|
|
anygroup++;
|
|
ResponseAppend_P(PSTR("%s"), (anygroup > 1) ? " " : "");
|
|
uint32_t anybit = 0;
|
|
power_t mask = 1;
|
|
for (uint32_t j = 0; j < max_relays; j++) {
|
|
if (Settings.interlock[i] & mask) {
|
|
anybit++;
|
|
ResponseAppend_P(PSTR("%s%d"), (anybit > 1) ? "," : "", j +1);
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
}
|
|
}
|
|
if (!anygroup) {
|
|
for (uint32_t j = 1; j <= max_relays; j++) {
|
|
ResponseAppend_P(PSTR("%s%d"), (j > 1) ? "," : "", j);
|
|
}
|
|
}
|
|
ResponseAppend_P(PSTR("\"}"));
|
|
} else {
|
|
Settings.flag.interlock = 0; // CMND_INTERLOCK - Enable/disable interlock
|
|
ResponseCmndStateText(Settings.flag.interlock);
|
|
}
|
|
}
|
|
|
|
void CmndTeleperiod(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
|
|
Settings.tele_period = (1 == XdrvMailbox.payload) ? TELE_PERIOD : XdrvMailbox.payload;
|
|
if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) Settings.tele_period = 10; // Do not allow periods < 10 seconds
|
|
// tele_period = Settings.tele_period;
|
|
}
|
|
tele_period = Settings.tele_period; // Show teleperiod data also on empty command
|
|
ResponseCmndNumber(Settings.tele_period);
|
|
}
|
|
|
|
void CmndReset(void)
|
|
{
|
|
switch (XdrvMailbox.payload) {
|
|
case 1:
|
|
restart_flag = 211;
|
|
ResponseCmndChar(PSTR(D_JSON_RESET_AND_RESTARTING));
|
|
break;
|
|
case 2 ... 6:
|
|
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;
|
|
Settings.bootcount_reset_time = 0;
|
|
ResponseCmndDone();
|
|
break;
|
|
default:
|
|
ResponseCmndChar(PSTR(D_JSON_ONE_TO_RESET));
|
|
}
|
|
}
|
|
|
|
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) {
|
|
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);
|
|
}
|
|
}
|
|
mqtt_data[0] = '\0';
|
|
ResponseAppendTimeFormat(format);
|
|
ResponseJsonEnd();
|
|
}
|
|
|
|
void CmndTimezone(void)
|
|
{
|
|
if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.payload >= -13)) {
|
|
Settings.timezone = XdrvMailbox.payload;
|
|
Settings.timezone_minutes = 0;
|
|
if (XdrvMailbox.payload < 15) {
|
|
char *p = strtok (XdrvMailbox.data, ":");
|
|
if (p) {
|
|
p = strtok (nullptr, ":");
|
|
if (p) {
|
|
Settings.timezone_minutes = strtol(p, nullptr, 10);
|
|
if (Settings.timezone_minutes > 59) { Settings.timezone_minutes = 59; }
|
|
}
|
|
}
|
|
} else {
|
|
Settings.timezone = 99;
|
|
}
|
|
ntp_force_sync = true;
|
|
}
|
|
if (99 == Settings.timezone) {
|
|
ResponseCmndNumber(Settings.timezone);
|
|
} else {
|
|
char stemp1[TOPSZ];
|
|
snprintf_P(stemp1, sizeof(stemp1), PSTR("%+03d:%02d"), Settings.timezone, Settings.timezone_minutes);
|
|
ResponseCmndChar(stemp1);
|
|
}
|
|
}
|
|
|
|
void CmndTimeStdDst(uint32_t ts)
|
|
{
|
|
// TimeStd 0/1, 0/1/2/3/4, 1..12, 1..7, 0..23, +/-780
|
|
if (XdrvMailbox.data_len > 0) {
|
|
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry
|
|
uint32_t tpos = 0; // Parameter index
|
|
int value = 0;
|
|
char *p = XdrvMailbox.data; // Parameters like "1, 2,3 , 4 ,5, -120" or ",,,,,+240"
|
|
char *q = p; // Value entered flag
|
|
while (p && (tpos < 7)) {
|
|
if (p > q) { // Any value entered
|
|
if (1 == tpos) { Settings.tflag[ts].hemis = value &1; }
|
|
if (2 == tpos) { Settings.tflag[ts].week = (value < 0) ? 0 : (value > 4) ? 4 : value; }
|
|
if (3 == tpos) { Settings.tflag[ts].month = (value < 1) ? 1 : (value > 12) ? 12 : value; }
|
|
if (4 == tpos) { Settings.tflag[ts].dow = (value < 1) ? 1 : (value > 7) ? 7 : value; }
|
|
if (5 == tpos) { Settings.tflag[ts].hour = (value < 0) ? 0 : (value > 23) ? 23 : value; }
|
|
if (6 == tpos) { Settings.toffset[ts] = (value < -900) ? -900 : (value > 900) ? 900 : value; }
|
|
}
|
|
p = Trim(p); // Skip spaces
|
|
if (tpos && (*p == ',')) { p++; } // Skip separator
|
|
p = Trim(p); // Skip spaces
|
|
q = p; // Reset any value entered flag
|
|
value = strtol(p, &p, 10);
|
|
tpos++; // Next parameter
|
|
}
|
|
ntp_force_sync = true;
|
|
} else {
|
|
if (0 == XdrvMailbox.payload) {
|
|
if (0 == ts) {
|
|
SettingsResetStd();
|
|
} else {
|
|
SettingsResetDst();
|
|
}
|
|
}
|
|
ntp_force_sync = true;
|
|
}
|
|
}
|
|
Response_P(PSTR("{\"%s\":{\"Hemisphere\":%d,\"Week\":%d,\"Month\":%d,\"Day\":%d,\"Hour\":%d,\"Offset\":%d}}"),
|
|
XdrvMailbox.command, Settings.tflag[ts].hemis, Settings.tflag[ts].week, Settings.tflag[ts].month, Settings.tflag[ts].dow, Settings.tflag[ts].hour, Settings.toffset[ts]);
|
|
}
|
|
|
|
void CmndTimeStd(void)
|
|
{
|
|
CmndTimeStdDst(0);
|
|
}
|
|
|
|
void CmndTimeDst(void)
|
|
{
|
|
CmndTimeStdDst(1);
|
|
}
|
|
|
|
void CmndAltitude(void)
|
|
{
|
|
if ((XdrvMailbox.data_len > 0) && ((XdrvMailbox.payload >= -30000) && (XdrvMailbox.payload <= 30000))) {
|
|
Settings.altitude = XdrvMailbox.payload;
|
|
}
|
|
ResponseCmndNumber(Settings.altitude);
|
|
}
|
|
|
|
void CmndLedPower(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_LEDS)) {
|
|
if (!PinUsed(GPIO_LEDLNK)) { XdrvMailbox.index = 1; }
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {
|
|
Settings.ledstate &= 8; // Disable power control
|
|
uint32_t mask = 1 << (XdrvMailbox.index -1); // Led to control
|
|
switch (XdrvMailbox.payload) {
|
|
case 0: // Off
|
|
led_power &= (0xFF ^ mask);
|
|
Settings.ledstate = 0;
|
|
break;
|
|
case 1: // On
|
|
led_power |= mask;
|
|
Settings.ledstate = 8;
|
|
break;
|
|
case 2: // Toggle
|
|
led_power ^= mask;
|
|
Settings.ledstate ^= 8;
|
|
break;
|
|
}
|
|
blinks = 0;
|
|
if (!PinUsed(GPIO_LEDLNK)) {
|
|
SetLedPower(Settings.ledstate &8);
|
|
} else {
|
|
SetLedPowerIdx(XdrvMailbox.index -1, (led_power & mask));
|
|
}
|
|
}
|
|
bool state = bitRead(led_power, XdrvMailbox.index -1);
|
|
if (!PinUsed(GPIO_LEDLNK)) {
|
|
state = bitRead(Settings.ledstate, 3);
|
|
}
|
|
ResponseCmndIdxChar(GetStateText(state));
|
|
}
|
|
}
|
|
|
|
void CmndLedState(void)
|
|
{
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < MAX_LED_OPTION)) {
|
|
Settings.ledstate = XdrvMailbox.payload;
|
|
if (!Settings.ledstate) {
|
|
SetLedPowerAll(0);
|
|
SetLedLink(0);
|
|
}
|
|
}
|
|
ResponseCmndNumber(Settings.ledstate);
|
|
}
|
|
|
|
void CmndLedMask(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
Settings.ledmask = XdrvMailbox.payload;
|
|
}
|
|
char stemp1[TOPSZ];
|
|
snprintf_P(stemp1, sizeof(stemp1), PSTR("%d (0x%04X)"), Settings.ledmask, Settings.ledmask);
|
|
ResponseCmndChar(stemp1);
|
|
}
|
|
|
|
void CmndWifiPower(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
Settings.wifi_output_power = (uint8_t)(CharToFloat(XdrvMailbox.data) * 10);
|
|
if (Settings.wifi_output_power > 205) {
|
|
Settings.wifi_output_power = 205;
|
|
}
|
|
WifiSetOutputPower();
|
|
}
|
|
ResponseCmndChar(WifiGetOutputPower().c_str());
|
|
}
|
|
|
|
#ifdef USE_I2C
|
|
void CmndI2cScan(void)
|
|
{
|
|
if (i2c_flg) {
|
|
I2cScan(mqtt_data, sizeof(mqtt_data));
|
|
}
|
|
}
|
|
|
|
void CmndI2cDriver(void)
|
|
{
|
|
if (XdrvMailbox.index < MAX_I2C_DRIVERS) {
|
|
if (XdrvMailbox.payload >= 0) {
|
|
bitWrite(Settings.i2c_drivers[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1);
|
|
restart_flag = 2;
|
|
}
|
|
}
|
|
Response_P(PSTR("{\"" D_CMND_I2CDRIVER "\":"));
|
|
I2cDriverState();
|
|
ResponseJsonEnd();
|
|
}
|
|
#endif // USE_I2C
|
|
|
|
#ifdef USE_DEVICE_GROUPS
|
|
void CmndDevGroupName(void)
|
|
{
|
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DEV_GROUP_NAMES)) {
|
|
if (XdrvMailbox.data_len > 0) {
|
|
if (XdrvMailbox.data_len > TOPSZ)
|
|
XdrvMailbox.data[TOPSZ - 1] = 0;
|
|
else if (1 == XdrvMailbox.data_len && ('"' == XdrvMailbox.data[0] || '0' == XdrvMailbox.data[0]))
|
|
XdrvMailbox.data[0] = 0;
|
|
SettingsUpdateText(SET_DEV_GROUP_NAME1 + XdrvMailbox.index - 1, XdrvMailbox.data);
|
|
restart_flag = 2;
|
|
}
|
|
ResponseCmndAll(SET_DEV_GROUP_NAME1, MAX_DEV_GROUP_NAMES);
|
|
}
|
|
}
|
|
|
|
#ifdef USE_DEVICE_GROUPS_SEND
|
|
void CmndDevGroupSend(void)
|
|
{
|
|
uint8_t device_group_index = (XdrvMailbox.usridx ? XdrvMailbox.index - 1 : 0);
|
|
if (device_group_index < device_group_count) {
|
|
if (!_SendDeviceGroupMessage(device_group_index, DGR_MSGTYPE_UPDATE_COMMAND)) {
|
|
ResponseCmndChar(XdrvMailbox.data);
|
|
}
|
|
}
|
|
}
|
|
#endif // USE_DEVICE_GROUPS_SEND
|
|
|
|
void CmndDevGroupShare(void)
|
|
{
|
|
uint32_t parm[2] = { Settings.device_group_share_in, Settings.device_group_share_out };
|
|
ParseParameters(2, parm);
|
|
Settings.device_group_share_in = parm[0];
|
|
Settings.device_group_share_out = parm[1];
|
|
Response_P(PSTR("{\"" D_CMND_DEVGROUP_SHARE "\":{\"In\":\"%X\",\"Out\":\"%X\"}}"), Settings.device_group_share_in, Settings.device_group_share_out);
|
|
}
|
|
|
|
void CmndDevGroupStatus(void)
|
|
{
|
|
DeviceGroupStatus((XdrvMailbox.usridx ? XdrvMailbox.index - 1 : 0));
|
|
}
|
|
#endif // USE_DEVICE_GROUPS
|
|
|
|
void CmndSensor(void)
|
|
{
|
|
XsnsCall(FUNC_COMMAND_SENSOR);
|
|
}
|
|
|
|
void CmndDriver(void)
|
|
{
|
|
XdrvCall(FUNC_COMMAND_DRIVER);
|
|
}
|
|
|
|
void CmndSetLedPwmOff(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
if (XdrvMailbox.payload < 0) {
|
|
Settings.ledpwm_off = 0;
|
|
} else if (XdrvMailbox.payload > Settings.pwm_range) {
|
|
Settings.ledpwm_off = Settings.pwm_range;
|
|
} else {
|
|
Settings.ledpwm_off = XdrvMailbox.payload;
|
|
}
|
|
UpdateLedPowerAll();
|
|
}
|
|
ResponseCmndNumber(Settings.ledpwm_off);
|
|
}
|
|
|
|
void CmndSetLedPwmOn(void)
|
|
{
|
|
if (XdrvMailbox.data_len > 0) {
|
|
if (XdrvMailbox.payload < 0) {
|
|
Settings.ledpwm_on = 0;
|
|
} else if (XdrvMailbox.payload > Settings.pwm_range) {
|
|
Settings.ledpwm_on = Settings.pwm_range;
|
|
} else {
|
|
Settings.ledpwm_on = XdrvMailbox.payload;
|
|
}
|
|
UpdateLedPowerAll();
|
|
}
|
|
ResponseCmndNumber(Settings.ledpwm_on);
|
|
}
|