Cumulative changes/pre-release

This commit is contained in:
Климов Андрей Николаевич
2023-04-02 17:27:02 +03:00
parent 3e0566cf07
commit ec306c4934
32 changed files with 734 additions and 367 deletions

View File

@@ -1,7 +1,7 @@
#-DW5500_CS_PIN=53
-DDMX_SMOOTH
-DSYSLOG_ENABLE
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
-DARTNET_ENABLE
-DOTA
-DSTATUSLED

View File

@@ -26,6 +26,10 @@
#-DmodbusSerial=Serial1
#-DMODBUS_DEBUG
#-DMODBUS_UART_RX_PIN=16
#-DMODBUS_UART_TX_PIN=17
#-DmodbusSerial=Serial2
# Use default pins for modbus UART
#-DMODBUS_UART_RX_PIN=-1
#-DMODBUS_UART_TX_PIN=-1

View File

@@ -12,8 +12,8 @@
-DTIMER_INT
#-DFLASH_OFFSET=-256
# Serial parameters for LEGACY Modbus
-DMODBUS_DIMMER_PARAM=SERIAL_8E1
# default MODBUS Serial parameters for LEGACY Modbus and MODBUS over IP
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
#Set Logariphmic law for DMX channels bright
-DBRIGHT_LOG

View File

@@ -1,4 +1,4 @@
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
-DAVR_DMXOUT_PIN=18
-DSYSLOG_ENABLE
-DWiz5100

View File

@@ -1,5 +1,5 @@
-DWiz5500
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
-DAVR_DMXOUT_PIN=18
-DSYSLOG_ENABLE
#-DPID_DISABLE

View File

@@ -1,5 +1,5 @@
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
#-DAVR_DMXOUT_PIN=18
-DDMX_DISABLE
-DMODBUS_DISABLE

View File

@@ -1,9 +1,9 @@
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
#-DAVR_DMXOUT_PIN=18
-DDMX_DISABLE
-DMODBUS_DISABLE
#-DMBUS_DISABLE
-DMBUS_DISABLE
#-DOWIRE_DISABLE
-DDHT_DISABLE
-DCOUNTER_DISABLE

Binary file not shown.

View File

@@ -12,6 +12,8 @@ int abstractOut::isActive()
case CMD_VOID:
return 0;
break;
case CMD_ON: //trying (PWM ON set=0 issue)
return 1;
default:
st.loadItem(item);
return st.getPercents255();

View File

@@ -10,6 +10,7 @@ public:
abstractOut(Item * _item):abstractCh(){item=_item;};
virtual int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true) =0;
virtual int isActive();
virtual bool isAllowed(itemCmd cmd){return true;};
virtual itemCmd getDefaultOnVal(){return itemCmd().Percents255(255);};
virtual int getChanType(){return 0;}
virtual int getDefaultStorageType(){return 0;} /// Remove?? Now getChanType used instead

View File

