diff --git a/HeishaMon/HeishaMon.ino b/HeishaMon/HeishaMon.ino index 40b721e1..53adf567 100644 --- a/HeishaMon/HeishaMon.ino +++ b/HeishaMon/HeishaMon.ino @@ -1,3 +1,4 @@ + #define LWIP_INTERNAL #include @@ -1013,6 +1014,9 @@ void timer_cb(int nr) { case -1: { LittleFS.begin(); LittleFS.format(); + //create first boot file + File startupFile = LittleFS.open("/heishamon", "w"); + startupFile.close(); WiFi.disconnect(true); timerqueue_insert(1, 0, -2); } break; @@ -1142,11 +1146,13 @@ void send_panasonic_query() { send_command(panasonicQuery, PANASONICQUERYSIZE); panasonicQuery[3] = 0x10; //setting 4th back to 0x10 for normal data request next time } else if (!extraDataBlockChecked) { - extraDataBlockChecked = true; - log_message(_F("Checking if connected heatpump has extra data")); - panasonicQuery[3] = 0x21; - send_command(panasonicQuery, PANASONICQUERYSIZE); - panasonicQuery[3] = 0x10; + if ((actData[0] == 0x71) && (actData[193] == 0) ) { //do we have data but 0 value in heat consumptiom power, then assume K or L series + extraDataBlockChecked = true; + log_message(_F("Checking if connected heatpump has extra data")); + panasonicQuery[3] = 0x21; + send_command(panasonicQuery, PANASONICQUERYSIZE); + panasonicQuery[3] = 0x10; + } } } diff --git a/HeishaMon/HeishaOT.cpp b/HeishaMon/HeishaOT.cpp index da546616..bd42e7d9 100644 --- a/HeishaMon/HeishaOT.cpp +++ b/HeishaMon/HeishaOT.cpp @@ -30,6 +30,7 @@ struct heishaOTDataStruct_t heishaOTDataStruct[] = { { "flameState", TBOOL, { .b = false }, 1 }, //provides current flame state to thermostat { "chState", TBOOL, { .b = false }, 1 }, //provides if boiler is in centrale heating state { "dhwState", TBOOL, { .b = false }, 1 }, //provides if boiler is in dhw heating state + { "roomSetOverride", TFLOAT, { .f = 0 }, 1 }, //provides a room setpoint override ID9 (not implemented completly in heishamon) { NULL, 0, 0, 0 } }; @@ -225,7 +226,7 @@ void processOTRequest(unsigned long request, OpenThermResponseStatus status) { unsigned long data = ot.temperatureToData(getOTStructMember(_F("inletTemp"))->value.f); otResponse = ot.buildResponse(OpenThermMessageType::READ_ACK, OpenThermMessageID::Tret, data); } else { - otResponse = ot.buildResponse(OpenThermMessageType::DATA_INVALID, OpenThermMessageID::Tboiler, request & 0xffff); + otResponse = ot.buildResponse(OpenThermMessageType::DATA_INVALID, OpenThermMessageID::Tret, request & 0xffff); } } break; case OpenThermMessageID::Tdhw: { @@ -234,7 +235,7 @@ void processOTRequest(unsigned long request, OpenThermResponseStatus status) { unsigned long data = ot.temperatureToData(getOTStructMember(_F("dhwTemp"))->value.f); otResponse = ot.buildResponse(OpenThermMessageType::READ_ACK, OpenThermMessageID::Tdhw, data); } else { - otResponse = ot.buildResponse(OpenThermMessageType::DATA_INVALID, OpenThermMessageID::Tboiler, request & 0xffff); + otResponse = ot.buildResponse(OpenThermMessageType::DATA_INVALID, OpenThermMessageID::Tdhw, request & 0xffff); } } break; case OpenThermMessageID::Toutside: { @@ -244,9 +245,21 @@ void processOTRequest(unsigned long request, OpenThermResponseStatus status) { otResponse = ot.buildResponse(OpenThermMessageType::READ_ACK, OpenThermMessageID::Toutside, data); } else { - otResponse = ot.buildResponse(OpenThermMessageType::DATA_INVALID, OpenThermMessageID::Tboiler, request & 0xffff); + otResponse = ot.buildResponse(OpenThermMessageType::DATA_INVALID, OpenThermMessageID::Toutside, request & 0xffff); + } + } break; + case OpenThermMessageID::TrOverride: { + log_message(_F("OpenTherm: Received read room set override temp")); + if (getOTStructMember(_F("roomSetOverride"))->value.f > -99) { + unsigned long data = ot.temperatureToData(getOTStructMember(_F("roomSetOverride"))->value.f); + otResponse = ot.buildResponse(OpenThermMessageType::READ_ACK, OpenThermMessageID::TrOverride, data); + + } else { + otResponse = ot.buildResponse(OpenThermMessageType::DATA_INVALID, OpenThermMessageID::TrOverride, request & 0xffff); } } break; + + /* case OpenThermMessageID::ASFflags: { log_message(_F("OpenTherm: Received read ASF flags")); diff --git a/HeishaMon/decode.cpp b/HeishaMon/decode.cpp index 01de6b20..8b3537a4 100644 --- a/HeishaMon/decode.cpp +++ b/HeishaMon/decode.cpp @@ -313,12 +313,7 @@ void decode_heatpump_data_extra(char* data, char* actDataExtra, PubSubClient &mq for (unsigned int Topic_Number = 0 ; Topic_Number < NUMBER_OF_TOPICS_EXTRA ; Topic_Number++) { String Topic_Value; Topic_Value = getDataValueExtra(data, Topic_Number); - { - char log_msg[256]; - sprintf_P(log_msg, PSTR("testing XTOP%d %s: %s"), Topic_Number, xtopics[Topic_Number], Topic_Value.c_str()); - log_message(log_msg); - } - + if ((updatenow) || ( getDataValueExtra(actDataExtra, Topic_Number) != Topic_Value )) { char log_msg[256]; char mqtt_topic[256]; @@ -326,7 +321,7 @@ void decode_heatpump_data_extra(char* data, char* actDataExtra, PubSubClient &mq log_message(log_msg); sprintf_P(mqtt_topic, PSTR("%s/%s/%s"), mqtt_topic_base, mqtt_topic_xvalues, xtopics[Topic_Number]); mqtt_client.publish(mqtt_topic, Topic_Value.c_str(), MQTT_RETAIN_VALUES); - rules_event_cb(_F("^"),xtopics[Topic_Number]); + rules_event_cb(_F("@"), xtopics[Topic_Number]); } } } diff --git a/HeishaMon/decode.h b/HeishaMon/decode.h index eb29d2e6..36f71f2b 100644 --- a/HeishaMon/decode.h +++ b/HeishaMon/decode.h @@ -9,6 +9,7 @@ void resetlastalldatatime(); String getDataValue(char* data, unsigned int Topic_Number); String getDataValueExtra(char* data, unsigned int Topic_Number); +String getOptDataValue(char* data, unsigned int Topic_Number); void decode_heatpump_data(char* data, char* actData, PubSubClient &mqtt_client, void (*log_message)(char*), char* mqtt_topic_base, unsigned int updateAllTime); void decode_heatpump_data_extra(char* data, char* actDataExtra, PubSubClient &mqtt_client, void (*log_message)(char*), char* mqtt_topic_base, unsigned int updateAllTime); void decode_optional_heatpump_data(char* data, char* actOptDat, PubSubClient &mqtt_client, void (*log_message)(char*), char* mqtt_topic_base, unsigned int updateAllTime); @@ -136,12 +137,12 @@ static const char optTopics[][20] PROGMEM = { }; static const char xtopics[][MAX_TOPIC_LEN] PROGMEM = { - "Heat_Power_Consumption", //XTOP0 - "Cool_Power_Consumption", //XTOP1 - "DHW_Power_Consumption", //XTOP2 - "Heat_Power_Production", //XTOP3 - "Cool_Power_Production", //XTOP4 - "DHW_Power_Production", //XTOP5 + "Heat_Power_Consumption_Extra", //XTOP0 + "Cool_Power_Consumption_Extra", //XTOP1 + "DHW_Power_Consumption_Extra", //XTOP2 + "Heat_Power_Production_Extra", //XTOP3 + "Cool_Power_Production_Extra", //XTOP4 + "DHW_Power_Production_Extra", //XTOP5 }; static const byte xtopicBytes[] PROGMEM = { //can store the index as byte (8-bit unsigned humber) as there aren't more then 255 bytes (actually only 203 bytes) to decode diff --git a/HeishaMon/rules.cpp b/HeishaMon/rules.cpp index 90d5b631..5863a4ce 100755 --- a/HeishaMon/rules.cpp +++ b/HeishaMon/rules.cpp @@ -27,6 +27,7 @@ #include "commands.h" #define MAXCOMMANDSINBUFFER 10 +#define OPTDATASIZE 20 bool send_command(byte* command, int length); @@ -34,6 +35,7 @@ extern int dallasDevicecount; extern dallasDataStruct *actDallasData; extern settingsStruct heishamonSettings; extern char actData[DATASIZE]; +extern char actOptData[OPTDATASIZE]; extern char actDataExtra[DATASIZE]; extern String openTherm[2]; static uint8_t parsing = 0; @@ -173,7 +175,6 @@ static int is_variable(char *text, unsigned int *pos, unsigned int size) { break; } } - if(match == 0) { int nrtopics = sizeof(topics)/sizeof(topics[0]); for(x=0;xtoken[0] == '&') { - for(i=0;itoken[1]) == 0) { + String dataValue = actOptData[0] == '\0' ? "" : getOptDataValue(actOptData, i); + char *str = (char *)dataValue.c_str(); + if(strlen(str) == 0) { + memset(&vnull, 0, sizeof(struct vm_vnull_t)); + vnull.type = VNULL; + vnull.ret = token; + + return (unsigned char *)&vnull; + } else { + float var = atof(str); + float nr = 0; + + // mosquitto_publish + if(modff(var, &nr) == 0) { + memset(&vinteger, 0, sizeof(struct vm_vinteger_t)); + vinteger.type = VINTEGER; + vinteger.value = (int)var; + + return (unsigned char *)&vinteger; + } else { + memset(&vfloat, 0, sizeof(struct vm_vfloat_t)); + vfloat.type = VFLOAT; + vfloat.value = var; + + return (unsigned char *)&vfloat; + } + } + } + } + for(i=0;itoken[1]) == 0) { String dataValue = actDataExtra[0] == '\0' ? "" : getDataValueExtra(actDataExtra, i); char *str = (char *)dataValue.c_str(); @@ -583,7 +670,7 @@ static unsigned char *vm_value_get(struct rules_t *obj, uint16_t token) { } } } - } + } if(node->token[0] == '%') { if(stricmp((char *)&node->token[1], "hour") == 0) { time_t now = time(NULL); diff --git a/HeishaMon/version.h b/HeishaMon/version.h index 47780950..f74fb834 100644 --- a/HeishaMon/version.h +++ b/HeishaMon/version.h @@ -1 +1 @@ -static const char* heishamon_version = "3.2"; +static const char* heishamon_version = "3.2.3"; diff --git a/HeishaMon/webfunctions.cpp b/HeishaMon/webfunctions.cpp index ea5be551..ddb264e1 100755 --- a/HeishaMon/webfunctions.cpp +++ b/HeishaMon/webfunctions.cpp @@ -1159,7 +1159,7 @@ int handleJsonOutput(struct webserver_t *client, char* actData, char* actDataExt client->content--; // The webserver also increases by 1 } else if ((client->content - NUMBER_OF_TOPICS - 1) < extraTopics) { if (client->content == NUMBER_OF_TOPICS + 1) { - webserver_send_content_P(client, PSTR("],\"heatpump extra\":["), 20); + webserver_send_content_P(client, PSTR("],\"heatpump extra\":["), 20); } for (uint8_t topic = (client->content - NUMBER_OF_TOPICS - 1); topic < extraTopics && topic < (client->content - NUMBER_OF_TOPICS + 4) ; topic++) { @@ -1260,11 +1260,11 @@ int showRules(struct webserver_t *client) { if (len1 > 0) { webserver_send_content(client, content, len1); - if (len1 < BUFFER_SIZE) { + if (len1 < BUFFER_SIZE || client->content * BUFFER_SIZE == len) { if (f) { if (*f) { f->close(); - } + } delete f; } client->userdata = NULL; diff --git a/HeishaMon/webfunctions.h b/HeishaMon/webfunctions.h index dae290e0..3603a8f5 100644 --- a/HeishaMon/webfunctions.h +++ b/HeishaMon/webfunctions.h @@ -49,7 +49,7 @@ struct settingsStruct { bool logMqtt = false; //log to mqtt from start bool logHexdump = false; //log hexdump from start bool logSerial1 = true; //log to serial1 (gpio2) from start - bool opentherm = true; //opentherm enable flag, current default true for opentherm build + bool opentherm = false; //opentherm enable flag s0SettingsStruct s0Settings[NUM_S0_COUNTERS]; gpioSettingsStruct gpioSettings; diff --git a/MQTT-Topics.md b/MQTT-Topics.md index 16e0fc14..38ef4e29 100644 --- a/MQTT-Topics.md +++ b/MQTT-Topics.md @@ -31,8 +31,8 @@ TOP11 | main/Operations_Hours | Heatpump operating time (Hour) TOP12 | main/Operations_Counter | Heatpump starts (counter) TOP13 | main/Main_Schedule_State | Main thermostat schedule state (inactive - active) TOP14 | main/Outside_Temp | Outside ambient temperature (°C) -TOP15 | main/Heat_Energy_Production | Thermal heat power production (Watt) -TOP16 | main/Heat_Energy_Consumption | Elektrical heat power consumption at heat mode (Watt) +TOP15 | main/Heat_Power_Production | Thermal heat power production (Watt) +TOP16 | main/Heat_Power_Consumption | Elektrical heat power consumption at heat mode (Watt) TOP17 | main/Powerful_Mode_Time | Powerful state in minutes (0, 1, 2 or 3 x 30min) TOP18 | main/Quiet_Mode_Level | Quiet mode level (0, 1, 2, 3) TOP19 | main/Holiday_Mode_State | Holiday mode (0=off, 1=scheduled, 2=active) @@ -54,10 +54,10 @@ TOP34 | main/Z2_Heat_Request_Temp | Zone 2 Heat Requested shift temp (-5 to 5) o TOP35 | main/Z2_Cool_Request_Temp | Zone 2 Cool Requested shift temp (-5 to 5) or direct cool temp (5 to 20) TOP36 | main/Z1_Water_Temp | Zone 1 Water outlet temperature (°C) TOP37 | main/Z2_Water_Temp | Zone 2 Water outlet temperature (°C) -TOP38 | main/Cool_Energy_Production | Thermal cooling power production (Watt) -TOP39 | main/Cool_Energy_Consumption | Elektrical cooling power consumption (Watt) -TOP40 | main/DHW_Energy_Production | Thermal DHW power production (Watt) -TOP41 | main/DHW_Energy_Consumption | Elektrical DHW power consumption (Watt) +TOP38 | main/Cool_Power_Production | Thermal cooling power production (Watt) +TOP39 | main/Cool_Power_Consumption | Elektrical cooling power consumption (Watt) +TOP40 | main/DHW_Power_Production | Thermal DHW power production (Watt) +TOP41 | main/DHW_Power_Consumption | Elektrical DHW power consumption (Watt) TOP42 | main/Z1_Water_Target_Temp | Zone 1 water target temperature (°C) TOP43 | main/Z2_Water_Target_Temp | Zone 2 water target temperature (°C) TOP44 | main/Error | Last active Error from Heat Pump @@ -191,7 +191,9 @@ SET27 | SetBufferDelta | Set buffer tank delta | 0 - 10 SET28 | SetBuffer | Set buffer installed | 0=not installed, 1=installed SET29 | SetHeatingOffOutdoorTemp | Set Outdoor Temperature to stop heating | 5 to 35 -*If you operate your heatpump with direct temperature setup: topics ending xxxRequestTemperature will set the absolute target temperature* +*If you operate your heatpump in water mode with direct temperature setup: topics ending xxxRequestTemperature will set the absolute target temperature.* + +*But if you operature your heatpump in internal/external thermostat or thermistor mode with direct temperature, you can not use these SET15 and other topics to set the direct temperature. The direct temperature in that modes is stored in the high target compenstation curve value. So to change the requested direct temperature in those modes, use the SET16 to set this value. Maybe this weird behaviour is different for newer heatpump types. So if your heatpump works different, please feel free to updates this note in github.* *To send Heating/Cooling Curves on topic SET16 you need to send a flattened JSON document. For example:* diff --git a/ProtocolByteDecrypt.md b/ProtocolByteDecrypt.md index 89081a81..f0f82c73 100644 --- a/ProtocolByteDecrypt.md +++ b/ProtocolByteDecrypt.md @@ -128,7 +128,7 @@ | TOP | 122 | 00 | | 0 byte | | TOP | 123 | 00 | | 0 byte | | TOP | 124 | 00 | | 0 byte | -| TOP | 125 | 00 | | 0 byte | +| TOP | 125 | 00 | (DEC-1)*2 | Possible water pressure (K/L series) | | TOP | 126 | 00 | | 0 byte | | TOP | 127 | 00 | | 0 byte | | TOP | 128 | 00 | | 0 byte | diff --git a/README.md b/README.md index a67da39a..53c9f429 100644 --- a/README.md +++ b/README.md @@ -58,9 +58,6 @@ These variables live inside a rule block. When a rule block finishes, these vari - `@`: Heatpump parameters These are the same as listed in the Manage Topics documentation page and as found on the HeishaMon homepage. The ruleset also follows the R/W logic as used through the MQTT and REST API. That means that the read topics differ from the write topics. So reading the heatpump state is done through `@Heatpump_State`, changing the heatpump state through `@SetHeatpump`. -- `^`: Heatpump extra parameters -These are the extra XTOP parameters for the newer heatpump models K and L which has some new values in a seperate information data block. Some are also visible on the normal TOP but only the XTOP versions of these values are the correct value, for example the Heat_Power_Consumption. So to use the Heat_Power_Consumption value in a rule, use @Heat_Power_Consumption for a H and J series heatpump and ^Heat_Power_Consumption for the K and L series heatpump. - - `%`: Datetime variables These can be used for date and time based rules. Currently `%hour` (0 - 23), `%minute` (0 - 59), `%month` (1 - 12), and `day` (1 - 7) are supported. All are plain integers. A proper NTP configuration is needed to set the correct system date and time on the HeishaMon. diff --git a/binaries/HeishaMon.ino.d1-v3.2.1.bin b/binaries/HeishaMon.ino.d1-v3.2.1.bin new file mode 100644 index 00000000..3f07f623 Binary files /dev/null and b/binaries/HeishaMon.ino.d1-v3.2.1.bin differ diff --git a/binaries/HeishaMon.ino.d1-v3.2.1.md5 b/binaries/HeishaMon.ino.d1-v3.2.1.md5 new file mode 100644 index 00000000..54bc93fa --- /dev/null +++ b/binaries/HeishaMon.ino.d1-v3.2.1.md5 @@ -0,0 +1 @@ +bc23dfd510f330bfc017761704a2caa2 \ No newline at end of file diff --git a/binaries/HeishaMon.ino.d1-v3.2.2.bin b/binaries/HeishaMon.ino.d1-v3.2.2.bin new file mode 100644 index 00000000..6f91422b Binary files /dev/null and b/binaries/HeishaMon.ino.d1-v3.2.2.bin differ diff --git a/binaries/HeishaMon.ino.d1-v3.2.2.md5 b/binaries/HeishaMon.ino.d1-v3.2.2.md5 new file mode 100644 index 00000000..8a68391b --- /dev/null +++ b/binaries/HeishaMon.ino.d1-v3.2.2.md5 @@ -0,0 +1 @@ +979e93a06e033c45469f3f8a94638887 \ No newline at end of file diff --git a/binaries/HeishaMon.ino.d1-v3.2.3.bin b/binaries/HeishaMon.ino.d1-v3.2.3.bin new file mode 100644 index 00000000..16bf6a85 Binary files /dev/null and b/binaries/HeishaMon.ino.d1-v3.2.3.bin differ diff --git a/binaries/HeishaMon.ino.d1-v3.2.3.md5 b/binaries/HeishaMon.ino.d1-v3.2.3.md5 new file mode 100644 index 00000000..8fc7c101 --- /dev/null +++ b/binaries/HeishaMon.ino.d1-v3.2.3.md5 @@ -0,0 +1 @@ +90517a6d69f6c1365beb43332990b6ba \ No newline at end of file