commands are case insensetive now

new commands for HVAC/Thermostates
core logic fixes: Group channel logic& stats
RGBx color change cmd will turn chan on
Modbus fm driver shutdown on alarm deadlock fixed
hsv bit flag in channels RAM profile added
MQTT send empty command for OH fixed
ON for thermostat causes HEAT string to stat topic (to be compatible 
with homekit & home assistant)
This commit is contained in:
2019-08-21 23:20:43 +03:00
parent a001bd9e35
commit 90965aad85
3 changed files with 79 additions and 29 deletions

View File

@@ -35,24 +35,26 @@ e-mail anklimov@gmail.com
#include "modules/out_spiled.h" #include "modules/out_spiled.h"
const char ON_P[] PROGMEM = "ON"; const char ON_P[] PROGMEM = "ON";
const char OFF_P[] PROGMEM = "OFF"; const char OFF_P[] PROGMEM = "OFF";
const char REST_P[] PROGMEM = "REST"; const char REST_P[] PROGMEM = "REST";
const char TOGGLE_P[] PROGMEM = "TOGGLE"; const char TOGGLE_P[] PROGMEM = "TOGGLE";
const char HALT_P[] PROGMEM = "HALT"; const char HALT_P[] PROGMEM = "HALT";
const char XON_P[] PROGMEM = "XON"; const char XON_P[] PROGMEM = "XON";
const char XOFF_P[] PROGMEM = "XOFF"; const char XOFF_P[] PROGMEM = "XOFF";
const char INCREASE_P[] PROGMEM = "INCREASE"; const char INCREASE_P[] PROGMEM = "INCREASE";
const char DECREASE_P[] PROGMEM = "DECREASE"; const char DECREASE_P[] PROGMEM = "DECREASE";
const char TRUE_P[] PROGMEM = "true"; const char TRUE_P[] PROGMEM = "TRUE";
const char FALSE_P[] PROGMEM = "false"; const char FALSE_P[] PROGMEM = "FALSE";
const char HEAT_P[] PROGMEM = "HEAT"; const char HEAT_P[] PROGMEM = "HEAT";
const char COOL_P[] PROGMEM = "COOL"; const char COOL_P[] PROGMEM = "COOL";
const char AUTO_P[] PROGMEM = "AUTO"; const char AUTO_P[] PROGMEM = "AUTO";
const char FAN_P[] PROGMEM = "FAN_ONLY";
const char DRY_P[] PROGMEM = "DRY";
const char SET_P[] PROGMEM = "set"; const char SET_P[] PROGMEM = "set";
const char CMD_P[] PROGMEM = "cmd"; const char CMD_P[] PROGMEM = "cmd";
const char MODE_P[] PROGMEM = "mode"; const char MODE_P[] PROGMEM = "mode";
/* /*
const char TEMP_P[] PROGMEM = "temp"; const char TEMP_P[] PROGMEM = "temp";
@@ -61,9 +63,9 @@ const char POWER_P[] PROGMEM = "power";
const char VOL_P[] PROGMEM = "vol"; const char VOL_P[] PROGMEM = "vol";
const char HEAT_P[] PROGMEM = "heat"; const char HEAT_P[] PROGMEM = "heat";
*/ */
const char HSV_P[] PROGMEM = "hsv"; const char HSV_P[] PROGMEM = "hsv";
const char RGB_P[] PROGMEM = "rgb"; const char RGB_P[] PROGMEM = "rgb";
const char RPM_P[] PROGMEM = "rpm"; const char RPM_P[] PROGMEM = "rpm";
const char STATE_P[] PROGMEM = "state"; const char STATE_P[] PROGMEM = "state";
short modbusBusy = 0; short modbusBusy = 0;
@@ -89,6 +91,8 @@ int txt2cmd(char *payload) {
else if (strcmp_P(payload, HEAT_P) == 0) cmd = CMD_HEAT; else if (strcmp_P(payload, HEAT_P) == 0) cmd = CMD_HEAT;
else if (strcmp_P(payload, COOL_P) == 0) cmd = CMD_COOL; else if (strcmp_P(payload, COOL_P) == 0) cmd = CMD_COOL;
else if (strcmp_P(payload, AUTO_P) == 0) cmd = CMD_AUTO; else if (strcmp_P(payload, AUTO_P) == 0) cmd = CMD_AUTO;
else if (strcmp_P(payload, FAN_P) == 0) cmd = CMD_FAN;
else if (strcmp_P(payload, DRY_P) == 0) cmd = CMD_DRY;
else if (strcmp_P(payload, TRUE_P) == 0) cmd = CMD_ON; else if (strcmp_P(payload, TRUE_P) == 0) cmd = CMD_ON;
else if (strcmp_P(payload, FALSE_P) == 0) cmd = CMD_OFF; else if (strcmp_P(payload, FALSE_P) == 0) cmd = CMD_OFF;
else if (strcmp_P(payload, INCREASE_P) == 0) cmd = CMD_UP; else if (strcmp_P(payload, INCREASE_P) == 0) cmd = CMD_UP;
@@ -351,6 +355,9 @@ else
setCommand = 0; /// Old-style - turn ON by set value setCommand = 0; /// Old-style - turn ON by set value
} }
int i=0;
while (payload[i]) {payload[i]=toupper(payload[i]);i++;};
int cmd = txt2cmd(payload); int cmd = txt2cmd(payload);
debugSerial<<F("Txt2Cmd:")<<cmd<<endl; debugSerial<<F("Txt2Cmd:")<<cmd<<endl;
@@ -421,6 +428,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode
if (itemType == CH_GROUP && !send) if (itemType == CH_GROUP && !send)
{ {
debugSerial<<F("Skip Grp")<<endl; debugSerial<<F("Skip Grp")<<endl;
return -1;
} }
int iaddr = getArg(); int iaddr = getArg();
@@ -462,9 +470,10 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode
if (driver) return driver->Ctrl(cmd, n, Parameters, send, suffixCode, subItem); if (driver) return driver->Ctrl(cmd, n, Parameters, send, suffixCode, subItem);
// Legacy code // Legacy code
bool instantON = false;
switch (cmd) { switch (cmd) {
case 0: // old style SET - with turning ON case 0: // old style SET - with turning ON
instantON = true;
case CMD_SET: // new style SET - w/o turning ON case CMD_SET: // new style SET - w/o turning ON
if (itemType !=CH_THERMO) setCmd(CMD_SET); //prevent ON thermostat by semp set ???? if (itemType !=CH_THERMO) setCmd(CMD_SET); //prevent ON thermostat by semp set ????
@@ -474,6 +483,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode
case CH_RGBW: //only if configured VAL array case CH_RGBW: //only if configured VAL array
if (!Par[1] && (n == 3)) itemType = CH_WHITE; if (!Par[1] && (n == 3)) itemType = CH_WHITE;
case CH_RGB: case CH_RGB:
/*
if (n == 3) { // Full triplet passed if (n == 3) { // Full triplet passed
st.h = Par[0]; st.h = Par[0];
st.s = Par[1]; st.s = Par[1];
@@ -499,11 +509,34 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode
} }
setCmd(cmd2changeActivity(chActive,cmd)); setCmd(cmd2changeActivity(chActive,cmd));
if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); // Send back triplet ? if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); // Send back triplet ?
break; break; */
case CH_GROUP: //Save for groups as well case CH_GROUP: //Save for groups as well
setVal(Par[n-1]); //Last/only parameter should contain volume st.aslong = getVal();
if (chActive && !Par[n-1]) setCmd(CMD_OFF); switch (n)
if (!chActive && Par[n-1]) setCmd(CMD_ON); {
case 1:
st.v = Par[0]; //Volume only
Par[0] = st.h;
Par[1] = st.s;
Par[2] = st.v;
n = 3;
break;
case 2: // Just hue and saturation
st.h = Par[0];
st.s = Par[1];
Par[2] = st.v;
st.hsv_flag = 1;
n = 3;
break;
case 3: //complete triplet
st.h = Par[0];
st.s = Par[1];
st.v = Par[2];
st.hsv_flag = 1;
}
setVal(st.aslong);
if (chActive && !st.v) setCmd(CMD_OFF);
if (!chActive && st.v) setCmd(CMD_ON);
if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED);//// Send back volume for grp? if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED);//// Send back volume for grp?
break; break;
case CH_PWM: case CH_PWM:
@@ -523,7 +556,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode
}//itemtype }//itemtype
if (cmd == CMD_SET && itemType !=CH_GROUP && !chActive>0) return 1; // Parameters are stored, no further action required if (getCmd() == CMD_SET && itemType !=CH_GROUP && !chActive>0) return 1; // Parameters are stored, no further action required
break; break;
case CMD_XON: case CMD_XON:
@@ -557,8 +590,8 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode
if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS ); if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS );
break; break;
} // if forcewhite } // if forcewhite
if (chActive>0) return 1; if (chActive>0) {SendStatus(SEND_COMMAND);return 1;}
{ {
short params = 0; short params = 0;
setCmd(cmd); setCmd(cmd);
@@ -1158,7 +1191,9 @@ int Item::checkFM() {
{ {
result = node.readHoldingRegisters(2111 - 1, 1); result = node.readHoldingRegisters(2111 - 1, 1);
if (result == node.ku8MBSuccess) aJson.addNumberToObject(out, "flt", (int) node.getResponseBuffer(0)); if (result == node.ku8MBSuccess) aJson.addNumberToObject(out, "flt", (int) node.getResponseBuffer(0));
Ctrl(CMD_OFF); //Shut down /// modbusBusy=0;
if (isActive()) Ctrl(CMD_OFF); //Shut down ///
modbusBusy=1;
} else aJson.addNumberToObject(out, "flt", 0); } else aJson.addNumberToObject(out, "flt", 0);
delay(50); delay(50);
@@ -1331,12 +1366,14 @@ int Item::Poll() {
sendDelayedStatus(); sendDelayedStatus();
return INTERVAL_CHECK_MODBUS; return INTERVAL_CHECK_MODBUS;
break; break;
case CH_RGB: //All channels with slider generate too many updates /* case CH_RGB: //All channels with slider generate too many updates
case CH_RGBW: case CH_RGBW:
case CH_DIMMER: case CH_DIMMER:
case CH_PWM: case CH_PWM:
case CH_VCTEMP: case CH_VCTEMP:
case CH_THERMO: case CH_THERMO:
case CH_GROUP:*/
default:
sendDelayedStatus(); sendDelayedStatus();
} }
return INTERVAL_POLLING; return INTERVAL_POLLING;
@@ -1377,9 +1414,12 @@ int Item::SendStatus(int sendFlags) {
case CH_RGB: case CH_RGB:
snprintf(valstr, sizeof(valstr), "%d,%d,%d", st.h,st.s,st.v); snprintf(valstr, sizeof(valstr), "%d,%d,%d", st.h,st.s,st.v);
break; break;
// case CH_GROUP: case CH_GROUP:
// sendFlags &= ~SEND_PARAMETERS; // Not send params for Group if (st.hsv_flag)
// break; snprintf(valstr, sizeof(valstr), "%d,%d,%d", st.h,st.s,st.v);
else
snprintf(valstr, sizeof(valstr), "%d", st.v);
break;
default: default:
snprintf(valstr, sizeof(valstr), "%d", st.aslong); snprintf(valstr, sizeof(valstr), "%d", st.aslong);
}//itemtype }//itemtype
@@ -1413,19 +1453,20 @@ int Item::SendStatus(int sendFlags) {
strncat(addrstr, itemArr->name, sizeof(addrstr)); strncat(addrstr, itemArr->name, sizeof(addrstr));
if (mqttClient.connected() && !ethernetIdleCount) if (mqttClient.connected() && !ethernetIdleCount)
{
if (sendFlags & SEND_PARAMETERS && chancmd != CMD_OFF && chancmd != CMD_HALT) if (sendFlags & SEND_PARAMETERS && chancmd != CMD_OFF && chancmd != CMD_HALT)
{ {
mqttClient.publish(addrstr, valstr, true); mqttClient.publish(addrstr, valstr, true);
debugSerial<<F("Pub: ")<<addrstr<<F("->")<<valstr<<endl; debugSerial<<F("Pub: ")<<addrstr<<F("->")<<valstr<<endl;
} }
else else if (sendFlags & SEND_COMMAND)
{ {
mqttClient.publish(addrstr, cmdstr, true); mqttClient.publish(addrstr, cmdstr, true);
debugSerial<<F("Pub: ")<<addrstr<<F("->")<<cmdstr<<endl; debugSerial<<F("Pub: ")<<addrstr<<F("->")<<cmdstr<<endl;
} }
}
else else
{ {
setFlag(sendFlags); setFlag(sendFlags);
@@ -1471,6 +1512,9 @@ int Item::SendStatus(int sendFlags) {
case CMD_COOL: case CMD_COOL:
strcpy_P(cmdstr, COOL_P); strcpy_P(cmdstr, COOL_P);
break; break;
case CMD_ON:
case CMD_XON:
if (itemType == CH_THERMO) strcpy_P(cmdstr, HEAT_P);
} }
setTopic(addrstr,sizeof(addrstr),T_OUT); setTopic(addrstr,sizeof(addrstr),T_OUT);

View File

@@ -66,7 +66,9 @@ e-mail anklimov@gmail.com
#define CMD_HEAT 0xa #define CMD_HEAT 0xa
#define CMD_COOL 0xb #define CMD_COOL 0xb
#define CMD_AUTO 0xc #define CMD_AUTO 0xc
#define CMD_SET 0xe #define CMD_FAN 0xd
#define CMD_DRY 0xe
#define CMD_SET 0xf
#define CMD_CURTEMP 0xf #define CMD_CURTEMP 0xf
#define CMD_MASK 0xf #define CMD_MASK 0xf
#define FLAG_MASK 0xf0 #define FLAG_MASK 0xf0
@@ -104,17 +106,20 @@ extern short thermoSetCurTemp(char *name, float t);
int txt2cmd (char * payload); int txt2cmd (char * payload);
#pragma pack(push, 1)
typedef union typedef union
{ {
long int aslong; long int aslong;
struct struct
{ {
int16_t h; int16_t hsv_flag:1;
int16_t h:15;
int8_t s; int8_t s;
int8_t v; int8_t v;
}; };
} HSVstore; } HSVstore;
typedef union typedef union
{ {
long int aslong; long int aslong;
@@ -126,6 +131,7 @@ typedef union
int8_t w; int8_t w;
}; };
} RGBWstore; } RGBWstore;
#pragma pack(pop)
class Item class Item
{ {

View File

@@ -7,7 +7,7 @@
#include "FastLED.h" #include "FastLED.h"
#include "item.h" #include "item.h"
#define NUM_LEDS 150 #define NUM_LEDS 15
#define DATA_PIN 4 #define DATA_PIN 4
static CRGB leds[NUM_LEDS]; static CRGB leds[NUM_LEDS];
@@ -35,7 +35,7 @@ int out_SPILed::Status()
return driverStatus; return driverStatus;
} }
int out_SPILed::isActive() int out_SPILed::isActive()
{ {
} }