@@ -293,6 +293,19 @@ bool systemConfig::setConfigFlags(systemConfigFlags flags)
return setConfigFlags(flags);
}
bool systemConfig::getDHCPfallback()
{
systemConfigFlags flags = getConfigFlags();
return flags.dhcpFallback;
}
bool systemConfig::setDHCPfallback(bool flag)
{
systemConfigFlags flags = getConfigFlags();
flags.dhcpFallback=flag;
return setConfigFlags(flags);
}
bool systemConfig::getLoadHTTPConfig()
{
systemConfigFlags flags = getConfigFlags();

View File

@@ -61,6 +61,9 @@ class systemConfig {
bool saveETAG();
bool loadETAG();
bool getDHCPfallback();
bool setDHCPfallback(bool flag);
systemConfigFlags getConfigFlags();
bool setConfigFlags(systemConfigFlags flags);

View File

@@ -541,9 +541,9 @@ void setupIpmodbus(){
// Calculate Modbus RTU character timeout and frame delay
byte bits = // number of bits per character (11 in default Modbus RTU settings)
1 + // start bit
(((MODBUS_DIMMER_PARAM & 0x06) >> 1) + 5) + // data bits
(((MODBUS_DIMMER_PARAM & 0x08) >> 3) + 1); // stop bits
if (((MODBUS_DIMMER_PARAM & 0x30) >> 4) > 1) bits += 1; // parity bit (if present)
(((MODBUS_SERIAL_PARAM & 0x06) >> 1) + 5) + // data bits
(((MODBUS_SERIAL_PARAM & 0x08) >> 3) + 1); // stop bits
if (((MODBUS_SERIAL_PARAM & 0x30) >> 4) > 1) bits += 1; // parity bit (if present)
//bits = 11;
int T = ((unsigned long)bits * 1000000UL) / MODBUS_SERIAL_BAUD; // time to send 1 character over serial in microseconds

View File

@@ -107,7 +107,7 @@ int txt2subItem(char *payload) {
if (!payload || !strlen(payload)) return S_NOTFOUND;
// Check for command
if (strcmp_P(payload, SET_P) == 0) cmd = S_SET;
//else if (strcmp_P(payload, ESET_P) == 0) cmd = S_ESET;
else if (strcmp_P(payload, CTRL_P) == 0) cmd = S_CTRL;
else if (strcmp_P(payload, CMD_P) == 0) cmd = S_CMD;
else if (strcmp_P(payload, MODE_P) == 0) cmd = S_MODE;
else if (strcmp_P(payload, HSV_P) == 0) cmd = S_HSV;
@@ -326,7 +326,7 @@ uint32_t Item::getFlag (uint32_t flag)
aJsonObject *itemCmd = aJson.getArrayItem(itemArr, I_CMD);
if (itemCmd && (itemCmd->type == aJson_Int))
{
return itemCmd->valueint & flag & FLAG_MASK;
return (uint32_t) itemCmd->valueint & flag & FLAG_MASK;
}
return 0;
}
@@ -572,7 +572,12 @@ long int Item::limitSetValue()
int Item::Ctrl(char * payload, char * subItem)
{
if (!payload) return 0;
int fr = freeRam();
if (fr < minimalMemory)
{
errorSerial<<F("CTRL/txt: OutOfMemory: ")<<fr<<endl;
return -1;
}
int suffixCode = 0;
@@ -741,51 +746,54 @@ bool digGroup (aJsonObject *itemArr, itemCmd *cmd, char* subItem)
return false;
}
//Main routine to control Item
//Return values
// 1 complete
// 3 complete, no action, target reached
// -3 ignored
// -1 system error
// -4 invalid argument
int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
int Item::isScheduled()
{
uint32_t time=millis();
int suffixCode = cmd.getSuffix();
bool operation = isNotRetainingStatus();
if ((!subItem || !strlen(subItem)) && strlen(defaultSubItem))
subItem = defaultSubItem; /// possible problem here with truncated default
if (!suffixCode && subItem && strlen(subItem))
aJsonObject *timestampObj = aJson.getArrayItem(itemArr, I_TIMESTAMP);
if (timestampObj && (timestampObj->subtype > 0))
{
suffixCode = retrieveCode(&subItem);
if (!cmd.getSuffix()) cmd.setSuffix(suffixCode);
return timestampObj->subtype;
}
return 0;
}
if (!suffixCode && defaultSuffixCode)
int Item::scheduleOppositeCommand(itemCmd cmd)
{
suffixCode = defaultSuffixCode;
if (!cmd.getSuffix()) cmd.setSuffix(suffixCode);
itemCmd nextCmd=cmd;
switch (cmd.getCmd()){
case CMD_XON: nextCmd.Cmd(CMD_XOFF);
break;
case CMD_XOFF: nextCmd.Cmd(CMD_XON);
break;
case CMD_ON: nextCmd.Cmd(CMD_OFF);
break;
case CMD_OFF: nextCmd.Cmd(CMD_ON);
break;
case CMD_ENABLE: nextCmd.Cmd(CMD_DISABLE);
break;
case CMD_DISABLE: nextCmd.Cmd(CMD_ENABLE);
break;
case CMD_FREEZE: nextCmd.Cmd(CMD_UNFREEZE);
break;
case CMD_UNFREEZE: nextCmd.Cmd(CMD_FREEZE);
break;
case CMD_HALT: nextCmd.Cmd(CMD_RESTORE);
break;
case CMD_RESTORE: nextCmd.Cmd(CMD_HALT);
break;
default: return 0;
}
debugSerial<<F("CTRL: Schedule cmd ")<<nextCmd.getCmd()<<F(" for (ms):")<<nextCmd.getInt()<<endl;
scheduleCommand(nextCmd);
return 1;
}
int fr = freeRam();
debugSerial<<F("RAM=")<<fr<<F(" Item=")<<itemArr->name<<F(" Sub=")<<subItem<<F(" ");
if (fr < 200)
int Item::scheduleCommand(itemCmd cmd)
{
errorSerial<<F("OutOfMemory!\n")<<endl;
return -1;
}
cmd.debugOut();
//debugSerial<<endl;
if (subItem && subItem[0] == '$') {debugSerial<<F("Skipped homie stuff")<<endl;return -4; }
if (!itemArr) return -1;
if (!itemArr) return 0;
/// DELAYED COMMANDS processing
if (suffixCode == S_DELAYED)
{
for (int i = aJson.getArraySize(itemArr); i <= I_TIMESTAMP; i++)
aJson.addItemToArray(itemArr, aJson.createNull());
@@ -807,6 +815,56 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
return 1;
}
return 0;
}
//Main routine to control Item
//Return values
// 1 complete
// 3 complete, no action, target reached
// -3 ignored
// -1 system error
// -4 invalid argument
int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
{
int fr = freeRam();
if (fr < minimalMemory)
{
errorSerial<<F("CTRL: OutOfMemory: ")<<fr<<endl;
return -1;
}
{
uint32_t time=millis();
int suffixCode = cmd.getSuffix();
bool operation = isNotRetainingStatus();
if ((!subItem || !strlen(subItem)) && strlen(defaultSubItem))
subItem = defaultSubItem; /// possible problem here with truncated default
if (!suffixCode && subItem && strlen(subItem))
{
suffixCode = retrieveCode(&subItem);
if (!cmd.getSuffix()) cmd.setSuffix(suffixCode);
}
if (!suffixCode && defaultSuffixCode)
{
suffixCode = defaultSuffixCode;
if (!cmd.getSuffix()) cmd.setSuffix(suffixCode);
}
debugSerial<<F("CTRL: RAM=")<<fr<<F(" Item=")<<itemArr->name<<F(" Sub=")<<subItem<<F(" ");
cmd.debugOut();
//debugSerial<<endl;
if (subItem && subItem[0] == '$') {debugSerial<<F("Skipped homie stuff")<<endl;return -4; }
if (!itemArr) return -1;
/// DELAYED COMMANDS processing
if (suffixCode == S_DELAYED)
{
return scheduleCommand(cmd);
}
///
int8_t chActive = -1;
@@ -827,6 +885,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
switch (suffixCode)
{
case S_NOTFOUND: //For empty (universal) OPENHAB suffix - turn ON/OFF automatically
if (subItem) {debugSerial<<F("CTRL: Unknown suffix")<<endl; break;}; // if some unknown suffix
toExecute=true;
scale100=true; //openHab topic format
chActive=(isActive()>0);
@@ -950,11 +1009,12 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
{
if (fr<350)
{
errorSerial<<F("Not enough memory for group operation")<<endl;
errorSerial<<F("CTRL: Not enough memory for group operation")<<endl;
return -1;
}
if (allowRecursion && itemArg->type == aJson_Array && operation)
{
chActive=(isActive()>0);
digGroup(itemArg,&cmd,subItem);
}
res=1;
@@ -965,7 +1025,8 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
case CMD_RESTORE: // individual for group members
switch (t = getCmd()) {
case CMD_HALT: //previous command was HALT ?
debugSerial << F("Restored from:") << t << endl;
if ((suffixCode==S_CMD) && cmd.isValue() && (!chActive || isScheduled())) scheduleOppositeCommand(cmd);
debugSerial << F("CTRL: Restored from:") << t << endl;
cmd.loadItemDef(this);
cmd.Cmd(CMD_ON); //turning on
status2Send |= FLAG_COMMAND | FLAG_SEND_IMMEDIATE;
@@ -978,20 +1039,30 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
case CMD_XOFF: // individual for group members
switch (t = getCmd()) {
case CMD_XON: //previous command was CMD_XON ?
debugSerial << F("Turned off from:") << t << endl;
if ((suffixCode==S_CMD) && cmd.isValue() && (chActive || isScheduled())) scheduleOppositeCommand(cmd);
debugSerial << F("CTRL: Turned off from:") << t << endl;
cmd.Cmd(CMD_OFF); //turning Off
status2Send |= FLAG_COMMAND | FLAG_SEND_IMMEDIATE;
break;
default:
debugSerial << F("XOFF skipped. Prev cmd:") << t <<endl;
debugSerial << F("CTRL: XOFF skipped. Prev cmd:") << t <<endl;
return 3;
}
break;
case CMD_XON:
chActive=(isActive()>0);
if (!getFlag(FLAG_DISABLED))
{
if (chActive == -1) chActive=(isActive()>0);
if ((suffixCode==S_CMD) && cmd.isValue() && (!chActive || isScheduled())) scheduleOppositeCommand(cmd);
if (!chActive) //if channel was'nt active before CMD_XON
{
cmd.loadItemDef(this);
cmd.Cmd(CMD_ON);
command2Set=CMD_XON;
@@ -999,13 +1070,21 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
}
else
{
debugSerial<<F("XON:Already Active\n");
debugSerial<<F("CTRL: XON:Already Active\n");
return 3;
}
}
else
{
debugSerial<<F("CTRL: XON: Disabled\n");
return 3;
}
break;
case CMD_HALT:
chActive=(isActive()>0);
if (chActive) //if channel was active before CMD_HALT
if (chActive == -1) chActive=(isActive()>0);
if ((suffixCode==S_CMD) && cmd.isValue() && (chActive || isScheduled())) scheduleOppositeCommand(cmd);
if (chActive) //if channel was active before CMD_HALT /// HERE bug - if cmd == On but 0 = active
{
cmd.Cmd(CMD_OFF);
command2Set=CMD_HALT;
@@ -1013,7 +1092,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
}
else
{
debugSerial<<F("HALT:Already Inactive\n");
debugSerial<<F("CTRL: HALT:Already Inactive\n");
return 3;
}
break;
@@ -1028,7 +1107,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
{ // NON GROUP part
if (chActive<0) chActive = (isActive()>0);
toExecute=chActive || toExecute; // Execute if active
debugSerial<<F("Active:")<<chActive<<F( " Exec:")<<toExecute<<endl;
debugSerial<<F("CTRL: Active:")<<chActive<<F( " Exec:")<<toExecute<<endl;
if (subItem)
{
//Check if subitem is some sort of command
@@ -1040,7 +1119,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
{
if (subitemCmd != prevCmd)
{
debugSerial<<F("Ignored, channel cmd=")<<prevCmd<<endl;
debugSerial<<F("CTRL: Ignored, channel cmd=")<<prevCmd<<endl;
return -3;
}
subItem=NULL;
@@ -1059,7 +1138,10 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
case CMD_RESTORE: // individual for group members
switch (t = getCmd()) {
case CMD_HALT: //previous command was HALT ?
debugSerial << F("Restored from:") << t << endl;
if ((suffixCode==S_CMD) && allowRecursion && cmd.isValue() && (chActive || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
debugSerial << F("CTRL: Restored from:") << t << endl;
cmd.loadItemDef(this);
toExecute=true;
if (itemType == CH_THERMO) cmd.Cmd(CMD_AUTO); ////
@@ -1074,33 +1156,52 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
case CMD_XOFF: // individual for group members
switch (t = getCmd()) {
case CMD_XON: //previous command was CMD_XON ?
debugSerial << F("Turned off from:") << t << endl;
if ((suffixCode==S_CMD) && allowRecursion && cmd.isValue() && (chActive || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
debugSerial << F("CTRL: Turned off from:") << t << endl;
toExecute=true;
cmd.Cmd(CMD_OFF); //turning Off
clearFlag(FLAG_XON);
status2Send |= FLAG_COMMAND | FLAG_SEND_IMMEDIATE;
break;
default:
debugSerial << F("XOFF skipped. Prev cmd:") << t <<endl;
debugSerial << F("CTRL: XOFF skipped. Prev cmd:") << t <<endl;
return 3;
}
break;
case CMD_XON:
if (!getFlag(FLAG_DISABLED))
{
if ((suffixCode==S_CMD) && allowRecursion && cmd.isValue() && (!chActive || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
if (!chActive) //if channel was'nt active before CMD_XON
{
cmd.loadItemDef(this);
cmd.Cmd(CMD_ON);
command2Set=CMD_XON;
setFlag(FLAG_XON);
status2Send |= FLAG_COMMAND | FLAG_SEND_IMMEDIATE;
toExecute=true;
}
else
{
debugSerial<<F("XON:Already Active\n");
debugSerial<<F("CTRL: XON:Already Active\n");
return 3;
}
}
else
{
debugSerial<<F("CTRL: XON: Disabled\n");
return 3;
}
break;
case CMD_HALT:
if ((suffixCode==S_CMD) && allowRecursion && cmd.isValue() && (chActive || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
if (chActive) //if channel was active before CMD_HALT
{
cmd.Cmd(CMD_OFF);
@@ -1110,7 +1211,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
}
else
{
debugSerial<<F("HALT:Already Inactive\n");
debugSerial<<F("CTRL: HALT:Already Inactive\n");
return 3;
}
break;
@@ -1123,11 +1224,18 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
}
if (getCmd() == CMD_HALT) return 3; //Halted, ignore OFF
if ((suffixCode==S_CMD) && allowRecursion && cmd.isValue() && (chActive || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
status2Send |= FLAG_COMMAND | FLAG_SEND_IMMEDIATE;
toExecute=true;
break;
case CMD_ON:
if ((suffixCode==S_CMD) && allowRecursion && cmd.isValue() && (!chActive || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
if (!cmd.isChannelCommand()) //Command for driver, not for whole channel
{
toExecute=true;
@@ -1135,7 +1243,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
}
if (chActive)
{
debugSerial<<F("ON:Already Active\n");
debugSerial<<F("CTRL: ON:Already Active\n");
setCmd(CMD_ON);
SendStatus(FLAG_COMMAND | FLAG_SEND_DEFFERED);
return 3;
@@ -1163,6 +1271,43 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
case CMD_UP:
break;
case CMD_ENABLE:
//clearFlag(FLAG_DISABLED); //saveItem have this
status2Send |= FLAG_FLAGS;
toExecute=true;
//debugSerial<<F("Disable Flag is:")<<getFlag(FLAG_DISABLED)<<endl;
if (allowRecursion && cmd.isValue() && (getFlag(FLAG_DISABLED) || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
break;
case CMD_DISABLE:
//setFlag(FLAG_DISABLED); //saveItem have this
status2Send |= FLAG_FLAGS;
toExecute=true;
//debugSerial<<F("Disable Flag is:")<<getFlag(FLAG_DISABLED)<<endl;
if ((suffixCode==S_CMD) && allowRecursion && cmd.isValue() && (!getFlag(FLAG_DISABLED) || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
break;
case CMD_UNFREEZE:
//clearFlag(FLAG_DISABLED); //saveItem have this
status2Send = FLAG_FLAGS;
toExecute=true;
//debugSerial<<F("Disable Flag is:")<<getFlag(FLAG_DISABLED)<<endl;
if ((suffixCode==S_CMD) && allowRecursion && cmd.isValue() && (getFlag(FLAG_FREEZED) || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
break;
case CMD_FREEZE:
//setFlag(FLAG_DISABLED); //saveItem have this
status2Send = FLAG_FLAGS;
command2Set = 0;
toExecute=true;
//debugSerial<<F("Disable Flag is:")<<getFlag(FLAG_DISABLED)<<endl;
if ((suffixCode==S_CMD) && allowRecursion && cmd.isValue() && (!getFlag(FLAG_FREEZED) || isScheduled())) //invoked not as group part, delayed, non Active or re-schedule
scheduleOppositeCommand(cmd);
break;
default:
if (cmd.isCommand()) status2Send |= FLAG_COMMAND;
if (cmd.isValue()) status2Send |= FLAG_PARAMETERS;
@@ -1170,6 +1315,9 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
} //Switch commands
} // NO GROUP
if (invalidArgument) return -4;
if ((!driver || driver->isAllowed(cmd)) && (!getFlag(FLAG_FREEZED)))
{
// UPDATE internal variables
if (status2Send) cmd.saveItem(this,status2Send);
//debugSerial<<F("sts:")<<status2Send<<endl;
@@ -1179,13 +1327,17 @@ if (driver) //New style modular code
res = driver->Ctrl(cmd, subItem, toExecute);
if (driver->getChanType() == CH_THERMO) status2Send |= FLAG_SEND_IMMEDIATE;
//if (res==-1) status2Send=0; ///////not working
if (status2Send & FLAG_FLAGS) res =1; //ENABLE & DISABLE processed by core
}
else
{
switch (itemType) {
/// rest of Legacy monolite core code (to be refactored ) BEGIN ///
case CH_RELAY:
if (cmd.isCommand())
{
short iaddr=getArg();
short icmd =cmd.getCmd();
@@ -1202,10 +1354,27 @@ switch (itemType) {
{
pinMode(iaddr, OUTPUT);
switch (icmd){
case CMD_AUTO:
case CMD_COOL:
case CMD_ON:
case CMD_DRY:
case CMD_FAN:
case CMD_XON:
digitalWrite(iaddr, k = (inverse) ? LOW : HIGH);
break;
case CMD_OFF:
case CMD_HALT:
case CMD_XOFF:
digitalWrite(iaddr, k = (inverse) ? HIGH : LOW);
}
/*
if (inverse)
digitalWrite(iaddr, k = ((icmd == CMD_ON || icmd == CMD_AUTO) ? LOW : HIGH));
else
digitalWrite(iaddr, k = ((icmd == CMD_ON || icmd == CMD_AUTO) ? HIGH : LOW));
*/
debugSerial<<F("Pin:")<<iaddr<<F("=")<<k<<endl;
status2Send |= FLAG_COMMAND | FLAG_SEND_IMMEDIATE;
res=1;
@@ -1266,15 +1435,26 @@ switch (itemType) {
/// rest of Legacy monolite core code (to be refactored ) END ///
} //switch
} //else (nodriver)
//update command for HALT & XON and send MQTT status
if (command2Set) setCmd(command2Set | FLAG_COMMAND);
if (operation) SendStatus(status2Send);
debugSerial<<F("Ctrl Res:")<<res<<F(" time:")<<millis()-time<<endl;
} //alowed cmd
else
{
errorSerial<<F("CTRL: Command blocked by driver or channel frozen")<<endl;
if ((status2Send & FLAG_FLAGS) && operation)
{
cmd.saveItem(this,FLAG_FLAGS);
SendStatus(FLAG_FLAGS);
}
}
debugSerial<<F("CTRL: Res:")<<res<<F(" time:")<<millis()-time<<endl;
return res;
}
}
void printActiveStatus(bool active)
{
@@ -1379,7 +1559,15 @@ if (timestampObj)
if (remain <0 && abs(remain)< 0xFFFFFFFFUL/2)
{
int fr = freeRam();
SendStatusImmediate(st,FLAG_SEND_DELAYED);
if (fr < minimalMemory)
{
errorSerial<<F("CTRL/poll: OutOfMemory: ")<<fr<<endl;
return -1;
}
Ctrl(itemCmd(ST_VOID,cmd));
timestampObj->subtype=0;
}
@@ -1430,7 +1618,7 @@ void Item::sendDelayedStatus()
int Item::SendStatus(int sendFlags) {
if (sendFlags & FLAG_SEND_IMMEDIATE) sendFlags &= ~ (FLAG_SEND_IMMEDIATE | FLAG_SEND_DEFFERED);
if ((sendFlags & FLAG_SEND_DEFFERED) || freeRam()<150 || (!isNotRetainingStatus() )) {
setFlag(sendFlags & (FLAG_COMMAND | FLAG_PARAMETERS));
setFlag(sendFlags & (FLAG_COMMAND | FLAG_PARAMETERS | FLAG_FLAGS));
debugSerial<<F("Status deffered\n");
return -1;
}
@@ -1438,7 +1626,7 @@ int Item::SendStatus(int sendFlags) {
{
itemCmd st(ST_VOID,CMD_VOID);
st.loadItem(this, FLAG_COMMAND | FLAG_PARAMETERS);
sendFlags |= getFlag(FLAG_COMMAND | FLAG_PARAMETERS); //if some delayed status is pending
sendFlags |= getFlag(FLAG_COMMAND | FLAG_PARAMETERS | FLAG_FLAGS); //if some delayed status is pending
//debugSerial<<F("ssi:")<<sendFlags<<endl;
return SendStatusImmediate(st,sendFlags);
}
@@ -1462,10 +1650,11 @@ int Item::SendStatus(int sendFlags) {
case CMD_COOL:
case CMD_DRY:
case CMD_FAN:
case CMD_ENABLE:
case CMD_DISABLE:
strcpy_P(cmdstr, ON_P);
break;
//case CMD_ENABLE:
//case CMD_DISABLE:
// break;
case CMD_OFF:
case CMD_HALT:
strcpy_P(cmdstr, OFF_P);
@@ -1501,7 +1690,7 @@ int Item::SendStatus(int sendFlags) {
mqttClient.publish(addrstr, valstr, true);
debugSerial<<F("Pub: ")<<addrstr<<F("->")<<valstr<<endl;
}
else if (sendFlags & FLAG_COMMAND)
else if ((sendFlags & FLAG_COMMAND) && (strlen(cmdstr)))
{
mqttClient.publish(addrstr, cmdstr, true);
debugSerial<<F("Pub: ")<<addrstr<<F("->")<<cmdstr<<endl;
@@ -1584,12 +1773,12 @@ int Item::SendStatus(int sendFlags) {
case CMD_FAN:
strcpy_P(cmdstr, FAN_ONLY_P);
break;
case CMD_ENABLE:
strcpy_P(cmdstr, ENABLE_P);
break;
case CMD_DISABLE:
strcpy_P(cmdstr, DISABLE_P);
break;
//case CMD_ENABLE:
// strcpy_P(cmdstr, ENABLE_P);
// break;
//case CMD_DISABLE:
// strcpy_P(cmdstr, DISABLE_P);
// break;
case CMD_ON:
case CMD_XON:
if (itemType == CH_THERMO) strcpy_P(cmdstr, AUTO_P);
@@ -1617,6 +1806,43 @@ int Item::SendStatus(int sendFlags) {
return 0;
}
}
// Send ctrl
if (sendFlags & FLAG_FLAGS)
{
if (getFlag(FLAG_DISABLED))
strcpy_P(cmdstr, DISABLE_P);
else if (getFlag(FLAG_FREEZED))
strcpy_P(cmdstr, FREEZE_P);
else strcpy_P(cmdstr, ENABLE_P);
//else strcpy_P(cmdstr, UNFREEZE_P);
setTopic(addrstr,sizeof(addrstr),T_OUT);
strncat(addrstr, itemArr->name, sizeof(addrstr)-1);
if (subItem)
{
strncat(addrstr, "/", sizeof(addrstr)-1);
strncat(addrstr, subItem, sizeof(addrstr)-1);
}
strncat(addrstr, "/", sizeof(addrstr)-1);
strncat_P(addrstr, CTRL_P, sizeof(addrstr)-1);
debugSerial<<F("Pub: ")<<addrstr<<F("->")<<cmdstr<<endl;
if (mqttClient.connected() && !ethernetIdleCount)
{
mqttClient.publish(addrstr, cmdstr,true);
clearFlag(FLAG_FLAGS);
}
else
{
setFlag(sendFlags);
return 0;
}
}
return 1;
}
}
@@ -1821,7 +2047,7 @@ int Item::VacomSetFan(itemCmd st) {
//uint8_t j;//, result;
//uint16_t data[1];
modbusSerial.begin(9600, fmPar);
modbusSerial.begin(MODBUS_FM_BAUD, MODBUS_FM_PARAM);
node.begin(addr, modbusSerial);
if (val) {
@@ -1866,7 +2092,7 @@ int addr;
}
modbusBusy = 1;
modbusSerial.begin(9600, fmPar);
modbusSerial.begin(MODBUS_FM_BAUD, MODBUS_FM_PARAM);
node.begin(addr, modbusSerial);
uint16_t regval;
@@ -1903,7 +2129,7 @@ int Item::modbusDimmerSet(int addr, uint16_t _reg, int _regType, int _mask, uint
};
modbusBusy = 1;
modbusSerial.begin(MODBUS_SERIAL_BAUD, dimPar);
modbusSerial.begin(MODBUS_SERIAL_BAUD, MODBUS_SERIAL_PARAM);
node.begin(addr, modbusSerial);
uint8_t t;
switch (_mask) {
@@ -1971,7 +2197,7 @@ int Item::checkFM() {
// aJson.addStringToObject(out,"type", "rect");
modbusSerial.begin(9600, fmPar);
modbusSerial.begin(MODBUS_FM_BAUD, MODBUS_FM_PARAM);
node.begin(getArg(), modbusSerial);
@@ -2090,7 +2316,7 @@ int Item::checkModbusDimmer() {
//node.setSlave(addr);
modbusSerial.begin(MODBUS_SERIAL_BAUD, dimPar);
modbusSerial.begin(MODBUS_SERIAL_BAUD, MODBUS_SERIAL_PARAM);
node.begin(addr, modbusSerial);
switch (_regType) {

View File

@@ -149,6 +149,7 @@ class Item
inline int Off(){return Ctrl(itemCmd(ST_VOID,CMD_OFF));};
inline int Toggle(){return Ctrl(itemCmd(ST_VOID,CMD_TOGGLE));};
int scheduleCommand(itemCmd cmd);
int scheduleOppositeCommand(itemCmd cmd);
int isScheduled();
protected:

View File

@@ -108,6 +108,7 @@ uint8_t itemCmd::getStoragetypeByChanType(short chanType)
case CH_PWM:
case CH_VC:
case CH_MODBUS:
//case CH_RELAY:
//case CH_GROUP:
return ST_PERCENTS255;
break;
@@ -1115,6 +1116,14 @@ bool itemCmd::saveItem(Item * item, uint16_t optionsFlag)
case CMD_ENABLE:
item->clearFlag(FLAG_DISABLED);
item->clearFlag(FLAG_FREEZED);
break;
case CMD_FREEZE:
item->setFlag(FLAG_FREEZED);
break;
case CMD_UNFREEZE:
item->clearFlag(FLAG_FREEZED);
break;
}
if (optionsFlag & FLAG_COMMAND)
@@ -1122,6 +1131,8 @@ bool itemCmd::saveItem(Item * item, uint16_t optionsFlag)
{
case CMD_DISABLE:
case CMD_ENABLE:
case CMD_FREEZE:
case CMD_UNFREEZE:
break;
default:
item->setCmd(cmd.cmdCode);

View File

@@ -26,8 +26,10 @@ typedef char cmdstr[9];
const cmdstr commands_P[] PROGMEM =
{
"","ON","OFF","REST","TOGGLE","HALT","XON","XOFF","INCREASE","DECREASE",
"HEAT","COOL","AUTO","FAN_ONLY","DRY","STOP","HIGH","MEDIUM","LOW","ENABLE","DISABLE",
"TRUE","FALSE","RGB","HSV"
"ENABLE","DISABLE","UNFREEZE","FREEZE",
"AUTO","FAN_ONLY",
"HIGH","MEDIUM","LOW",
"HEAT","COOL","DRY","STOP","RGB","HSV"
};
#define commandsNum sizeof(commands_P)/sizeof(cmdstr)
@@ -41,20 +43,24 @@ const cmdstr commands_P[] PROGMEM =
#define CMD_XOFF 7 /// OFF only if was previously turned on by CMD_XON
#define CMD_UP 8 /// increase
#define CMD_DN 9 /// decrease
#define CMD_HEAT 0xa /// Thermostat/AC set to HEATing mode
#define CMD_COOL 0xb /// Thermostat/AC set to COOLing mode
#define CMD_AUTO 0xc /// Thermostat/AC set to Auto mode
#define CMD_FAN 0xd /// AC set to Fan-only mode
#define CMD_DRY 0xe /// AC set to Dry mode
#define CMD_STOP 0xf /// stop dimming (for further use)
#define CMD_ENABLE 0xa /// for PID regulator and XON/XOFF - chan limitation
#define CMD_DISABLE 0xb /// for PID regulator
#define CMD_UNFREEZE 0xc /// Aliase for ON
#define CMD_FREEZE 0xd /// Aliase for OFF
#define CMD_AUTO 0xe /// Thermostat/AC set to Auto mode
#define CMD_FAN 0xf /// AC set to Fan-only mode
#define CMD_HIGH 0x10 /// AC/Vent fan level HIGH
#define CMD_MED 0x11 /// AC/Vent fan level MEDIUM
#define CMD_LOW 0x12 /// AC/Vent fan level LOW
#define CMD_ENABLE 0x13 /// for PID regulator
#define CMD_DISABLE 0x14 /// for PID regulator
#define CMD_TRUE 0x15 /// Aliase for ON
#define CMD_FALSE 0x16 /// Aliase for OFF
#define CMD_HEAT 0x13 /// Thermostat/AC set to HEATing mode
#define CMD_COOL 0x14 /// Thermostat/AC set to COOLing mode
#define CMD_DRY 0x15 /// AC set to Dry mode
#define CMD_STOP 0x16 /// stop dimming (for further use)
#define CMD_RGB 0x17
#define CMD_HSV 0x18
@@ -78,7 +84,7 @@ const cmdstr commands_P[] PROGMEM =
#define FLAG_ACTION_IN_PROCESS 0x8000UL
#define FLAG_DISABLED 0x10000UL
#define FLAG_DISABLED_ALL 0x20000UL
#define FLAG_FREEZED 0x20000UL
#define FLAG_HALTED 0x40000UL
#define FLAG_XON 0x80000UL

View File

@@ -39,7 +39,7 @@ e-mail anklimov@gmail.com
Syslog udpSyslog(udpSyslogClient, SYSLOG_PROTO_BSD);
static char syslogDeviceHostname[16];
#if defined(debugSerialPort)
#if defined(debugSerialPort) && !defined(NOSERIAL)
Streamlog debugSerial(&debugSerialPort,LOG_DEBUG,&udpSyslog);
Streamlog errorSerial(&debugSerialPort,LOG_ERROR,&udpSyslog,ledRED);
Streamlog infoSerial (&debugSerialPort,LOG_INFO,&udpSyslog);
@@ -50,7 +50,7 @@ static char syslogDeviceHostname[16];
#endif
#else
#if defined(debugSerialPort)
#if defined(debugSerialPort) && !defined(NOSERIAL)
Streamlog debugSerial(&debugSerialPort,LOG_DEBUG);
Streamlog errorSerial(&debugSerialPort,LOG_ERROR, ledRED);
Streamlog infoSerial (&debugSerialPort,LOG_INFO);
@@ -139,6 +139,7 @@ bool owReady = false;
bool configOk = false; // At least once connected to MQTT
bool configLoaded = false;
bool initializedListeners = false;
uint8_t DHCP_failures = 0;
volatile int8_t ethernetIdleCount =0;
volatile int8_t configLocked = 0;
@@ -762,7 +763,8 @@ lan_status lanLoop() {
wdt_dis();
if (lanStatus >= HAVE_IP_ADDRESS)
{
int etherStatus = Ethernet.maintain();
int etherStatus = 0;
if (!DHCP_failures) etherStatus = Ethernet.maintain();
#ifndef Wiz5500
#define NO_LINK 5
@@ -1108,7 +1110,11 @@ if (WiFi.status() == WL_CONNECTED) {
IPAddress ip, dns, gw, mask;
int res = 1;
infoSerial<<F("Starting lan")<<endl;
if (sysConf.getIP(ip)) {
bool loadAddressRes = sysConf.getIP(ip);
if ( loadAddressRes &&
(!sysConf.getDHCPfallback() || (DHCP_failures >= DHCP_ATTEMPTS_FALLBACK))
)
{
infoSerial<<F("Loaded from flash IP:");
printIPAddress(ip);
if (sysConf.getDNS(dns)) {
@@ -1142,6 +1148,7 @@ if (WiFi.status() == WL_CONNECTED) {
if (res == 0) {
errorSerial<<F("Failed to configure Ethernet using DHCP. You can set ip manually!")<<F("'ip [ip[,dns[,gw[,subnet]]]]' - set static IP\n");
DHCP_failures++;
lanStatus = DO_REINIT;//-10;
//timerLanCheckTime = millis();// + DHCP_RETRY_INTERVAL;
#ifdef RESET_PIN
@@ -1149,8 +1156,25 @@ if (WiFi.status() == WL_CONNECTED) {
#endif
} else {
infoSerial<<F("Got IP address:");
printIPAddress(Ethernet.localIP());
ip=Ethernet.localIP();
printIPAddress(ip);
infoSerial<<endl;
sysConf.setIP(ip);
dns=Ethernet.dnsServerIP();
sysConf.setDNS(dns);
gw=Ethernet.gatewayIP();
sysConf.setGW(gw);
mask=Ethernet.subnetMask();
sysConf.setMask(mask);
sysConf.setDHCPfallback(true);
DHCP_failures = 0;
lanStatus = HAVE_IP_ADDRESS;
}
}//DHCP
@@ -1608,6 +1632,7 @@ int cmdFunctionIp(int arg_cnt, char **args)
printIPAddress(current_mask); */
//}
infoSerial<<F("Saved\n");
sysConf.setDHCPfallback(false);
return 200;
}
@@ -1757,7 +1782,7 @@ if (!sysConf.getServer(configServer,sizeof(configServer)))
// FILE is the return STREAM type of the HTTPClient
configStream = hclient.getURI(URI,NULL,get_header);
responseStatusCode = hclient.getLastReturnCode();
//debugSerial<<F("http retcode ")<<responseStatusCode<<endl;delay(100);
debugSerial<<F("http retcode ")<<responseStatusCode<<endl;delay(100);
//wdt_en();
if (configStream != NULL) {
@@ -2101,12 +2126,12 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
void setup_main() {
#if (SERIAL_BAUD)
#if defined(debugSerialPort)
#if defined(debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.begin(SERIAL_BAUD);
#endif
#else
#if not defined (__SAM3X8E__) && defined (debugSerialPort)
#if not defined (__SAM3X8E__) && defined (debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.begin();
#endif
delay(1000);
@@ -2125,13 +2150,13 @@ void setup_main() {
if(SPIFFS.begin())
#endif
{
#if defined(debugSerialPort)
#if defined(debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.println("SPIFFS Initialize....ok");
#endif
}
else
{
#if defined(debugSerialPort)
#if defined(debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.println("SPIFFS Initialization...failed");
#endif
}
@@ -2148,7 +2173,7 @@ void setup_main() {
if (!sysConf.isValidSysConf())
{
#if defined(debugSerialPort)
#if defined(debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.println(F("No valid EEPROM data. Initializing."));
#endif
sysConf.clear();
@@ -2185,7 +2210,7 @@ void setup_main() {
#else
pinMode(TXEnablePin, OUTPUT);
#endif
modbusSerial.begin(MODBUS_SERIAL_BAUD,dimPar);
modbusSerial.begin(MODBUS_SERIAL_BAUD,MODBUS_SERIAL_PARAM);
node.idle(&modbusIdle);
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
@@ -2277,11 +2302,17 @@ infoSerial<<F("\nFirmware MAC Address " QUOTE(CUSTOM_FIRMWARE_MAC));
#endif
#ifdef _modbus
infoSerial<<F("\n(+)MODBUS " QUOTE(MODBUS_DIMMER_PARAM) " at " QUOTE(modbusSerial) " speed:" QUOTE(MODBUS_SERIAL_BAUD));
infoSerial<<F("\n(+)MODBUS " QUOTE(MODBUS_SERIAL_PARAM) " at " QUOTE(modbusSerial) " speed:" QUOTE(MODBUS_SERIAL_BAUD));
#else
infoSerial<<F("\n(-)MODBUS");
#endif
#ifdef IPMODBUS
infoSerial<<F("\n(+)IPMODBUS ");// QUOTE(MODBUS_TCP_PARAM) " at " QUOTE(modbusSerial) " speed:" QUOTE(MODBUS_TCP_BAUD));
#else
infoSerial<<F("\n(-)IPMODBUS");
#endif
#ifndef OWIRE_DISABLE
infoSerial<<F("\n(+)OWIRE");
#ifdef USE_1W_PIN
@@ -2400,13 +2431,17 @@ infoSerial<<F("\n(-)MULTIVENT");
infoSerial<<F("\n(+)HUMIDIFIER");
#endif
#ifdef NOSERIAL
infoSerial<<F("\nNOSERIAL");
#endif
#ifdef ELEVATOR_ENABLE
infoSerial<<F("\n(+)ELEVATOR");
#endif
#ifdef IPMODBUS
infoSerial<<F("\n(+)IPMODBUS");
#endif
//#ifdef IPMODBUS
//infoSerial<<F("\n(+)IPMODBUS");
//#endif
infoSerial<<endl;
// WDT_Disable( WDT ) ;
@@ -2432,18 +2467,23 @@ void publishStat(){
uint32_t ut = millis()/1000UL;
if (!mqttClient.connected() || ethernetIdleCount) return;
setTopic(topic,sizeof(topic),T_DEV);
strncat_P(topic, stats_P, sizeof(topic));
strncat_P(topic, stats_P, sizeof(topic)-1);
strncat(topic, "/", sizeof(topic));
strncat_P(topic, freeheap_P, sizeof(topic));
strncat_P(topic, freeheap_P, sizeof(topic)-1);
printUlongValueToStr(intbuf, fr);
mqttClient.publish(topic,intbuf,true);
setTopic(topic,sizeof(topic),T_DEV);
strncat_P(topic, stats_P, sizeof(topic));
strncat_P(topic, stats_P, sizeof(topic)-1);
strncat(topic, "/", sizeof(topic));
strncat_P(topic, uptime_P, sizeof(topic));
strncat_P(topic, uptime_P, sizeof(topic)-1);
printUlongValueToStr(intbuf, ut);
mqttClient.publish(topic,intbuf,true);
setTopic(topic,sizeof(topic),T_DEV);
strncat_P(topic, state_P, sizeof(topic)-1);
strncpy_P(intbuf, ready_P, sizeof(intbuf)-1);
mqttClient.publish(topic,intbuf,true);
}
void setupMacAddress() {

View File

@@ -14,7 +14,7 @@
#define INTERVAL_AC_POLLING 5000L
static int driverStatus = CST_UNKNOWN;
//static int driverStatus = CST_UNKNOWN;
static int fresh =0;
static int power = 0;
@@ -39,6 +39,32 @@ const char QUIET_P[] PROGMEM = "queit";
const char SWING_P[] PROGMEM = "swing";
const char RAW_P[] PROGMEM = "raw";
void out_AC::getConfig(){
ACSerial=&AC_Serial;
if (item->getArgCount())
switch(portNum=item->getArg(0)){
case 0: ACSerial=&Serial;
break;
//#if defined (Serial1)
case 1: ACSerial=&Serial1;
break;
//#endif
//#if defined (Serial2)
case 2: ACSerial=&Serial2;
break;
//#endif
//#if defined (Serial3)
case 3: ACSerial=&Serial3;
break;
//#endif
}
}
void out_AC::InsertData(byte data[], size_t size){
char s_mode[10];
@@ -177,11 +203,11 @@ byte getCRC(byte req[], size_t size){
}
void out_AC::SendData(byte req[], size_t size){
AC_Serial.write(req, size - 1);
AC_Serial.write(getCRC(req, size-1));
//AC_Serial.flush();
ACSerial->write(req, size - 1);
ACSerial->write(getCRC(req, size-1));
//ACSerial->flush();
item->setExt(millisNZ());
debugSerial.print("AirCon<<");
debugSerial<<F("AirCon ")<<portNum<<F(" <<");
for (int i=0; i < size-1; i++)
{
if (req[i] < 10){
@@ -206,23 +232,30 @@ inline unsigned char toHex( char ch ){
int out_AC::Setup()
{
abstractOut::Setup();
debugSerial<<F("AC Init")<<endl;
AC_Serial.begin(9600);
driverStatus = CST_INITIALIZED;
if (!item) return 0;
debugSerial<<F("AC Init: ")<<portNum<<endl;
if (!portNum)// && (g_APinDescription[0].ulPinType == PIO_PA8A_URXD))
{
pinMode(0, INPUT_PULLUP);
}
ACSerial->begin(9600);
item->itemArr->subtype = CST_INITIALIZED;
//driverStatus = CST_INITIALIZED;
return 1;
}
int out_AC::Stop()
{
debugSerial<<F("AC De-Init")<<endl;
driverStatus = CST_UNKNOWN;
if (!item) return 0;
debugSerial<<F("AC De-Init: ")<<portNum<<endl;
item->itemArr->subtype = CST_UNKNOWN;
return 1;
}
int out_AC::Status()
{
return driverStatus;
if (!item) return 0;
return item->itemArr->subtype;
}
int out_AC::isActive()
@@ -240,16 +273,34 @@ if (cause!=POLLING_SLOW) return false;
SendData(qstn, sizeof(qstn)/sizeof(byte)); //Опрос кондиционера
}
if(AC_Serial.available() >= 37){ //was 0
AC_Serial.readBytes(data, 37);
while(AC_Serial.available()){
if(ACSerial->available() >= 37){ //was 0
ACSerial->readBytes(data, 37);
while(ACSerial->available()){
delay(2);
AC_Serial.read();
ACSerial->read();
}
debugSerial<<F("AirCon ")<<portNum<<F(" >> ");
for (int i=0; i < 37-1; i++)
{
if (data[i] < 10){
debugSerial.print("0");
debugSerial.print(data[i], HEX);
}
else
{
debugSerial.print(data[i], HEX);
}
}
if (data[36] != inCheck){
inCheck = data[36];
InsertData(data, 37);
debugSerial<<F(" OK");
}
debugSerial.println();
}
return true;
};
@@ -434,8 +485,8 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
hexbyte[0] = buf[i] ;
hexbyte[1] = buf[i+1] ;
data[i/2] = (toHex(hexbyte[0]) << 4) | toHex(hexbyte[1]);
AC_Serial.write(data, 37);
AC_Serial.flush();
ACSerial->write(data, 37);
ACSerial->flush();
publishTopic("RAW", buf);
}
*/
@@ -474,12 +525,12 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
data[9] = 1;
data[10] = 77;
data[11] = 95;
AC_Serial.flush();
ACSerial->flush();
uint32_t ts=item->getExt();
while (ts && !isTimeOver(ts,millis(),100)) yield();
SendData(data, sizeof(data)/sizeof(byte));
//InsertData(data, sizeof(data)/sizeof(byte));
//AC_Serial.flush();
//ACSerial->flush();
//item->setExt(millisNZ());
return 1;
}

View File

@@ -24,7 +24,8 @@ extern void modbusIdle(void) ;
class out_AC : public abstractOut {
public:
out_AC(Item * _item):abstractOut(_item){};
out_AC(Item * _item):abstractOut(_item){getConfig();};
void getConfig();
int Setup() override;
int Poll(short cause) override;
int Stop() override;
@@ -37,5 +38,12 @@ public:
protected:
void InsertData(byte data[], size_t size);
void SendData(byte req[], size_t size);
uint8_t portNum;
#if defined (__SAM3X8E__)
UARTClass *ACSerial;
#else
HardwareSerial *ACSerial;
#endif
};
#endif

View File

@@ -358,8 +358,10 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramObj->name);
if (execObj)
{
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array) markObj = execObj->child;
//Retrive previous data
aJsonObject *lastMeasured = aJson.getObjectItem(execObj,"@S");
aJsonObject *lastMeasured = aJson.getObjectItem(markObj,"@S");
if (lastMeasured)
{
if (lastMeasured->type == aJson_Int)
@@ -372,7 +374,7 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
else //No container to store value yet
{
debugSerial<<F("MBUS: Add @S: ")<<paramObj->name<<endl;
aJson.addNumberToObject(execObj, "@S", (long) param);
aJson.addNumberToObject(markObj, "@S", (long) param);
}
@@ -386,7 +388,7 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
if (*submitParam)
{
// Compare with last submitted val (if @V NOT marked as NULL in config)
aJsonObject *settedValue = aJson.getObjectItem(execObj,"@V");
aJsonObject *settedValue = aJson.getObjectItem(markObj,"@V");
if (settedValue && settedValue->type==aJson_Int && (settedValue->valueint == param))
{
debugSerial<<F("MBUSD: Ignored - equal with setted val")<<endl;
@@ -473,11 +475,14 @@ void out_Modbus::initLine()
int out_Modbus::sendModbus(char * paramName, int32_t value, uint8_t regType)
{
if (!store) return -1;
if (!store) {errorSerial<<F(" internal send error - no store")<<endl; return -1;}
aJsonObject * templateParamObj = aJson.getObjectItem(store->parameters, paramName);
if (!templateParamObj) return -1;
if (!templateParamObj) {errorSerial<<F(" internal send error - no template")<<endl; return -1;}
aJsonObject * regObj = aJson.getObjectItem(templateParamObj, "reg");
if (!regObj) return -2;
if (!regObj) {errorSerial<<F(" internal send error - no regObj")<<endl; return -2;}
int res = -1;
// int8_t regType = PAR_I16;
@@ -525,11 +530,16 @@ aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{
aJsonObject *execObj = itemParametersObj->child;
while (execObj && execObj->type == aJson_Object)
while (execObj && (execObj->type == aJson_Object) || (execObj->type == aJson_Array) )
{
if ((execObj->subtype & MB_NEED_SEND) && !(execObj->subtype & MB_SEND_ERROR))
{
aJsonObject *outValue = aJson.getObjectItem(execObj,"@V");
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array) markObj = execObj->child;
aJsonObject *outValue = aJson.getObjectItem(markObj,"@V");
if (outValue)
{
modbusBusy=1;
@@ -571,7 +581,7 @@ if (isTimeOver(store->timestamp,millis(),store->pollingInterval) && ( !mbusSlenc
if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{
aJsonObject *execObj = itemParametersObj->child;
while (execObj && execObj->type == aJson_Object)
while (execObj && (execObj->type == aJson_Object) || (execObj->type == aJson_Array))
{
if (execObj->subtype & MB_SEND_ERROR) execObj->subtype&=~ MB_SEND_ERROR;
if ((execObj->subtype & 0x3) >= MB_SEND_ATTEMPTS)
@@ -667,7 +677,7 @@ aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,suffixStr);
if (execObj && execObj->type == aJson_Object)
if (execObj && (execObj->type == aJson_Object) || (execObj->type == aJson_Array))
{
/*
aJsonObject *polledValue = aJson.getObjectItem(execObj,"@S");
@@ -680,7 +690,10 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{ //Schedule update
execObj->subtype |= MB_NEED_SEND;
aJsonObject *outValue = aJson.getObjectItem(execObj,"@V");
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array) markObj = execObj->child;
aJsonObject *outValue = aJson.getObjectItem(markObj,"@V");
if (outValue) // Existant. Preserve original @type
{
outValue->valueint=Value;
@@ -690,12 +703,12 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
// If no @V in config - creating with INT type - normal behavior - no supress in-to-out
{
debugSerial<<F("Add @V: ")<<execObj->name<<endl;
aJson.addNumberToObject(execObj, "@V", Value);
outValue = aJson.getObjectItem(execObj,"@V");
aJson.addNumberToObject(markObj, "@V", Value);
outValue = aJson.getObjectItem(markObj,"@V");
if (outValue) outValue->subtype =regType & 0xF;
}
aJsonObject *polledValue = aJson.getObjectItem(execObj,"@S");
aJsonObject *polledValue = aJson.getObjectItem(markObj,"@S");
if (polledValue && outValue->type == aJson_Int) polledValue->valueint=Value; //to pevent suppressing to change back to previously polled value if this occurs before next polling
}

View File

@@ -50,7 +50,7 @@ int out_Motor::Setup()
{
abstractOut::Setup();
getConfig();
debugSerial.println("Motor Init");
debugSerial.println("Motor: Init");
pinMode(pinUp,OUTPUT);
pinMode(pinDown,OUTPUT);
@@ -70,7 +70,7 @@ return 1;
int out_Motor::Stop()
{
debugSerial.println("Motor De-Init");
debugSerial.println("Motor: De-Init");
digitalWrite(pinUp,INACTIVE);
digitalWrite(pinDown,INACTIVE);
@@ -145,13 +145,13 @@ if (curPos>255) curPos=255;
}
if (motorOfftime && isTimeOver(motorOfftime,millis(),maxOnTime))
{dif = 0; debugSerial<<F("Motor timeout")<<endl;}
{dif = 0; debugSerial<<F("Motor: timeout")<<endl;}
else if (curPos>=0)
dif=targetPos-curPos;
else
dif=targetPos-255/2; // Have No feedback
debugSerial<<F("In:")<<pinFeedback<<F(" Val:")<<fb<<F("/")<<curPos<<F("->")<<targetPos<<F(" delta:")<<dif<<endl;
debugSerial<<F("Motor: in:")<<pinFeedback<<F(" Val:")<<fb<<F("/")<<curPos<<F("->")<<targetPos<<F(" delta:")<<dif<<endl;
if (dif<-POS_ERR)
{
@@ -241,7 +241,7 @@ else
}
else //Target zone
{ debugSerial.println("Target");
{ debugSerial.println("Motor: Target");
digitalWrite(pinUp,INACTIVE);
digitalWrite(pinDown,INACTIVE);
item->setExt(0);
@@ -263,10 +263,7 @@ int out_Motor::getChanType()
int out_Motor::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
{
//int chActive = item->isActive();
//bool toExecute = (chActive>0);
int suffixCode = cmd.getSuffix();
//itemCmd st(ST_PERCENTS,CMD_VOID);
if (cmd.isCommand() && !suffixCode) suffixCode=S_CMD; //if some known command find, but w/o correct suffix - got it
item->setFlag(FLAG_ACTION_NEEDED);
@@ -276,30 +273,15 @@ switch(suffixCode)
case S_NOTFOUND:
// turn on and set
toExecute = true;
debugSerial<<F("Forced execution");
debugSerial<<F("Motor: Forced execution");
case S_SET:
//case S_ESET:
if (!cmd.isValue()) return 0;
// item->setVal(cmd.getPercents());
if (item->getExt()) item->setExt(millisNZ()); //Extend motor time
/*
st.assignFrom(cmd);
//Store
st.saveItem(item);
if (!suffixCode)
{
if (chActive>0 && !st.getPercents()) item->setCmd(CMD_OFF);
if (chActive==0 && st.getPercents()) item->setCmd(CMD_ON);
item->SendStatus(FLAG_COMMAND | FLAG_PARAMETERS | FLAG_SEND_DEFFERED);
if (item->getExt()) item->setExt(millisNZ()); //Extend motor time
}
else item->SendStatus(FLAG_PARAMETERS | FLAG_SEND_DEFFERED);
*/
return 1;
//break;
case S_CMD:
//item->setCmd(cmd.getCmd());
switch (cmd.getCmd())
{
case CMD_ON:
@@ -307,7 +289,6 @@ case S_CMD:
return 1;
case CMD_OFF:
////item->SendStatus(FLAG_COMMAND);
if (item->getExt()) item->setExt(millisNZ()); //Extend motor time
return 1;

View File

@@ -97,6 +97,7 @@ int out_Multivent::getChanType()
int out_Multivent::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
{
if (cmd.getCmd()==CMD_DISABLE || cmd.getCmd()==CMD_ENABLE) return 0;
int suffixCode = cmd.getSuffix();
if (cmd.isCommand() && !suffixCode) suffixCode=S_CMD; //if some known command find, but w/o correct suffix - got it
@@ -229,6 +230,9 @@ debugSerial << F("Total V:")<<totalV<<F(" active V:")<<activeV/255<< F(" fan%:")
executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV).Cmd((fanV)?CMD_ON:CMD_OFF));
//Move gates only if fan is actually on
if (!fanV) return 1;
i=NULL;
if (gatesObj) i = gatesObj->child; //Pass 2: re-distribute airflow
@@ -250,8 +254,8 @@ while (i)
debugSerial<<i->name<<(" Req:")<<requestedV/255<<F(" Out:")<<out<<endl;
}
// executeCommand(i,-1,itemCmd().Percents255(out));
if (out != outObj->valueint)
if ((out != outObj->valueint))
{
//report out
executeCommand(i,-1,itemCmd().Percents255(out));
@@ -262,37 +266,6 @@ while (i)
}
return 1;
switch(suffixCode)
{
case S_NOTFOUND:
// turn on and set
toExecute = true;
debugSerial<<F("Forced execution");
case S_SET:
if (!cmd.isValue()) return 0;
return 1;
//break;
case S_CMD:
//item->setCmd(cmd.getCmd());
switch (cmd.getCmd())
{
case CMD_ON:
return 1;
case CMD_OFF:
return 1;
} //switch cmd
break;
} //switch suffix
debugSerial<<F("Unknown cmd")<<endl;
return 0;
}
#endif

View File

@@ -26,7 +26,7 @@ bool out_pid::getConfig()
aJsonObject * kPIDObj = aJson.getArrayItem(item->itemArg, 0);
if (!kPIDObj || kPIDObj->type != aJson_Array)
{
errorSerial<<F("Invalid PID param array.")<<endl;
errorSerial<<F("PID: Invalid param array.")<<endl;
return false;
}
double outMin=0.;
@@ -103,7 +103,7 @@ bool out_pid::getConfig()
if (limits) store->pid->SetOutputLimits(outMin,outMax);
store->pid->SetSampleTime(dT*1000.0);
return true;}
else errorSerial<<F("PID already initialized")<<endl;
else errorSerial<<F("PID: already initialized")<<endl;
return false;
}
@@ -120,7 +120,7 @@ store->pid=NULL;
//store->timestamp=millis();
if (getConfig())
{
infoSerial<<F("PID config loaded ")<< item->itemArr->name<<endl;
infoSerial<<F("PID: config loaded ")<< item->itemArr->name<<endl;
//item->On(); // Turn ON pid by default
// if (item->getCmd()) item->setFlag(FLAG_COMMAND);
// if (item->itemVal) item->setFlag(FLAG_PARAMETERS);
@@ -129,7 +129,7 @@ if (getConfig())
return 1;
}
else
{ errorSerial<<F("PID config error")<<endl;
{ errorSerial<<F("PID: config error")<<endl;
store->driverStatus = CST_FAILED;
return 0;
}
@@ -138,7 +138,7 @@ else
int out_pid::Stop()
{
debugSerial.println("PID De-Init");
debugSerial.println("PID: De-Init");
if (store) delete (store->pid);
delete store;
item->setPersistent(NULL);
@@ -164,29 +164,32 @@ int out_pid::Poll(short cause)
if (cause==POLLING_SLOW) return 0;
if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCmd()!=CMD_OFF))
{
//double prevOut=store->output;
//itemCmd st;
//st.loadItem(item);
//short cmd = st.getCmd();
if (item->getCmd() != CMD_OFF && /* item->getCmd() != CMD_DISABLE*/ ! item->getFlag(FLAG_DISABLED))
if (item->getCmd() != CMD_OFF && ! item->getFlag(FLAG_DISABLED))
{
if(store->pid->Compute() )
{
float alarmVal;
if (store->alarmArmed && ((alarmVal=getAlarmVal())>=0.)) store->output=alarmVal;
debugSerial<<F("PID ")<<item->itemArr->name<<F(" set:")<<store->setpoint<<F(" in:")<<store->input<<(" out:") << store->output <<F(" P:")<<store->pid->GetKp() <<F(" I:")<<store->pid->GetKi() <<F(" D:")<<store->pid->GetKd();
if (store->alarmArmed) debugSerial << F(" Alarm");
debugSerial<<F("PID: ")<<item->itemArr->name<<F(" set:")<<store->setpoint<<F(" in:")<<store->input<<(" out:") << store->output <<F(" P:")<<store->pid->GetKp() <<F(" I:")<<store->pid->GetKi() <<F(" D:")<<store->pid->GetKd();
//if (item->getFlag(FLAG_DISABLED)) debugSerial << F(" <DIS>");
if (store->alarmArmed) debugSerial << F(" <ALM>");
debugSerial<<endl;
if (((abs(store->output-store->prevOut)>OUTPUT_TRESHOLD) || (item->getCmd() == CMD_ENABLE)) && !store->alarmArmed)
if (((abs(store->output-store->prevOut)>OUTPUT_TRESHOLD) || (item->getFlag(FLAG_ACTION_NEEDED))) && !store->alarmArmed)
{
aJsonObject * oCmd = aJson.getArrayItem(item->itemArg, 1);
if ((item->getCmd() == CMD_ENABLE) && (store->output>0.))
if (((store->prevOut == 0.) && (store->output>0)) || item->getFlag(FLAG_ACTION_NEEDED))
// if ((item->getFlag(FLAG_ACTION_NEEDED)) && (store->output>0.))
{
executeCommand(oCmd,-1,itemCmd().Cmd(CMD_ON));
item->setCmd(CMD_VOID);
// item->clearFlag(FLAG_ACTION_NEEDED);
}
itemCmd value((float) (store->output));// * (100./255.)));
item->clearFlag(FLAG_ACTION_NEEDED);
itemCmd value((float) (store->output));
value.setSuffix(S_SET);
executeCommand(oCmd,-1,value);
store->prevOut=store->output;
@@ -200,6 +203,7 @@ if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCm
}
}
return 1;//store->pollingInterval;
};
@@ -208,7 +212,7 @@ float out_pid::getAlarmVal()
aJsonObject * kPIDObj = aJson.getArrayItem(item->itemArg, 0);
if (!kPIDObj || kPIDObj->type != aJson_Array)
{
errorSerial<<F("Invalid PID param array.")<<endl;
errorSerial<<F("PID: Invalid param array.")<<endl;
return -1.;
}
@@ -244,7 +248,7 @@ float out_pid::getAlarmVal()
else if (!alarmValDefined) outAlarm = 255.;
}
}
debugSerial<<F("Alarm value: ")<<outAlarm<< " ";
// debugSerial<<F("Alarm value: ")<<outAlarm<< " ";
return outAlarm;
}
@@ -295,7 +299,7 @@ case S_VAL:
// Input value for PID
if (!cmd.isValue()) return 0;
store->input=cmd.getFloat();
debugSerial<<F("Input value:")<<store->input<<endl;
debugSerial<<F("PID: ")<< item->itemArr->name <<F(" Input value:")<<store->input<<endl;
store->alarmTimer=millis();
if (store->alarmArmed)
@@ -309,11 +313,11 @@ return 1;
case S_NOTFOUND:
case S_SET:
//case S_ESET:
// Setpoint for PID
if (!cmd.isValue()) return 0;
store->setpoint=cmd.getFloat();
debugSerial<<F("Setpoint:")<<store->setpoint<<endl;
debugSerial<<F("PID: ")<< item->itemArr->name <<F(" Setpoint:")<<store->setpoint<<endl;
{
aJsonObject * itemCascadeObj = aJson.getArrayItem(item->itemArg, 2);
@@ -345,11 +349,14 @@ case S_CTRL:
case CMD_DRY:
executeCommand(oCmd,-1,value);
executeCommand(oCmd,-1,itemCmd().Cmd((item->getFlag(FLAG_DISABLED))?CMD_DISABLE:CMD_ENABLE));
item->SendStatus(FLAG_FLAGS);
return 1;
case CMD_ENABLE:
//item->setCmd(CMD_ENABLE);
//item->SendStatus(FLAG_COMMAND);
item->setFlag(FLAG_ACTION_NEEDED);
executeCommand(oCmd,-1,value);
store->prevOut=-2.0;
return 1;

View File

@@ -1,7 +1,7 @@
#pragma once
#include <Arduino.h>
#define DHCP_ATTEMPTS_FALLBACK 3
#define TENS_FRACT_LEN 2
#define TENS_BASE 100
@@ -138,12 +138,22 @@
#define MODBUS_SERIAL_BAUD 9600
#endif
#ifndef MODBUS_DIMMER_PARAM
#define MODBUS_DIMMER_PARAM SERIAL_8N1
#ifndef MODBUS_SERIAL_PARAM
#define MODBUS_SERIAL_PARAM SERIAL_8N1
#endif
#define dimPar MODBUS_DIMMER_PARAM
#define fmPar SERIAL_8N1
/*
#ifndef MODBUS_TCP_BAUD
#define MODBUS_TCP_BAUD 9600
#endif
#ifndef MODBUS_TCP_PARAM
#define MODBUS_TCP_PARAM SERIAL_8N1
#endif
*/
#define MODBUS_FM_BAUD 9600
#define MODBUS_FM_PARAM SERIAL_8N1
#ifndef SERIAL_BAUD
#define SERIAL_BAUD 115200
@@ -303,7 +313,7 @@
//#ifdef M5STACK
//#define debugSerial M5.Lcd
//#endif
#ifdef noSerial
#ifdef NOSERIAL
#undef debugSerialPort
#else
#ifndef debugSerialPort
@@ -346,3 +356,9 @@
//#define PINS_COUNT NUM_DIGITAL_PINS
#define isAnalogPin(p) ((p >= 14) && (p<=21))
#endif
#ifdef AVR
#define minimalMemory 200
#else
#define minimalMemory 1200
#endif

View File

@@ -30,7 +30,7 @@ Streamlog::Streamlog (SerialPortType * _serialPort, uint8_t _severity, uint8_t
severity=_severity;
}
#endif
/*
void Streamlog::begin(unsigned long speed)
{
if (serialPort) serialPort->begin(speed);
@@ -40,6 +40,7 @@ void Streamlog::end()
{
if (serialPort) serialPort->end();
};
*/
int Streamlog::available(void)
{
@@ -79,7 +80,7 @@ if (syslogInitialized && (udpDebugLevel>=severity))
}
else
{
if (logBufferPos<LOGBUFFER_SIZE-1 && (ch!='\r')) logBuffer[logBufferPos++]=ch;
if ((logBufferPos<LOGBUFFER_SIZE-1) && (ch!='\r')) logBuffer[logBufferPos++]=ch;
}
}
#endif
@@ -87,8 +88,8 @@ if (syslogInitialized && (udpDebugLevel>=severity))
#if defined (STATUSLED)
if ((ch=='\n') && ledPattern) statusLED.flash(ledPattern);
#endif
if (serialPort && (serialDebugLevel>=severity)) return serialPort->write(ch);
#if !defined(noSerial)
if (serialPort && (serialDebugLevel>=severity)) serialPort->write(ch);
#endif
return 1;
};

View File

@@ -36,8 +36,8 @@ class Streamlog : public Print
#else
Streamlog (SerialPortType * _serialPort, uint8_t _severity = LOG_DEBUG, uint8_t _ledPattern = 0);
#endif
void begin(unsigned long speed);
void end() ;
//void begin(unsigned long speed);
//void end() ;
int available(void);
int peek(void);

View File

@@ -27,7 +27,8 @@ const char EEPROM_signature[] = EEPROM_SIGNATURE;
uint8_t notGetConfigFromHTTP:1;
uint8_t udpDebugLevel:3;
uint8_t notSaveSuccedConfig:1;
uint8_t spare2;
uint8_t dhcpFallback:1;
uint8_t spare2:7;
uint16_t sysConfigHash;
};
} systemConfigFlags;

View File

@@ -114,7 +114,8 @@ const char LOW_P[] PROGMEM = "LOW";
const char ERROR_P[] PROGMEM = "ERR";
const char ENABLE_P[] PROGMEM = "ENABLE";
const char DISABLE_P[] PROGMEM = "DISABLE";
const char FREEZE_P[] PROGMEM = "FREEZE";
const char UNFREEZE_P[] PROGMEM = "UNFREEZE";
// SubTopics
const char SET_P[] PROGMEM = "set";

View File

@@ -719,6 +719,13 @@ switch (cmdType)
Item it(item->valuestring);
if (it.isValid())
{
int fr = freeRam();
if (fr < minimalMemory)
{
errorSerial<<F("CTRL/exec: OutOfMemory: ")<<fr<<endl;
return -1;
}
if (itemCommand) it.Ctrl(itemCommand);
else it.Ctrl(_itemCmd);
}

View File

@@ -331,6 +331,7 @@ monitor_speed = 115200
platform = atmelavr
board = megaatmega2560
upload_port = net:192.168.88.2:23000
_upload_command = custom-build-flags/upload_mega2560slim-5100 $SOURCE
framework = arduino
build_flags = !python get_build_flags.py mega2560slim-5100
extra_scripts = post:toBin.py