diff --git a/lighthub/dmx.cpp b/lighthub/dmx.cpp index 7c44313..07bbf9b 100644 --- a/lighthub/dmx.cpp +++ b/lighthub/dmx.cpp @@ -192,6 +192,7 @@ void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* d void DMXinSetup(int channels) { + if (DMXin) return;/// ToDo: re-init // //Use digital pin 3 for DMX output. Must be a PWM channel. // DmxSimple.usePin(pin); //DmxSimple.maxChannel(channels); diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 04d2569..5a4c50b 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -35,10 +35,10 @@ e-mail anklimov@gmail.com #define fmPar SERIAL_8N1 short modbusBusy = 0; -extern aJsonObject *modbusItem; +extern aJsonObject *pollingItem; -int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value); +//int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value); extern PubSubClient mqttClient; //extern char outprefix[]; @@ -83,13 +83,14 @@ void Item::Parse() { itemArg = aJson.getArrayItem(itemArr, I_ARG); itemVal = aJson.getArrayItem(itemArr, I_VAL); - +/* Serial.print(F(" Item:")); Serial.print(itemArr->name); Serial.print(F(" T:")); Serial.print(itemType); Serial.print(F(" =")); Serial.println(getArg()); + */ } } @@ -163,9 +164,9 @@ void Item::setVal(short n, int par) // Only store if VAL is array defined in c void Item::setVal(long int par) // Only store if VAL is int (autogenerated or config-defined) { if (!itemVal || itemVal->type != aJson_Int) return; - Serial.print(F(" Store ")); - Serial.print(F(" Val=")); - Serial.println(par); + // Serial.print(F(" Store ")); + // Serial.print(F(" Val=")); + // Serial.println(par); itemVal->valueint = par; } @@ -193,7 +194,7 @@ void analogWrite(int pin, int val) boolean Item::getEnableCMD(int delta) { - return ((millis() - lastctrl > (unsigned long) delta));//|| (itemArr!=lastobj)); + return ((millis() - lastctrl > (unsigned long) delta));// || ((void *)itemArr != (void *) lastobj)); } int Item::Ctrl(short cmd, short n, int *Par, boolean send) { @@ -246,14 +247,14 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) { st.s = Par[1]; st.v = Par[2]; setVal(st.aslong); - if (send) SendCmd(0,3,Par); // Send back triplet ? + if (send) SendStatus(0,3,Par,true); // Send back triplet ? break; case CH_PWM: case CH_VC: case CH_DIMMER: case CH_MODBUS: - if (send) SendCmd(0, 1, Par); // Send back parameter for channel above this line + if (send) SendStatus(0, 1, Par,true); // Send back parameter for channel above this line case CH_THERMO: case CH_VCTEMP: setVal(Par[0]); // Store value @@ -280,8 +281,9 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) { Par[1] = st.s; Par[2] = st.v; if (!Par[2]) Par[2]=80; //If RGB value==0 set to 80% + setVal(st.aslong); params = 3; - SendCmd(0, params, Par); // Send restored triplet. In any cases + SendStatus(0, params, Par,true); // Send restored triplet. In any cases break; case CH_VCTEMP: @@ -293,15 +295,15 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) { Par[0] = st.aslong; params = 1; - SendCmd(0, params, Par); // Send restored parameter, even if send=false - no problem, loop will be supressed at next hop + SendStatus(0, params, Par, true); // Send restored parameter, even if send=false - no problem, loop will be supressed at next hop break; case CH_THERMO: Par[0] = st.aslong; params = 0; - if (send) SendCmd(CMD_ON); // Just ON (switch) + if (send) SendStatus(CMD_ON); // Just ON (switch) break; default: - if (send) SendCmd(cmd); // Just send ON + if (send) SendStatus(cmd); // Just send ON }//itemtype else {// Default settings Serial.print(st.aslong); @@ -329,7 +331,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) { if (send) setCmd(cmd); } else { //Double ON - apply special preset - clean white full power - switch (itemType) { + if (getEnableCMD(500)) switch (itemType) { case CH_RGBW: Serial.println(F("Force White")); itemType = CH_WHITE; @@ -343,7 +345,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) { setVal(st.aslong); //Send to OH - if (send) SendCmd(0, 3, Par); + if (send) SendStatus(0, 3, Par); break; } //itemtype } //else @@ -361,7 +363,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) { Par[1] = 0; Par[2] = 0; setCmd(cmd); - if (send) SendCmd(cmd); ///? + if (send) SendStatus(cmd); } break; @@ -372,7 +374,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) { Par[1] = 0; Par[2] = 0; setCmd(cmd); - SendCmd(CMD_OFF); //HALT to OFF mapping - send in any cases + SendStatus(CMD_OFF); //HALT to OFF mapping - send in any cases Serial.println(F(" Halted")); } @@ -433,7 +435,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) { int _reg = aJson.getArrayItem(itemArg, 1)->valueint; int _mask = aJson.getArrayItem(itemArg, 2)->valueint; - modbusSet(_addr, _reg, _mask, map(Par[0], 0, 100, 0, 0x3f)); + modbusDimmerSet(_addr, _reg, _mask, map(Par[0], 0, 100, 0, 0x3f)); } break; } @@ -655,9 +657,12 @@ POLL 2101x10 */ -void mb_fail(short addr, short op, int val, int cmd) { +void Item::mb_fail(short addr, short op, int val, int cmd) { Serial.println(F("Modbus op failed")); - +// int cmd = getCmd(); +// if (cmd<0) return; + setCmd(cmd | CMD_RETRY); + setVal(val); } extern ModbusMaster node; @@ -731,16 +736,24 @@ int Item::VacomSetHeat(int addr, int8_t val, int8_t cmd) { } -int Item::SendCmd(short cmd, short n, int *Par) { +int Item::SendStatus(short cmd, short n, int *Par, boolean deffered) { /// ToDo: relative patches, configuration + if (deffered) { + setCmd(cmd | CMD_REPORT); + Serial.println(F("Status deffered")); + // mqttClient.publish("/push", "1"); + return 0; + // Todo: Parameters? Now expected that parameters already stored by setVal() + } + else { //publush to MQTT char addrstr[32]; //char addrbuf[17]; char valstr[16] = ""; strcpy_P(addrstr, outprefix); - strncat(addrstr, itemArr->name, sizeof(addrstr)); //// + strncat(addrstr, itemArr->name, sizeof(addrstr)); switch (cmd) { @@ -766,21 +779,24 @@ int Item::SendCmd(short cmd, short n, int *Par) { } break; default: + Serial.println(F("Unknown cmd ")); return -1; } - + Serial.print(F("Pub: ")); Serial.print(addrstr); Serial.print(F("->")); Serial.println(valstr); mqttClient.publish(addrstr, valstr,true); return 0; + } } -int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value) { +int Item::modbusDimmerSet(int addr, uint16_t _reg, int _mask, uint16_t value) { if (modbusBusy) { mb_fail(3, addr, value, 0); + return -1; }; modbusBusy = 1; @@ -810,6 +826,7 @@ int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value) { int Item::checkFM() { if (modbusBusy) return -1; + if (checkModbusRetry()) return -2; modbusBusy = 1; uint8_t j, result; @@ -888,13 +905,19 @@ int Item::checkFM() { } int set = node.getResponseBuffer(0); - if (set) aJson.addNumberToObject(out, "set", set * a + b); - aJson.addNumberToObject(out, "t", (int) node.getResponseBuffer(1) * a + b); + float fset; + float ftemp; + if (set) aJson.addNumberToObject(out, "set", fset =set * a + b); + aJson.addNumberToObject(out, "t", ftemp =(int) node.getResponseBuffer(1) * a + b); // aJson.addNumberToObject(out,"d", (int) node.getResponseBuffer(2)*a+b); int pwr = node.getResponseBuffer(3); if (pwr > 0) aJson.addNumberToObject(out, "pwr", pwr / 10.); else aJson.addNumberToObject(out, "pwr", 0); - - + + if (ftemp>fset+FM_OVERHEAT_CELSIUS) + { + mqttClient.publish("/alarm/ovrht", itemArr->name); + Ctrl(CMD_OFF); //Shut down + } Serial.println(); } else { Serial.print(F("Modbus polling error=")); @@ -910,9 +933,21 @@ int Item::checkFM() { modbusBusy = 0; } +boolean Item::checkModbusRetry() { + int cmd = getCmd(); + if (cmd & CMD_RETRY) { // if last sending attempt of command was failed + int val = getVal(); + Serial.println(F("Retrying CMD")); + cmd &= ~CMD_RETRY; // Clean retry flag + Ctrl(cmd,1,&val); // Execute command again + return true; + } +return false; +} -int Item::checkModbus() { +int Item::checkModbusDimmer() { if (modbusBusy) return -1; + if (checkModbusRetry()) return -2; modbusBusy = 1; uint8_t result; @@ -933,9 +968,11 @@ int Item::checkModbus() { if (result == node.ku8MBSuccess) { data = node.getResponseBuffer(0); - Serial.print(F("Modbus Val: ")); + Serial.print(F("MB: ")); + Serial.print(itemArr->name); + Serial.print(F(" Val: ")); Serial.println(data, HEX); - checkModbus(data); + checkModbusDimmer(data); } else { Serial.print(F("Modbus polling error=")); Serial.println(result, HEX); @@ -944,18 +981,18 @@ int Item::checkModbus() { modbusBusy = 0; // Looking 1 step ahead for modbus item, which uses same register - Item nextItem(modbusItem->next); - if (modbusItem && nextItem.isValid() && nextItem.itemType == CH_MODBUS && nextItem.getArg(0) == addr && + Item nextItem(pollingItem->next); + if (pollingItem && nextItem.isValid() && nextItem.itemType == CH_MODBUS && nextItem.getArg(0) == addr && nextItem.getArg(1) == reg) { - nextItem.checkModbus(data); - modbusItem = modbusItem->next; - if (!modbusItem) modbusItem = items->child; + nextItem.checkModbusDimmer(data); + pollingItem = pollingItem->next; + if (!pollingItem) pollingItem = items->child; } } -int Item::checkModbus(int data) { +int Item::checkModbusDimmer(int data) { short mask = getArg(2); int d = data; if (mask) d >>= 8; @@ -966,14 +1003,14 @@ int Item::checkModbus(int data) { if (getVal() != d || d && cmd == CMD_OFF || d && cmd == CMD_HALT) //volume changed or turned on manualy { if (d) { // Actually turned on - if (cmd == CMD_OFF || cmd == CMD_HALT) SendCmd(CMD_ON); //update OH with ON if it was turned off before - SendCmd(0, 1, &d); //update OH with value + if (cmd == CMD_OFF || cmd == CMD_HALT) SendStatus(CMD_ON); //update OH with ON if it was turned off before + SendStatus(0, 1, &d); //update OH with value setCmd(CMD_ON); //store command setVal(d); //store value } else { if (cmd != CMD_HALT && cmd != CMD_OFF) { setCmd(CMD_OFF); // store command (not value) - SendCmd(CMD_OFF);// update OH + SendStatus(CMD_OFF);// update OH } } } //if data changed @@ -982,10 +1019,60 @@ int Item::checkModbus(int data) { int Item::Poll() { switch (itemType) { case CH_MODBUS: - checkModbus(); + checkModbusDimmer(); + sendDelayedStatus(); + return INTERVAL_CHECK_MODBUS; break; case CH_VC: checkFM(); + return INTERVAL_CHECK_MODBUS; + break; + case CH_RGB: //All channels with slider generate too many updates + case CH_RGBW: + case CH_DIMMER: + case CH_PWM: + sendDelayedStatus(); } + return INTERVAL_POLLING; +} + +void Item::sendDelayedStatus(){ + HSVstore st; + int cmd=getCmd(); + short params = 0; + int Par[3]; + if (cmd & CMD_REPORT) + { + //retrive stored values + st.aslong = getVal(); + switch (itemType) { + //case CH_GROUP: + case CH_RGBW: + case CH_RGB: + Par[0] = st.h; + Par[1] = st.s; + Par[2] = st.v; + params = 3; + SendStatus(0, params, Par); // Send restored triplet. + break; + + case CH_VCTEMP: + case CH_PWM: + case CH_DIMMER: //Everywhere, in flat VAL + case CH_MODBUS: + case CH_VC: + case CH_THERMO: + + + Par[0] = st.aslong; + params = 1; + SendStatus(0, params, Par); // Send restored parameter + break; + default: + SendStatus(cmd); // Just send CMD + }//itemtype + cmd &= ~CMD_REPORT; // Clean report flag + setCmd(cmd); + } } diff --git a/lighthub/item.h b/lighthub/item.h index 6ff8c79..bc5bbbe 100644 --- a/lighthub/item.h +++ b/lighthub/item.h @@ -38,6 +38,8 @@ e-mail anklimov@gmail.com #define CMD_TOGGLE 4 #define CMD_CURTEMP 127 #define CMD_SET 9 +#define CMD_RETRY 64 +#define CMD_REPORT 32 #define I_TYPE 0 //Type of item #define I_ARG 1 //Chanel-type depended argument or array of arguments (pin, address etc) @@ -99,15 +101,19 @@ class Item inline int Off(){Ctrl(CMD_OFF);}; inline int Toggle(){Ctrl(CMD_TOGGLE);}; int Poll(); - int SendCmd(short cmd,short n=0, int * Par=NULL); + int SendStatus(short cmd, short n=0, int * Par=NULL, boolean deferred = false); protected: int VacomSetFan (int8_t val, int8_t cmd=0); int VacomSetHeat(int addr, int8_t val, int8_t cmd=0); + int modbusDimmerSet(int addr, uint16_t _reg, int _mask, uint16_t value); + void mb_fail(short addr, short op, int val, int cmd); int isActive(); void Parse(); - int checkModbus(); - int checkModbus(int data); + int checkModbusDimmer(); + int checkModbusDimmer(int data); + boolean checkModbusRetry(); + void sendDelayedStatus(); int checkFM(); diff --git a/lighthub/main.cpp b/lighthub/main.cpp index ef1cbca..676cc87 100644 --- a/lighthub/main.cpp +++ b/lighthub/main.cpp @@ -1,5 +1,4 @@ -/* Copyright © 2017-2018 Andrey Klimov. All rights reserved. - +/* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -83,12 +82,12 @@ aJsonObject *modbusArr = NULL; aJsonObject *owArr = NULL; aJsonObject *dmxArr = NULL; -unsigned long nextModbusCheck = 0; +unsigned long nextPollingCheck = 0; unsigned long nextInputCheck = 0; unsigned long lanCheck = 0; unsigned long nextThermostatCheck = 0; -aJsonObject *modbusItem = NULL; +aJsonObject *pollingItem = NULL; bool owReady = false; int lanStatus = 0; @@ -201,10 +200,10 @@ void mqttCallback(char *topic, byte *payload, unsigned int length) { } case CMD_ON: - if (item.getEnableCMD(500) || lanStatus == 4) + // if (item.getEnableCMD(500) || lanStatus == 4) item.Ctrl(cmd, 0, NULL, !retaining); //Accept ON command not earlier then 500 ms after set settings (Homekit hack) - else Serial.println(F("on Skipped")); + // else Serial.println(F("on Skipped")); break; default: //some known command @@ -563,6 +562,7 @@ void applyConfig() { if (owArr && !owReady) { aJsonObject *item = owArr->child; owReady = owSetup(&Changed); + t_count=0; while (item) { if ((item->type == aJson_Object)) { DeviceAddress addr; @@ -575,7 +575,7 @@ void applyConfig() { } #endif items = aJson.getObjectItem(root, "items"); - modbusItem = items->child; + pollingItem = items->child; inputs = aJson.getObjectItem(root, "in"); mqttArr = aJson.getObjectItem(root, "mqtt"); printConfigSummary(); @@ -761,9 +761,9 @@ int getConfig(int arg_cnt, char **args) lanCheck = millis() + 15000; return -11; } else { - char *outstr = aJson.print(root); - Serial.println(outstr); - free(outstr); + // char *outstr = aJson.print(root); + // Serial.println(outstr); + // free(outstr); applyConfig(); @@ -956,13 +956,13 @@ void loop_main() { #endif // if (lastpacket && (lastpacket%10==0)) Serial.println(lastpacket); -#ifdef _modbus - if (modbusArr && items) modbusLoop(); -#endif - +if (items) { +if (lanStatus!=4) pollingLoop(); #ifdef _owire - if (items) thermoLoop(); +thermoLoop(); #endif +} + if (inputs) inputLoop(); @@ -1023,27 +1023,18 @@ void inputLoop(void) { } } -void modbusLoop(void) { +void pollingLoop(void) { boolean done = false; - if (millis() > nextModbusCheck) { - while (modbusItem && !done) { - if (modbusItem->type == aJson_Array) { - switch (aJson.getArrayItem(modbusItem, 0)->valueint) { - case CH_MODBUS: - //case CH_VCTEMP: - case CH_VC: { - Item it(modbusItem); - it.Poll(); - nextModbusCheck = millis() + INTERVAL_CHECK_MODBUS; - done = true; - break; //case; - } - } //switch - + if (millis() > nextPollingCheck) { + while (pollingItem && !done) { + if (pollingItem->type == aJson_Array) { + Item it(pollingItem); + nextPollingCheck = millis() + it.Poll(); //INTERVAL_CHECK_MODBUS; + done= true; }//if - modbusItem = modbusItem->next; - if (!modbusItem) { - modbusItem = items->child; + pollingItem = pollingItem->next; + if (!pollingItem) { + pollingItem = items->child; return; } //start from 1-st element } //while @@ -1076,9 +1067,11 @@ void thermoLoop(void) { } else { if (!(--aJson.getArrayItem(itemExtensionArray, IET_ATTEMPTS)->valueint)) - mqttClient.publish("/alarm", item->name); + mqttClient.publish("/alarm/snsr", item->name); } + if (curtemp>itemTempSetting+THERMO_OVERHEAT_CELSIUS) mqttClient.publish("/alarm/ovrht", item->name); + thermostatCheckPrinted = true; Serial.print(item->name); Serial.print(F(" Set:")); @@ -1139,7 +1132,7 @@ short thermoSetCurTemp(char *name, short t) { else if (extArray = aJson.getArrayItem(item, I_EXT)) { aJsonObject *att = aJson.getArrayItem(extArray, IET_ATTEMPTS); aJson.getArrayItem(extArray, IET_TEMP)->valueint = t; - if (att->valueint == 0) mqttClient.publish("/alarmoff", item->name); + if (att->valueint == 0) mqttClient.publish("/alarmoff/snsr", item->name); att->valueint = (int) T_ATTEMPTS; } //if diff --git a/lighthub/main.h b/lighthub/main.h index 972ed77..1437b35 100644 --- a/lighthub/main.h +++ b/lighthub/main.h @@ -162,7 +162,7 @@ void modbusIdle(void); void inputLoop(void); -void modbusLoop(void); +void pollingLoop(void); void thermoLoop(void); diff --git a/lighthub/options.h b/lighthub/options.h index 62fdedc..a949e7b 100644 --- a/lighthub/options.h +++ b/lighthub/options.h @@ -1,6 +1,6 @@ // Configuration of drivers enabled #ifndef PIO_SRC_REV -#define PIO_SRC_REV v0.992 +#define PIO_SRC_REV v0.993 #endif #define TXEnablePin 13 @@ -10,11 +10,14 @@ #define IET_ATTEMPTS 1 #define THERMO_GIST_CELSIUS 2 +#define THERMO_OVERHEAT_CELSIUS 5 +#define FM_OVERHEAT_CELSIUS 5. #define EEPROM_offset 32+6 #define INTERVAL_CHECK_INPUT 50 #define INTERVAL_CHECK_MODBUS 2000 +#define INTERVAL_POLLING 100 #define THERMOSTAT_CHECK_PERIOD 5000 #ifndef MODBUS_SERIAL_BAUD diff --git a/lighthub/owTerm.cpp b/lighthub/owTerm.cpp index eec479b..884b0d6 100644 --- a/lighthub/owTerm.cpp +++ b/lighthub/owTerm.cpp @@ -86,7 +86,7 @@ int owUpdate() { int owSetup(owChangedType owCh) { //// todo - move memory allocation to here - + if (net) return true; // Already initialized #ifdef DS2482_100_I2C_TO_1W_BRIDGE Serial.println(F("DS2482_100_I2C_TO_1W_BRIDGE init")); net = new OneWire; @@ -182,6 +182,7 @@ int owFind(DeviceAddress addr) { } void owAdd(DeviceAddress addr) { + if (t_count>=t_max) return; wstat[t_count] = SW_FIND; //Newly detected memcpy(term[t_count], addr, 8); //term[t_count]=addr;