diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 138e2974e..950b19802 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -450,22 +450,24 @@ void showInfo() { } // For SM10/SM100 Solar Module - if (EMS_Other.SM) { + if (ems_getThermostatEnabled()) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sSolar Module stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); - _renderShortValue("Collector temperature", "C", EMS_Other.SMcollectorTemp); - _renderShortValue("Bottom temperature", "C", EMS_Other.SMbottomTemp); - _renderIntValue("Pump modulation", "%", EMS_Other.SMpumpModulation); - _renderBoolValue("Pump active", EMS_Other.SMpump); - _renderShortValue("Energy Last Hour", "Wh", EMS_Other.SMEnergyLastHour, 1); // *10 - _renderShortValue("Energy Today", "Wh", EMS_Other.SMEnergyToday, 0); - _renderShortValue("Energy Total", "kWH", EMS_Other.SMEnergyTotal, 1); // *10 + myDebug_P(PSTR(" Solar Module: %s"), ems_getSolarModuleDescription(buffer_type)); + _renderShortValue("Collector temperature", "C", EMS_SolarModule.collectorTemp); + _renderShortValue("Bottom temperature", "C", EMS_SolarModule.bottomTemp); + _renderIntValue("Pump modulation", "%", EMS_SolarModule.pumpModulation); + _renderBoolValue("Pump active", EMS_SolarModule.pump); + _renderShortValue("Energy Last Hour", "Wh", EMS_SolarModule.EnergyLastHour, 1); // *10 + _renderShortValue("Energy Today", "Wh", EMS_SolarModule.EnergyToday, 0); + _renderShortValue("Energy Total", "kWH", EMS_SolarModule.EnergyTotal, 1); // *10 } // For HeatPumps if (EMS_Other.HP) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sHeat Pump stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); + myDebug_P(PSTR(" Solar Module: %s"), ems_getHeatPumpDescription(buffer_type)); _renderIntValue("Pump modulation", "%", EMS_Other.HPModulation); _renderIntValue("Pump speed", "%", EMS_Other.HPSpeed); } @@ -762,32 +764,32 @@ void publishValues(bool force) { // handle the other values separately // For SM10 and SM100 Solar Modules - if (EMS_Other.SM) { + if (ems_getSolarModuleEnabled()) { // build new json object doc.clear(); JsonObject rootSM = doc.to(); - if (abs(EMS_Other.SMcollectorTemp) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_COLLECTORTEMP] = (double)EMS_Other.SMcollectorTemp / 10; + if (abs(EMS_SolarModule.collectorTemp) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_COLLECTORTEMP] = (double)EMS_SolarModule.collectorTemp / 10; - if (abs(EMS_Other.SMbottomTemp) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_BOTTOMTEMP] = (double)EMS_Other.SMbottomTemp / 10; + if (abs(EMS_SolarModule.bottomTemp) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_BOTTOMTEMP] = (double)EMS_SolarModule.bottomTemp / 10; - if (EMS_Other.SMpumpModulation != EMS_VALUE_INT_NOTSET) - rootSM[SM_PUMPMODULATION] = EMS_Other.SMpumpModulation; + if (EMS_SolarModule.pumpModulation != EMS_VALUE_INT_NOTSET) + rootSM[SM_PUMPMODULATION] = EMS_SolarModule.pumpModulation; - if (EMS_Other.SMpump != EMS_VALUE_INT_NOTSET) { - rootSM[SM_PUMP] = _bool_to_char(s, EMS_Other.SMpump); + if (EMS_SolarModule.pump != EMS_VALUE_INT_NOTSET) { + rootSM[SM_PUMP] = _bool_to_char(s, EMS_SolarModule.pump); } - if (abs(EMS_Other.SMEnergyLastHour) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_ENERGYLASTHOUR] = (double)EMS_Other.SMEnergyLastHour / 10; + if (abs(EMS_SolarModule.EnergyLastHour) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_ENERGYLASTHOUR] = (double)EMS_SolarModule.EnergyLastHour / 10; - if (abs(EMS_Other.SMEnergyToday) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_ENERGYTODAY] = EMS_Other.SMEnergyToday; + if (abs(EMS_SolarModule.EnergyToday) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_ENERGYTODAY] = EMS_SolarModule.EnergyToday; - if (abs(EMS_Other.SMEnergyTotal) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_ENERGYTOTAL] = (double)EMS_Other.SMEnergyTotal / 10; + if (abs(EMS_SolarModule.EnergyTotal) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_ENERGYTOTAL] = (double)EMS_SolarModule.EnergyTotal / 10; data[0] = '\0'; // reset data for next package serializeJson(doc, data, sizeof(data)); @@ -927,7 +929,7 @@ void do_regularUpdates() { myDebugLog("Requesting scheduled EMS device data"); ems_getThermostatValues(); ems_getBoilerValues(); - ems_getOtherValues(); + ems_getSolarModuleValues(); } } diff --git a/src/ems.cpp b/src/ems.cpp index 48ae1dc66..a41185152 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -182,15 +182,17 @@ const _EMS_Type EMS_Types[] = { }; // calculate sizes of arrays at compile -uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types -uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of boiler models -uint8_t _Other_Types_max = ArraySize(Other_Types); // number of other ems devices -uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types +uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types +uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of boiler models +uint8_t _Solar_Module_Types_max = ArraySize(SolarModule_Types);// number of solar module types +uint8_t _Other_Types_max = ArraySize(Other_Types); // number of other ems devices +uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types // these structs contain the data we store from the Boiler and Thermostat -_EMS_Boiler EMS_Boiler; // for boiler -_EMS_Thermostat EMS_Thermostat; // for thermostat -_EMS_Other EMS_Other; // for other known EMS devices +_EMS_Boiler EMS_Boiler; // for boiler +_EMS_Thermostat EMS_Thermostat; // for thermostat +_EMS_SolarModule EMS_SolarModule; // for solar modules +_EMS_Other EMS_Other; // for other known EMS devices // CRC lookup table with poly 12 for faster checking const uint8_t ems_crc_table[] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, @@ -298,16 +300,24 @@ void ems_init() { EMS_Boiler.pump_mod_max = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation max. power EMS_Boiler.pump_mod_min = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation min. power + // Solar Module values + EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 + EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 + EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 + EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active + EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.device_id = EMS_ID_NONE; + EMS_SolarModule.model_id = EMS_MODEL_NONE; + EMS_SolarModule.product_id = EMS_ID_NONE; + // Other EMS devices values - EMS_Other.SMcollectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 - EMS_Other.SMbottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 - EMS_Other.SMpumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 - EMS_Other.SMpump = EMS_VALUE_INT_NOTSET; // pump active - EMS_Other.SMEnergyLastHour = EMS_VALUE_SHORT_NOTSET; - EMS_Other.SMEnergyToday = EMS_VALUE_SHORT_NOTSET; - EMS_Other.SMEnergyTotal = EMS_VALUE_SHORT_NOTSET; EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET; EMS_Other.HPSpeed = EMS_VALUE_INT_NOTSET; + EMS_Other.device_id = EMS_ID_NONE; + EMS_Other.model_id = EMS_MODEL_NONE; + EMS_Other.product_id = EMS_ID_NONE; // calculated values EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off @@ -323,7 +333,6 @@ void ems_init() { strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version)); // set other types - EMS_Other.SM = false; EMS_Other.HP = false; // default logging is none @@ -360,10 +369,22 @@ bool ems_getThermostatEnabled() { return (EMS_Thermostat.device_id != EMS_ID_NONE); } +bool ems_getSolarModuleEnabled() { + return (EMS_SolarModule.device_id != EMS_ID_NONE); +} + uint8_t ems_getThermostatModel() { return (EMS_Thermostat.model_id); } +uint8_t ems_getOtherModel() { + return (EMS_Other.model_id); +} + +uint8_t ems_getSolarModuleModel() { + return (EMS_SolarModule.model_id); +} + void ems_setTxDisabled(bool b) { EMS_Sys_Status.emsTxDisabled = b; } @@ -1350,12 +1371,12 @@ void _process_RCOutdoorTempMessage(_EMS_RxTelegram * EMS_RxTelegram) { * SM10Monitor - type 0x97 */ void _process_SM10Monitor(_EMS_RxTelegram * EMS_RxTelegram) { - EMS_Other.SMcollectorTemp = _toShort(2); // collector temp from SM10, is *10 - EMS_Other.SMbottomTemp = _toShort(5); // bottom temp from SM10, is *10 - EMS_Other.SMpumpModulation = _toByte(4); // modulation solar pump - EMS_Other.SMpump = _bitRead(7, 1); // active if bit 1 is set + EMS_SolarModule.collectorTemp = _toShort(2); // collector temp from SM10, is *10 + EMS_SolarModule.bottomTemp = _toShort(5); // bottom temp from SM10, is *10 + EMS_SolarModule.pumpModulation = _toByte(4); // modulation solar pump + EMS_SolarModule.pump = _bitRead(7, 1); // active if bit 1 is set - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1371,13 +1392,13 @@ void _process_SM100Monitor(_EMS_RxTelegram * EMS_RxTelegram) { return; } - EMS_Other.SMcollectorTemp = _toShort(0); // collector temp from SM100, is *10 + EMS_SolarModule.collectorTemp = _toShort(0); // collector temp from SM100, is *10 if (EMS_RxTelegram->data_length > 2) { - EMS_Other.SMbottomTemp = _toShort(2); // bottom temp from SM100, is *10 + EMS_SolarModule.bottomTemp = _toShort(2); // bottom temp from SM100, is *10 } - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1389,13 +1410,13 @@ void _process_SM100Monitor(_EMS_RxTelegram * EMS_RxTelegram) { void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram) { // check for complete telegram if (EMS_RxTelegram->offset == 0) { - EMS_Other.SMpumpModulation = _toByte(9); // modulation solar pump + EMS_SolarModule.pumpModulation = _toByte(9); // modulation solar pump } else if (EMS_RxTelegram->offset == 0x09) { // or short telegram with a single byte with offset 09 - EMS_Other.SMpumpModulation = _toByte(0); // modulation solar pump + EMS_SolarModule.pumpModulation = _toByte(0); // modulation solar pump } - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1405,13 +1426,13 @@ void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram) { void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) { // check for complete telegram if (EMS_RxTelegram->offset == 0) { - EMS_Other.SMpump = _bitRead(10, 2); // 03=off 04=on at offset 10 which is byte 10 + EMS_SolarModule.pump = _bitRead(10, 2); // 03=off 04=on at offset 10 which is byte 10 } else if (EMS_RxTelegram->offset == 0x0A) { // or short telegram with a single byte with offset 0A - EMS_Other.SMpump = _bitRead(0, 2); // 03=off 04=on + EMS_SolarModule.pump = _bitRead(0, 2); // 03=off 04=on } - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1420,11 +1441,11 @@ void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) { * e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35 */ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) { - EMS_Other.SMEnergyLastHour = _toShort(2); // last hour / 10 in Wh - EMS_Other.SMEnergyToday = _toShort(6); // todays in Wh - EMS_Other.SMEnergyTotal = _toShort(10); // total / 10 in kWh + EMS_SolarModule.EnergyLastHour = _toShort(2); // last hour / 10 in Wh + EMS_SolarModule.EnergyToday = _toShort(6); // todays in Wh + EMS_SolarModule.EnergyTotal = _toShort(10); // total / 10 in kWh - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1455,17 +1476,17 @@ void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { if (EMS_RxTelegram->offset == 0) { // e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0 - EMS_Other.SMcollectorTemp = _toShort(4); // Collector Temperature - EMS_Other.SMbottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler - EMS_Other.SMEnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour - EMS_Other.SMpump = _bitRead(8,0); // Solar pump on (1) or off (0) - EMS_Other.SM = true; + EMS_SolarModule.collectorTemp = _toShort(4); // Collector Temperature + EMS_SolarModule.bottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler + EMS_SolarModule.EnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour + EMS_SolarModule.pump = _bitRead(8,0); // Solar pump on (1) or off (0) + // EMS_Other.SM = true; } if (EMS_RxTelegram->offset == 4) { // e.g. B0 00 FF 04 00 03 02 E5 - EMS_Other.SMcollectorTemp = _toShort(0); // Collector Temperature - EMS_Other.SM = true; + EMS_SolarModule.collectorTemp = _toShort(0); // Collector Temperature + // EMS_Other.SM = true; } } @@ -1521,7 +1542,6 @@ void ems_clearDeviceList() { */ void _addDevice(uint8_t product_id, uint8_t device_id, char * version, const char * model_string) { _Generic_Type device; - // if its a duplicate don't add bool found = false; for (std::list<_Generic_Type>::iterator it = Devices.begin(); it != Devices.end(); it++) { @@ -1529,7 +1549,6 @@ void _addDevice(uint8_t product_id, uint8_t device_id, char * version, const cha found = true; } } - if (!found) { device.product_id = product_id; device.device_id = device_id; @@ -1644,6 +1663,37 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { return; } + + // finally look for Solar Modules + i = 0; + while (i < _Solar_Module_Types_max) { + if (SolarModule_Types[i].product_id == product_id) { + typeFound = true; // we have a matching product id. i is the index. + break; + } + i++; + } + + if (typeFound) { + myDebug_P(PSTR("Solar Module found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"), SolarModule_Types[i].model_string, SolarModule_Types[i].device_id, product_id, version); + + // add to list + _addDevice(product_id, SolarModule_Types[i].device_id, version, SolarModule_Types[i].model_string); + + // EMS_Other.SM = true; // we have detected a Solar Module (SM10, SM100, ISM1 ...) + myDebug_P(PSTR("Solar Module support enabled.")); + EMS_SolarModule.model_id = Other_Types[i].model_id; + EMS_SolarModule.device_id = Other_Types[i].device_id; + EMS_SolarModule.product_id = product_id; + strlcpy(EMS_SolarModule.version, version, sizeof(EMS_SolarModule.version)); + + // fetch Solar Module values + ems_getSolarModuleValues(); + return; + + } + + // finally look for the other EMS devices i = 0; while (i < _Other_Types_max) { @@ -1660,20 +1710,18 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { // add to list _addDevice(product_id, Other_Types[i].device_id, version, Other_Types[i].model_string); - // see if this is a Solar Module SM10 - if (Other_Types[i].device_id == EMS_ID_SM) { - EMS_Other.SM = true; // we have detected a SM10 - myDebug_P(PSTR("SM10 Solar Module support enabled.")); - } - // see if this is a HeatPump if (Other_Types[i].device_id == EMS_ID_HP) { EMS_Other.HP = true; // we have detected a HP myDebug_P(PSTR("HeatPump support enabled.")); + EMS_Other.model_id = Other_Types[i].model_id; + EMS_Other.device_id = Other_Types[i].device_id; + EMS_Other.product_id = product_id; + strlcpy(EMS_Other.version, version, sizeof(EMS_Other.version)); + // fetch Solar Module values > not yet implemented + } - // fetch other values - ems_getOtherValues(); return; } else { @@ -1822,9 +1870,18 @@ void ems_getBoilerValues() { /* * Get other values from EMS devices */ -void ems_getOtherValues() { - if (EMS_Other.SM) { - ems_doReadCommand(EMS_TYPE_SM10Monitor, EMS_ID_SM); // fetch all from SM10Monitor +void ems_getSolarModuleValues() { + + uint8_t product_id = EMS_SolarModule.product_id; + + if (ems_getSolarModuleEnabled()) { + if (product_id == EMS_PRODUCTID_SM10) { + ems_doReadCommand(EMS_TYPE_SM10Monitor, EMS_ID_SM); // fetch all from SM10Monitor + } + else if (product_id == EMS_PRODUCTID_SM100) { + ems_doReadCommand(EMS_TYPE_SM100Monitor, EMS_ID_SM); // fetch all from SM100Monitor + } + } } @@ -1912,6 +1969,88 @@ char * ems_getBoilerDescription(char * buffer) { return buffer; } +/** + * returns current Solar Module type as a string + */ +char * ems_getSolarModuleDescription(char * buffer) { + uint8_t size = 128; + if (!ems_getSolarModuleEnabled()) { + strlcpy(buffer, "", size); + } else { + int i = 0; + bool found = false; + char tmp[6] = {0}; + + // scan through known ID types + while (i < _Solar_Module_Types_max) { + if (SolarModule_Types[i].product_id == EMS_SolarModule.product_id) { + found = true; // we have a match + break; + } + i++; + } + if (found) { + strlcpy(buffer, SolarModule_Types[i].model_string, size); + } else { + strlcpy(buffer, "DeviceID: 0x", size); + strlcat(buffer, _hextoa(EMS_SolarModule.device_id, tmp), size); + } + + strlcat(buffer, " (ProductID:", size); + if (EMS_SolarModule.product_id == EMS_ID_NONE) { + strlcat(buffer, "?", size); + } else { + strlcat(buffer, itoa(EMS_SolarModule.product_id, tmp, 10), size); + } + strlcat(buffer, " Version:", size); + strlcat(buffer, EMS_SolarModule.version, size); + strlcat(buffer, ")", size); + } + + return buffer; +} + +/** + * returns current Heat Pump type as a string + */ +char * ems_getHeatPumpDescription(char * buffer) { + uint8_t size = 128; + if (!EMS_Other.HP) { + strlcpy(buffer, "", size); + } else { + int i = 0; + bool found = false; + char tmp[6] = {0}; + + // scan through known ID types + while (i < _Other_Types_max) { + if (Other_Types[i].product_id == EMS_Other.product_id) { + found = true; // we have a match + break; + } + i++; + } + if (found) { + strlcpy(buffer, Other_Types[i].model_string, size); + } else { + strlcpy(buffer, "DeviceID: 0x", size); + strlcat(buffer, _hextoa(EMS_Other.device_id, tmp), size); + } + + strlcat(buffer, " (ProductID:", size); + if (EMS_Other.product_id == EMS_ID_NONE) { + strlcat(buffer, "?", size); + } else { + strlcat(buffer, itoa(EMS_Other.product_id, tmp, 10), size); + } + strlcat(buffer, " Version:", size); + strlcat(buffer, EMS_Other.version, size); + strlcat(buffer, ")", size); + } + + return buffer; +} + /** * Find the versions of our connected devices */ @@ -1928,6 +2067,11 @@ void ems_scanDevices() { Device_Ids.push_back(tt.device_id); } + // copy over solar modules + for (_SolarModule_Type sm : SolarModule_Types) { + Device_Ids.push_back(sm.device_id); + } + // copy over others for (_Other_Type ot : Other_Types) { Device_Ids.push_back(ot.device_id); @@ -1963,6 +2107,16 @@ void ems_printAllDevices() { Boiler_Types[i].product_id); } + myDebug_P(PSTR("\nThese %d devices are supported as solar module devices:"), _Solar_Module_Types_max); + for (i = 0; i < _Solar_Module_Types_max; i++) { + myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"), + COLOR_BOLD_ON, + SolarModule_Types[i].model_string, + COLOR_BOLD_OFF, + SolarModule_Types[i].device_id, + SolarModule_Types[i].product_id); + } + myDebug_P(PSTR("\nThese %d devices are supported as other known EMS devices:"), _Other_Types_max); for (i = 0; i < _Other_Types_max; i++) { myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"), diff --git a/src/ems.h b/src/ems.h index e20ca7660..63680b903 100644 --- a/src/ems.h +++ b/src/ems.h @@ -17,12 +17,17 @@ // Fixed EMS IDs #define EMS_ID_ME 0x0B // our device, hardcoded as the "Service Key" #define EMS_ID_BOILER 0x08 // all UBA Boilers have 0x08 -#define EMS_ID_SM 0x30 // Solar Module SM10 and SM100 +#define EMS_ID_SM 0x30 // Solar Module SM10, SM100 and ISM1 #define EMS_ID_HP 0x38 // HeatPump #define EMS_ID_GATEWAY 0x48 // KM200 Web Gateway #define EMS_PRODUCTID_HEATRONICS 95 // ProductID for a Junkers Heatronic3 device +#define EMS_PRODUCTID_SM10 73 // ProductID for SM10 solar module +#define EMS_PRODUCTID_SM100 163 // ProductID for SM10 solar module +#define EMS_PRODUCTID_ISM1 101 // ProductID for SM10 solar module + + #define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC // max length of a telegram, including CRC, for Rx and Tx. @@ -154,6 +159,13 @@ typedef struct { char model_string[50]; } _Boiler_Type; +typedef struct { + uint8_t model_id; + uint8_t product_id; + uint8_t device_id; + char model_string[50]; +} _SolarModule_Type; + typedef struct { uint8_t model_id; uint8_t product_id; @@ -241,21 +253,32 @@ typedef struct { // UBAParameterWW * Telegram package defintions for Other EMS devices */ -// SM Solar Module - SM10Monitor/SM100Monitor +// Other ems devices than solar modules, thermostats and boilers typedef struct { - bool SM; // set true if there is a Solar Module available bool HP; // set true if there is a Heat Pump available - int16_t SMcollectorTemp; // collector temp - int16_t SMbottomTemp; // bottom temp - uint8_t SMpumpModulation; // modulation solar pump - uint8_t SMpump; // pump active - int16_t SMEnergyLastHour; - int16_t SMEnergyToday; - int16_t SMEnergyTotal; uint8_t HPModulation; // heatpump modulation in % uint8_t HPSpeed; // speed 0-100 % + uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) + uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) + uint8_t product_id; // (e.g. 101) + char version[10]; } _EMS_Other; +// SM Solar Module - SM10/SM100/ISM1 +typedef struct { + int16_t collectorTemp; // collector temp + int16_t bottomTemp; // bottom temp + uint8_t pumpModulation; // modulation solar pump + uint8_t pump; // pump active + int16_t EnergyLastHour; + int16_t EnergyToday; + int16_t EnergyTotal; + uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) + uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) + uint8_t product_id; // (e.g. 101) + char version[10]; +} _EMS_SolarModule; + // Thermostat data typedef struct { uint8_t device_id; // the device ID of the thermostat @@ -322,17 +345,22 @@ void ems_setTxDisabled(bool b); char * ems_getThermostatDescription(char * buffer); char * ems_getBoilerDescription(char * buffer); +char * ems_getSolarModuleDescription(char * buffer); +char * ems_getHeatPumpDescription(char * buffer); void ems_getThermostatValues(); void ems_getBoilerValues(); -void ems_getOtherValues(); +void ems_getSolarModuleValues(); bool ems_getPoll(); bool ems_getTxEnabled(); bool ems_getThermostatEnabled(); bool ems_getBoilerEnabled(); +bool ems_getSolarModuleEnabled(); bool ems_getBusConnected(); _EMS_SYS_LOGGING ems_getLogging(); bool ems_getEmsRefreshed(); uint8_t ems_getThermostatModel(); +uint8_t ems_getSolarModuleModel(); +uint8_t ems_getOtherModel(); void ems_discoverModels(); bool ems_getTxCapable(); uint32_t ems_getPollFrequency(); @@ -350,4 +378,5 @@ void _removeTxQueue(); extern _EMS_Sys_Status EMS_Sys_Status; extern _EMS_Boiler EMS_Boiler; extern _EMS_Thermostat EMS_Thermostat; +extern _EMS_SolarModule EMS_SolarModule; extern _EMS_Other EMS_Other; diff --git a/src/ems_devices.h b/src/ems_devices.h index eed586eca..f10262018 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -124,6 +124,9 @@ typedef enum { // generic ID for the boiler EMS_MODEL_UBA, + // generic ID for the solar module + EMS_MODEL_SOLAR_MODULE, + // generic ID for all the other weird devices EMS_MODEL_OTHER, @@ -147,7 +150,7 @@ typedef enum { } _EMS_MODEL_ID; -// EMS types for known devices. This list will be extended when new devices are recognized. +// EMS types for known boilers. This list will be extended when new devices are recognized. // The device_id is always 0x08 // format is MODEL_ID, PRODUCT ID, DESCRIPTION const _Boiler_Type Boiler_Types[] = { @@ -164,7 +167,19 @@ const _Boiler_Type Boiler_Types[] = { }; -// Other EMS devices which are not considered boilers or thermostats +/* + * Known Solar Module types + */ +const _SolarModule_Type SolarModule_Types[] = { + + {EMS_MODEL_OTHER, EMS_PRODUCTID_SM10, EMS_ID_SM, "SM10 Solar Module"}, + {EMS_MODEL_OTHER, EMS_PRODUCTID_SM100, EMS_ID_SM, "SM100 Solar Module"}, + {EMS_MODEL_OTHER, EMS_PRODUCTID_ISM1, EMS_ID_SM, "Junkers ISM1 Solar Module"} + +}; + + +// Other EMS devices which are not considered boilers, thermostats or solar modules const _Other_Type Other_Types[] = { {EMS_MODEL_OTHER, 69, 0x21, "MM10 Mixer Module"}, @@ -178,11 +193,8 @@ const _Other_Type Other_Types[] = { {EMS_MODEL_OTHER, 125, 0x09, "BC25 Base Controller"}, {EMS_MODEL_OTHER, 152, 0x09, "Junkers Controller"}, {EMS_MODEL_OTHER, 205, 0x02, "Nefit Moduline Easy Connect"}, - {EMS_MODEL_OTHER, 73, EMS_ID_SM, "SM10 Solar Module"}, - {EMS_MODEL_OTHER, 163, EMS_ID_SM, "SM100 Solar Module"}, {EMS_MODEL_OTHER, 171, 0x02, "EMS-OT OpenTherm converter"}, {EMS_MODEL_OTHER, 252, EMS_ID_HP, "HeatPump Module"}, // warning, fake product id! - {EMS_MODEL_OTHER, 101, 0x30, "Junkers ISM1 Solar Controller"}, {EMS_MODEL_OTHER, 189, EMS_ID_GATEWAY, "Web Gateway KM200"} };