diff --git a/src/core/emsdevice.cpp b/src/core/emsdevice.cpp index 36992c1e8..d3318c401 100644 --- a/src/core/emsdevice.cpp +++ b/src/core/emsdevice.cpp @@ -857,7 +857,7 @@ void EMSdevice::publish_value(void * value_p) const { break; case DeviceValueType::STRING: if (Helpers::hasValue((char *)(value_p))) { - strlcpy(payload, (char *)(value_p), sizeof(payload)); + Helpers::render_string(payload, (char *)(value_p), sizeof(payload)); } break; default: @@ -967,7 +967,8 @@ void EMSdevice::generate_values_web(JsonObject output, const bool is_dashboard) // handle TEXT strings else if (dv.type == DeviceValueType::STRING) { - obj["v"] = (char *)(dv.value_p); + char s[55]; + obj["v"] = Helpers::render_string(s, (char *)(dv.value_p), sizeof(s)); } // handle ENUMs @@ -1079,7 +1080,8 @@ void EMSdevice::generate_values_web_customization(JsonArray output) { // handle TEXT strings else if (dv.type == DeviceValueType::STRING) { - obj["v"] = (char *)(dv.value_p); + char s[55]; + obj["v"] = Helpers::render_string(s, (char *)(dv.value_p), sizeof(s)); } // handle ENUMs @@ -1648,7 +1650,8 @@ void EMSdevice::get_value_json(JsonObject json, DeviceValue & dv) { case DeviceValueType::STRING: if (Helpers::hasValue((char *)(dv.value_p))) { - json[value] = (char *)(dv.value_p); + char s[55]; + json[value] = Helpers::render_string(s, (char *)(dv.value_p), sizeof(s)); } json[type] = ("string"); break; @@ -1782,7 +1785,8 @@ bool EMSdevice::generate_values(JsonObject output, const int8_t tag_filter, cons // handle TEXT strings else if (dv.type == DeviceValueType::STRING) { - json[name] = (char *)(dv.value_p); + char s[55]; + json[name] = Helpers::render_string(s, (char *)(dv.value_p), sizeof(s)); } // handle ENUMs diff --git a/src/core/helpers.cpp b/src/core/helpers.cpp index 911ca5876..7e5ccd6c0 100644 --- a/src/core/helpers.cpp +++ b/src/core/helpers.cpp @@ -381,6 +381,91 @@ char * Helpers::render_value(char * result, const uint32_t value, const int8_t f return result; } +// convert special Latin1 characters to UTF8 +char * Helpers::render_string(char * result, const char * c, const uint8_t len) { + char * p = result; + while (*c != '\0' && (p - result < len)) { + switch (*c) { + case 0xC4: // Ä + *p = 0xC3; + *(++p) = 0x84; + break; + case 0xD6: // Ö + *p = 0xC3; + *(++p) = 0x96; + break; + case 0xDC: // Ü + *p = 0xC3; + *(++p) = 0x9C; + break; + case 0xDF: // ß + *p = 0xC3; + *(++p) = 0x9F; + break; + case 0xE4: // ä + *p = 0xC3; + *(++p) = 0xA4; + break; + case 0xF6: // ö + *p = 0xC3; + *(++p) = 0xB6; + break; + case 0xFC: // ü + *p = 0xC3; + *(++p) = 0xBC; + break; + default: + *p = (*c & 0x80) ? '?' : *c; + break; + } + c++; + p++; + } + *p = '\0'; // terminat result + return result; +} + +char * Helpers::utf8tolatin1(char * result, const char * c, const uint8_t len) { + char * p = result; + while (*c != '\0' && (p - result < len)) { + if (*c == 0xC3) { + c++; + switch (*c) { + case 0x84: // Ä + *p = 0xC4; + break; + case 0x96: // Ö + *p = 0xD6; + break; + case 0x9C: // Ü + *p = 0xDC; + break; + case 0x9F: // ß + *p = 0xDF; + break; + case 0xA4: // ä + *p = 0xE4; + break; + case 0xB6: // ö + *p = 0xF6; + break; + case 0xBC: // ü + *p = 0xFC; + break; + default: + break; + } + } else if (*c > 127) { + *p = '?'; + } else { + *p = *c; + } + c++; + p++; + } + *p = '\0'; // terminat result + return result; +} // creates string of hex values from an array of bytes std::string Helpers::data_to_hex(const uint8_t * data, const uint8_t length) { if (length == 0) { diff --git a/src/core/helpers.h b/src/core/helpers.h index 7a9dc92dd..1ec344c47 100644 --- a/src/core/helpers.h +++ b/src/core/helpers.h @@ -34,6 +34,8 @@ class Helpers { static char * render_value(char * result, const int16_t value, const int8_t format, const uint8_t fahrenheit = 0); static char * render_value(char * result, const int32_t value, const int8_t format, const uint8_t fahrenheit = 0); static char * render_boolean(char * result, const bool value, const bool dashboard = false); + static char * render_string(char * result, const char * s, const uint8_t len); + static char * utf8tolatin1(char * result, const char * s, const uint8_t len); static char * hextoa(char * result, const uint8_t value); static char * hextoa(char * result, const uint16_t value); diff --git a/src/devices/connect.cpp b/src/devices/connect.cpp index 721a5d71f..508088a84 100644 --- a/src/devices/connect.cpp +++ b/src/devices/connect.cpp @@ -145,8 +145,7 @@ void Connect::process_roomThermostatName(std::shared_ptr telegra has_update(telegram, rc->icon_, 0); for (uint8_t i = telegram->offset; i < telegram->message_length + telegram->offset && i < 100; i++) { if ((i > 1) && (i % 2) == 0) { - // replace ISOLatin1 characters with questionmark - rc->name_[(i - 2) / 2] = telegram->message_data[i - telegram->offset] & 0x80 ? '?' : telegram->message_data[i - telegram->offset]; + rc->name_[(i - 2) / 2] = telegram->message_data[i - telegram->offset]; } } rc->name_[50] = '\0'; // make sure name is terminated @@ -229,14 +228,12 @@ bool Connect::set_name(const char * value, const int8_t id) { if (rc == nullptr || value == nullptr || strlen(value) > 50) { return false; } - uint8_t len = strlen(value) * 2 + 2; + Helpers::utf8tolatin1(rc->name_, value, sizeof(rc->name_)); + uint8_t len = strlen(rc->name_) * 2 + 2; uint8_t data[len]; - for (uint8_t i = 0; i < strlen(value) + 1; i++) { // include terminating '\0' + for (uint8_t i = 0; i < strlen(rc->name_) + 1; i++) { // include terminating '\0' data[2 * i] = 0; - data[2 * i + 1] = value[i]; - if (value[i] & 0x80) { // accept only ascii names - return false; - } + data[2 * i + 1] = rc->name_[i]; } uint8_t ofs = 0; while (len > 0) {