How do I get the whole message in a string? I'm planning on sending it over HTTP.
I thought of using the "pb_read" but it's giving me trouble with the buffers.
Without seeing your program it is impossible to make sense of your question.
What is a Nanopb?
It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.
...R
Nanopb is a C implementation of the Protocol Buffers library from google.
I'm compiling this example from the library.
As you can see it has the code for coding and decoding the function, but say I print the whole function over serial.
This guy has pretty much my problem, but I didn't understand how he did it.
What is "Protocol Buffers" ?
If you really want to get help you need to provide as much information as you can.
...R
From their website: "Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data." Protocol Buffers.
If you open the second link on my last reply, it sums up the problem I'm having.
I realise that I'm not the most observant of people, but I am struggling to see the connection with Arduino?
oyarzopablo:
From their website: "Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data." Protocol Buffers.
I don't understand that and I have a sneaking suspicion that you don't either.
How about a simple explanation that your Granny would understand?
...R
This is a little late to the comment thread, I came across this thread when researching nanopb on the Arduino. For anyone else going forward looking to solve similar problems, here ya go.
Nanopb is a great way of taking a bunch of data and wrapping it all together into a structure that you can send out over whichever protocol you desire and then unpack it in a variety of different programming languages/environments.
My current project takes a bunch of different data streams and bundles it all together and sends it out over Ethernet using MQTT. It also receives commands over the same pipe. Another client on the MQTT host analyzes the data and directs the arduino to do what it's supposed to do.
Here are a couple of things that I found helpful:
http://zakovinko.com/57-how-to-speak-from-arduino-to-python-and-back.html
As for getting it to encode and decode you are going to have to use a structure. The order is important of when you do things (e.g. submessages have to be handled first when decoding and last when encoding). The example here shows how to encode/decode for various data structures.
for the example below, here are the pertinent globals and declarations:
// Header Files
#include "PubSubClient.h" // MQTT library
#include "pb_decode.h" // nanopb decode library
#include "pb_encode.h" // nanopb encode library
#include "RCB_Protocol_Buffer.pb.h" // nanopb generated protobuf library
// Create various objects
RCB_Protocol_Buffer_ClientMessage_MinerStatus minerStatus[2 * shelfNumber];
and from void setup():
// initialize protobuf structures
for (uint8_t i = 0; i < 2 * shelfNumber; i++) {
minerStatus[i] = RCB_Protocol_Buffer_ClientMessage_MinerStatus_init_zero;
minerStatus[i].Error = true; // set up so that the program assumes nothing installed
minerStatus[i].id = i;
}
Here is an example of encoding a message to be sent:
void mqtt_send_rsr() {
uint8_t sMsg[MSG_SIZE];
_RCB_Protocol_Buffer_ClientMessage msg = RCB_Protocol_Buffer_ClientMessage_init_zero;
pb_ostream_t buffer = pb_ostream_from_buffer(sMsg, MSG_SIZE);
Conv32 bigmac;
bigmac.bytes[0] = mac[5];
bigmac.bytes[1] = mac[4];
bigmac.bytes[2] = mac[3];
bigmac.bytes[3] = mac[2];
msg.mac = bigmac.value;
msg.BoardTemp = temp.readCelsius();
msg.InletTemp = temp.readInternal();
msg.Flow = digitalRead(flowSwitchPin);
msg.PowerAvail = digitalRead(powerAvailPin);
msg.IPRFlag = ipFlag;
msg.time = getTimestamp();
msg.miners.funcs.encode = &mqtt_encode_callback;
//Encode the message
if (!pb_encode(&buffer, RCB_Protocol_Buffer_ClientMessage_fields, &msg)) {
Serial.println(F("Encoding failed"));
Serial.println(PB_GET_ERROR(&buffer));
}
/*
// check message content
Serial.println(buffer.bytes_written);
for (uint8_t i = 0; i < buffer.bytes_written; i++) {
Serial.print(sMsg[i],HEX);
Serial.print(F(":"));
}
Serial.println();
*/
ethClient.disableInterrupt();
// publish the buffer
if(!client.publish("rcb", sMsg)) {
Serial.println(F("Publishing Failed"));
tReconnect.restart();
tGenerateRSR.enableDelayed(5000);
}
else {
ipFlag = false;
}
ethClient.enableInterrupt(); // restore interrupt
}
/*
* Callback function to read in the individual miner status
*/
bool mqtt_encode_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
for (uint8_t i = 0; i < 2 * shelfNumber; i++)
if (!pb_encode_submessage(stream, RCB_Protocol_Buffer_ClientMessage_MinerStatus_fields, &minerStatus[i]))
return false;
return true;
}
Here is an example of decoding a message:
int mqtt_callback(char* topic, byte* payload, unsigned int length){
mqtt_ping_reset(); // reset the ping timer
if (length > MQTT_MAX_PACKET_SIZE) {
payload = {'\0'}; // if garbage, flush the buffer
return 0;
}
RCB_Protocol_Buffer_BrokerMessage msg = RCB_Protocol_Buffer_BrokerMessage_init_default;
pb_istream_t stream = pb_istream_from_buffer(payload, length);
msg.miners.funcs.decode = &mqtt_decode_callback;
//msg.miners.funcs.arg = *minerTemp;
if (!pb_decode(&stream, RCB_Protocol_Buffer_BrokerMessage_fields, &msg)) // This has to follow the submessages
return 1;
Conv32 bigmac;
// enendianess is set properly here don't mess it up
bigmac.bytes[0] = mac[5];
bigmac.bytes[1] = mac[4];
bigmac.bytes[2] = mac[3];
bigmac.bytes[3] = mac[2];
if (msg.mac != bigmac.value)
return 0;
parseCommand(msg); // execute the control function
return 0;
}
bool mqtt_decode_callback(pb_istream_t *stream, const pb_field_t *field, void * const **arg) {
RCB_Protocol_Buffer_BrokerMessage_MinerCmdMessage minermsg = RCB_Protocol_Buffer_BrokerMessage_MinerCmdMessage_init_default;
if (!pb_decode(stream, RCB_Protocol_Buffer_BrokerMessage_MinerCmdMessage_fields, &minermsg))
return false;
bitWrite(minerIPReport, minermsg.id, minermsg.IPReport);
bitWrite(minerReset, minermsg.id, minermsg.Reset);
bitWrite(minerPower, minermsg.id, minermsg.Power);
return true;
}
I forgot this link was increadibly helpful in figuring out how to get everythign to work, it is from the nanopb wiki
https://jpa.kapsi.fi/nanopb/docs/concepts.html#id10
adn a correction to the use of structure above, it is a stream.