Yes - I have found nanopb to be an incredibly convenient option for my app, where there are a highly-variable combination of “required” and “optional” fields. The encoding is really efficient and it is trivial to program.
Some people find it easier to understand if they see an example, so here’s a snippet from one of my projects:
{
// Allocate space on the stack to store the message data
teletype_Telecast message = teletype_Telecast_init_zero;
// Create a pb stream within that buffer
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
// Set fields marked as required in .proto
message.DeviceType = teletype_Telecast_deviceType_BGEIGIE_NANO;
strncpy(message.DeviceID, DeviceID, sizeof(message.DeviceID));
strncpy(message.CapturedAt, DateTimeISO, sizeof(message.CapturedAt));
message.Unit = teletype_Telecast_unit_CPM;
message.Value = RadiationCPM;
// Set fields marked as optional in .proto
if (GPSValid) {
message.Latitude = GPSLatitude;
message.Longitude = GPSLongitude;
message.Altitude = GPSAltitude;
message.has_Latitude =
message.has_Longitude =
message.has_Altitude = true;
}
// Encode and transmit the message
status = pb_encode(&stream, teletype_Telecast_fields, &message);
if (!status)
DEBUG_PRINTF("pb_encode: %s\n", PB_GET_ERROR(&stream));
else
send_to_ttn(buffer, stream.bytes_written);
}