{"id":2784,"date":"2020-05-18T08:38:00","date_gmt":"2020-05-18T06:38:00","guid":{"rendered":"https:\/\/www.basyskom.de\/?p=2784"},"modified":"2020-05-29T11:01:50","modified_gmt":"2020-05-29T09:01:50","slug":"protobuf-for-iot","status":"publish","type":"post","link":"https:\/\/www.basyskom.de\/en\/protobuf-for-iot\/","title":{"rendered":"Protobuf for IoT: Sending cost-optimized into the cloud (Part 2 of 4)"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"2784\" class=\"elementor elementor-2784\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-f943174 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"f943174\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-82a7e9f\" data-id=\"82a7e9f\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-62b2559 elementor-widget elementor-widget-text-editor\" data-id=\"62b2559\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2 class=\"western\">Introduction<\/h2><p>IoT devices for industrial use are often deployed in places without an ethernet or WiFi connection and have to use a mobile broadband connection. To reduce traffic costs, it is required to keep the amount of data that has to be transmitted as low as possible.<\/p><p>Cloud providers also calculate in data blocks of a certain size for billing, so a small message size combined with batching can save money for the cloud side too.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-2c39800c elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"2c39800c\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-6cf64826\" data-id=\"6cf64826\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-146564c9\" data-id=\"146564c9\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-7573b567 elementor-view-default elementor-invisible elementor-widget elementor-widget-icon\" data-id=\"7573b567\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;swing&quot;}\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"hm hm-key\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-339dd06f\" data-id=\"339dd06f\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-2dee4d7 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"2dee4d7\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-23f7434\" data-id=\"23f7434\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-b48f037 elementor-widget elementor-widget-text-editor\" data-id=\"b48f037\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Protobuf<\/h2>\n<img decoding=\"async\" class=\"wp-image-2837\" src=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2020\/04\/protobuf_google_developer-300x228.png\" alt=\"Protobuf\" width=\"137\" height=\"104\" align=\"right\" data-wp-editing=\"1\" srcset=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2020\/04\/protobuf_google_developer-300x228.png 300w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2020\/04\/protobuf_google_developer-1024x778.png 1024w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2020\/04\/protobuf_google_developer-768x584.png 768w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2020\/04\/protobuf_google_developer-560x426.png 560w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2020\/04\/protobuf_google_developer.png 1400w\" sizes=\"(max-width: 137px) 100vw, 137px\" \/><a class=\"western\" href=\"https:\/\/developers.google.com\/protocol-buffers\" target=\"_blank\" rel=\"noopener\">Protobuf<\/a>\u00a0is a serialization method for structured data developed by Google which offers a compact binary wire format and built-in mechanisms which make it easy to remain forward and backward compatible when updating the messages.\n\nIt uses an interface description language to specify the structured data and the Protobuf compiler to generate code for serialization, deserialization and message handling for C++, Java, Python, Objective-C, C#, JavaScript, Ruby, Go, PHP and Dart.\n\nThe compact wire format and the compatibility related features make Protobuf very interesting for the usage in IoT systems. The wide range of supported languages enables the creation of a heterogeneous processing infrastructure for Protobuf encoded device messages.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-c5cdc2e elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"c5cdc2e\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c21ad31\" data-id=\"c21ad31\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-c43bcb8 elementor-widget elementor-widget-text-editor\" data-id=\"c43bcb8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Using Protobuf in an IoT example<\/h2><p>To show the workflow with Protobuf, let\u2018s define the Protobuf messages for an environment data sensor device in the current proto3 format. The device measures temperature, pressure, humidity and CO<sub>2<\/sub> level and generates events if certain threshold values are exceeded or if a sensor fails.<\/p><p>An important key to understanding why the messages have been designed like this is that there is no way to recognize the message type from the serialized data.\u00a0 We don&#8217;t want to send an identifier in addition to the serialized data, so there must be a single point of entry for all message types we are going to send.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4599883 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"4599883\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>syntax = &quot;proto3&quot;;\n\npackage iotexample;\n\nmessage EnvironmentData {\n  double temperature = 1;\n  double pressure = 2;\n  double humidity = 3;\n  double co2_level = 4;\n}\n\nenum ErrorLevel {\n  UNSPECIFIED = 0;\n  ERROR = 1;\n  WARNING = 2;\n  INFO = 3;\n}\n\nmessage Event {\n  int32 event_number = 1;\n  ErrorLevel error_level = 2;\n  string message = 3;\n}\n\nmessage TelemetryMessage {\n  uint64 timestamp = 1;\n  oneof payload {\n    EnvironmentData environment_data = 2;\n    Event event = 3;\n  }\n}\n\nmessage DeviceMessages {\n  repeated TelemetryMessage telemetry_messages = 1;\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-78274f2 elementor-widget elementor-widget-text-editor\" data-id=\"78274f2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>The first line defines that the following description is in the &#8220;proto3&#8221; syntax which is the most current version of the Protobuf interface description language.<\/p><p>The second line states that the messages defined below belong to the package &#8220;iotexample&#8221;. This is required to resolve messages imported from other files and will be used to create namespaces in the generated code.<\/p><p>The keyword <code>message<\/code> in the following line introduces a new message called <code>EnvironmentData<\/code> which has four data fields for storing environment sensor values. Each of the data fields has a type, a name and a field number. The name and the field number must be unique inside a message.<\/p><p>In proto3, all fields of a message are optional. If a field is not present in a serialized <code>message<\/code>, the value will be set to a <a class=\"western\" href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3#default\" target=\"_blank\" rel=\"noopener\">default value<\/a>\u00a0by the receiver except for fields with another message as type. Only the field number and the value are serialized, the mapping from field numbers to names is done by the receiver. This means that the length of the field names has no impact on the size of the serialized message.<\/p><p>The <code>enum<\/code> keyword in the next block defines an enumeration named <code>ErrorLevel<\/code> with four values. A proto3 enum must have 0 as constant for the first value due to the default initialization behavior explained before.<\/p><p>The following message is named <code>Event<\/code> and stores data to describe an event that has occurred on our IoT device. It uses the <code>ErrorLevel enum<\/code> as type for the second field to encode the severity of the event.<\/p><p>The message <code>TelemetryMessage<\/code> is the first step to having a single point of entry for all messages. It combines the two messages we have defined before with a timestamp field. The keyword <code>oneof<\/code> makes sure that only one of the fields enclosed in the curly braces has a value at any time. This is enforced by the generated message handling code which clears any previous set field if a member of the oneof is set.<\/p><p>The <code>DeviceMessages<\/code> message uses the <code>repeated<\/code> keyword to define an array of <code>TelemetryMessage<\/code> values.<\/p><p>To sum it all up, we now have the message <code>DeviceMessages<\/code> as our point of entry which can be used to create a batch of <code>TelemetryMessage<\/code> values which each contain a timestamp and an <code>Event<\/code> or <code>EnvironmentData<\/code> value.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-1bf8373 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"1bf8373\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c56e62e\" data-id=\"c56e62e\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-dfd0aa0 elementor-widget elementor-widget-text-editor\" data-id=\"dfd0aa0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2 class=\"western\">Important hint for field numbers<\/h2><p>The Protobuf encoding requires a\u00a0<a class=\"western\" href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3#assigning-field-numbers\" target=\"_blank\" rel=\"noopener\">different amount<\/a>\u00a0of bytes to encode field numbers depending on the number. The field numbers 1-15 can be encoded using one byte, the following numbers up to 2047 require two bytes. If your message contains fields that are not used too often, you should consider assigning them a field number above 15 to have some one byte field numbers available for any extensions with new fields that will be used frequently.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-e085f5b elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"e085f5b\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-6509edf\" data-id=\"6509edf\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6c4137d elementor-widget elementor-widget-text-editor\" data-id=\"6c4137d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Working with generated code<\/h2><p>The previously defined messages are saved to a file which is then used to generate code with protoc.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9142b90 elementor-widget elementor-widget-text-editor\" data-id=\"9142b90\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>C++<\/h3>\nC++ is our language of choice for the software on the IoT device due to low resource requirements, low level access to the underlying operating system and easy integration of the <a href=\"https:\/\/github.com\/Azure\/azure-iot-sdk-c\" target=\"_blank\" rel=\"noopener\">Azure IoT SDK<\/a>.\n\nThe following paragraph will show how to use the C++ code generated by protoc. The generated code makes use of the <a href=\"https:\/\/github.com\/protocolbuffers\/protobuf\/tree\/master\/src\" target=\"_blank\" rel=\"noopener\">Protobuf library<\/a>, so a C++ application using code generated by protoc must be linked against <code>libprotobuf<\/code>.\n\nProtoc is invoked as follows and generates the two files <code>environment_iot_messages.pb.cc<\/code> and <code>environment_iot_messages.pb.h<\/code>.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e92f6bc elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"e92f6bc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-solid'>protoc --cpp_out=generated environment_iot_messages.proto <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-34a70dc elementor-widget elementor-widget-text-editor\" data-id=\"34a70dc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tThese files are included into\u00a0a C++\u00a0application that\u00a0shows how to instantiate and\u00a0populate all messages,\u00a0serialization and deserialization as well as\u00a0dealing with <code>oneofs<\/code>.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-15d9028 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"15d9028\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>#include &lt;generated\/environment_iot_messages.pb.h&gt;\n\n#include &lt;QByteArray&gt;\n#include &lt;QDateTime&gt;\n#include &lt;QDebug&gt;\n\nint main()\n{\n    auto environmentData = new iotexample::EnvironmentData();\n    environmentData-&gt;set_humidity(75);\n    environmentData-&gt;set_pressure(1080);\n    environmentData-&gt;set_temperature(23);\n    environmentData-&gt;set_co2_level(415);\n\n    auto eventData = new iotexample::Event();\n    eventData-&gt;set_event_number(123);\n    eventData-&gt;set_message(std::string(&quot;My event message&quot;));\n    eventData-&gt;set_error_level(iotexample::ErrorLevel::ERROR);\n\n    iotexample::DeviceMessages message;\n    auto currentMessage = message.add_telemetry_messages();\n    currentMessage-&gt;set_timestamp(QDateTime::currentMSecsSinceEpoch());\n    currentMessage-&gt;set_allocated_environment_data(environmentData);\n\n    currentMessage = message.add_telemetry_messages();\n    currentMessage-&gt;set_timestamp(QDateTime::currentMSecsSinceEpoch());\n    currentMessage-&gt;set_allocated_event(eventData);\n\n    qDebug() &lt;&lt; &quot;Serialized size:&quot; &lt;&lt; message.ByteSizeLong() &lt;&lt; &quot;bytes&quot;;\n\n    QByteArray serializedMessage(message.ByteSizeLong(), Qt::Initialization::Uninitialized);\n    auto success = message.SerializeToArray(serializedMessage.data(), message.ByteSizeLong());\n\n    if (!success)\n        return 1;\n\n    iotexample::DeviceMessages deserializedMessage;\n    success = deserializedMessage.ParseFromArray(serializedMessage.constData(), serializedMessage.length());\n\n    if (!success)\n        return 2;\n\n    qDebug() &lt;&lt; &quot;Decoded message with &quot; &lt;&lt; deserializedMessage.telemetry_messages_size() &lt;&lt; &quot;values&quot;;\n\n    for (int i = 0; i &lt; deserializedMessage.telemetry_messages_size(); ++i) {\n        const auto &amp;current = deserializedMessage.telemetry_messages(i);\n        qDebug() &lt;&lt; &quot;Message&quot; &lt;&lt; i + 1;\n        qDebug() &lt;&lt; &quot;  Timestamp:&quot; &lt;&lt; QDateTime::fromMSecsSinceEpoch(current.timestamp()).toString(Qt::ISODate);\n        if (current.has_event()) {\n            qDebug() &lt;&lt; &quot;  Event number:&quot; &lt;&lt; current.event().event_number();\n            qDebug() &lt;&lt; &quot;  Event error level:&quot; &lt;&lt; current.event().error_level();\n            qDebug() &lt;&lt; &quot;  Event message:&quot; &lt;&lt; QString::fromStdString(current.event().message());\n        } else if (current.has_environment_data()) {\n            qDebug() &lt;&lt; &quot;  Temperature:&quot; &lt;&lt; current.environment_data().temperature();\n            qDebug() &lt;&lt; &quot;  Pressure:&quot; &lt;&lt; current.environment_data().pressure();\n            qDebug() &lt;&lt; &quot;  Humidity:&quot; &lt;&lt; current.environment_data().humidity();\n            qDebug() &lt;&lt; &quot;  CO2:&quot; &lt;&lt; current.environment_data().co2_level();\n        } else {\n            qDebug() &lt;&lt; &quot;  Empty TelemetryMessages&quot;;\n        }\n    }\n\n\n    return 0;\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3ba49bc elementor-widget elementor-widget-text-editor\" data-id=\"3ba49bc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tThe <code>has_event()<\/code> and <code>has_environment_data()<\/code> functions have been added by the protobuf compiler because these two fields have another message as type.\n\nThe output of this application shows a serialized data size of 80 bytes, all fields are deserialized as expected.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1d89039 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"1d89039\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-solid'>Serialized size: 80 bytes\nDecoded message with  2 values\nMessage 1\n  Timestamp: &quot;2020-04-28T11:04:21&quot;\n  Temperature: 23\n  Pressure: 1080\n  Humidity: 75\n  CO2: 415\nMessage 2\n  Timestamp: &quot;2020-04-28T11:04:21&quot;\n  Event number: 123\n  Event error level: 1\n  Event message: &quot;My event message&quot; <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0026113 elementor-widget elementor-widget-text-editor\" data-id=\"0026113\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFor an application running on the IoT device, the use of Protobuf would be finished after the call to <code>SerializeToArray()<\/code> and the serialized data created by this method call would be passed to the component that sends the data into the cloud.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-082b545 elementor-widget elementor-widget-text-editor\" data-id=\"082b545\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>JavaScript \/ Node.js<\/h3>\nNode.js is well supported on different cloud platforms which makes it a good choice for handling the incoming data from our IoT device, for example in an Azure Function App triggered by an IoT Hub.\n\nThe file <code>environment_iot_messages_pb.js<\/code> is generated by invoking protoc.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-455842e elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"455842e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-solid'>protoc --js_out=import_style=commonjs,binary:generated environment_iot_messages.proto <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-94c175b elementor-widget elementor-widget-text-editor\" data-id=\"94c175b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span>The new file is included into a Node.js application. This application requires the\u00a0<a class=\"western\" href=\"https:\/\/www.npmjs.com\/package\/google-protobuf\" target=\"_blank\" rel=\"noopener\">google-protobuf<\/a> module and performs the same steps as the C++ example from the previous section.<\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-507a8fe elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"507a8fe\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-javascript'>const messages = require(&#039;.\/generated\/environment_iot_messages_pb.js&#039;)\n\nlet environmentData = new proto.iotexample.EnvironmentData();\nenvironmentData.setHumidity(75);\nenvironmentData.setPressure(1080);\nenvironmentData.setTemperature(23);\nenvironmentData.setCo2Level(415);\n\nlet eventData = new proto.iotexample.Event();\neventData.setEventNumber(123);\neventData.setErrorLevel(proto.iotexample.ErrorLevel.ERROR);\neventData.setMessage(&#039;My event message&#039;);\n\nlet message = new proto.iotexample.DeviceMessages();\n\nlet telemetry = new proto.iotexample.TelemetryMessage();\ntelemetry.setTimestamp(Date.now());\ntelemetry.setEnvironmentData(environmentData);\nmessage.addTelemetryMessages(telemetry);\n\ntelemetry = new proto.iotexample.TelemetryMessage();\ntelemetry.setTimestamp(Date.now());\ntelemetry.setEvent(eventData);\nmessage.addTelemetryMessages(telemetry);\n\nconst serializedMessage = message.serializeBinary();\n\nconsole.log(`Serialized size: ${serializedMessage.length} bytes`);\n\nconst deserializedMessage = new proto.iotexample.DeviceMessages.deserializeBinary(serializedMessage);\n\nconsole.log(`Decoded message with ${deserializedMessage.getTelemetryMessagesList().length} values`);\n\nfor (let i = 0; i &lt; deserializedMessage.getTelemetryMessagesList().length; ++i) {\n    const current = deserializedMessage.getTelemetryMessagesList()[i];\n    console.log(`Message ${i + 1}`);\n    console.log(`  Timestamp: ${new Date(current.getTimestamp()).toISOString()}`)\n    if (current.hasEvent()) {\n        console.log(`  Event number: ${current.getEvent().getEventNumber()}`)\n        console.log(`  Event error level: ${current.getEvent().getErrorLevel()}`)\n        console.log(`  Event message: ${current.getEvent().getMessage()}`)\n    } else if (current.hasEnvironmentData()) {\n        console.log(`  Temperature: ${current.getEnvironmentData().getTemperature()}`)\n        console.log(`  Pressure: ${current.getEnvironmentData().getPressure()}`)\n        console.log(`  Humidity: ${current.getEnvironmentData().getHumidity()}`)\n        console.log(`  CO2: ${current.getEnvironmentData().getCo2Level()}`)\n    } else {\n        console.log(&#039;Empty TelemetryMessages&#039;)\n    }\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4fe9805 elementor-widget elementor-widget-text-editor\" data-id=\"4fe9805\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>The output is identical to the C++ example and there is not much difference in the complexity of the message handling.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-91ecd48 elementor-widget elementor-widget-text-editor\" data-id=\"91ecd48\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFor a message processor application running in the cloud, the use of Protobuf would start with calling <code>deserializeBinary()<\/code> on a serialized message that has been received from an IoT Device.\nThe JavaScript generated code also offers a <code>toObject()<\/code> method for all messages which returns the content of the message as a JavaScript object.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0c880e6 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"0c880e6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-json'>{\n  &quot;telemetryMessagesList&quot;: [\n    {\n      &quot;timestamp&quot;: 1588065035911,\n      &quot;environmentData&quot;: {\n        &quot;temperature&quot;: 23,\n        &quot;pressure&quot;: 1080,\n        &quot;humidity&quot;: 75,\n        &quot;co2Level&quot;: 415\n      }\n    },\n    {\n      &quot;timestamp&quot;: 1588065035911,\n      &quot;event&quot;: {\n        &quot;eventNumber&quot;: 123,\n        &quot;errorLevel&quot;: 1,\n        &quot;message&quot;: &quot;My event message&quot;\n      }\n    }\n  ]\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-7974fcc elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"7974fcc\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-254a862\" data-id=\"254a862\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6373fba elementor-widget elementor-widget-text-editor\" data-id=\"6373fba\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2 class=\"western\">Size comparison with JSON encoding<\/h2><p>JSON is a widespread format for storing and transmitting structured data in a human readable form.<\/p><p>Let\u2019s encode our example data in JSON to see the difference in data size<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-aab3163 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"aab3163\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-json'>[\n    {\n        &quot;timestamp&quot;: 1587988060797,\n        &quot;environment_data&quot;: {\n            &quot;temperature&quot;: 23,\n            &quot;pressure&quot;: 1080,\n            &quot;humidity&quot;: 75\n        }\n    },\n    {\n        &quot;timestamp&quot;: 1587988060797,\n        &quot;event&quot;: {\n            &quot;event_number&quot;: 123,\n            &quot;error_level&quot;: 1,\n            &quot;message&quot;: &quot;My event message&quot;\n        }\n    }\n ] <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0b31c21 elementor-widget elementor-widget-text-editor\" data-id=\"0b31c21\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>The property names have the highest impact on data size. As the property names must always be included, this is a static additional amount of bytes and choosing shorter names leads to a smaller encoded message size.<\/p><p>The influence of numeric values depends on the number of characters needed to encode that number. This could be better or worse than Protobuf, depending on the value.<\/p><p>If all unnecessary whitespaces are removed, the JSON encoded value is still 211 bytes in size, which is\u00a0<b>2.63x<\/b> the size of the Protobuf encoded data from our example.<\/p><p>Even if the property names are replaced by single letters and only single digit numbers are used, the JSON encoding is still <b>88 bytes<\/b> in size compared to the <b>80 bytes<\/b>\u00a0for Protobuf with real values.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-19aa9f7 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"19aa9f7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-json'>[\n  {\n    &quot;a&quot;: 1,\n    &quot;b&quot;: {\n      &quot;a&quot;: 1,\n      &quot;b&quot;: 1,\n      &quot;c&quot;: 1,\n      &quot;d&quot;: 1\n    }\n  },\n  {\n    &quot;a&quot;: 1,\n    &quot;c&quot;: {\n      &quot;a&quot;: 1,\n      &quot;b&quot;: 1,\n      &quot;c&quot;: &quot;My event message&quot;\n    }\n  }\n] <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-d0ce98f elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"d0ce98f\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-de39063\" data-id=\"de39063\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-f6803df elementor-widget elementor-widget-text-editor\" data-id=\"f6803df\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Protobuf message updates and how to keep them backward compatible<\/h2><p>Sooner or later, it may become necessary to extend one of the messages with additional fields or fields have become obsolete and will no longer be processed by the cloud. This would not be a problem if all devices always had the latest hardware revision with the newest firmware. But in real deployments, this won\u2018t always be the case and the cloud side must be able to deal with receiving different versions of the Protobuf message.<\/p><p>An important rule when changing Protobuf messages is not to reuse field numbers or names in a message for a different purpose.<\/p><p>As an example, let\u2018s assume that the next revision of our IoT device hardware replaces the CO<sub>2<\/sub> sensor by an ambient light sensor. If the <code>co2_level<\/code> field is just renamed to <code>ambientLight<\/code> and a sender still uses the old message, the sender&#8217;s assumption is that it is sending the <code>co2_level<\/code> value. The receiver which is using the new message assumes the field means <code>ambientLight<\/code> and writes a wrong value into the database.<\/p><p>To avoid situations like this, <code>ambientLight<\/code> should become a new field with a number that was not previously used.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d1b00c0 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"d1b00c0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>message EnvironmentData {\n  double temperature = 1;\n  double pressure = 2; \n  double humidity = 3;\n  double co2_level = 4;\n  double ambientLight = 5;\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-49f8b5f elementor-widget elementor-widget-text-editor\" data-id=\"49f8b5f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAs long as there are active devices with the old hardware and firmware, the\u00a0<code>co2_level<\/code>\u00a0field should be left in the message to keep supporting the old sensor by the cloud side system. The new devices don&#8217;t have to set the\u00a0<code>co2_level<\/code>\u00a0field and the receiver will automatically decode it as 0.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2788459 elementor-widget elementor-widget-text-editor\" data-id=\"2788459\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>Find out if a field has been set<\/h4><p>Except for fields with a message as type, Proto3 offers no direct way to find out if a value has been explicitly set or is default initialized. As a workaround, a field can be put in a <code>oneof<\/code> with exactly one member. The generated code will then contain a function to check if the value has been set.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-46bf03a elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"46bf03a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>message EnvironmentData {\n  double temperature = 1;\n  double pressure = 2; \n  double humidity = 3;\n  double co2_level = 4;\n  oneof ambient_light_oneof { double ambient_light = 5; }\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7418abc elementor-widget elementor-widget-text-editor\" data-id=\"7418abc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>It is <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3#backwards-compatibility-issues\" target=\"_blank\" rel=\"noopener\">safe<\/a> to move a single existing field into a new <code>oneof<\/code>, so in our example, the <code>co2_level<\/code> field could be moved into a new <code>oneof<\/code> to allow the receiver to determine if this is an old or a new device<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-465bf89 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"465bf89\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>message EnvironmentData {\n  double temperature = 1;\n  double pressure = 2; \n  double humidity = 3;\n  oneof co2_level_oneof { double co2_level = 4; }\n  oneof ambient_light_oneof { double ambient_light = 5; }\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-58e40eb elementor-widget elementor-widget-text-editor\" data-id=\"58e40eb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tThe generated C++ code contains a function to check which field of the <code>oneof<\/code> is set.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-169dfd5 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"169dfd5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>qDebug() &lt;&lt; &quot;  Temperature:&quot; &lt;&lt; current.environment_data().temperature();\nqDebug() &lt;&lt; &quot;  Pressure:&quot; &lt;&lt; current.environment_data().pressure();\nqDebug() &lt;&lt; &quot;  Humidity:&quot; &lt;&lt; current.environment_data().humidity();\nif (environmentData-&gt;co2_level_oneof_case() == iotexample::EnvironmentData::Co2LevelOneofCase::kCo2Level)\n    qDebug() &lt;&lt; &quot;  CO2:&quot; &lt;&lt; current.environment_data().co2_level();\nif (environmentData-&gt;ambient_light_oneof_case() == iotexample::EnvironmentData::AmbientLightOneofCase::kAmbientLight)\n    qDebug() &lt;&lt; &quot;  Ambient light:&quot; &lt;&lt; current.environment_data().co2_level(); <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f25ddf9 elementor-widget elementor-widget-text-editor\" data-id=\"f25ddf9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tThe generated JavaScript code has the same function but also adds a <code>hasXYZ()<\/code> function for each member of the <code>oneof<\/code>. The following example shows both ways of checking <code>oneof<\/code> fields.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-639ca59 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"639ca59\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-javascript'>console.log(`  Temperature: ${current.getEnvironmentData().getTemperature()}`)\nconsole.log(`  Pressure: ${current.getEnvironmentData().getPressure()}`)\nconsole.log(`  Humidity: ${current.getEnvironmentData().getHumidity()}`)\nif (current.getEnvironmentData().getCo2LevelOneofCase() === proto.iotexample.EnvironmentData.Co2LevelOneofCase.CO2_LEVEL)\n    console.log(`  CO2: ${current.getEnvironmentData().getCo2Level()}`)\nif (current.getEnvironmentData().hasAmbientLight());\n    console.log(`  Ambient light: ${current.getEnvironmentData().getAmbientLight()}`) <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0c783ad elementor-widget elementor-widget-text-editor\" data-id=\"0c783ad\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>Removing fields<\/h4>\nIf the\u00a0<code>co2_level<\/code>\u00a0field is to be removed, Protobuf supports the\u00a0<code>reserved<\/code>\u00a0keyword which can be used to prevent names and field numbers from being reused.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3230d83 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"3230d83\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>message EnvironmentData {\n  reserved 4;\n  reserved &ldquo;co2_level&rdquo;;\n  double temperature = 1;\n  double pressure = 2; \n  double humidity = 3;\n  oneof ambient_light_oneof { double ambient_light = 5; }\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5d79ab3 elementor-widget elementor-widget-text-editor\" data-id=\"5d79ab3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>If an attempt is made to reuse a field number or name that has been marked as reserved, protoc will refuse to generate code that violates these constraints<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b73e87b elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"b73e87b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-solid'>environment_iot_messages.proto: Field &quot;newField&quot; uses reserved number 4.\nenvironment_iot_messages.proto:7:12: Field name &quot;co2_level&quot; is reserved. <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6ffb79f elementor-widget elementor-widget-text-editor\" data-id=\"6ffb79f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tIf the design rules for compatibility have been observed, the sender using the old message will still send the field number 4, but the receiver will ignore it and not misinterpret it. For the new\u00a0<code>ambientLight<\/code>\u00a0value, the receiver will see the default value 0 or get the information that the value has not been set if the workaround from the previous section has been employed.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-9725122 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"9725122\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e4f9b6d\" data-id=\"e4f9b6d\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-095a34f elementor-widget elementor-widget-text-editor\" data-id=\"095a34f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Extending the IoT Hub example<\/h2><p>In order to demonstrate how to use Protobuf in an IoT application, we will now extend the Qt based example from the\u00a0<a href=\"https:\/\/www.basyskom.de\/2020\/connect-qt-app-with-azure-iot-hub\/\" target=\"_blank\" rel=\"noopener\">previous part<\/a> of the series.<\/p><p>The full example code is hosted on <a href=\"https:\/\/github.com\/basysKom\/iot_from_scratch\/tree\/master\/Part2_IoTHub_with_Protobuf\" target=\"_blank\" rel=\"noopener\">github<\/a>.<\/p><p>First we have to add new includes for the generated Protobuf code and the Qt random number generator which will provide values to populate the Protobuf messages.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-83279f9 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"83279f9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>#include &lt;generated\/environment_iot_messages.pb.h&gt;\n#include &lt;QRandomGenerator&gt; <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fa1634b elementor-widget elementor-widget-text-editor\" data-id=\"fa1634b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Then we replace the slot for the <code>timeout<\/code> signal of <code>sendMessageTimer<\/code> with a new slot which sends an <code>EnvironmentData<\/code> message on every invocation and sometimes an additional\u00a0<code>Event<\/code> message.<\/p><p>The messages are serialized and passed to the <code>sendMessage()<\/code> method of the <code>IotHubClient<\/code> object.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b8bd658 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"b8bd658\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>\/\/ Initial values for the simulated data\ndouble humidity = 80;\ndouble pressure = 1000;\ndouble temperature = 23;\ndouble co2Level = 410;\n\nQObject::connect(&amp;sendMessageTimer, &amp;QTimer::timeout, &amp;client, [&amp;]() {\n    qDebug() &lt;&lt; &quot;Message send timer triggered&quot; &lt;&lt; QDateTime::currentDateTime().toString(Qt::ISODate);\n    auto environmentData = new iotexample::EnvironmentData();\n    environmentData-&gt;set_humidity(nextRandomValue(humidity, 50, 100, 1));\n    environmentData-&gt;set_pressure(nextRandomValue(pressure, 900, 1100, 1));\n    environmentData-&gt;set_temperature(nextRandomValue(temperature, 10, 75, 1));\n    environmentData-&gt;set_co2_level(nextRandomValue(co2Level,300, 500, 1));\n\n    iotexample::DeviceMessages message;\n    auto currentMessage = message.add_telemetry_messages();\n    currentMessage-&gt;set_timestamp(QDateTime::currentMSecsSinceEpoch());\n    currentMessage-&gt;set_allocated_environment_data(environmentData);\n\n    \/\/ 1% chance of generating an error\n    if (QRandomGenerator::global()-&gt;generateDouble() &lt; 0.01) {\n        qDebug() &lt;&lt; &quot;Generate error message&quot;;\n        auto event = new iotexample::Event();\n        event-&gt;set_message(&quot;Simulated event&quot;);\n        event-&gt;set_error_level(static_cast&lt;iotexample::ErrorLevel&gt;(QRandomGenerator::global()-&gt;bounded(1, 4)));\n        event-&gt;set_event_number(QRandomGenerator::global()-&gt;bounded(1, 10));\n\n        currentMessage = message.add_telemetry_messages();\n        currentMessage-&gt;set_timestamp(QDateTime::currentMSecsSinceEpoch());\n        currentMessage-&gt;set_allocated_event(event);\n    }\n\n    qDebug() &lt;&lt; &quot;Serialized size:&quot; &lt;&lt; message.ByteSizeLong() &lt;&lt; &quot;bytes&quot;;\n\n    QByteArray serializedMessage(message.ByteSizeLong(), Qt::Initialization::Uninitialized);\n    auto success = message.SerializeToArray(serializedMessage.data(), message.ByteSizeLong());\n\n    if (success) {\n        client.sendMessage(++messageId, serializedMessage);\n    } else {\n        qWarning() &lt;&lt; &quot;Message serialization failed&quot;;\n    }\n}); <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6b5e805 elementor-widget elementor-widget-text-editor\" data-id=\"6b5e805\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tThe <code>nextRandomValue()<\/code> function called in the new slot is a simple helper function with generates a slowly changing random value.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bed250d elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"bed250d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>double nextRandomValue(double current, double min, double max, double maxIncrement) {\n    if (current &lt; min || current &gt; max)\n        current = (min + max) \/ 2;\n\n    const double factor = QRandomGenerator::global()-&gt;generateDouble() &lt; 0.5 ? 1 : -1;\n    const double increment = maxIncrement * QRandomGenerator::global()-&gt;generateDouble() * factor;\n\n    if (current + increment &gt; max || current + increment &lt; min)\n        return current - increment;\n\n    return current + increment;\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9ea8c49 elementor-widget elementor-widget-text-editor\" data-id=\"9ea8c49\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tThe final step is to extend the <code>.pro<\/code> file for generating and building the generated Protobuf code and linking to the Protobuf library\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-91c0eb6 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"91c0eb6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-solid'>HEADERS += \\\n        generated\/environment_iot_messages.pb.h\n\nSOURCES += \\\n        generated\/environment_iot_messages.pb.cc\n\nLIBS += -lprotobuf\n\nPROTO_COMPILER = protoc\nsystem($$PROTO_COMPILER --version) {\n  PROTOFILES = $$files(*.proto, true)\n  for (PROTO_FILE, PROTOFILES) {\n    command = $$PROTO_COMPILER --cpp_out=generated $$PROTO_FILE\n    system($$command)\n  }\n} else {\n    error(&quot;protoc is required to build this application&quot;)\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-7430768 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"7430768\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5df37ec\" data-id=\"5df37ec\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-3998922 elementor-widget elementor-widget-text-editor\" data-id=\"3998922\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Conclusion<\/h2><p>Designing and updating Protobuf messages is not very complicated if a few important rules regarding field numbers are observed. The generated handling code uses the same concepts in different programming languages and is easy to use after reading a short introduction on how the different features of Protobuf messages are mapped to code.<\/p><p>The serialized Protobuf data is quite small compared to JSON data which makes it suitable for applications like IoT devices with a mobile broadband connection where small messages are favored for monetary reasons. If all messages have a common point of entry, the raw serialized data can be sent without adding any additional meta information.<\/p><p>A combination of C++ on the IoT device and JavaScript on the receiving side could be used to get data from the IoT device into the cloud.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-621bc51 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"621bc51\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a1b8da7\" data-id=\"a1b8da7\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-1bbbb7b elementor-widget elementor-widget-text-editor\" data-id=\"1bbbb7b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Further reading<\/h2><p><a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3\" target=\"_blank\" rel=\"noopener\">The proto3 language guide<\/a><\/p><p><a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/reference\/overview\" target=\"_blank\" rel=\"noopener\">The Protobuf API reference<\/a><\/p><p><a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/style\" target=\"_blank\" rel=\"noopener\">The Protobuf style guide<\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-20b284e elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"20b284e\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-59b87ff\" data-id=\"59b87ff\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Protobuf is a great choice to transfer data from a IoT device into the cloud. This blog will show you what Protobuf is, how it can be used with C++ and Javascript and how to handle updates without breaking backwards compatibility.<\/p>","protected":false},"author":4,"featured_media":2837,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1,2,134,8],"tags":[137,136,135,15],"class_list":["post-2784","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-allgemein","category-blog","category-cloud","category-qt","tag-cloud","tag-iot","tag-protobuf","tag-qt"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/2784","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/comments?post=2784"}],"version-history":[{"count":100,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/2784\/revisions"}],"predecessor-version":[{"id":3646,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/2784\/revisions\/3646"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/media\/2837"}],"wp:attachment":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/media?parent=2784"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/categories?post=2784"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/tags?post=2784"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}