arduino json on the serial stream - arduino

Im using the BLuno arduino,
Its connecting fine to my iOS phone, sending and receiving messages.
Now I want to use arduino json to parse messages from my phone,
The serial connection receives data fine, but Im doing something wrong taking the stream to parse with the json library...
I get the error:
deserializeJson() failed: InvalidInput
The code:
#include <ArduinoJson.h>
StaticJsonDocument<400> doc;
void setup() {
Serial.begin(115200);
}
void loop()
{
if (Serial.available() > 0)
{
String s = Serial.readStringUntil("#"); // Until CR (Carriage Return)
s.replace("#", "");
Serial.println(s);
DeserializationError error = deserializeJson(doc, s);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return;
}
int value = doc["value"];
Serial.println(Serial.println(value));
IS
deserializeJson(doc, s);
correct?, I try to send different values, from the phone:
I just need to parse a key value pair, but none of the following ways worked:
{'a':'b'}
or
"{"a":"b"}"
or
{\"a\":\"b\"}
Where is my problem please?
how to format the {"a":"b"}
so the serial likes it for parsing?

There is nothing wrong with your code and ArduinoJson method, the
{'a':'b'} "{"a":"b"}" {\"a\":\"b\"}
is not a valid JSON object nor a serialised string representation of a JSON object.
If you JSON consists of multiple objects, the correct format should be:
[{"a": "b"},{"a": "b"},{"a": "b"}]
and with the serialised string representation should be like this:
"[{\"a\": \"b\"},{\"a\": \"b\"},{\"a\": \"b\"}]"
It is always a good idea to utilise one of those online JSON Validator to valid your JSON object during your development.
Update
Looks like that you had updated your question, based on your update, there are two problems in your code:
if the JSON object is {"a":"b"}, then there is no doc["value"] in the deserialised data, it should be doc["a"] to access the value "b".
the doc["a"] will not be int as in your int value = doc["value"], doc["value"] return a pointer to a char.
Here will be the code that produce the correct value.
void loop() {
char s[] = "{\"a\":\"b\"}";
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, s);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return;
}
const char* value = doc["a"];
Serial.println(value);
while(1) {};
}

Related

Thingsboard Arduino Client Library issues

So I've been working on modifying the thingsboard arduino library to support device provisioning. I've duplicated/renamed/modified a handful of functions in the library to support pointing to the correct topics, and added the supporting code in my main application to make use of them. However, I am now getting a compiler error in a section of the library code I did not touch. I'm hoping someone can point out what I goofed up, as it appears like it should be a fairly simple fix if I can find it.
This is the bit of code giving me the error-
inline Telemetry(const char *key, T val)
:m_type(TYPE_INT), m_key(key), m_value() { m_value.integer = val; }
Here is the error -
In file included from src\main.cpp:12:0:
.pio\libdeps\win\ThingsBoard\src/ThingsBoard.h: In instantiation of 'Telemetry::Telemetry(const char*, T) [with T = String; <template-parameter-1-2> = ArduinoJson6172_91::enable_if<false, void>]':
src\main.cpp:514:33: required from here
.pio\libdeps\win\ThingsBoard\src/ThingsBoard.h:46:64: error: cannot convert 'String' to 'int' in assignment
:m_type(TYPE_INT), m_key(key), m_value() { m_value.integer = val; }
Here's the bulk of what I added to my main code to handle device registration.
RPC_Response processDeviceRegistration(const RPC_Data &data)
{
Serial.println("Received the device registration response");
if(data["status"]=="SUCCESS"){
String credential = data["credentialsValue"];
EEPROM.write(10, sizeof(credential));
EEPROM.writeString(20, (String)credential);
dr.DR_Unsubscribe();
return RPC_Response("registration response", true);
}
else{
Serial.println("Device registration failed");
return RPC_Response("registration response", false);
}
}
const size_t callbacks_size = 2;
RPC_Callback callbacks[callbacks_size] = {
{ "device_registration", processDeviceRegistration }
};
void reinitialize()
{
if (!dr.RPC_Subscribe(callbacks, 1)) {
Serial.println("Failed to subscribe for RPC");
return;
}
dr.loop();
String IMEI = modem.getIMEI();
const int data_items = 3;
Telemetry data[data_items] = {
Telemetry("deviceName", IMEI),
Telemetry("provisionDeviceKey", provision_device_key),
Telemetry("provisionDeviceSecret", provision_device_secret),
};
if (!dr.sendDR(data, data_items)){
Serial.println("Device registration send failed");
}
If it would be helpful, I can fork and upload the full library code and post a link to my github.
----- Edit -----
Upon further investigation, it appears the template for the Telemetry class is detecting the IMEI variable as an integer rather than a string and trying to convert it for some reason. I have no idea why, or how to fix it. Any suggestions would be greatly appreciated.
Well then, helps if I take a few minutes to actually understand the code I didn't write that is giving me grief. There was no handler in the Telemetry constructor for a character array or string type variable. Added that and now everything is working :)
Full Telemetry constructor below -
inline Telemetry()
:m_type(TYPE_NONE), m_key(NULL), m_value() { }
// Constructs telemetry record from integer value.
// EnableIf trick is required to overcome ambiguous float/integer conversion
template<
typename T,
typename = ARDUINOJSON_NAMESPACE::enable_if<ARDUINOJSON_NAMESPACE::is_integral<T>::value>
>
inline Telemetry(const char *key, T val)
:m_type(TYPE_INT), m_key(key), m_value() { m_value.integer = val; }
// Constructs telemetry record from boolean value.
inline Telemetry(const char *key, bool val)
:m_type(TYPE_BOOL), m_key(key), m_value() { m_value.boolean = val; }
// Constructs telemetry record from float value.
inline Telemetry(const char *key, float val)
:m_type(TYPE_REAL), m_key(key), m_value() { m_value.real = val; }
// Constructs telemetry record from string value.
inline Telemetry(const char *key, const char *val)
:m_type(TYPE_STR), m_key(key), m_value() { m_value.str = val; }
// Constructs telemetry record from string value.
inline Telemetry(const char *key, char *val)
:m_type(TYPE_STR), m_key(key), m_value() { m_value.str = val; }

Receiving a string through UART in STM32F4

I've written this code to receive a series of char variable through USART6 and have them stored in a string. But the problem is first received value is just a junk! Any help would be appreciated in advance.
while(1)
{
//memset(RxBuffer, 0, sizeof(RxBuffer));
i = 0;
requestRead(&dt, 1);
RxBuffer[i++] = dt;
while (i < 11)
{
requestRead(&dt, 1);
RxBuffer[i++] = dt;
HAL_Delay(5);
}
function prototype
static void requestRead(char *buffer, uint16_t length)
{
while (HAL_UART_Receive_IT(&huart6, buffer, length) != HAL_OK)
HAL_Delay(10);
}
First of all, the HAL_Delay seems to be redundant. Is there any particular reason for it?
The HAL_UART_Receive_IT function is used for non-blocking mode. What you have written seems to be more like blocking mode, which uses the HAL_UART_Receive function.
Also, I belive you need something like this:
Somewhere in the main:
// global variables
volatile uint8_t Rx_byte;
volatile uint8_t Rx_data[10];
volatile uint8_t Rx_indx = 0;
HAL_UART_Receive_IT(&huart1, &Rx_byte, 1);
And then the callback function:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == UART1) { // Current UART
Rx_data[Rx_indx++] = Rx_byte; // Add data to Rx_Buffer
}
HAL_UART_Receive_IT(&huart1, &Rx_byte, 1);
}
The idea is to receive always only one byte and save it into an array. Then somewhere check the number of received bytes or some pattern check, etc and then process the received frame.
On the other side, if the number of bytes is always same, you can change the "HAL_UART_Receive_IT" function and set the correct bytes count.

Arduino read JSON data

Can you help me to solve a problem? I'm using an Arduino. How can I read and split JSON data in Arduino? The value is {$sen1:$sen2}.
Example
How to deserialize a JSON document with ArduinoJson.
Source code
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2017
// MIT License
#include <ArduinoJson.h>
void setup() {
// Initialize serial port
Serial.begin(9600);
while (!Serial) continue;
// Memory pool for JSON object tree.
//
// Inside the brackets, 200 is the size of the pool in bytes.
// Don't forget to change this value to match your JSON document.
// Use arduinojson.org/assistant to compute the capacity.
StaticJsonBuffer<200> jsonBuffer;
// StaticJsonBuffer allocates memory on the stack, it can be
// replaced by DynamicJsonBuffer which allocates in the heap.
//
// DynamicJsonBuffer jsonBuffer(200);
// JSON input string.
//
// It's better to use a char[] as shown here.
// If you use a const char* or a String, ArduinoJson will
// have to make a copy of the input in the JsonBuffer.
char json[] =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
// Root of the object tree.
//
// It's a reference to the JsonObject, the actual bytes are inside the
// JsonBuffer with all the other nodes of the object tree.
// Memory is freed when jsonBuffer goes out of scope.
JsonObject& root = jsonBuffer.parseObject(json);
// Test if parsing succeeds.
if (!root.success()) {
Serial.println("parseObject() failed");
return;
}
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do root["time"].as<long>();
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
// Print values.
Serial.println(sensor);
Serial.println(time);
Serial.println(latitude, 6);
Serial.println(longitude, 6);
}
void loop() {
// not used in this example
}

How to convert string to int in processing

I am trying to make a hands free mouse using Arduino IDE and Processing IDE. I don't have a problem with serializing the code and converting to string, but when I try and convert the serial string into int the int goes to 0. I have tried to trim it and used integer.parseInt but it still gives me the error:
NumberFormatException : For input String:"".
Here is my code:
import processing.serial.*;
import java.awt.event.KeyListener;
import java.awt.Robot;
Serial myPort; // Create object from Serial class
Robot robot;
String val; // Data received from the serial port
boolean valtrue;
int xy = 0;
int x=0;
void setup()
{
String portName = Serial.list()[3];
myPort = new Serial(this, portName, 9600);
myPort.bufferUntil('.');
try {
robot = new Robot();
}
catch (Exception e) {
e.printStackTrace();
}
}
void draw() {
//reading serial port until \n
String sensorValue = myPort.readStringUntil('\n');
if (sensorValue != null) {
int value = Integer.parseInt(sensorValue.trim());
println(value);
}
}
If anyone is able to help, please answer.
Processing has an int() function that you can use instead of Integer.parseInt(). Behind the scenes the int() function is calling the Integer.parseInt() function, but it's shorter. Up to you.
But your error says it all: you're passing an empty String value "" into the parseInt() function. An empty String value can't be turned into a number, so you get the exception.
You're going to have to track down why your String value is empty, but that's what's causing this particular error. I will point out that the draw() function is called 60 times per second, and you're trying to read from your port every single time, so maybe you're reading faster than you're writing?

Qextserialport breaks my xml

I am trying to rewrite in c++ an application written in python.
All it does is to open a serial port and read some xml. In python i was using pyserial to read the xml and beautifulsoup to retrieve information. The output was like this.
<file><property>xx32</property></file>
Now i am using qextserialport to read from the serial port and the xml i get is something like this.
<
fil
e>
<prope
rty>xx32
</prop
erty>
</
file>
My problem is that i cant parse an xml like this. I get errors.
EDIT:
Qextserialport reads data from the serial port in set of bytes that are not fixed.
So how do i concatenate my xml into one string? I get an xml string every 4-5 seconds from the serial port.
here is my code
this->port = new QextSerialPort(com_port,QextSerialPort::EventDriven);
port->setBaudRate(BAUD57600);
port->setFlowControl(FLOW_OFF);
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(STOP_1);
port->setTimeout(0);
if (port->open(QIODevice::ReadOnly) == true)
{
//qDebug()<< "hello";
connect(port,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
}
and the function that actually reads from the serial port
void CurrentCost::onReadyRead()
{
QByteArray bytes;
bytes = port->readAll();
//qDebug() << "bytes read:" << bytes.size();
//qDebug() << "bytes:" << bytes;
ui->textBrowser->append(bytes);
}
I mean something like this:
class CurrentCost...{
private:
QByteArray xmlData;
private slots:
void onReadyRead();
};
void CurrentCost::onReadyRead()
{
xmlData.append(port->readAll());
if(xmlData.endsWith(/*what your port sending then xml is over&*/))
{
ui->textBrowser->append(xmlData);
xmlData.clear();
}
}

Resources