ArduinoJson can't use degree symbol

Trying to setup a device for Home Assistant over mqtt.
No matter how I try, I can't get the degree symbol to be included in the message. I have tried as in the code below, as ASCHII, but it will just not work. It will just show up as a ? symbol both in serial monitor and in HA.

Seems to be an issue with ArduinoJson

Any ideas?


   char buffer[1024];
   JsonDocument doc;
  
    doc["name"] = "poe_boardtemp";
    doc["unique_id"] = "poe_boardtemp";
    doc["device_class"] = "temperature";
    doc["state_topic"] = "poe/boardtemp/state";
    doc["unit_of_measurement"] = "°C";
    doc["value_template"] = "{{ value | float | round(2) }}";
    doc["device"]["identifiers"][0] = "poe001";

    n = serializeJson(doc, buffer);

    client.publish(discoveryTopic.c_str(), buffer, n);
    Serial.print("Discoverytopic sent: ");
    Serial.print(discoveryTopic);
    Serial.print(", buffer: ");
    Serial.print(buffer);
    Serial.print(", n: ");
    Serial.println(n);

A codepage thing... the value might be different for your display, but something like this...

void setup() {
  Serial.begin(115200);
  Serial.print(char(176));
  Serial.print("\xB0"); // hex for 176
  Serial.write(176);
}
void loop() {}

LCDs might use:

  lcd.write(223);
  lcd.print((char)223);
  lcd.print(0xDF)

TFT/OLED probably another value... 247?

Thanks, but the problem is in the Json string, not in the serial print.

I am sending message over mqtt, serialized Json. The serial print is just a printout of the Json message being sent, and will not generate the degree sign.

Replace the string symbol with the hex/dec/oct value.

I also tried that, but it still does not work.

I tried:
unit_of_measurement"] = String(char(176)+"C";

Did you mean some other way?

Maybe this...

... or send a place-holder (like ^ or * or ~) and change it at the other end to a degree symbol.

Worked as expected for me.

const char tempC[] = "37°C";
Serial.println(tempC);
JsonDocument doc;
doc["temp"] = tempC;

uint8_t buf[100];
size_t len = serializeJson(doc, buf);
log_buf_i(buf, len); // available with ESP32 at least

HTTPClient http;
if (http.begin("http://httpbin.org/anything")) {
  http.addHeader("Content-Type", "application/json");
  Serial.printf("status %d\n", http.POST(buf, len));
  Serial.println(http.getString());
}

Serial Monitor

37°C

First, does the Serial Monitor print the symbol? Yes.

0x7b, 0x22, 0x74, 0x65, 0x6d, 0x70, 0x22, 0x3a, 0x22, 0x33, 0x37, 0xc2, 0xb0, 0x43, 0x22, 0x7d, // {"temp":"37..C"}

See the 0xc2, 0xb0? That the UTF-8 encoding of U+00B0, the degree symbol. At the end there is "37..C": instead of that symbol is two dots. One for each of those two octets, which by themselves, have no character to display. (A few different possibilities for exactly why, but not that important).

Sending the JSON to an echo service at httpbin.org, the raw "data" has \u00b0, which is the expected JSON encoding. (Note that the Content-Length of what was sent is 16, which is the number of hex octets above. There are 24 characters between the quotes. 4 are the double-quote-escaping backslashes, so there are four more characters. The response itself is JSON, so it is replacing the two UTF-8 octets sent with the six octets of the \u encoding.)

status 200
{
  "args": {}, 
  "data": "{\"temp\":\"37\u00b0C\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept-Encoding": "identity;q=1,chunked;q=0.1,*;q=0", 
    "Content-Length": "16", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "ESP32HTTPClient", 
    "X-Amzn-Trace-Id": "Root=1-6603c664-596b67e1450b36e906c3258c"
  }, 
  "json": {
    "temp": "37\u00b0C"
  }, 
  "method": "POST", 
  "origin": "172.8.222.85", 
  "url": "http://httpbin.org/anything"
}

which is also present in the resulting parsed "json".

If you put the symbol at the very top of the file

// 37°C

and dump the bytes, do you get the c2 b0?

$ hexdump -C degree.ino | head -n 1
00000000  2f 2f 20 33 37 c2 b0 43  0a 23 69 6e 63 6c 75 64  |// 37..C.#includ|

Is your editor saving in UTF-8?

Thanks guys!

This did not work:
doc["unit_of_measurement"] = "\xB0 C"; //"°C"

This did the trick:
doc["unit_of_measurement"] = "\u00b0C"; //"°C"