In my recent project, I have to parse incoming JSON data in Arduino and I successfully did it. But it is only for one constant data string.
For example, if my incoming JSON string like:
{"TPS":"0.40","MAP":"0.95","LOAD":"14"}
And Arduino code for parsing this data is below:
#include <LiquidCrystal.h>
#include <ArduinoJson.h>
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
String response = "";
bool begin = false;
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
}
void loop() {
StaticJsonBuffer<100> jsonBuffer;
while(Serial.available() || !begin) {
char in = Serial.read();
if (in == '{') {
begin = true;
}
if(begin) {
response += (in);
}
if(in == '}') {
break;
}
delay(1);
}
JsonObject& root = jsonBuffer.parseObject(response);
String TPS = root["TPS"];
String MAP = root["MAP"];
String LOAD = root["LOAD"];
lcd.setCursor(0, 0);
lcd.print(TPS);
lcd.setCursor(8, 0);
lcd.print(MAP);
lcd.setCursor(0, 1);
lcd.print(LOAD);
}
Then the output looks like:
TPS : 0.40
MAP : 0.95
LOAD : 14
That's fine, but when the incoming JSON string changes, what should I do?
Suppose the incoming JSON string looks like:
{"LOAD":"2.40","RPM":"4200","INJECTION_TIME":"4.87"}
Because I have to handle both incoming JSON strings, I can't replace any part like:
String LOAD = root["LOAD"];
String RPM = root["RPM"];
String INJECTION_TIME = root["INJECTION_TIME"];
lcd.setCursor(0, 0);
lcd.print(LOAD);
lcd.setCursor(8, 0);
lcd.print(RPM);
lcd.setCursor(0, 1);
lcd.print(INJECTION_TIME);
Instead of
String TPS = root["TPS"];
String MAP = root["MAP"];
String LOAD = root["LOAD"];
lcd.setCursor(0, 0);
lcd.print(TPS);
lcd.setCursor(8, 0);
lcd.print(MAP);
lcd.setCursor(0, 1);
lcd.print(LOAD);
2 Answers 2
If you want to read 3 values of a object that you don't know the names of the key, you can use an iterator as shown in the ArduinoJson library's docs.
And as already mentioned in the comments, you can also replace all the serial reading code with just Serial
passed into the jsonBuffer.parseObject
function.
#include <LiquidCrystal.h>
#include <ArduinoJson.h>
const struct LCDPos {
uint8_t x;
uint8_t y;
} lcd_pos[] = {
{0, 0},
{8, 0},
{0, 1},
};
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
void setup() {
Serial.begin(115200);
lcd.begin(16, 2);
}
void loop() {
StaticJsonBuffer<100> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(Serial);
if (root == JsonObject::invalid())
return;
uint8_t i = 0;
for (JsonObject::iterator it = root.begin(); it != root.end() && i<(sizeof(lcd_pos)/sizeof(lcd_pos[0])); ++it, i++)
{
lcd.setCursor(lcd_pos[i].x, lcd_pos[i].y);
lcd.print(it->value.asString());
}
}
You will need to make sure, that the values are sent in the order that you want them on your LCD.
EDIT:
I don't have an LCD screen, so I didn't test the code with an LCD, but the code that just dumps the parsed data back to serial works.
//#include <LiquidCrystal.h>
#include <ArduinoJson.h>
const struct LCDPos {
uint8_t x;
uint8_t y;
} lcd_pos[] = {
{0, 0},
{8, 0},
{0, 1},
};
//LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
void setup() {
Serial.begin(115200);
//lcd.begin(16, 2);
}
void loop() {
StaticJsonBuffer<100> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(Serial);
if (root == JsonObject::invalid())
return;
Serial.println("JSON received");
uint8_t i = 0;
for (JsonObject::iterator it = root.begin(); it != root.end() && i < (sizeof(lcd_pos) / sizeof(lcd_pos[0])); ++it, i++)
{
//lcd.setCursor(lcd_pos[i].x, lcd_pos[i].y);
//lcd.print(it->value.asString());
Serial.print(i);
Serial.print(':');
Serial.print(lcd_pos[i].x);
Serial.print(',');
Serial.print(lcd_pos[i].y);
Serial.print(' ');
Serial.println(it->value.asString());
}
Serial.println();
}
If I send
{"TPS":"0.40","MAP":"0.95","LOAD":"14"}{"LOAD":"2.40","RPM":"4200","INJECTION_TIME":"4.87"}
over the serial, it returns
JSON received
0:0,0 0.40
1:8,0 0.95
2:0,1 14
JSON received
0:0,0 2.40
1:8,0 4200
2:0,1 4.87
Finally got the solution. I'm using the extra key name.
So, my modified serial data string now looks like:
{"ActionOne":"ONE","TPS":"0.40","MAP":"0.95","LOAD":"14"}
{"ActionTwo":"TWO","LOAD":"2.40","RPM":"4200","INJECTION_TIME":"4.87"}
and so now using containsKey()
function, just check which one is coming. If ActionOne
is coming then according to that serial data we got. And If ActionTwo
is coming then according to that serial data we got.
#include <LiquidCrystal.h>
#include <ArduinoJson.h>
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
String response = "";
bool begin = false, finished;
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
}
void loop() {
StaticJsonBuffer<100> jsonBuffer;
while (finished == false)
{
if (Serial.available())
{
const char in = Serial.read();
if (in == '{')
{
response = ""; // Blank the string
begin = true;
}
if (begin)
{
response += (in); // Only write if within the {}
}
if (in == '}')
{
begin = false; // Prevent any chars between } and { leaking through.
break;
}
}
delay(1);
}
JsonObject& root = jsonBuffer.parseObject(response);
const char* ActionOne = root["ActionOne"];
const char* ActionTwo = root["ActionTwo"];
if(root.containsKey("ActionOne"))
{
float TPS = root["TPS"];
float MAP = root["MAP"];
int LOAD = root["LOAD"];
lcd.setCursor(0, 0);
lcd.print(TPS);
lcd.setCursor(8, 0);
lcd.print(MAP);
lcd.setCursor(0, 1);
lcd.print(LOAD);
}
if(root.containsKey("ActionTwo"))
{
float LOAD = root["LOAD"];
int RPM = root["RPM"];
float INJECTION_TIME = root["INJECTION_TIME"];
lcd.setCursor(0, 0);
lcd.print(LOAD);
lcd.setCursor(8, 0);
lcd.print(RPM);
lcd.setCursor(0, 1);
lcd.print(INJECTION_TIME);
}
}
jsonBuffer.parse(Serial)
?jsonBuffer.parse(Serial)
?