Deserialize JSON received from Serial port

I wrote a Windows executable in C++ that reads sensor data from HWiNFO64, serializes the data and then sends it through a serial connection.

This is what I'm sending through the serial port

{"CPU [#0]: Intel Core i7-13700K: DTS":{"CPU Package":[{"Average":44.841623},{"Current":34.000000},{"Maximum":47.000000},{"Minimum":32.000000},{"Unit":"°C"}]}}

The data is being received correctly as shown in my photo, I'm just not why sure it didn't stop printing at the last character.
I tried with Serial.readStringUntil('\0') and with Serial.readString(), same result.
https://i.imgur.com/Vi9M1Nk.jpg

tft.setCursor(0, 0);
tft.print(Serial.readStringUntil('\0'));

I am not able to deserialize the data with ArduinoJson and I don't know what I'm doing wrong.
deserializeJson() always fails, so I left that part of the code commented out.

#define ARDUINOJSON_ENABLE_PROGMEM 0

#include <ArduinoJson.h>
#include <TFT_eSPI.h>

TFT_eSPI tft = TFT_eSPI();
const uint8_t rotation = 3;
const uint8_t textFont = 1;

uint16_t pollingRate = 1500;

String error;
void setup()
{
	tft.begin();
	tft.fillScreen(TFT_BLACK);
	tft.setRotation(rotation);
	tft.setTextFont(textFont);

	Serial.begin(576000);
	while (!Serial.available())
	{
		String message = F("COM port not connected");
		tft.setCursor(0, 36);
		tft.setTextColor(TFT_WHITE, TFT_RED);
		tft.print(message);
		error = message;
		delay(pollingRate);
	}
}

void loop()
{
	unsigned long epoch = millis();

	if (!Serial.available())
	{
		String message = F("COM port connection lost");
		if (error != message)
		{
			tft.fillScreen(TFT_RED);
			tft.setCursor(0, 36);
			tft.setTextColor(TFT_WHITE, TFT_RED);
			tft.print(message);
		}
		error = message;
		delay(pollingRate);
		return;
	}
/*
	const size_t capacity = JSON_ARRAY_SIZE(18) + 18*JSON_OBJECT_SIZE(6);
	DynamicJsonDocument json(capacity);

	DeserializationError jsonError = deserializeJson(json, Serial.readStringUntil('\0'));
	if (jsonError)
	{
		String message = F("Deserialize JSON failed");
		if (error != message)
		{
			tft.fillScreen(TFT_RED);
			tft.setCursor(CenterX(message), CenterY());
			tft.setTextColor(TFT_WHITE, TFT_RED);
			tft.print(message);
		}
		error = message;
		delay(pollingRate);
		return;
	}
*/
	if (!error.isEmpty())
	{
		error.clear();
		tft.fillScreen(TFT_BLACK);
	}
////////////////////////////////////////////
	tft.setCursor(0, 0);
	tft.setTextColor(TFT_WHITE, TFT_BLACK);
	tft.print(Serial.readStringUntil('\0'));
////////////////////////////////////////////
	unsigned long passed = (millis() - epoch);
	if (passed < pollingRate)
	{
		delay(pollingRate - passed);
	}
}

On the Windows side, this is how I am sending my serialized json string

Serial.WriteSerialPort(&json[0]);

I tried adding a terminating character, same result.

json += '\0';
Serial.WriteSerialPort(&json[0]);

I am doing something wrong with either the Serial port or the ArduinoJson library.
I'd be really thankful if someone could point out what I'm doing wrong.

On the windows side send the json

Serial.WriteSerialPort(const_cast<char*>(json.c_str()));

and then

Serial.WriteSerialPort('\n');

then on the arduino side I would suggest to study Serial Input Basics to handle this and use the '\n' as the end marker you are waiting for.

as a first start, to ensure the communication is working fine, write a simple arduino program echoing each character as it comes through

Compilation error:
sketch.ino:75:10: error: 'class String' has no member named 'clear'
reason.clear();
line 75 reason.clear();

Are you using arduino Uno, Mega, ........?

I'm using an ESP32.

I tried the example written by @Robin2 for receiving data with start and end markers and it only works correctly when I comment out the newData variable.

const byte numChars = 255;
char receivedChars[numChars];
//bool newData = false;

void loop()
{
	unsigned long epoch = millis();

	static bool receiving = false;
	static byte receivedCharIndex = 0;
	char startMarker = '<';
	char endMarker = '>';
	char receivedChar;
	while (Serial.available() > 0/* && !newData*/)
	{
		receivedChar = Serial.read();
		if (receiving)
		{
			if (receivedChar != endMarker)
			{
				receivedChars[receivedCharIndex] = receivedChar;
				receivedCharIndex++;
				if (receivedCharIndex >= numChars)
				{
					receivedCharIndex = numChars - 1;
				}
			}
			else
			{
				receivedChars[receivedCharIndex] = '\0';
				receiving = false;
				receivedCharIndex = 0;
				//newData = true;
			}
		}
		else if (receivedChar == startMarker)
		{
			receiving = true;
		}
	}
	//if (newData)
	//{
		tft.setCursor(0, 0);
		tft.setTextColor(TFT_WHITE, TFT_BLACK);
		tft.print(receivedChars);
		//newData = false;
	//}

	unsigned long passed = (millis() - epoch);
	if (passed < pollingRate)
	{
		delay(pollingRate - passed);
	}
}

Windows:

string json = "<{";
//json += ...;
json += "}>";
Serial.WriteSerialPort(&json[0]);

I always get the correct output with the newData variable commented out.
https://i.imgur.com/CsvaGJf.png

But if I use the code without commenting out the newData variable, sometimes I get overlapped messages.
https://i.imgur.com/QeRDOg5.png

I created a web server on the ESP32 to help me visualize what is being received on the Serial port.

I am using my board's built-in CH340C to receive the data.

My goal is to send about 30000 characters of data from the computer to the ESP32 every 1500ms.

I made some small modifications to the sketch in the original post, but if .clear() doesn't compile use any other method to empty the String.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.