mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-09 01:09:51 +03:00
feat: add Modbus support
This commit is contained in:
@@ -121,6 +121,22 @@
|
||||
#define EMSESP_DEFAULT_TELNET_ENABLED true
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_MODBUS_ENABLED
|
||||
#define EMSESP_DEFAULT_MODBUS_ENABLED false
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_MODBUS_PORT
|
||||
#define EMSESP_DEFAULT_MODBUS_PORT 502
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_MODBUS_MAX_CLIENTS
|
||||
#define EMSESP_DEFAULT_MODBUS_MAX_CLIENTS 10
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_MODBUS_TIMEOUT
|
||||
#define EMSESP_DEFAULT_MODBUS_TIMEOUT 10000
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_BOARD_PROFILE
|
||||
#define EMSESP_DEFAULT_BOARD_PROFILE "default"
|
||||
#endif
|
||||
|
||||
@@ -1374,6 +1374,33 @@ void EMSdevice::dump_value_info() {
|
||||
Serial.print(entityid);
|
||||
}
|
||||
|
||||
Serial.print(",");
|
||||
|
||||
// modbus specific infos
|
||||
|
||||
|
||||
Serial.print(device_type());
|
||||
Serial.print(',');
|
||||
|
||||
Serial.print(dv.tag);
|
||||
Serial.print(',');
|
||||
|
||||
// numeric operator -> scale factor
|
||||
if (dv.numeric_operator == 0)
|
||||
Serial.print("1");
|
||||
else if (dv.numeric_operator > 0)
|
||||
Serial.printf("1/%d", dv.numeric_operator);
|
||||
else
|
||||
Serial.print(-dv.numeric_operator);
|
||||
Serial.print(",");
|
||||
|
||||
Serial.printf("%d", EMSESP::modbus_->getRegisterOffset(dv));
|
||||
Serial.print(",");
|
||||
|
||||
Serial.printf("%d", EMSESP::modbus_->getRegisterCount(dv));
|
||||
|
||||
// /modbus specific infos
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
@@ -1901,4 +1928,155 @@ std::string EMSdevice::name() {
|
||||
return custom_name_;
|
||||
}
|
||||
|
||||
// copy a raw value (i.e. without applying the numeric_operator) to the output buffer.
|
||||
// returns true on success.
|
||||
int EMSdevice::get_modbus_value(uint8_t tag, const std::string & shortname, std::vector<uint16_t> & result) {
|
||||
// find device value by shortname
|
||||
// TODO linear search is inefficient
|
||||
const auto & it = std::find_if(devicevalues_.begin(), devicevalues_.end(), [&](const DeviceValue & x) { return x.tag == tag && x.short_name == shortname; });
|
||||
if (it == devicevalues_.end())
|
||||
return -1;
|
||||
|
||||
auto & dv = *it;
|
||||
|
||||
// check if it exists, there is a value for the entity. Set the flag to ACTIVE
|
||||
// not that this will override any previously removed states
|
||||
(dv.hasValue()) ? dv.add_state(DeviceValueState::DV_ACTIVE) : dv.remove_state(DeviceValueState::DV_ACTIVE);
|
||||
|
||||
if (!dv.has_state(DeviceValueState::DV_ACTIVE))
|
||||
return -2;
|
||||
|
||||
// handle Booleans
|
||||
if (dv.type == DeviceValueType::BOOL) {
|
||||
if (result.size() != 1)
|
||||
return -3;
|
||||
auto value_bool = *(uint8_t *)(dv.value_p);
|
||||
if (!Helpers::hasValue(value_bool, EMS_VALUE_BOOL))
|
||||
return -4;
|
||||
result[0] = value_bool ? 1 : 0;
|
||||
}
|
||||
|
||||
// handle TEXT strings
|
||||
else if (dv.type == DeviceValueType::STRING) {
|
||||
auto value_s = (char *)dv.value_p;
|
||||
size_t length_s = strlen(value_s) + 1; // length including terminating zero in bytes
|
||||
size_t register_length_s = (length_s + 1) / 2; // length including terminating zero in uint16_t-registers
|
||||
|
||||
if ((long)result.size() < (long)register_length_s) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
for (auto i = 0; i < register_length_s; i++) {
|
||||
auto hi = (uint8_t)value_s[2 * i];
|
||||
auto lo = (uint8_t)(2 * i + 1 < length_s ? value_s[2 * i + 1] : 0);
|
||||
result[i] = ((uint16_t)hi << 8) | lo;
|
||||
}
|
||||
}
|
||||
|
||||
// handle ENUMs
|
||||
else if (dv.type == DeviceValueType::ENUM) {
|
||||
if (result.size() != 1)
|
||||
return -6;
|
||||
auto value_enum = *(uint8_t *)(dv.value_p);
|
||||
if (value_enum >= dv.options_size)
|
||||
return -7;
|
||||
result[0] = (uint16_t)value_enum;
|
||||
}
|
||||
|
||||
// handle Numbers
|
||||
else if (dv.type == DeviceValueType::INT8) {
|
||||
if (result.size() != 1)
|
||||
return -8;
|
||||
result[0] = (uint16_t)(uint8_t)(*(int8_t *)(dv.value_p));
|
||||
} else if (dv.type == DeviceValueType::UINT8) {
|
||||
if (result.size() != 1)
|
||||
return -9;
|
||||
result[0] = (uint16_t)(*(uint8_t *)(dv.value_p));
|
||||
} else if (dv.type == DeviceValueType::INT16) {
|
||||
if (result.size() != 1)
|
||||
return -10;
|
||||
result[0] = (uint16_t)(*(int16_t *)(dv.value_p));
|
||||
} else if (dv.type == DeviceValueType::UINT16) {
|
||||
if (result.size() != 1)
|
||||
return -11;
|
||||
result[0] = *(uint16_t *)(dv.value_p);
|
||||
} else if (dv.type == DeviceValueType::UINT24 || dv.type == DeviceValueType::UINT32 || dv.type == DeviceValueType::TIME) {
|
||||
if (result.size() != 2)
|
||||
return -12;
|
||||
auto value_uint32 = *(uint32_t *)(dv.value_p);
|
||||
result[0] = (uint16_t)(value_uint32 >> 16);
|
||||
result[1] = (uint16_t)(value_uint32 & 0xffff);
|
||||
}
|
||||
|
||||
else {
|
||||
return -13;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool EMSdevice::modbus_value_to_json(uint8_t tag, const std::string & shortname, const std::vector<uint8_t> & modbus_data, JsonObject & jsonValue) {
|
||||
//Serial.printf("modbus_value_to_json(%d,%s,[%d bytes])\n", tag, shortname.c_str(), modbus_data.size());
|
||||
|
||||
// find device value by shortname
|
||||
const auto & it = std::find_if(devicevalues_.begin(), devicevalues_.end(), [&](const DeviceValue & x) { return x.tag == tag && x.short_name == shortname; });
|
||||
if (it == devicevalues_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto & dv = *it;
|
||||
|
||||
// handle Booleans
|
||||
if (dv.type == DeviceValueType::BOOL) {
|
||||
// bools are 1 16 bit register
|
||||
if (modbus_data.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
jsonValue["value"] = modbus_data[0] || modbus_data[1];
|
||||
}
|
||||
|
||||
// handle TEXT strings
|
||||
else if (dv.type == DeviceValueType::STRING) {
|
||||
// text is optionally nul terminated
|
||||
// check if the data contains a null char
|
||||
auto nul_or_end = std::find(modbus_data.begin(), modbus_data.end(), 0);
|
||||
jsonValue["value"] = std::string(modbus_data.begin(), nul_or_end);
|
||||
}
|
||||
|
||||
// handle ENUMs
|
||||
else if (dv.type == DeviceValueType::ENUM) {
|
||||
// these data types are 1 16 bit register
|
||||
if (modbus_data.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jsonValue["value"] = (uint16_t)modbus_data[0] << 8 | (uint16_t)modbus_data[1];
|
||||
}
|
||||
|
||||
// handle Numbers
|
||||
else if (dv.type == DeviceValueType::INT8 || dv.type == DeviceValueType::UINT8 || dv.type == DeviceValueType::INT16 || dv.type == DeviceValueType::UINT16) {
|
||||
// these data types are 1 16 bit register
|
||||
if (modbus_data.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jsonValue["value"] = Helpers::numericoperator2scalefactor(dv.numeric_operator) * (float)((uint16_t)modbus_data[0] << 8 | (uint16_t)modbus_data[1]);
|
||||
} else if (dv.type == DeviceValueType::UINT24 || dv.type == DeviceValueType::UINT32 || dv.type == DeviceValueType::TIME) {
|
||||
// these data types are 2 16 bit register
|
||||
if (modbus_data.size() != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jsonValue["value"] =
|
||||
Helpers::numericoperator2scalefactor(dv.numeric_operator)
|
||||
* (float)((uint32_t)modbus_data[0] << 24 | (uint32_t)modbus_data[1] << 16 | (uint32_t)modbus_data[2] << 8 | (uint32_t)modbus_data[3]);
|
||||
}
|
||||
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -202,6 +202,9 @@ class EMSdevice {
|
||||
}
|
||||
}
|
||||
|
||||
int get_modbus_value(uint8_t tag, const std::string & shortname, std::vector<uint16_t> & result);
|
||||
bool modbus_value_to_json(uint8_t tag, const std::string & shortname, const std::vector<uint8_t> & modbus_data, JsonObject & jsonValue);
|
||||
|
||||
const char * brand_to_char();
|
||||
const std::string to_string();
|
||||
const std::string to_string_short();
|
||||
|
||||
@@ -72,6 +72,7 @@ uuid::syslog::SyslogService System::syslog_;
|
||||
RxService EMSESP::rxservice_; // incoming Telegram Rx handler
|
||||
TxService EMSESP::txservice_; // outgoing Telegram Tx handler
|
||||
Mqtt EMSESP::mqtt_; // mqtt handler
|
||||
Modbus * EMSESP::modbus_; // modbus handler
|
||||
System EMSESP::system_; // core system services
|
||||
TemperatureSensor EMSESP::temperaturesensor_; // Temperature sensors
|
||||
AnalogSensor EMSESP::analogsensor_; // Analog sensors
|
||||
@@ -334,8 +335,8 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
|
||||
void EMSESP::dump_all_values(uuid::console::Shell & shell) {
|
||||
Serial.println("---- CSV START ----"); // marker use by py script
|
||||
// add header for CSV
|
||||
Serial.println(
|
||||
"device name,device type,product id,shortname,fullname,type [options...] \\| (min/max),uom,writeable,discovery entityid v3.4, discovery entityid");
|
||||
Serial.println("device name,device type,product id,shortname,fullname,type [options...] \\| (min/max),uom,writeable,discovery entityid v3.4,discovery "
|
||||
"entityid,modbus unit identifier,modbus block,modbus scale factor,modbus offset,modbus count");
|
||||
|
||||
for (const auto & device_class : EMSFactory::device_handlers()) {
|
||||
// go through each device type so they are sorted
|
||||
@@ -1655,6 +1656,11 @@ void EMSESP::start() {
|
||||
#endif
|
||||
}
|
||||
|
||||
if (system_.modbus_enabled()) {
|
||||
modbus_ = new Modbus;
|
||||
modbus_->start(1, system_.modbus_port(), system_.modbus_max_clients(), system_.modbus_timeout());
|
||||
}
|
||||
|
||||
mqtt_.start(); // mqtt init
|
||||
system_.start(); // starts commands, led, adc, button, network (sets hostname), syslog & uart
|
||||
shower_.start(); // initialize shower timer and shower alert
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "emsfactory.h"
|
||||
#include "telegram.h"
|
||||
#include "mqtt.h"
|
||||
#include "modbus.h"
|
||||
#include "system.h"
|
||||
#include "temperaturesensor.h"
|
||||
#include "analogsensor.h"
|
||||
@@ -216,6 +217,7 @@ class EMSESP {
|
||||
|
||||
// services
|
||||
static Mqtt mqtt_;
|
||||
static Modbus * modbus_;
|
||||
static System system_;
|
||||
static TemperatureSensor temperaturesensor_;
|
||||
static AnalogSensor analogsensor_;
|
||||
|
||||
@@ -837,4 +837,13 @@ uint16_t Helpers::string2minutes(const std::string & str) {
|
||||
}
|
||||
}
|
||||
|
||||
float Helpers::numericoperator2scalefactor(uint8_t numeric_operator) {
|
||||
if (numeric_operator == 0)
|
||||
return 1.0f;
|
||||
else if (numeric_operator > 0)
|
||||
return 1.0f / numeric_operator;
|
||||
else
|
||||
return -numeric_operator;
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -50,6 +50,7 @@ class Helpers {
|
||||
static bool check_abs(const int32_t i);
|
||||
static uint32_t abs(const int32_t i);
|
||||
static uint16_t string2minutes(const std::string & str);
|
||||
static float numericoperator2scalefactor(uint8_t numeric_operator);
|
||||
|
||||
static float transformNumFloat(float value, const int8_t numeric_operator, const uint8_t fahrenheit = 0);
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ MAKE_WORD(ems)
|
||||
MAKE_WORD(devices)
|
||||
MAKE_WORD(shower)
|
||||
MAKE_WORD(mqtt)
|
||||
MAKE_WORD(modbus)
|
||||
MAKE_WORD(emsesp)
|
||||
MAKE_WORD(connected)
|
||||
MAKE_WORD(disconnected)
|
||||
|
||||
509
src/modbus.cpp
Normal file
509
src/modbus.cpp
Normal file
@@ -0,0 +1,509 @@
|
||||
/**
|
||||
* TODO:
|
||||
* - verwendete libs in readme hinzufügen
|
||||
*/
|
||||
#include "modbus.h"
|
||||
#include "modbus_entity_parameters.hpp"
|
||||
#include "emsesp.h"
|
||||
#include "emsdevice.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
#ifdef EMSESP_STANDALONE
|
||||
// no eModbus lib in standalone build
|
||||
enum FunctionCode : uint8_t { WRITE_HOLD_REGISTER = 0x06, WRITE_MULT_REGISTERS = 0x10 };
|
||||
#endif
|
||||
|
||||
uuid::log::Logger Modbus::logger_{F_(modbus), uuid::log::Facility::DAEMON};
|
||||
|
||||
void Modbus::start(uint8_t systemServerId, uint16_t port, uint8_t max_clients, uint32_t timeout) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (!check_parameter_order()) {
|
||||
LOG_ERROR("Unable to enable Modbus - the parameter list order is corrupt. This is a firmware bug.");
|
||||
return;
|
||||
}
|
||||
|
||||
modbusServer_ = new ModbusServerTCPasync();
|
||||
modbusServer_->registerWorker(systemServerId, READ_INPUT_REGISTER, [this](auto && request) { return handleSystemRead(request); });
|
||||
|
||||
for (uint8_t i = EMSdevice::DeviceType::BOILER; i < EMSdevice::DeviceType::UNKNOWN; i++) {
|
||||
if (i != systemServerId) {
|
||||
modbusServer_->registerWorker(i, READ_INPUT_REGISTER, [this](auto && request) { return handleRead(request); });
|
||||
modbusServer_->registerWorker(i, READ_HOLD_REGISTER, [this](auto && request) { return handleRead(request); });
|
||||
modbusServer_->registerWorker(i, WRITE_HOLD_REGISTER, [this](auto && request) { return handleWrite(request); });
|
||||
modbusServer_->registerWorker(i, WRITE_MULT_REGISTERS, [this](auto && request) { return handleWrite(request); });
|
||||
}
|
||||
}
|
||||
modbusServer_->start(port, max_clients, timeout);
|
||||
LOG_INFO("Modbus server with ID %d started on port %d", systemServerId, port);
|
||||
#else
|
||||
if (!check_parameter_order()) {
|
||||
LOG_ERROR("Unable to enable Modbus - the parameter list order is corrupt. This is a firmware bug.");
|
||||
}
|
||||
LOG_INFO("Modbus deactivated in standalone build.");
|
||||
#endif
|
||||
}
|
||||
|
||||
// this is currently never called, just for good measure
|
||||
void Modbus::stop() {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
modbusServer_->stop();
|
||||
delete modbusServer_;
|
||||
modbusServer_ = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check that the Modbus parameters defined in modbus_entity_parameters.cpp are correctly ordered
|
||||
bool Modbus::check_parameter_order() {
|
||||
EntityModbusInfo const * prev = nullptr;
|
||||
bool isFirst = true;
|
||||
for (const auto & mi : modbus_register_mappings) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else if (prev == nullptr || !prev->isLessThan(mi)) {
|
||||
LOG_ERROR("Error in modbus parameters: %s must be listed before %s.", mi.short_name, prev->short_name);
|
||||
return false;
|
||||
}
|
||||
prev = &mi;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int8_t Modbus::tag_to_type(int8_t tag) {
|
||||
// this coulod even be an array
|
||||
switch (tag) {
|
||||
case DeviceValue::TAG_NONE:
|
||||
return TAG_TYPE_NONE;
|
||||
|
||||
case DeviceValue::TAG_DEVICE_DATA:
|
||||
return TAG_TYPE_DEVICE_DATA;
|
||||
|
||||
case DeviceValue::TAG_HC1:
|
||||
return TAG_TYPE_HC;
|
||||
|
||||
case DeviceValue::TAG_HC2:
|
||||
return TAG_TYPE_HC;
|
||||
|
||||
case DeviceValue::TAG_HC3:
|
||||
return TAG_TYPE_HC;
|
||||
|
||||
case DeviceValue::TAG_HC4:
|
||||
return TAG_TYPE_HC;
|
||||
|
||||
case DeviceValue::TAG_HC5:
|
||||
return TAG_TYPE_HC;
|
||||
|
||||
case DeviceValue::TAG_HC6:
|
||||
return TAG_TYPE_HC;
|
||||
|
||||
case DeviceValue::TAG_HC7:
|
||||
return TAG_TYPE_HC;
|
||||
|
||||
case DeviceValue::TAG_HC8:
|
||||
return TAG_TYPE_HC;
|
||||
|
||||
case DeviceValue::TAG_DHW1:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_DHW2:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_DHW3:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_DHW4:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_DHW5:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_DHW6:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_DHW7:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_DHW8:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_DHW9:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_DHW10:
|
||||
return TAG_TYPE_DHW;
|
||||
|
||||
case DeviceValue::TAG_AHS1:
|
||||
return TAG_TYPE_AHS;
|
||||
|
||||
case DeviceValue::TAG_HS1:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS2:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS3:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS4:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS5:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS6:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS7:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS8:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS9:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS10:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS11:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS12:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS13:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS14:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS15:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
case DeviceValue::TAG_HS16:
|
||||
return TAG_TYPE_HS;
|
||||
|
||||
default:
|
||||
return INVALID_TAG_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
/* DEBUG
|
||||
template <typename TInputIter>
|
||||
std::string make_hex_string(TInputIter first, TInputIter last) {
|
||||
std::ostringstream ss;
|
||||
ss << std::hex << std::setfill('0');
|
||||
|
||||
while (first != last)
|
||||
ss << std::setw(2) << static_cast<int>(*first++);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
ModbusMessage Modbus::handleSystemRead(const ModbusMessage & request) {
|
||||
ModbusMessage response;
|
||||
|
||||
uint16_t start_address = 0;
|
||||
uint16_t num_words = 0;
|
||||
|
||||
request.get(2, start_address);
|
||||
request.get(4, num_words);
|
||||
|
||||
LOG_DEBUG("Got request for serverId %d, startAddress %d, numWords %d", request.getServerID(), start_address, num_words);
|
||||
|
||||
if (start_address < 1000) {
|
||||
switch (start_address) {
|
||||
case 1:
|
||||
response.add(request.getServerID());
|
||||
response.add(request.getFunctionCode());
|
||||
response.add((uint8_t)2);
|
||||
response.add((uint16_t)EMSESP::emsdevices.size());
|
||||
break;
|
||||
|
||||
default:
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
}
|
||||
} else if (start_address < 1000 + EMSESP::emsdevices.size()) {
|
||||
const auto & dev = EMSESP::emsdevices[start_address - 1000];
|
||||
response.add(request.getServerID());
|
||||
response.add(request.getFunctionCode());
|
||||
response.add((uint8_t)2);
|
||||
response.add(dev->device_type());
|
||||
response.add(dev->device_id());
|
||||
} else {
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
ModbusMessage Modbus::handleRead(const ModbusMessage & request) {
|
||||
ModbusMessage response;
|
||||
|
||||
uint8_t device_type = request.getServerID(); // the server ID is the same as the device type
|
||||
uint16_t start_address = 0;
|
||||
uint16_t num_words = 0;
|
||||
|
||||
request.get(2, start_address);
|
||||
request.get(4, num_words);
|
||||
|
||||
LOG_DEBUG("Got read request for serverId %d, startAddress %d, numWords %d", device_type, start_address, num_words);
|
||||
|
||||
// each register block corresponds to a device value tag
|
||||
auto tag = (uint8_t)(start_address / REGISTER_BLOCK_SIZE);
|
||||
auto tag_type = tag_to_type(tag);
|
||||
|
||||
if (tag_type == INVALID_TAG_TYPE) {
|
||||
// invalid register block, does not correspond to an existing tag
|
||||
LOG_ERROR("invalid register block, does not correspond to an existing tag");
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
return response;
|
||||
}
|
||||
|
||||
auto register_offset = start_address - tag * REGISTER_BLOCK_SIZE;
|
||||
|
||||
const auto & dev_it =
|
||||
std::find_if(EMSESP::emsdevices.begin(), EMSESP::emsdevices.end(), [&](const std::unique_ptr<EMSdevice> & x) { return x->device_type() == device_type; });
|
||||
|
||||
if (dev_it == EMSESP::emsdevices.end()) {
|
||||
// device not found => invalid server ID
|
||||
LOG_ERROR("device with type %d not found => invalid server ID", device_type);
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
return response;
|
||||
}
|
||||
|
||||
const auto & dev = *dev_it;
|
||||
|
||||
// binary search in modbus infos
|
||||
auto key = EntityModbusInfoKey(dev->device_type(), tag_type, register_offset);
|
||||
|
||||
const auto & modbusInfo = std::lower_bound(std::begin(modbus_register_mappings),
|
||||
std::end(modbus_register_mappings),
|
||||
key,
|
||||
[](const EntityModbusInfo & a, const EntityModbusInfoKey & b) { return a.isLessThan(b); });
|
||||
|
||||
|
||||
if (modbusInfo == std::end(modbus_register_mappings) || !modbusInfo->equals(key)) {
|
||||
// combination of device_type/tag_type/register_offset does not exist
|
||||
LOG_ERROR("combination of device_type/tag_type/register_offset does not exist");
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
return response;
|
||||
}
|
||||
|
||||
// only reading a single value at a time is supported for now
|
||||
if (num_words != modbusInfo->registerCount) {
|
||||
// number of registers requested does not match actual register count for entity
|
||||
LOG_ERROR("number of registers requested does not match actual register count for entity");
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
return response;
|
||||
}
|
||||
|
||||
auto buf = std::vector<uint16_t>(num_words);
|
||||
if (dev->get_modbus_value(tag, modbusInfo->short_name, buf) == 0) {
|
||||
response.add(request.getServerID());
|
||||
response.add(request.getFunctionCode());
|
||||
response.add((uint8_t)(num_words * 2));
|
||||
for (auto & value : buf)
|
||||
response.add(value);
|
||||
} else {
|
||||
LOG_ERROR("Unable to read raw device value %s for tag=%d", modbusInfo->short_name, (int)tag);
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), SERVER_DEVICE_FAILURE);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
ModbusMessage Modbus::handleWrite(const ModbusMessage & request) {
|
||||
ModbusMessage response;
|
||||
|
||||
uint8_t device_type = request.getServerID(); // the server ID is the same as the device type
|
||||
uint8_t function_code = request.getFunctionCode();
|
||||
uint16_t start_address = 0;
|
||||
uint16_t num_words = 0;
|
||||
uint8_t byte_count = 0;
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
if (function_code == WRITE_MULT_REGISTERS) {
|
||||
request.get(2, start_address);
|
||||
request.get(4, num_words);
|
||||
request.get(6, byte_count);
|
||||
request.get(7, data, byte_count);
|
||||
} else if (function_code == WRITE_HOLD_REGISTER) {
|
||||
num_words = 1;
|
||||
byte_count = 2;
|
||||
request.get(2, start_address);
|
||||
request.get(4, data, byte_count);
|
||||
} else {
|
||||
LOG_ERROR("Function code %d is not implemented", function_code);
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_FUNCTION);
|
||||
return response;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Got write request for serverId %d, startAddress %d, numWords %d, byteCount %d", device_type, start_address, num_words, byte_count);
|
||||
|
||||
// each register block corresponds to a device value tag
|
||||
auto tag = (uint8_t)(start_address / REGISTER_BLOCK_SIZE);
|
||||
auto tag_type = tag_to_type(tag);
|
||||
|
||||
if (tag_type == INVALID_TAG_TYPE) {
|
||||
// invalid register block, does not correspond to an existing tag
|
||||
LOG_ERROR("invalid register block (%d), does not correspond to an existing tag", tag);
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
return response;
|
||||
}
|
||||
|
||||
auto register_offset = start_address - tag * REGISTER_BLOCK_SIZE;
|
||||
|
||||
const auto & dev_it =
|
||||
std::find_if(EMSESP::emsdevices.begin(), EMSESP::emsdevices.end(), [&](const std::unique_ptr<EMSdevice> & x) { return x->device_type() == device_type; });
|
||||
|
||||
if (dev_it == EMSESP::emsdevices.end()) {
|
||||
// device not found => invalid server ID
|
||||
LOG_ERROR("device_type (%d) not found => invalid server ID", device_type);
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
return response;
|
||||
}
|
||||
|
||||
const auto & dev = *dev_it;
|
||||
|
||||
// binary search in modbus infos
|
||||
auto key = EntityModbusInfoKey(dev->device_type(), tag_type, register_offset);
|
||||
auto modbusInfo = std::lower_bound(std::begin(modbus_register_mappings),
|
||||
std::end(modbus_register_mappings),
|
||||
key,
|
||||
[](const EntityModbusInfo & mi, const EntityModbusInfoKey & k) { return mi.isLessThan(k); });
|
||||
|
||||
if (modbusInfo == std::end(modbus_register_mappings) || !modbusInfo->equals(key)) {
|
||||
// combination of device_type/tag_type/register_offset does not exist
|
||||
LOG_ERROR("combination of device_type (%d)/tag_type (%d)/register_offset (%d) does not exist",
|
||||
key.device_type,
|
||||
key.device_value_tag_type,
|
||||
key.registerOffset);
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
return response;
|
||||
}
|
||||
|
||||
// only writing a single value at a time is supported for now
|
||||
if (num_words != modbusInfo->registerCount) {
|
||||
// number of registers requested does not match actual register count for entity
|
||||
LOG_ERROR("number of registers (%d) requested does not match actual register count (%d) for entity", num_words, modbusInfo->registerCount);
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
return response;
|
||||
}
|
||||
|
||||
JsonDocument input_doc;
|
||||
JsonObject input = input_doc.to<JsonObject>();
|
||||
|
||||
if (!dev->modbus_value_to_json(tag, modbusInfo->short_name, data, input)) {
|
||||
// error getting modbus value as json
|
||||
LOG_ERROR("error getting modbus value as json");
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
|
||||
return response;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (tag < DeviceValueTAG::TAG_HC1) {
|
||||
path = std::string("ems-esp/") + std::string(EMSdevice::device_type_2_device_name(dev->device_type())) + "/" + modbusInfo->short_name;
|
||||
} else {
|
||||
path = std::string("ems-esp/") + std::string(EMSdevice::device_type_2_device_name(dev->device_type())) + "/" + EMSdevice::tag_to_mqtt(tag) + "/"
|
||||
+ modbusInfo->short_name;
|
||||
}
|
||||
|
||||
LOG_DEBUG("path: %s\n", path.c_str());
|
||||
|
||||
std::string inputStr;
|
||||
serializeJson(input, inputStr);
|
||||
LOG_DEBUG("input: %s\n", inputStr.c_str());
|
||||
|
||||
JsonDocument output_doc;
|
||||
JsonObject output = output_doc.to<JsonObject>();
|
||||
uint8_t return_code = Command::process(path.c_str(), true, input, output); // modbus is always authenticated
|
||||
|
||||
if (return_code != CommandRet::OK) {
|
||||
char error[100];
|
||||
if (output.size()) {
|
||||
snprintf(error,
|
||||
sizeof(error),
|
||||
"Modbus write command failed with error: %s (%s)",
|
||||
(const char *)output["message"],
|
||||
Command::return_code_string(return_code).c_str());
|
||||
} else {
|
||||
snprintf(error, sizeof(error), "Modbus write command failed with error code (%s)", Command::return_code_string(return_code).c_str());
|
||||
}
|
||||
LOG_ERROR(error);
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_VALUE);
|
||||
} else {
|
||||
// all good
|
||||
response.add(request.getServerID());
|
||||
response.add(request.getFunctionCode());
|
||||
response.add(start_address);
|
||||
response.add(num_words);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
#if defined(EMSESP_STANDALONE)
|
||||
// return the relative register start offset for a DeviceValue, i.e. the address within the
|
||||
// register block corresponding to the value's tag type.
|
||||
int Modbus::getRegisterOffset(const DeviceValue & dv) {
|
||||
auto it = std::find_if(std::begin(modbus_register_mappings), std::end(modbus_register_mappings), [&](const EntityModbusInfo & mi) {
|
||||
return mi.device_type == dv.device_type && mi.device_value_tag_type == tag_to_type(dv.tag) && !strcmp(mi.short_name, dv.short_name);
|
||||
});
|
||||
if (it != std::end(modbus_register_mappings)) {
|
||||
return it->registerOffset;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// return the number of registers
|
||||
int Modbus::getRegisterCount(const DeviceValue & dv) {
|
||||
auto it = std::find_if(std::begin(modbus_register_mappings), std::end(modbus_register_mappings), [&](const EntityModbusInfo & mi) {
|
||||
return mi.device_type == dv.device_type && mi.device_value_tag_type == tag_to_type(dv.tag) && !strcmp(mi.short_name, dv.short_name);
|
||||
});
|
||||
if (it != std::end(modbus_register_mappings)) {
|
||||
// look up actual size
|
||||
return it->registerCount;
|
||||
} else {
|
||||
// guess based on type
|
||||
switch (dv.type) {
|
||||
case DeviceValue::BOOL: // 8 bit
|
||||
case DeviceValue::INT8:
|
||||
case DeviceValue::UINT8:
|
||||
case DeviceValue::INT16:
|
||||
case DeviceValue::UINT16:
|
||||
case DeviceValue::ENUM: // 8 bit
|
||||
case DeviceValue::CMD:
|
||||
return 1;
|
||||
|
||||
case DeviceValue::UINT24:
|
||||
case DeviceValue::UINT32:
|
||||
case DeviceValue::TIME: // 32 bit
|
||||
return 2;
|
||||
|
||||
case DeviceValue::STRING:
|
||||
break; // impossible to guess, needs to be hardcoded
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return the absolute register start address for a DeviceValue
|
||||
int Modbus::getRegisterStartAddress(const DeviceValue & dv) {
|
||||
return dv.tag * REGISTER_BLOCK_SIZE + getRegisterOffset(dv);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace emsesp
|
||||
112
src/modbus.h
Normal file
112
src/modbus.h
Normal file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// Created by Michael Heyse on 08.02.24.
|
||||
//
|
||||
|
||||
#ifndef EMSESP_MODBUS_H_
|
||||
#define EMSESP_MODBUS_H_
|
||||
|
||||
#include "helpers.h"
|
||||
#include "emsdevice.h"
|
||||
#include "emsdevicevalue.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#if defined(EMSESP_STANDALONE) || defined(EMSESP_TEST)
|
||||
|
||||
#include <modbus_test.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
#include <ModbusServerTCPasync.h>
|
||||
#endif
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Modbus {
|
||||
public:
|
||||
static const int REGISTER_BLOCK_SIZE = 1000;
|
||||
|
||||
void start(uint8_t systemServerId, uint16_t port, uint8_t max_clients, uint32_t timeout);
|
||||
void stop();
|
||||
|
||||
#if defined(EMSESP_STANDALONE)
|
||||
int getRegisterOffset(const DeviceValue & dv);
|
||||
int getRegisterCount(const DeviceValue & dv);
|
||||
int getRegisterStartAddress(const DeviceValue & dv);
|
||||
#endif
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
struct EntityModbusInfoKey {
|
||||
const uint8_t device_type;
|
||||
const uint8_t device_value_tag_type;
|
||||
const uint16_t registerOffset;
|
||||
|
||||
EntityModbusInfoKey(uint8_t deviceType, uint8_t deviceValueTagType, uint16_t registerOffset)
|
||||
: device_type(deviceType)
|
||||
, device_value_tag_type(deviceValueTagType)
|
||||
, registerOffset(registerOffset) {
|
||||
}
|
||||
|
||||
bool equals(const EntityModbusInfoKey & other) const {
|
||||
return device_type == other.device_type && device_value_tag_type == other.device_value_tag_type && registerOffset == other.registerOffset;
|
||||
}
|
||||
};
|
||||
|
||||
struct EntityModbusInfo {
|
||||
const uint8_t device_type;
|
||||
const uint8_t device_value_tag_type;
|
||||
const char * const short_name;
|
||||
const uint16_t registerOffset;
|
||||
const uint16_t registerCount;
|
||||
|
||||
bool equals(const EntityModbusInfoKey & other) const {
|
||||
return device_type == other.device_type && device_value_tag_type == other.device_value_tag_type && registerOffset == other.registerOffset;
|
||||
}
|
||||
|
||||
bool isLessThan(const EntityModbusInfoKey & other) const {
|
||||
return device_type < other.device_type || ((device_type == other.device_type) && (device_value_tag_type < other.device_value_tag_type))
|
||||
|| ((device_type == other.device_type) && (device_value_tag_type == other.device_value_tag_type) && (registerOffset < other.registerOffset));
|
||||
}
|
||||
|
||||
bool isLessThan(const EntityModbusInfo & other) const {
|
||||
return device_type < other.device_type || ((device_type == other.device_type) && (device_value_tag_type < other.device_value_tag_type))
|
||||
|| ((device_type == other.device_type) && (device_value_tag_type == other.device_value_tag_type) && (registerOffset < other.registerOffset));
|
||||
}
|
||||
};
|
||||
|
||||
enum DeviceValueTAGType : int8_t {
|
||||
TAG_TYPE_NONE = DeviceValue::DeviceValueTAG::TAG_NONE,
|
||||
TAG_TYPE_DEVICE_DATA = DeviceValue::DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
TAG_TYPE_HC = DeviceValue::DeviceValueTAG::TAG_HC1,
|
||||
TAG_TYPE_DHW = DeviceValue::DeviceValueTAG::TAG_DHW1,
|
||||
TAG_TYPE_AHS = DeviceValue::DeviceValueTAG::TAG_AHS1,
|
||||
TAG_TYPE_HS = DeviceValue::DeviceValueTAG::TAG_HS1,
|
||||
INVALID_TAG_TYPE = -2
|
||||
};
|
||||
|
||||
static const std::initializer_list<EntityModbusInfo> modbus_register_mappings;
|
||||
|
||||
static int8_t tag_to_type(int8_t tag);
|
||||
static bool check_parameter_order();
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
ModbusServerTCPasync * modbusServer_;
|
||||
#endif
|
||||
|
||||
#if defined(EMSESP_STANDALONE) || defined(EMSESP_TEST)
|
||||
public:
|
||||
#endif
|
||||
|
||||
static ModbusMessage handleSystemRead(const ModbusMessage & request);
|
||||
static ModbusMessage handleRead(const ModbusMessage & request);
|
||||
static ModbusMessage handleWrite(const ModbusMessage & request);
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif //EMSESP_MODBUS_H_
|
||||
515
src/modbus_entity_parameters.hpp
Normal file
515
src/modbus_entity_parameters.hpp
Normal file
@@ -0,0 +1,515 @@
|
||||
#include "modbus.h"
|
||||
#include "emsdevice.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
using dt = EMSdevice::DeviceType;
|
||||
|
||||
#define REGISTER_MAPPING(device_type, device_value_tag_type, long_name, modbus_register_offset, modbus_register_count) \
|
||||
{ device_type, device_value_tag_type, long_name[0], modbus_register_offset, modbus_register_count }
|
||||
|
||||
// IMPORTANT: This list MUST be ordered by keys "device_type", "device_value_tag_type" and "modbus_register_offset" in this order.
|
||||
const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_mappings = {
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(reset), 0, 1), // reset
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(forceHeatingOff), 1, 1), // heatingoff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingActive), 2, 1), // heatingactive
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tapwaterActive), 3, 1), // tapwateractive
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(selFlowTemp), 4, 1), // selflowtemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingPumpMod), 5, 1), // heatingpumpmod
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(outdoorTemp), 6, 1), // outdoortemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curFlowTemp), 7, 1), // curflowtemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(retTemp), 8, 1), // rettemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(switchTemp), 9, 1), // switchtemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(sysPress), 10, 1), // syspress
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilTemp), 11, 1), // boiltemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(headertemp), 12, 1), // headertemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingActivated), 13, 1), // heatingactivated
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingTemp), 14, 1), // heatingtemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingPump), 15, 1), // heatingpump
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpModMax), 16, 1), // pumpmodmax
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpModMin), 17, 1), // pumpmodmin
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpMode), 18, 1), // pumpmode
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpCharacter), 19, 1), // pumpcharacter
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpDelay), 20, 1), // pumpdelay
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setFlowTemp), 21, 1), // setflowtemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setBurnPow), 22, 1), // setburnpow
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(selBurnPow), 23, 1), // selburnpow
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curBurnPow), 24, 1), // curburnpow
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnStarts), 25, 2), // burnstarts
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnWorkMin), 27, 2), // burnworkmin
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burn2WorkMin), 29, 2), // burn2workmin
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatWorkMin), 31, 2), // heatworkmin
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatStarts), 33, 2), // heatstarts
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(UBAuptime), 35, 2), // ubauptime
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(lastCode), 37, 28), // lastcode
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(serviceCode), 65, 2), // servicecode
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(serviceCodeNumber), 67, 1), // servicecodenumber
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maintenanceMessage), 68, 2), // maintenancemessage
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maintenanceType), 70, 1), // maintenance
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maintenanceTime), 71, 1), // maintenancetime
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maintenanceDate), 72, 6), // maintenancedate
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(emergencyOps), 78, 1), // emergencyops
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(emergencyTemp), 79, 1), // emergencytemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgTotal), 80, 2), // nrgtotal
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat), 82, 2), // nrgheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterTotal), 84, 2), // metertotal
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterComp), 86, 2), // metercomp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterEHeat), 88, 2), // metereheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterHeat), 90, 2), // meterheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeTotal), 92, 2), // uptimetotal
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeControl), 94, 2), // uptimecontrol
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeCompHeating), 96, 2), // uptimecompheating
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeCompCooling), 98, 2), // uptimecompcooling
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(upTimeCompPool), 100, 2), // uptimecomppool
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(totalCompStarts), 102, 2), // totalcompstarts
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingStarts), 104, 2), // heatingstarts
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(coolingStarts), 106, 2), // coolingstarts
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolStarts), 108, 2), // poolstarts
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsTotal), 110, 2), // nrgconstotal
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompTotal), 112, 2), // nrgconscomptotal
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompHeating), 114, 2), // nrgconscompheating
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompCooling), 116, 2), // nrgconscompcooling
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgConsCompPool), 118, 2), // nrgconscomppool
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxElecHeatNrgConsTotal), 120, 2), // auxelecheatnrgconstotal
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxElecHeatNrgConsHeating), 122, 2), // auxelecheatnrgconsheating
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxElecHeatNrgConsPool), 124, 2), // auxelecheatnrgconspool
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppTotal), 126, 2), // nrgsupptotal
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppHeating), 128, 2), // nrgsuppheating
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppCooling), 130, 2), // nrgsuppcooling
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgSuppPool), 132, 2), // nrgsupppool
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPower), 134, 1), // hppower
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpMaxPower), 135, 1), // hpmaxpower
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSetDiffPress), 136, 1), // hpsetdiffpress
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompOn), 137, 1), // hpcompon
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpActivity), 138, 1), // hpactivity
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrinePumpSpd), 139, 1), // hpbrinepumpspd
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSwitchValve), 140, 1), // hpswitchvalve
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompSpd), 141, 1), // hpcompspd
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCircSpd), 142, 1), // hpcircspd
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineIn), 143, 1), // hpbrinein
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineOut), 144, 1), // hpbrineout
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc0), 145, 1), // hptc0
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc1), 146, 1), // hptc1
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc3), 147, 1), // hptc3
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr1), 148, 1), // hptr1
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr3), 149, 1), // hptr3
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr4), 150, 1), // hptr4
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr5), 151, 1), // hptr5
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr6), 152, 1), // hptr6
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr7), 153, 1), // hptr7
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTl2), 154, 1), // hptl2
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPl1), 155, 1), // hppl1
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPh1), 156, 1), // hpph1
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTa4), 157, 1), // hpta4
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTw1), 158, 1), // hptw1
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolSetTemp), 159, 1), // poolsettemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp4wayValve), 160, 1), // hp4way
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput1), 161, 1), // hpin1
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn1Opt), 162, 8), // hpin1opt
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput2), 170, 1), // hpin2
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn2Opt), 171, 8), // hpin2opt
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput3), 179, 1), // hpin3
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn3Opt), 180, 8), // hpin3opt
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput4), 188, 1), // hpin4
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn4Opt), 189, 8), // hpin4opt
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatComp), 197, 1), // maxheatcomp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatHeat), 198, 1), // maxheatheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(manDefrost), 199, 1), // mandefrost
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pvCooling), 200, 1), // pvcooling
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOnly), 201, 1), // auxheateronly
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOff), 202, 1), // auxheateroff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterStatus), 203, 1), // auxheaterstatus
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterDelay), 204, 1), // auxheaterdelay
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxMaxLimit), 205, 1), // auxmaxlimit
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxLimitStart), 206, 1), // auxlimitstart
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMode), 207, 1), // auxheatrmode
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystHeat), 208, 1), // hphystheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystCool), 209, 1), // hphystcool
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystPool), 210, 1), // hphystpool
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentMode), 211, 1), // silentmode
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentFrom), 212, 1), // silentfrom
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentTo), 213, 1), // silentto
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(minTempSilent), 214, 1), // mintempsilent
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempParMode), 215, 1), // tempparmode
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMixValve), 216, 1), // auxheatmix
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffHeat), 217, 1), // tempdiffheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffCool), 218, 1), // tempdiffcool
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(vp_cooling), 219, 1), // vpcooling
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 220, 1), // heatcable
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(VC0valve), 221, 1), // vc0valve
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePump), 222, 1), // primepump
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePumpMod), 223, 1), // primepumpmod
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp3wayValve), 224, 1), // hp3way
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep1), 225, 1), // elheatstep1
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep2), 226, 1), // elheatstep2
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep3), 227, 1), // elheatstep3
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpEA0), 228, 1), // hpea0
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPumpMode), 229, 1), // hppumpmode
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpFan), 230, 1), // fan
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpShutdown), 231, 1), // shutdown
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(exhaustTemp), 232, 1), // exhausttemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas), 233, 1), // burngas
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas2), 234, 1), // burngas2
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(flameCurr), 235, 1), // flamecurr
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanWork), 236, 1), // fanwork
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(ignWork), 237, 1), // ignwork
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(oilPreHeat), 238, 1), // oilpreheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPower), 239, 1), // burnminpower
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMaxPower), 240, 1), // burnmaxpower
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPeriod), 241, 1), // burnminperiod
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(absBurnPow), 242, 1), // absburnpow
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatblock), 243, 1), // heatblock
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOn), 244, 1), // boilhyston
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOff), 245, 1), // boilhystoff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOn), 246, 1), // boil2hyston
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOff), 247, 1), // boil2hystoff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveOn), 248, 1), // curveon
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveBase), 249, 1), // curvebase
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveEnd), 250, 1), // curveend
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(summertemp), 251, 1), // summertemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrostmode), 252, 1), // nofrostmode
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrosttemp), 253, 1), // nofrosttemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(gasMeterHeat), 254, 2), // gasmeterheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat2), 256, 2), // nrgheat2
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nomPower), 258, 1), // nompower
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(netFlowTemp), 259, 1), // netflowtemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatValve), 260, 1), // heatvalve
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(keepWarmTemp), 261, 1), // keepwarmtemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setReturnTemp), 262, 1), // setreturntemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingOn), 263, 1), // heating
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(nrgWw), 0, 2), // nrg
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(meterWw), 2, 2), // meter
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(upTimeCompWw), 4, 2), // uptimecomp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwStarts2), 6, 2), // starts2
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(nrgConsCompWw), 8, 2), // nrgconscomp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(auxElecHeatNrgConsWw), 10, 2), // auxelecheatnrgcons
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(nrgSuppWw), 12, 2), // nrgsupp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(maxHeatDhw), 14, 1), // maxheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwAlternatingOper), 15, 1), // alternatingop
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwAltOpPrioHeat), 16, 1), // altopprioheat
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwAltOpPrioWw), 17, 1), // altopprio
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwComfOffTemp), 18, 1), // comfoff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwEcoOffTemp), 19, 1), // ecooff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwEcoPlusOffTemp), 20, 1), // ecoplusoff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwComfDiffTemp), 21, 1), // comfdiff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwEcoDiffTemp), 22, 1), // ecodiff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwEcoPlusDiffTemp), 23, 1), // ecoplusdiff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwComfStopTemp), 24, 1), // comfstop
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwEcoStopTemp), 25, 1), // ecostop
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwEcoPlusStopTemp), 26, 1), // ecoplusstop
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(hpCircPumpWw), 27, 1), // hpcircpump
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwtapactivated), 28, 1), // tapactivated
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwSetTemp), 29, 1), // settemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(selRoomTemp), 30, 1), // seltemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwSelTempLow), 31, 1), // seltemplow
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwSelTempEco), 32, 1), // tempecoplus
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwSelTempOff), 33, 1), // seltempoff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwSelTempSingle), 34, 1), // seltempsingle
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwSolarTemp), 35, 1), // solartemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwType), 36, 1), // type
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwComfort), 37, 1), // comfort
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwComfort1), 38, 1), // comfort1
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(flowtempoffset), 39, 1), // flowtempoffset
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwChargeOptimization), 40, 1), // chargeoptimization
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwMaxPower), 41, 1), // maxpower
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwMaxTemp), 42, 1), // maxtemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwCircPump), 43, 1), // circpump
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwChargeType), 44, 1), // chargetype
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwHystOn), 45, 1), // hyston
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwHystOff), 46, 1), // hystoff
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwDisinfectionTemp), 47, 1), // disinfectiontemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwCircMode), 48, 1), // circmode
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwCirc), 49, 1), // circ
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwCurTemp), 50, 1), // curtemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwCurTemp2), 51, 1), // curtemp2
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwCurFlow), 52, 1), // curflow
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwStorageTemp1), 53, 1), // storagetemp1
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwStorageTemp2), 54, 1), // storagetemp2
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(activated), 55, 1), // activated
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwOneTime), 56, 1), // onetime
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwDisinfecting), 57, 1), // disinfecting
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwCharging), 58, 1), // charging
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwRecharging), 59, 1), // recharging
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwTempOK), 60, 1), // tempok
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwActive), 61, 1), // active
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(ww3wayValve), 62, 1), // 3wayvalve
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwSetPumpPower), 63, 1), // setpumppower
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwMixerTemp), 64, 1), // mixertemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(cylMiddleTemp), 65, 1), // cylmiddletemp
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwStarts), 66, 2), // starts
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwWorkM), 68, 2), // workm
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(gasMeterWw), 70, 2), // gasmeter
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(nrgWw2), 72, 2), // nrg2
|
||||
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwValve), 74, 1), // dhwvalve
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(errorCode), 0, 8), // errorcode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(lastCode), 8, 25), // lastcode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(dateTime), 33, 13), // datetime
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(ibaCalIntTemperature), 46, 1), // intoffset
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(floordrystatus), 47, 1), // floordry
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(dampedoutdoortemp), 48, 1), // dampedoutdoortemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(floordrytemp), 49, 1), // floordrytemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(ibaBuildingType), 50, 1), // building
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(ibaMinExtTemperature), 51, 1), // minexttemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(damping), 52, 1), // damping
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(hybridStrategy), 53, 1), // hybridstrategy
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(switchOverTemp), 54, 1), // switchovertemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(energyCostRatio), 55, 1), // energycostratio
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(fossileFactor), 56, 1), // fossilefactor
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(electricFactor), 57, 1), // electricfactor
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(delayBoiler), 58, 1), // delayboiler
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(tempDiffBoiler), 59, 1), // tempdiffboiler
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(pvEnableWw), 60, 1), // pvenabledhw
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(pvRaiseHeat), 61, 1), // pvraiseheat
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(pvLowerCool), 62, 1), // pvlowercool
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(ibaMainDisplay), 63, 1), // display
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(ibaLanguage), 64, 1), // language
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(ibaClockOffset), 65, 1), // clockoffset
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(tempsensor1), 66, 1), // inttemp1
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(tempsensor2), 67, 1), // inttemp2
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(autodst), 68, 1), // autodst
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(backlight), 69, 1), // backlight
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(brightness), 70, 1), // brightness
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(mixingvalves), 71, 1), // mixingvalves
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(heatingPID), 72, 1), // heatingpid
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(preheating), 73, 1), // preheating
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(vacations), 74, 13), // vacations
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(selRoomTemp), 0, 1), // seltemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roomTemp), 1, 1), // currtemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(haclimate), 2, 1), // haclimate
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(mode), 3, 1), // mode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(modetype), 4, 1), // modetype
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(ecotemp), 5, 1), // ecotemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(manualtemp), 6, 1), // manualtemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(comforttemp), 7, 1), // comforttemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(summertemp), 8, 1), // summertemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(designtemp), 9, 1), // designtemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(offsettemp), 10, 1), // offsettemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(minflowtemp), 11, 1), // minflowtemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(maxflowtemp), 12, 1), // maxflowtemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roominfluence), 13, 1), // roominfluence
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roominfl_factor), 14, 1), // roominflfactor
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(curroominfl), 15, 1), // curroominfl
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(nofrostmode), 16, 1), // nofrostmode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(nofrosttemp), 17, 1), // nofrosttemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(targetflowtemp), 18, 1), // targetflowtemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatingtype), 19, 1), // heatingtype
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(summersetmode), 20, 1), // summersetmode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpoperatingmode), 21, 1), // hpoperatingmode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(summermode), 22, 1), // summermode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpoperatingstate), 23, 1), // hpoperatingstate
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(controlmode), 24, 1), // controlmode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(program), 25, 1), // program
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(tempautotemp), 26, 1), // tempautotemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(remoteseltemp), 27, 1), // remoteseltemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(fastheatup), 28, 1), // fastheatup
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchonoptimization), 29, 1), // switchonoptimization
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducemode), 30, 1), // reducemode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(noreducetemp), 31, 1), // noreducetemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducetemp), 32, 1), // reducetemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(wwprio), 33, 1), // dhwprio
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpcooling), 34, 1), // cooling
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolingOn), 35, 1), // coolingon
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpmode), 36, 1), // hpmode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(dewoffset), 37, 1), // dewoffset
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roomtempdiff), 38, 1), // roomtempdiff
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpminflowtemp), 39, 1), // hpminflowtemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(control), 40, 1), // control
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(remotetemp), 41, 1), // remotetemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(remotehum), 42, 1), // remotehum
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatondelay), 43, 1), // heatondelay
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatoffdelay), 44, 1), // heatoffdelay
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(instantstart), 45, 1), // instantstart
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boost), 46, 1), // boost
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boosttime), 47, 1), // boosttime
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daytemp), 48, 1), // daytemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(nighttemp2), 49, 1), // nighttemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(holidaytemp), 50, 1), // holidaytemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(holidaymode), 51, 1), // holidaymode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(flowtempoffset), 52, 1), // flowtempoffset
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(holidays), 53, 13), // holidays
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations), 66, 13), // vacations
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(pause), 79, 1), // pause
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(party), 80, 1), // party
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacreducetemp), 81, 1), // vacreducetemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacreducemode), 82, 1), // vacreducemode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchtime1), 83, 8), // switchtime1
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchtime2), 91, 8), // switchtime2
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(offtemp), 99, 1), // offtemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daylowtemp), 100, 1), // daytemp2
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daymidtemp), 101, 1), // daytemp3
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(dayhightemp), 102, 1), // daytemp4
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(wwswitchtime), 103, 8), // switchtime
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations1), 111, 11), // vacations1
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations2), 122, 11), // vacations2
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations3), 133, 11), // vacations3
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations4), 144, 11), // vacations4
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations5), 155, 11), // vacations5
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations6), 166, 11), // vacations6
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations7), 177, 11), // vacations7
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducehours), 188, 1), // reducehours
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reduceminutes), 189, 1), // reduceminutes
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heattemp), 190, 1), // heattemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roomsensor), 191, 1), // roomsensor
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatup), 192, 1), // heatup
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(mode), 0, 1), // mode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwSetTemp), 1, 1), // settemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwSetTempLow), 2, 1), // settemplow
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwCircMode), 3, 1), // circmode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwChargeDuration), 4, 1), // chargeduration
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwCharge), 5, 1), // charge
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwExtra), 6, 1), // extra
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwDisinfecting), 7, 1), // disinfecting
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwDisinfectDay), 8, 1), // disinfectday
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwDisinfectTime), 9, 1), // disinfecttime
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwDailyHeating), 10, 1), // dailyheating
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwDailyHeatTime), 11, 1), // dailyheattime
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwProgMode), 12, 1), // progmode
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwCircProg), 13, 1), // circprog
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwDisinfectHour), 14, 1), // disinfecthour
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwMaxTemp), 15, 1), // maxtemp
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwOneTimeKey), 16, 1), // onetimekey
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwswitchtime), 17, 8), // switchtime
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwcircswitchtime), 25, 8), // circswitchtime
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(holidays), 33, 13), // holidays
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(vacations), 46, 13), // vacations
|
||||
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwWhenModeOff), 59, 1), // whenmodeoff
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_HC, FL_(flowTempHc), 0, 1), // flowtemphc
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_HC, FL_(valveStatus), 1, 1), // valvestatus
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_HC, FL_(flowSetTemp), 2, 1), // flowsettemp
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_HC, FL_(wwPumpStatus), 3, 1), // pumpstatus
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_HC, FL_(activated), 4, 1), // activated
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_HC, FL_(mixerSetTime), 5, 1), // valvesettime
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_HC, FL_(flowTempVf), 6, 1), // flowtempvf
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_HC, FL_(flowtempoffset), 7, 1), // flowtempoffset
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_DHW, FL_(flowTempHc), 0, 1), // flowtemphc
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_DHW, FL_(valveStatus), 1, 1), // valvestatus
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_DHW, FL_(flowSetTemp), 2, 1), // flowsettemp
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_DHW, FL_(wwPumpStatus), 3, 1), // pumpstatus
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_DHW, FL_(activated), 4, 1), // activated
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_DHW, FL_(mixerSetTime), 5, 1), // valvesettime
|
||||
REGISTER_MAPPING(dt::MIXER, TAG_TYPE_DHW, FL_(flowtempoffset), 6, 1), // flowtempoffset
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collectorTemp), 0, 1), // collectortemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylBottomTemp), 1, 1), // cylbottomtemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump), 2, 1), // solarpump
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(pumpWorkTime), 3, 2), // pumpworktime
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylMaxTemp), 5, 1), // cylmaxtemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collectorShutdown), 6, 1), // collectorshutdown
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylHeated), 7, 1), // cylheated
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpMod), 8, 1), // solarpumpmod
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(pumpMinMod), 9, 1), // pumpminmod
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpTurnonDiff), 10, 1), // turnondiff
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpTurnoffDiff), 11, 1), // turnoffdiff
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPower), 12, 1), // solarpower
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(energyLastHour), 13, 2), // energylasthour
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(maxFlow), 15, 1), // maxflow
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarIsEnabled), 16, 1), // solarenabled
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylMiddleTemp), 17, 1), // cylmiddletemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(retHeatAssist), 18, 1), // retheatassist
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(m1Valve), 19, 1), // heatassistvalve
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector2Temp), 20, 1), // collector2temp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(m1Power), 21, 1), // heatassistpower
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2), 22, 1), // solarpump2
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2Mod), 23, 1), // solarpump2mod
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cyl2BottomTemp), 24, 1), // cyl2bottomtemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatExchangerTemp), 25, 1), // heatexchangertemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylPumpMod), 26, 1), // cylpumpmod
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(valveStatus), 27, 1), // valvestatus
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(vs1Status), 28, 1), // vs1status
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collectorMaxTemp), 29, 1), // collectormaxtemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collectorMinTemp), 30, 1), // collectormintemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(energyToday), 31, 2), // energytoday
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(energyTotal), 33, 2), // energytotal
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(pump2WorkTime), 35, 2), // pump2worktime
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(m1WorkTime), 37, 2), // m1worktime
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatTransferSystem), 39, 1), // heattransfersystem
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(externalCyl), 40, 1), // externalcyl
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(thermalDisinfect), 41, 1), // thermaldisinfect
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatMetering), 42, 1), // heatmetering
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(activated), 43, 1), // activated
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpMode), 44, 1), // solarpumpmode
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpKick), 45, 1), // pumpkick
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(plainWaterMode), 46, 1), // plainwatermode
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(doubleMatchFlow), 47, 1), // doublematchflow
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(pump2MinMod), 48, 1), // pump2minmod
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2TurnonDiff), 49, 1), // turnondiff2
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2TurnoffDiff), 50, 1), // turnoffdiff2
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2Kick), 51, 1), // pump2kick
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(climateZone), 52, 1), // climatezone
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector1Area), 53, 1), // collector1area
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector1Type), 54, 1), // collector1type
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector2Area), 55, 1), // collector2area
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector2Type), 56, 1), // collector2type
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylPriority), 57, 1), // cylpriority
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatCntFlowTemp), 58, 1), // heatcntflowtemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatCntRetTemp), 59, 1), // heatcntrettemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatCnt), 60, 1), // heatcnt
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(swapFlowTemp), 61, 1), // swapflowtemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(swapRetTemp), 62, 1), // swaprettemp
|
||||
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DHW, FL_(wwMinTemp), 0, 1), // mintemp
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(airHumidity), 0, 1), // airhumidity
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(dewTemperature), 1, 1), // dewtemperature
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(curFlowTemp), 2, 1), // curflowtemp
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(retTemp), 3, 1), // rettemp
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(sysRetTemp), 4, 1), // sysrettemp
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpTa4), 5, 1), // hpta4
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpTr1), 6, 1), // hptr1
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpTr3), 7, 1), // hptr3
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpTr4), 8, 1), // hptr4
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpTr5), 9, 1), // hptr5
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpTr6), 10, 1), // hptr6
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpTl2), 11, 1), // hptl2
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpPl1), 12, 1), // hppl1
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpPh1), 13, 1), // hpph1
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatingPumpMod), 14, 1), // heatingpumpmod
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpCompSpd), 15, 1), // hpcompspd
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hybridStrategy), 16, 1), // hybridstrategy
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(lowNoiseMode), 17, 1), // lownoisemode
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(lowNoiseStart), 18, 1), // lownoisestart
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(lowNoiseStop), 19, 1), // lownoisestop
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hybridDHW), 20, 1), // hybriddhw
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(energyPriceGas), 21, 1), // energypricegas
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(energyPriceEl), 22, 1), // energypriceel
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(energyPricePV), 23, 1), // energyfeedpv
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(switchOverTemp), 24, 1), // switchovertemp
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(airPurgeMode), 25, 1), // airpurgemode
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatPumpOutput), 26, 1), // heatpumpoutput
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(coolingCircuit), 27, 1), // coolingcircuit
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(compStartMod), 28, 1), // compstartmod
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatDrainPan), 29, 1), // heatdrainpan
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 30, 1), // heatcable
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(nrgTotal), 31, 2), // nrgtotal
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat), 33, 2), // nrgheat
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterTotal), 35, 2), // metertotal
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterComp), 37, 2), // metercomp
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterEHeat), 39, 2), // metereheat
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterHeat), 41, 2), // meterheat
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DHW, FL_(nrgWw), 0, 2), // nrg
|
||||
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DHW, FL_(meterWw), 2, 2), // meter
|
||||
REGISTER_MAPPING(dt::SWITCH, TAG_TYPE_DEVICE_DATA, FL_(activated), 0, 1), // activated
|
||||
REGISTER_MAPPING(dt::SWITCH, TAG_TYPE_DEVICE_DATA, FL_(flowTempHc), 1, 1), // flowtemphc
|
||||
REGISTER_MAPPING(dt::SWITCH, TAG_TYPE_DEVICE_DATA, FL_(status), 2, 1), // status
|
||||
REGISTER_MAPPING(dt::CONTROLLER, TAG_TYPE_DEVICE_DATA, FL_(dateTime), 0, 13), // datetime
|
||||
REGISTER_MAPPING(dt::ALERT, TAG_TYPE_DEVICE_DATA, FL_(setFlowTemp), 0, 1), // setflowtemp
|
||||
REGISTER_MAPPING(dt::ALERT, TAG_TYPE_DEVICE_DATA, FL_(setBurnPow), 1, 1), // setburnpow
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(flowTempVf), 0, 1), // flowtempvf
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(input), 1, 1), // input
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(outPower), 2, 1), // outpow
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(setPower), 3, 1), // setpower
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(setPoint), 4, 1), // setpoint
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(minV), 5, 1), // minv
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(maxV), 6, 1), // maxv
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(minT), 7, 1), // mint
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(maxT), 8, 1), // maxt
|
||||
REGISTER_MAPPING(dt::EXTENSION, TAG_TYPE_DEVICE_DATA, FL_(mode), 9, 1), // mode
|
||||
REGISTER_MAPPING(dt::VENTILATION, TAG_TYPE_DEVICE_DATA, FL_(outFresh), 0, 1), // outfresh
|
||||
REGISTER_MAPPING(dt::VENTILATION, TAG_TYPE_DEVICE_DATA, FL_(inFresh), 1, 1), // infresh
|
||||
REGISTER_MAPPING(dt::VENTILATION, TAG_TYPE_DEVICE_DATA, FL_(outEx), 2, 1), // outexhaust
|
||||
REGISTER_MAPPING(dt::VENTILATION, TAG_TYPE_DEVICE_DATA, FL_(inEx), 3, 1), // inexhaust
|
||||
REGISTER_MAPPING(dt::VENTILATION, TAG_TYPE_DEVICE_DATA, FL_(ventInSpeed), 4, 1), // ventinspeed
|
||||
REGISTER_MAPPING(dt::VENTILATION, TAG_TYPE_DEVICE_DATA, FL_(ventOutSpeed), 5, 1), // ventoutspeed
|
||||
REGISTER_MAPPING(dt::VENTILATION, TAG_TYPE_DEVICE_DATA, FL_(ventMode), 6, 1), // ventmode
|
||||
REGISTER_MAPPING(dt::VENTILATION, TAG_TYPE_DEVICE_DATA, FL_(airquality), 7, 1), // airquality
|
||||
REGISTER_MAPPING(dt::VENTILATION, TAG_TYPE_DEVICE_DATA, FL_(airHumidity), 8, 1), // airhumidity
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
106
src/modbus_test.h
Normal file
106
src/modbus_test.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#if defined(EMSESP_STANDALONE) || defined(EMSESP_TEST)
|
||||
|
||||
#ifndef MODBUS_TEST_H
|
||||
#define MODBUS_TEST_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
// Mocked ModbusMessage for tests
|
||||
|
||||
enum Error : uint8_t {
|
||||
SUCCESS = 0x00,
|
||||
ILLEGAL_FUNCTION = 0x01,
|
||||
ILLEGAL_DATA_ADDRESS = 0x02,
|
||||
ILLEGAL_DATA_VALUE = 0x03,
|
||||
SERVER_DEVICE_FAILURE = 0x04,
|
||||
ACKNOWLEDGE = 0x05,
|
||||
SERVER_DEVICE_BUSY = 0x06,
|
||||
NEGATIVE_ACKNOWLEDGE = 0x07,
|
||||
MEMORY_PARITY_ERROR = 0x08,
|
||||
GATEWAY_PATH_UNAVAIL = 0x0A,
|
||||
GATEWAY_TARGET_NO_RESP = 0x0B,
|
||||
TIMEOUT = 0xE0,
|
||||
INVALID_SERVER = 0xE1,
|
||||
CRC_ERROR = 0xE2, // only for Modbus-RTU
|
||||
FC_MISMATCH = 0xE3,
|
||||
SERVER_ID_MISMATCH = 0xE4,
|
||||
PACKET_LENGTH_ERROR = 0xE5,
|
||||
PARAMETER_COUNT_ERROR = 0xE6,
|
||||
PARAMETER_LIMIT_ERROR = 0xE7,
|
||||
REQUEST_QUEUE_FULL = 0xE8,
|
||||
ILLEGAL_IP_OR_PORT = 0xE9,
|
||||
IP_CONNECTION_FAILED = 0xEA,
|
||||
TCP_HEAD_MISMATCH = 0xEB,
|
||||
EMPTY_MESSAGE = 0xEC,
|
||||
ASCII_FRAME_ERR = 0xED,
|
||||
ASCII_CRC_ERR = 0xEE,
|
||||
ASCII_INVALID_CHAR = 0xEF,
|
||||
BROADCAST_ERROR = 0xF0,
|
||||
UNDEFINED_ERROR = 0xFF // otherwise uncovered communication error
|
||||
};
|
||||
|
||||
class ModbusMessage {
|
||||
public:
|
||||
ModbusMessage() {
|
||||
}
|
||||
|
||||
ModbusMessage(std::vector<uint8_t> data) {
|
||||
_data = data;
|
||||
}
|
||||
|
||||
void get(uint16_t index, uint8_t & value) const {
|
||||
value = _data[index];
|
||||
}
|
||||
|
||||
void get(uint16_t index, uint16_t & value) const {
|
||||
value = (_data[index] << 8) + _data[index + 1];
|
||||
}
|
||||
|
||||
void get(uint16_t index, std::vector<uint8_t> & data, uint8_t byte_count) const {
|
||||
for (auto i = 0; i < byte_count; i++)
|
||||
data.push_back(_data[i + index]);
|
||||
}
|
||||
|
||||
void add(uint8_t value) {
|
||||
_data.push_back(value);
|
||||
}
|
||||
|
||||
void add(uint16_t value) {
|
||||
_data.push_back(value >> 8);
|
||||
_data.push_back(value & 0xff);
|
||||
}
|
||||
|
||||
uint8_t getServerID() const {
|
||||
return _data[0];
|
||||
}
|
||||
|
||||
uint8_t getFunctionCode() const {
|
||||
return _data[1];
|
||||
}
|
||||
|
||||
Error getError() const {
|
||||
if (_data.size() > 2) {
|
||||
if (_data[1] & 0x80) {
|
||||
return static_cast<Error>(_data[2]);
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Error setError(uint8_t serverID, uint8_t functionCode, Error errorCode) {
|
||||
_data.reserve(3);
|
||||
_data.shrink_to_fit();
|
||||
_data.clear();
|
||||
add(serverID);
|
||||
add(static_cast<uint8_t>((functionCode | 0x80) & 0xFF));
|
||||
add(static_cast<uint8_t>(errorCode));
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -396,6 +396,11 @@ void System::reload_settings() {
|
||||
board_profile_ = settings.board_profile;
|
||||
telnet_enabled_ = settings.telnet_enabled;
|
||||
|
||||
modbus_enabled_ = settings.modbus_enabled;
|
||||
modbus_port_ = settings.modbus_port;
|
||||
modbus_max_clients_ = settings.modbus_max_clients;
|
||||
modbus_timeout_ = settings.modbus_timeout;
|
||||
|
||||
rx_gpio_ = settings.rx_gpio;
|
||||
tx_gpio_ = settings.tx_gpio;
|
||||
dallas_gpio_ = settings.dallas_gpio;
|
||||
|
||||
20
src/system.h
20
src/system.h
@@ -120,6 +120,22 @@ class System {
|
||||
return telnet_enabled_;
|
||||
}
|
||||
|
||||
bool modbus_enabled() {
|
||||
return modbus_enabled_;
|
||||
}
|
||||
|
||||
uint16_t modbus_port() {
|
||||
return modbus_port_;
|
||||
}
|
||||
|
||||
uint8_t modbus_max_clients() {
|
||||
return modbus_max_clients_;
|
||||
}
|
||||
|
||||
uint32_t modbus_timeout() {
|
||||
return modbus_timeout_;
|
||||
}
|
||||
|
||||
bool analog_enabled() {
|
||||
return analog_enabled_;
|
||||
}
|
||||
@@ -339,6 +355,10 @@ class System {
|
||||
uint8_t enum_format_;
|
||||
bool readonly_mode_;
|
||||
String version_;
|
||||
bool modbus_enabled_;
|
||||
uint16_t modbus_port_;
|
||||
uint8_t modbus_max_clients_;
|
||||
uint32_t modbus_timeout_;
|
||||
|
||||
// ethernet
|
||||
uint8_t phy_type_;
|
||||
|
||||
@@ -1759,6 +1759,215 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (command == "modbus") {
|
||||
shell.printfln("Testing Modbus...");
|
||||
|
||||
System::test_set_all_active(true);
|
||||
add_device(0x08, 172); // boiler: Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i
|
||||
|
||||
const auto & it = std::find_if(EMSESP::emsdevices.begin(), EMSESP::emsdevices.end(), [&](const std::unique_ptr<EMSdevice> & dev) {
|
||||
return dev && dev->device_id() == 0x08;
|
||||
});
|
||||
|
||||
if (it == EMSESP::emsdevices.end()) {
|
||||
EMSESP::logger().err("ERROR - can not find mocked heatpump device");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto & device = *it;
|
||||
|
||||
{
|
||||
auto test_int8 = [&](const std::unique_ptr<EMSdevice> & device, uint8_t tag, const std::string & shortname) {
|
||||
std::vector<uint16_t> modbus_regs(1);
|
||||
if (auto result = device->get_modbus_value(tag, shortname, modbus_regs)) {
|
||||
shell.printf("INT8 %s FAILED (ERROR %d)\n", shortname.c_str(), result);
|
||||
} else {
|
||||
shell.printf("INT8 %s: %d ", shortname.c_str(), (int8_t)modbus_regs[0]);
|
||||
if ((int8_t)modbus_regs[0] == (int8_t)EMS_VALUE_DEFAULT_INT8_DUMMY)
|
||||
shell.printfln("[OK]");
|
||||
else
|
||||
shell.printfln("[ERROR] - expected %d, got %d", (int8_t)EMS_VALUE_DEFAULT_INT8_DUMMY, (int8_t)modbus_regs[0]);
|
||||
}
|
||||
};
|
||||
|
||||
auto test_uint8 = [&](const std::unique_ptr<EMSdevice> & device, uint8_t tag, const std::string & shortname) {
|
||||
std::vector<uint16_t> modbus_regs(1);
|
||||
if (auto result = device->get_modbus_value(tag, shortname, modbus_regs)) {
|
||||
shell.printf("UINT8 %s FAILED (ERROR %d)\n", shortname.c_str(), result);
|
||||
} else {
|
||||
shell.printf("UINT8 %s: %d ", shortname.c_str(), (uint8_t)modbus_regs[0]);
|
||||
if ((uint8_t)modbus_regs[0] == (uint8_t)EMS_VALUE_DEFAULT_UINT8_DUMMY)
|
||||
shell.printfln("[OK]");
|
||||
else
|
||||
shell.printfln("[ERROR] - expected %d, got %d", (uint8_t)EMS_VALUE_DEFAULT_UINT8_DUMMY, (uint8_t)modbus_regs[0]);
|
||||
}
|
||||
};
|
||||
|
||||
auto test_int16 = [&](const std::unique_ptr<EMSdevice> & device, uint8_t tag, const std::string & shortname) {
|
||||
std::vector<uint16_t> modbus_regs(1);
|
||||
if (auto result = device->get_modbus_value(tag, shortname, modbus_regs)) {
|
||||
shell.printf("INT16 %s FAILED (ERROR %d)\n", shortname.c_str(), result);
|
||||
} else {
|
||||
shell.printf("INT16 %s: %d ", shortname.c_str(), (int16_t)modbus_regs[0]);
|
||||
if ((int16_t)modbus_regs[0] == (int16_t)EMS_VALUE_DEFAULT_INT16_DUMMY)
|
||||
shell.printfln("[OK]");
|
||||
else
|
||||
shell.printfln("[ERROR] - expected %d, got %d", (int16_t)EMS_VALUE_DEFAULT_INT16_DUMMY, (int16_t)modbus_regs[0]);
|
||||
}
|
||||
};
|
||||
|
||||
auto test_uint16 = [&](const std::unique_ptr<EMSdevice> & device, uint8_t tag, const std::string & shortname) {
|
||||
std::vector<uint16_t> modbus_regs(1);
|
||||
if (auto result = device->get_modbus_value(tag, shortname, modbus_regs)) {
|
||||
shell.printf("UINT16 %s FAILED (ERROR %d)\n", shortname.c_str(), result);
|
||||
} else {
|
||||
shell.printf("UINT16 %s: %d ", shortname.c_str(), (uint16_t)modbus_regs[0]);
|
||||
if ((uint16_t)modbus_regs[0] == (uint16_t)EMS_VALUE_DEFAULT_UINT16_DUMMY)
|
||||
shell.printfln("[OK]");
|
||||
else
|
||||
shell.printfln("[ERROR] - expected %d, got %d", (uint16_t)EMS_VALUE_DEFAULT_UINT16_DUMMY, (uint16_t)modbus_regs[0]);
|
||||
}
|
||||
};
|
||||
|
||||
auto test_uint24 = [&](const std::unique_ptr<EMSdevice> & device, uint8_t tag, const std::string & shortname) {
|
||||
std::vector<uint16_t> modbus_regs(2);
|
||||
if (auto result = device->get_modbus_value(tag, shortname, modbus_regs)) {
|
||||
shell.printf("UINT24 %s FAILED (ERROR %d)\n", shortname.c_str(), result);
|
||||
} else {
|
||||
uint32_t value = ((uint32_t)modbus_regs[0] << 16) | (uint32_t)modbus_regs[1];
|
||||
shell.printf("UINT24 %s: %d ", shortname.c_str(), value);
|
||||
if (value == (uint32_t)EMS_VALUE_DEFAULT_UINT24_DUMMY)
|
||||
shell.printfln("[OK]");
|
||||
else
|
||||
shell.printfln("[ERROR] - expected %d, got %d", (uint32_t)EMS_VALUE_DEFAULT_UINT24_DUMMY, value);
|
||||
}
|
||||
};
|
||||
|
||||
/* there seem to be no uint32 entities to run this test on.
|
||||
auto test_uint32 = [&](const std::unique_ptr<EMSdevice> & device, uint8_t tag, const std::string & shortname) {
|
||||
std::vector<uint16_t> modbus_regs(2);
|
||||
if (auto result = device->get_modbus_value(tag, shortname, modbus_regs)) {
|
||||
shell.printf("UINT32 %s FAILED (ERROR %d)\n", shortname.c_str(), result);
|
||||
} else {
|
||||
uint32_t value = ((uint32_t)modbus_regs[0] << 16) | (uint32_t)modbus_regs[1];
|
||||
shell.printf("UINT32 %s: %d ", shortname.c_str(), value);
|
||||
if (value == (uint32_t)EMS_VALUE_DEFAULT_UINT32_DUMMY)
|
||||
shell.printfln("[OK]");
|
||||
else
|
||||
shell.printfln("[ERROR] - expected %d, got %d", (uint32_t)EMS_VALUE_DEFAULT_UINT32_DUMMY, value);
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
auto test_bool = [&](const std::unique_ptr<EMSdevice> & device, uint8_t tag, const std::string & shortname) {
|
||||
std::vector<uint16_t> modbus_regs(1);
|
||||
if (auto result = device->get_modbus_value(tag, shortname, modbus_regs)) {
|
||||
shell.printf("BOOL %s FAILED (ERROR %d)\n", shortname.c_str(), result);
|
||||
} else {
|
||||
shell.printf("BOOL %s: %d ", shortname.c_str(), (uint8_t)modbus_regs[0]);
|
||||
if ((uint8_t)modbus_regs[0] == (uint8_t)EMS_VALUE_DEFAULT_BOOL_DUMMY)
|
||||
shell.printfln("[OK]");
|
||||
else
|
||||
shell.printfln("[ERROR] - expected %d, got %d", (uint8_t)EMS_VALUE_DEFAULT_BOOL_DUMMY, (uint8_t)modbus_regs[0]);
|
||||
}
|
||||
};
|
||||
|
||||
auto test_enum = [&](const std::unique_ptr<EMSdevice> & device, uint8_t tag, const std::string & shortname) {
|
||||
std::vector<uint16_t> modbus_regs(1);
|
||||
if (auto result = device->get_modbus_value(tag, shortname, modbus_regs)) {
|
||||
shell.printf("ENUM %s FAILED (ERROR %d)\n", shortname.c_str(), result);
|
||||
} else {
|
||||
shell.printf("ENUM %s: %d ", shortname.c_str(), (uint8_t)modbus_regs[0]);
|
||||
if ((uint8_t)modbus_regs[0] == (uint8_t)EMS_VALUE_DEFAULT_ENUM_DUMMY)
|
||||
shell.printfln("[OK]");
|
||||
else
|
||||
shell.printfln("[ERROR] - expected %d, got %d", (uint8_t)EMS_VALUE_DEFAULT_ENUM_DUMMY, (uint8_t)modbus_regs[0]);
|
||||
}
|
||||
};
|
||||
|
||||
shell.println();
|
||||
shell.printfln("Testing device->get_modbus_value():");
|
||||
test_int8(device, DeviceValueTAG::TAG_DEVICE_DATA, "mintempsilent");
|
||||
test_uint8(device, DeviceValueTAG::TAG_DEVICE_DATA, "selflowtemp");
|
||||
test_int16(device, DeviceValueTAG::TAG_DEVICE_DATA, "outdoortemp");
|
||||
test_uint16(device, DeviceValueTAG::TAG_DEVICE_DATA, "rettemp");
|
||||
// test_uint32(device, DeviceValueTAG::TAG_DEVICE_DATA, "heatstarts"); // apparently there are no uint32 entities?
|
||||
test_uint24(device, DeviceValueTAG::TAG_DEVICE_DATA, "heatstarts");
|
||||
test_bool(device, DeviceValueTAG::TAG_DEVICE_DATA, "heatingactivated");
|
||||
test_enum(device, DeviceValueTAG::TAG_DEVICE_DATA, "pumpmode");
|
||||
}
|
||||
|
||||
// modbus_value_to_json
|
||||
{
|
||||
shell.println();
|
||||
shell.printfln("Testing device->modbus_value_to_json():");
|
||||
|
||||
std::vector<uint8_t> modbus_bytes(2);
|
||||
JsonDocument input;
|
||||
JsonObject inputObject = input.to<JsonObject>();
|
||||
modbus_bytes[0] = 0;
|
||||
modbus_bytes[1] = EMS_VALUE_DEFAULT_UINT8_DUMMY;
|
||||
device->modbus_value_to_json(DeviceValueTAG::TAG_DEVICE_DATA, "selflowtemp", modbus_bytes, inputObject);
|
||||
|
||||
std::string jsonString;
|
||||
serializeJson(inputObject, jsonString);
|
||||
shell.printf("UINT8 %s: %s (%d) ", "selflowtemp", jsonString.c_str(), inputObject["value"].as<int>());
|
||||
|
||||
if (inputObject["value"] == (uint8_t)EMS_VALUE_DEFAULT_UINT8_DUMMY)
|
||||
shell.println("[OK]");
|
||||
else
|
||||
shell.println("[ERROR]");
|
||||
}
|
||||
|
||||
// handleRead
|
||||
{
|
||||
shell.println();
|
||||
shell.printfln("Testing modbus->handleRead():");
|
||||
|
||||
uint16_t reg = Modbus::REGISTER_BLOCK_SIZE * DeviceValueTAG::TAG_DEVICE_DATA + 209; // mintempsilent is tag 2 (TAG_DEVICE_DATA), offset 209
|
||||
|
||||
ModbusMessage request({device->device_type(), 0x03, static_cast<unsigned char>(reg >> 8), static_cast<unsigned char>(reg & 0xff), 0, 1});
|
||||
auto response = EMSESP::modbus_->handleRead(request);
|
||||
|
||||
if (response.getError() == SUCCESS) {
|
||||
shell.print("mintempsilent MODBUS response:");
|
||||
for (const auto & d : response._data) {
|
||||
shell.printf(" %d", d);
|
||||
}
|
||||
if (response._data.size() == 5 && response._data[3] == 0 && response._data[4] == (uint8_t)EMS_VALUE_DEFAULT_INT8_DUMMY) {
|
||||
shell.printf(" [OK]");
|
||||
} else {
|
||||
shell.printf(" [ERROR - invalid response]");
|
||||
}
|
||||
shell.println();
|
||||
} else {
|
||||
shell.printf("mintempsilent [MODBUS ERROR %d]\n", response.getError());
|
||||
}
|
||||
}
|
||||
|
||||
// handleWrite
|
||||
{
|
||||
shell.println();
|
||||
shell.printfln("Testing modbus->handleWrite():");
|
||||
|
||||
uint16_t reg = Modbus::REGISTER_BLOCK_SIZE * DeviceValueTAG::TAG_DEVICE_DATA + 4; // selflowtemp is tag 2 (TAG_DEVICE_DATA), offset 4
|
||||
ModbusMessage request({device->device_type(), 0x06, static_cast<unsigned char>(reg >> 8), static_cast<unsigned char>(reg & 0xff), 0, 1, 2, 0, 45});
|
||||
auto response = EMSESP::modbus_->handleWrite(request);
|
||||
|
||||
if (response.getError() == SUCCESS) {
|
||||
shell.print("selflowtemp MODBUS response:");
|
||||
for (const auto & d : response._data) {
|
||||
shell.printf(" %d", d);
|
||||
}
|
||||
shell.println(" [OK]");
|
||||
} else {
|
||||
shell.printf("selflowtemp [MODBUS ERROR %d]\n", response.getError());
|
||||
}
|
||||
}
|
||||
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (command == "poll2") {
|
||||
shell.printfln("Testing Tx Sending last message on queue...");
|
||||
|
||||
|
||||
@@ -77,6 +77,10 @@ void WebSettings::read(WebSettings & settings, JsonObject root) {
|
||||
root["eth_clock_mode"] = settings.eth_clock_mode;
|
||||
String platform = EMSESP_PLATFORM;
|
||||
root["platform"] = (platform == "ESP32" && EMSESP::system_.PSram()) ? "ESP32R" : platform;
|
||||
root["modbus_enabled"] = settings.modbus_enabled;
|
||||
root["modbus_port"] = settings.modbus_port;
|
||||
root["modbus_max_clients"] = settings.modbus_max_clients;
|
||||
root["modbus_timeout"] = settings.modbus_timeout;
|
||||
}
|
||||
|
||||
// call on initialization and also when settings are updated via web or console
|
||||
@@ -272,6 +276,22 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
settings.low_clock = root["low_clock"];
|
||||
check_flag(prev, settings.low_clock, ChangeFlags::RESTART);
|
||||
|
||||
prev = settings.modbus_enabled;
|
||||
settings.modbus_enabled = root["modbus_enabled"] | EMSESP_DEFAULT_MODBUS_ENABLED;
|
||||
check_flag(prev, settings.modbus_enabled, ChangeFlags::RESTART);
|
||||
|
||||
prev = settings.modbus_port;
|
||||
settings.modbus_port = root["modbus_port"] | EMSESP_DEFAULT_MODBUS_PORT;
|
||||
check_flag(prev, settings.modbus_port, ChangeFlags::RESTART);
|
||||
|
||||
prev = settings.modbus_max_clients;
|
||||
settings.modbus_max_clients = root["modbus_max_clients"] | EMSESP_DEFAULT_MODBUS_MAX_CLIENTS;
|
||||
check_flag(prev, settings.modbus_max_clients, ChangeFlags::RESTART);
|
||||
|
||||
prev = settings.modbus_timeout;
|
||||
settings.modbus_timeout = root["modbus_timeout"] | EMSESP_DEFAULT_MODBUS_TIMEOUT;
|
||||
check_flag(prev, settings.modbus_timeout, ChangeFlags::RESTART);
|
||||
|
||||
//
|
||||
// these may need mqtt restart to rebuild HA discovery topics
|
||||
//
|
||||
|
||||
@@ -68,6 +68,10 @@ class WebSettings {
|
||||
uint8_t weblog_buffer;
|
||||
bool weblog_compact;
|
||||
bool fahrenheit;
|
||||
bool modbus_enabled;
|
||||
uint16_t modbus_port;
|
||||
uint8_t modbus_max_clients;
|
||||
uint32_t modbus_timeout;
|
||||
|
||||
uint8_t phy_type;
|
||||
int8_t eth_power; // -1 means disabled
|
||||
|
||||
Reference in New Issue
Block a user