<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Olivier LOURME on Medium]]></title>
        <description><![CDATA[Stories by Olivier LOURME on Medium]]></description>
        <link>https://medium.com/@o.lourme?source=rss-48724cb81b49------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*6ug9Y3G7i3p8z0oiFA0l5A.jpeg</url>
            <title>Stories by Olivier LOURME on Medium</title>
            <link>https://medium.com/@o.lourme?source=rss-48724cb81b49------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 23:03:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@o.lourme/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[GCP-Cloud IoT Core with ESP32 and Mongoose OS — Addendum]]></title>
            <link>https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-2nd-config-state-encrypt-7c5e937e5be9?source=rss-48724cb81b49------2</link>
            <guid isPermaLink="false">https://medium.com/p/7c5e937e5be9</guid>
            <category><![CDATA[mongoose-os]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[iot]]></category>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[esp32]]></category>
            <dc:creator><![CDATA[Olivier LOURME]]></dc:creator>
            <pubDate>Fri, 29 Mar 2019 19:31:19 GMT</pubDate>
            <atom:updated>2020-05-30T06:59:39.727Z</atom:updated>
            <content:encoded><![CDATA[<h3>GCP-Cloud IoT Core with ESP32 and Mongoose OS — Addendum</h3><p>A description of <strong>“config” and “state” MQTT topics</strong> of GCP-Cloud IoT Core and an illustration of <strong>ESP32 flash memory encryption</strong> w/Mongoose OS.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8Mia8GkT-cZCZ1I7zmS0rw.jpeg" /><figcaption>Cherry blossom season in Lille, France.</figcaption></figure><h3>TL;DR</h3><p>My Medium home page is <a href="https://medium.com/@o.lourme">here</a>.</p><p>This short post is an extension to the previous one called “How to check the weather using GCP-Cloud IoT Core with ESP32 and Mongoose OS”: [<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7">link</a>]. Today, we tackle <strong>config and </strong><strong>state special MQTT topics</strong> of <strong>Google Cloud Platform-Cloud IoT Core</strong> and we also talk about actions countering <strong>local attacks</strong> on the device, the most important being the <strong>ESP32 flash memory encryption</strong>. At last, simple measures of <strong>ESP32 current/power consumption</strong> are made.</p><p><em>Note:</em> Most of the informations given here come from Mongoose OS web site ([<a href="https://mongoose-os.com/">link</a>]) and from Cloud IOT Core documentation ([<a href="https://cloud.google.com/iot/docs/">link</a>]).</p><h3>A) “config” and “state” special MQTT topics</h3><h4>A) 1) Presentation</h4><p>Basic understanding of the role of these two topics is given here: <a href="https://cloud.google.com/iot/docs/concepts/devices">https://cloud.google.com/iot/docs/concepts/devices</a>. It can be good to know that their use is a mean to obtain an equivalent of <strong>AWS IoT device shadow</strong>.</p><p>On the project architecture diagram given at the beginning of our previous post ([<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7">link</a>]), we see besides telemetry two other data flows, <strong>Config </strong>and <strong>State</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/249/1*kBpmaNkEksBh_SAju-XpxA.png" /><figcaption>Config and State data flows</figcaption></figure><ul><li>Indeed, the Cloud IoT Core service may publish <strong>configuration update messages</strong> to a special topic the device has subscribed to ([<a href="https://cloud.google.com/iot/docs/how-tos/config/configuring-devices">link</a>]). It is useful when we need the device to go to a new state, <em>e.g.</em> by updating a parameter of its associated sensor, by changing a deep sleep period, moving a servomotor, etc. For efficiency, there shouldn’t be more than one message of that type per second per device. Such a message is an arbitrary user-defined blob (we’ll use JSON), up to 64 kiB. At last, the name of this special MQTT topic is imperatively:</li></ul><pre>/devices/{device-id}/config</pre><ul><li>On the other direction, a device may publish to a special topic — that Cloud IoT Core has automatically subscribed to — <strong>messages concerning its state </strong>([<a href="https://cloud.google.com/iot/docs/how-tos/config/getting-state">link</a>])<strong>, </strong><em>e.g.</em> quantity of RAM available, state of a button, etc. It is often used to see if the previous config message sent to the device had the desired effect. For efficiency, this kind of publication shouldn’t be done more than once per second per device. Such a message is an arbitrary user-defined blob (we’ll use JSON), up to 64 kiB. At last, the topic to which the device publishes its state data has imperatively this name:</li></ul><pre>/devices/{device-id}/state</pre><p><em>Note:</em> Sending<strong> commands </strong>to devices is also possible from Cloud IoT Core: see [<a href="https://cloud.google.com/iot/docs/how-tos/commands">link</a>] but we won’t illustrate it.</p><p>The following two sections A) 2 and A) 3) illustrate simple use cases of config and state special MQTT topics:</p><ul><li>Illustrating config will use the blue built-in LED connected to GPIO2 of ESP32 DEVKIT V1.</li><li>Illustrating state will use a push button we chose to connect to GPIO4:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/596/1*Ts4PWmwWyoQ2n3OpiOdfgQ.png" /><figcaption><strong>ESP32 DEVKIT V1: </strong>Blue built-in LED is connected to GPIO2. A push button is connected to GPIO4. Image : [<a href="https://randomnerdtutorials.com/esp32-pinout-reference-gpios/">link</a>]</figcaption></figure><h4>A) 2) Updating device config from Cloud IoT Core</h4><p><strong>Context</strong></p><p>We use the blue built-in LED connected to GPIO2 of ESP32 DEVKIT V1.</p><blockquote>The config we want to impose from GCP-Cloud IoT Core to the device is the desired state of the blue built-in LED.</blockquote><p>So, if we want to switch on (respectively off) the device blue LED from Cloud IoT Core, we choose to publish to the topic whose name is /devices/{device-id}/config the JSON message {&quot;on&quot;: true} ( respectively {&quot;on&quot;: false}).</p><p>Accordingly, in the device firmware, we should subscribe to that topic and parse the JSON message received to switch on (respectively off) the LED. Really simple!</p><p><strong>ESP32 firmware featuring a subscribe to “config” topic</strong></p><p>We write the following fs/init.js file to meet our goal. Useful documentation links are provided at the beginning of the source code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/abc95e8e17dad00cfc4757f23c5f5533/href">https://medium.com/media/abc95e8e17dad00cfc4757f23c5f5533/href</a></iframe><p>To upload this file to ESP32 file system, from the folder (of the host computer) containing the fs folder containing itself the init.js file, we type:</p><pre>mos put fs/init.js<br>mos call Sys.Reboot</pre><p><strong>Publishing a new config to the device from Google Cloud Console</strong></p><p>We head to <a href="https://console.cloud.google.com/iot/">https://console.cloud.google.com/iot/</a> and then we follow the different steps indicated below, the green figures indicating where to click or type something:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/841/1*HRdkX8HfLNY7P5hp9hfx1Q.png" /><figcaption>Google Cloud Console — Publishing a new config to the device (1/2)</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/929/1*CsR_amJg3Vj1f4rTpiiETQ.png" /><figcaption>Google Cloud Console — Publishing a new config to the device (2/2)</figcaption></figure><p>This will switch the blue LED on ! The device will also send an acknowledgment message to GCP, telling it it has received the new configuration (in that case, there is a green “check” icon, otherwise the icon is a yellow “warning” one):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/660/1*nbwd3NpI9RgGtwTqH4KVeg.png" /><figcaption>Google Cloud Console — Device has received the new configuration and acknowledged it.</figcaption></figure><p><em>Note: </em>When you use MQTT, a good point is that, if the device has no connection, <strong>the configuration will be propagated to the device when it connects</strong>. Try this feature by setting the blue LED on, then switch off the device, then switch it on back: the blue LED will recover its ‘on’ state.</p><p><em>Note:</em> It is also possible to impose a config from a Command Line Terminal, using a gcloud command. For instance, if the device-id is esp32_F70468, if the project-id is hello-cloud-iot-core and if the registry name is weather-devices-registry, the command to switch the LED off is:</p><pre>gcloud beta iot devices configs update --device esp32_F70468 --project hello-cloud-iot-core --region europe-west1 --registry weather-devices-registry --config-data &quot;{\&quot;on\&quot;: <strong>false</strong>}&quot;</pre><h4>A) 3) Publishing state from device to Cloud IoT Core</h4><p><strong>Context</strong></p><p>We connect one pin of a push button to GPIO4 of an ESP32 DEVKIT V1 and we connect the other pin to 3.3 V.</p><blockquote>We chose that the state the device will communicate to GCP-Cloud IoT Core is: “The button connected to my GPIO4 has just been pressed. It was at the Epoch time xxx.”</blockquote><p>Let’s consider these 3 points:</p><ul><li>We didn’t add<strong> </strong>any<strong> pull-down resistor</strong> between GPIO4 and GND because ESP32 has such built-in resistors (we’ll have to validate programmatically the one for GPIO4).</li><li>When we push and release the button, there is a <strong>high to low transition</strong> on GPIO4 and this is the type of transition we should detect to initiate a MQTT publication to the state topic.</li><li>With buttons, it’s good to have a <strong>debounce time</strong> of, let’s say, 200 ms.</li></ul><p>The good new is that Mongoose OS “GPIO” API has a method called set_button_handler ([<a href="https://mongoose-os.com/docs/mongoose-os/api/core/mgos_gpio.h.md#gpio-set_button_handler">link</a>]) where we can specify all those aspects:</p><pre>GPIO.set_button_handler(pin, GPIO.PULL_DOWN, GPIO.INT_EDGE_NEG, 200, function(x) {<br>  print(&#39;Button press, pin: &#39;, x);<strong><br>  </strong>// Make MQTT publication to &#39;state&#39; topic...<br>}, null);</pre><p><strong>ESP32 firmware featuring publication to “state” topic</strong></p><p>We write the following fs/init.js file to meet our goal. Of course, it could be merged with the previous fs/init.js file we wrote when we dealt with “config” topic. Useful documentation links are provided at the beginning of the source code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/53b1b9c20ff1f6564ca2e10abccc7b9a/href">https://medium.com/media/53b1b9c20ff1f6564ca2e10abccc7b9a/href</a></iframe><p>To upload this file to ESP32’s file system, from the folder where there is the fs folder containing the init.js file, we type:</p><pre>mos put fs/init.js<br>mos call Sys.Reboot</pre><p><strong>Seeing the published state in Google Cloud Console</strong></p><p>Now, our button is ready to be pressed! So let’s press it! In Cloud IoT Core, where can we see the matching state publication ?</p><p>We head to <a href="https://console.cloud.google.com/iot/">https://console.cloud.google.com/iot/</a> and then we follow the different steps indicated below, the green figures indicating where to click:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/815/1*eelr3dDUy_perbvFersfcQ.png" /><figcaption>Google Cloud Console — Seeing publication to “state” topic (1/2)</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/839/1*9uHKJibriBzkz91qcDVtHw.png" /><figcaption>Google Cloud Console — Seeing publication to “state” topic (2/2)</figcaption></figure><p>That’s all! Not really hard, is it?</p><h3>B) ESP32 flash memory encryption and other stuffs for local security</h3><h4>B) 1) Introduction</h4><p>We already talked about security in the previous post (See [<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7">link</a>] and look for “security”): We use TLS for communication between devices and Cloud Iot Core and JWT authentication protected by asymmetrical keys.</p><p>Another aspect of security is <strong>local security</strong>, <em>i.e.</em> the actions undertaken to prevent someone gaining <strong>physical access to the device</strong> to perform damages : firmware corruption, information theft, credentials retrievals, access to the whole data chain, destruction, etc.</p><p>Concerning this topic, there is a lot to say but three points seem the most important to us :</p><ul><li>Consider a device that can have its <strong>flash memory encrypted</strong>. ESP32 is in this category. Or at least, consider adding to your device a secure element like <a href="https://www.microchip.com/wwwproducts/en/ATECC608A">ATECC608A</a> from Microchip.</li><li>Consider a device handling <strong>secure boot</strong>. In one word, at each startup the device should check that its firmware is the one that the provisionner uploaded to it. This is especially important after a firmware update. This can be done with an ESP32, not by Mongoose OS but by ESPressif Iot Development Framework (ESP-IDF) : [<a href="https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html">link</a>].</li><li>In production, <strong>prevent access to UART and JTAG connectors</strong> by cutting the pins or adding some resin, etc.</li></ul><p><em>Note: </em>This IoT security related video, in french, taken at Devoxx FR 2019, helped us to make this list : [<a href="https://www.youtube.com/watch?v=TZony98Q7ZA">link</a>]. It is made by @disk_91, the runner of the cool IoT blog <a href="https://www.disk91.com/">disk91.com</a>.</p><p>In the following paragraphs, we discuss only about the first point. We haven’t tackled the second one yet because of a lack of time, but someday…</p><h4>B) 2) Reading flash memory</h4><p>Just to remember, in our 3-post serie dealing with ESP8266 and Firebase, with Arduino style programs (we weren’t using Mongoose OS yet), we showed in the first of these posts (See [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>] at section “Security considerations”) how it was easy for an attacker having physical access to the chip to recover sensitive information like Wifi SSID and password. Indeed they were, like everything else,<strong> stored in plain text</strong> in the flash memory.</p><p>With ESP32 and Mongoose OS, if you don’t do anything special, it’s the same situation. For instance, it’s easy to recover the ESP32 private key it uses along with the JSON Web Token to get authenticated with GCP-Cloud IoT Core. It is a serious <strong>security issue</strong>. Moreover, it is also easy to practice <strong>reverse engineering</strong> by reading the code stored in plain text. A good point however is that we didn’t manage to recover Wifi credentials.</p><p>At the beginning of the following video, Mongoose OS team show these aspects, using their tool called <strong>mos </strong>to read the memory. It is also detailed in the Mongoose OS web site at the Security section: <a href="https://mongoose-os.com/docs/mongoose-os/userguide/security.md">https://mongoose-os.com/docs/mongoose-os/userguide/security.md</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fvideoseries%3Flist%3DPLNOffh-6mSoRfxD4wTvRziUDUiSLSyJKE&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D16jF0HUyedg&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F16jF0HUyedg%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/f6bdbb5b05ad4d60db3644fdf23381f2/href">https://medium.com/media/f6bdbb5b05ad4d60db3644fdf23381f2/href</a></iframe><p>With a 4 MiB flash memory, an ESP32 communicating to host PC thanks to COM18, here are a few examples of commands performing partial or total memory read (from mos tool or from a Command Line Terminal).</p><pre><strong># Print to console 2000 bytes from address 0x190000</strong><br>mos flash-read --port COM18 --platform esp32 0x190000 2000 -</pre><pre><strong># Save to a file called &quot;flash_content.bin&quot; 2000 bytes from address 0x190000</strong><br>mos flash-read --port COM18 --platform esp32 0x190000 2000 flash_content.bin</pre><pre>#<strong> Save to a file called &quot;flash_content.bin&quot; all bytes</strong><br>mos flash-read --port COM18 --platform esp32 flash_content.bin</pre><p><em>Note:</em> To read our <strong>ESP32 DEVKIT V1 development board, </strong>we need ESP32 to boot in a specific mode. So before hitting the Enter key to validate the command, we press BOOT and EN buttons on the board. Then we validate the command hitting Enter, then we release EN button, then BOOT button. Some explanations are given here: [<a href="https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection">link</a>].</p><p>Dumping memory content to a file and performing a Search inside it makes private key obtention really easy. For instance, look for the second time the expression -----END EC PRIVATE KEY----- appears in the full file, the private key lies just before it! You can compare it with the content of the file gcp-{device-id}.key, they are the same!</p><pre>...EzNgaTW1rNxaHeu1lIXg==<br>-----END EC PRIVATE KEY-----</pre><p>We also easily retrieve parts of our program, stored in plain text:</p><pre>// This button handler will trigger function when button is released, with a 200 ms debounce time:<br>let bh = GPIO.set_button_handler(pin, GPIO.PULL_DOWN, GPIO.INT_EDGE_NEG, 200, function(x) {<br>  print(&#39;Button press,...</pre><h4>B) 3) Encrypting flash memory</h4><p>Normally you should be now convinced of the necessity to encrypt the memory content!</p><p>Happily, ESP32 flash memory is designed to be encrypted and Mongoose OS handles that easily! Another good point for Mongoose OS! Please note that <strong>the process of encrypting memory is irreversible</strong> and that we have to store the <strong>encrypting key</strong> in a safe place, if we need someday to reflash the memory.</p><p><strong>a. </strong>The following command enables flash encryption at next flashing. The device must be connected to the host PC issuing this command. We chose a name for the flash encryption key related to the device id. For instance, if this one is esp32_F70468, we name the key esp32_F70468_fe.key.</p><pre>mos -X esp32-gen-key flash_encryption_key <strong>esp32_F70468_fe.key</strong> --esp32-enable-flash-encryption --dry-run=false</pre><p>This should end up with the message:</p><pre>Programming eFuses...<br>Success</pre><p><strong>b.</strong> Then we flash the device. After it reboots, the encryption begins. It takes about 2 minutes long but this will be the only time it is done. The command for our device is:</p><pre>mos flash esp32 --esp32-encryption-key-file <strong>esp32_F70468_fe.key</strong></pre><p>It should end up with a message like:</p><pre>All done!</pre><p>Of course, as we flashed the device, we need to:</p><ul><li>reconfigure Wifi,</li><li>re-upload init.js file to the device,</li><li>register again the device with Cloud IoT core project.</li></ul><p>All of this is explained in our previous post ([<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7">link</a>]).</p><p>Now, a memory read produces nothing readable. Try it yourself!</p><p>For security, we encrypted the memory content of all our ESP32s connected to GCP. This is a good habit, don’t postpone this!</p><h3>C) Bonus: Power considerations</h3><p>We must be aware that we have a permanent MQTT connection to GCP-Cloud IoT Core (and so a permanent Wifi connection) and we didn’t set up any deep sleep in our ESP32 programs. That being said, with a publication every two minutes, just like in the live demo ([<a href="https://hello-cloud-iot-core.firebaseapp.com/">link</a>]), a cheap usb current meter ([<a href="https://www.banggood.com/USB-Volt-Voltage-Current-Meter-Voltmeter-Detector-Power-Capacity-Charger-Tester-p-1137098.html">link</a>]) says the <strong>current consumption is almost 100 mA</strong> (under 5 V) and yes, that’s pretty much. 2000 mAh batteries wouldn’t last a full day. As far as we’re concerned, we use mobile phone chargers to power our devices.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*H2HCKdkfS_suhNhcUT0hDQ.jpeg" /><figcaption>Current consumption, among other measures.</figcaption></figure><p>Mongoose OS has no API to handle<strong> deep sleep</strong> but doesn’t prevent from using the <strong>ESP32 native APIs</strong>. Maybe this solution should be tested to see if consumption reduces significantly. But the programs we wrote would stop being cross platform.</p><h3>Conclusion</h3><p>In this small post, we completed the first one dealing with ESP32s running Mongoose OS and managed by GCP-Cloud IoT Core ([<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7">link</a>]). Today, we showed the use of special “config” and “state” MQTT topics, a nice way to manage a device. We also showed ESP32 flash memory encryption, making our IoT system even more secure.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7c5e937e5be9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to check the weather using GCP-Cloud IoT Core with ESP32 and Mongoose OS]]></title>
            <link>https://medium.com/free-code-camp/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7?source=rss-48724cb81b49------2</link>
            <guid isPermaLink="false">https://medium.com/p/5c88d8134ac7</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[iot]]></category>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[google-cloud]]></category>
            <category><![CDATA[tech]]></category>
            <dc:creator><![CDATA[Olivier LOURME]]></dc:creator>
            <pubDate>Thu, 28 Feb 2019 22:07:21 GMT</pubDate>
            <atom:updated>2021-03-01T13:29:45.528Z</atom:updated>
            <content:encoded><![CDATA[<h3>TL;DR</h3><p>My Medium home page is <a href="https://medium.com/@o.lourme">here</a>.</p><p>The version of this post you are reading now on www.medium.com is the most up to date. The www.freecodecamp.org version is not maintained.</p><p>This post is a step-by-step tutorial for newbies to <strong>Google Cloud Platform-Cloud IoT Core</strong>. The devices are <strong>ESP32 Wi-Fi chips</strong> running <strong>Mongoose OS</strong>. To go through this tutorial, the concepts and then the setup of a simple <strong>IoT system</strong> <strong>measuring weather data</strong> are described.</p><p><strong>Live demo is here:</strong> <a href="https://hello-cloud-iot-core.firebaseapp.com/">https://hello-cloud-iot-core.firebaseapp.com/</a></p><p><strong>GitHub for last section<em> </em></strong><em>(Logging, storing and visualizing weather data with Firebase)</em> <strong>is here: </strong><a href="https://github.com/olivierlourme/iot-store-display">https://github.com/olivierlourme/iot-store-display</a></p><p><strong>This post is completed by a second one:</strong> see <a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-2nd-config-state-encrypt-7c5e937e5be9">here</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GGNvAgxLJXeagpiyQnlHvQ.jpeg" /><figcaption>“For the moment we’re just the two of us but soon we’ll be a thousand!”</figcaption></figure><h3>Introduction</h3><h4>1) History</h4><p>In a previous 3-post series [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>, <a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>, <a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4">link</a>], we used an <strong>ESP8266 Wi-Fi chip </strong>to regularly measure luminosity and feed a database with the obtained data. The data set was ultimately lively plotted to a web app (see live plot here: [<a href="https://esp8266-rocks.firebaseapp.com/">link</a>]). We massively used <strong>Firebase products </strong>(Realtime Database, Cloud Functions, SDK and Hosting) to meet our goals.</p><p>This project worked fine, and thanks to deep sleep it drew very little power. We really enjoyed developing it — but:</p><ul><li><strong>This project was okay to handle just a few connected sensors</strong>. Setting up a set of a hundred sensors would require a lot of (rigorous) manual intervention and monitoring/exploiting them would be challenging as well. Indeed, there was no central place where we can manage our system.</li><li><strong>Arduino IDE</strong> and <strong>Arduino core for ESP8266</strong> were great for discovering ESP8266 but they are <strong>quickly insufficient</strong>: The IDE file management is really basic, there is only one program in the chip, and <strong>there is no Operating System</strong> <strong>providing useful APIs for IoT</strong>.</li><li><strong>FirebaseArduino</strong> <strong>library</strong>, allowing an ESP8266 to push data to a Firebase Realtime Database, <strong>was experimental</strong>. Some features like authentication should be improved. For now, the “secret” type authentication we used gives ESP8266 admin rights over the whole database!</li><li>Eventually, <strong>ESP8266 SPI flash memory was not designed to be encrypted</strong>. In our first post [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>], we showed how easy it was to recover a Wi-Fi password when reading this memory.</li></ul><blockquote>In a word, this past project couldn’t be used in an industrial context. It was more a prototype for a Proof of Concept. We learnt a lot with it but today <strong>we’d like to develop a professional and fully secured solution capable of managing in a simple way a lot of connected sensors</strong>.</blockquote><p>This is why we decided to:</p><ul><li><strong>investigate Google Cloud Platform-Cloud IoT Core</strong> [<a href="https://cloud.google.com/iot-core/">link</a>]<strong> </strong>to manage our system : devices setup, provision, authentication and monitoring;</li><li><strong>move from ESP8266 to ESP32</strong>, which offers memory encryption;</li><li><strong>run Mongoose OS</strong> [<a href="https://mongoose-os.com/">link</a>] in our ESP32s. This OS accepts programs written in Javascript (JS) and provides a lot of APIs to deal with time, MQTT protocol (the most used in IoT, described a few paragraphs later), sensors, etc. Moreover, Mongoose OS comes with a development tool called <strong>mos</strong>, allowing to easily set up a device and provision it with Cloud IoT Core.</li></ul><h4><strong>2) A word about ESP32 Wi-Fi chip</strong></h4><p>ESP32 Wi-Fi chip is a successor of the famous ESP8266 we described here: [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>]. Compared to it, every feature is enhanced (speed up to 240 MHz, two cores, 520 kiB RAM, number of GPIOs, variety of peripherals, etc.) and there are some new ones: Bluetooth (legacy/BLE), <strong>4 MiB-flash memory encryption capability</strong> and <strong>cryptographic hardware acceleration</strong> (AES, SHA-2, RSA, ECC, RNG). There are a lot of resources on the web concerning ESP32. The following one deals with the <strong>ESP32 DEVKIT V1 development board </strong>that we will use and gives its pinout: [<a href="https://randomnerdtutorials.com/esp32-pinout-reference-gpios/">link</a>].</p><p>There is also this extensive resource concerning the wide variety of ESP32 chips and development kits : <a href="http://esp32.net/">http://esp32.net/</a> . On their home page, searching for “ESP32 DevKit” or “GeekCreit” leads to a link to the <a href="https://github.com/SmartArduino/ESP/blob/master/SchematicsforESP32.pdf">schematic</a> of our ESP32 DEVKIT V1. This development board embeds an official Espressif ESP32-WROOM-32 chip and costs about 6€ at Banggood.</p><h3>Basic IoT concepts explained through our use case</h3><p>So, what will be our playground for test all these new tools?</p><blockquote>To illustrate IoT concepts through Cloud IoT Core, we chose to build <strong>a weather station</strong> <strong>reporting humidity and temperature from different places</strong>.</blockquote><p>For simplicity we’ll handle only 2 places: inside our house (“indoor”) and outside our house (“outdoor”). It’s up to you to deal with many more places.</p><h4>1) Project hardware : ESP32 &amp; DHT22</h4><p>At each of theses places, we’ll install a connected sensor (<strong>“a device”</strong>) constituted by a <strong>DHT22</strong> <strong>humidity/temperature sensor </strong>(description: [<a href="https://learn.adafruit.com/dht">link</a>], datasheet: [<a href="https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf">link</a>], 4€ at Banggood)<strong> </strong>connected to an <strong>ESP32 DEVKIT V1</strong> development board. DHT22 observes a kind of “1-Wire” protocol. Each ESP32 will house <strong>Mongoose OS</strong> for operating system. Its installation on an ESP32, a “Hello, World!” and a test with a DHT22 are given in the section called “Mongoose OS installation on devices”.</p><p>Just below are given DHT22 specifications. Afterwards, we think the accuracy figures are a bit optimistic but that’s not our concern today. If you want more accurate sensors, have a look at SHT3X series or BME280.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/682/1*WIxEy4NLdDr_2SVhcjmv0g.png" /><figcaption>DHT22 sensor characteristics ([<a href="https://learn.adafruit.com/dht/overview">link</a>])</figcaption></figure><p>We can already build the following assembly twice (one for indoor and one for outdoor). For now, power will come from the USB connector connected to our host machine. In production, power may come from a phone charger. A power bank is not a realistic choice as current consumption is pretty high - we show this in the post following this one : [<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-2nd-config-state-encrypt-7c5e937e5be9">link</a>].</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tFxxVtWwVH9gFajtrCWQ0w.png" /><figcaption>Assembly Diagram — ESP32 DEVKIT V1 and DHT22 sensor constitute a “device”. Pinout is here : [<a href="https://randomnerdtutorials.com/esp32-pinout-reference-gpios/">link</a>]</figcaption></figure><p>That’s all for hardware! The rest of the project uses <strong>serverless solutions </strong>from Google. We describe them now…</p><h4>2) Project architecture : Cloud IoT Core &amp; Firebase</h4><p>All this “Project architecture” section is theoretical, there is no step to perform. Its aim is to introduce vocabulary and notions related to IoT, more specifically when this domain involves Google Cloud solutions.</p><p>Here is the general architecture of our project:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PttQxTGMbDHCGwzCsWlZvA.png" /><figcaption>Project architecture</figcaption></figure><p><em>Note: </em>There is no <strong>gateways </strong>between our devices and Cloud IoT Core because they “speak” MQTT.</p><p><em>Note:</em> Devices can also communicate with Cloud IoT Core via its <strong>HTTP bridge</strong>. As it is less performant than the <strong>MQTT bridge</strong> (see a comparison : [<a href="https://cloud.google.com/iot/docs/concepts/protocols">link</a>]), we will disallow this communication later during registry configuration. Limiting access just to what is necessary is a good practice.</p><p>Let’s explain this architecture in three sections:</p><ul><li>“From Devices to Cloud Pub/Sub” describes the classical Google IoT architecture.</li><li>“From Cloud Pub/Sub to data storage and visualization”, describes the choices we made to exploit data.</li><li>“Additional config and state topics” completes this architecture presentation.</li></ul><p><strong>From Devices to Cloud Pub/Sub</strong></p><ul><li><em>Cloud IoT Core</em></li></ul><p><strong>Cloud IoT Core</strong> is the Google Cloud Platform service to which each of our <strong>registered devices </strong>will send temperature/humidity data. When such a data is sent, we say that <strong>the device publishes a telemetry event</strong> (sometimes also called a “telemetry message”).</p><p><em>Note:</em> Pricing is detailed here : [<a href="https://cloud.google.com/iot/pricing">link</a>]. For small projects with a few devices, there’s little chance you get charged.</p><ul><li><em>MQTT</em></li></ul><p>This publication is done through a <strong>MQTT connection</strong>. MQTT is a publish/subscribe-based message protocol; most of the time it lies over TCP [<a href="https://en.wikipedia.org/wiki/MQTT">link</a>] (or better: over TLS, itself being over TCP). The telemetry message has to be published by the device (a MQTT client) to the Cloud Iot Core “MQTT bridge” (a MQTT server) in a <strong>MQTT topic</strong> whose name imperatively respects this format:</p><pre>/devices/{device-id}/events</pre><p><em>Note:</em> Sub-folders in the topic name are possible. We won’t need this feature here but see [<a href="https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#publishing_telemetry_events">link</a>], as it can sometimes be useful.</p><p>{device-id} is unique to each device. In our case, Mongoose OS creates it from the last 3 bytes of the MAC address of the ESP32. For example it could be esp32_ABB3B4.</p><ul><li><em>Quality of Service (QoS)</em></li></ul><p>The MQTT specification describes three <strong>Quality of Service (QoS)</strong> levels, when publishing to a topic ([<a href="https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#quality_of_service_qos">link</a>]):</p><p>&gt; QoS 0, the message is delivered at most once;</p><p>&gt; QoS 1, the message is delivered at least once;</p><p>&gt; QoS 2, the message is delivered exactly once.</p><p>Cloud IoT Core does not support QoS 2. And QoS 1 is better than QoS 0. So <strong>QoS 1 is the one we will adopt</strong>. Mongoose OS can do that.</p><ul><li><em>Security</em></li></ul><p>Concerning <strong>security</strong>, in our Mongoose OS/Cloud IoT Core context, MQTT communications are made over <strong>TLS </strong>([<a href="https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#mqtt_server">link</a>]), so (1) the device is assured to be connected to Cloud IoT Core MQTT server (CA’s certificates are stored in Mongoose OS ca.pem file), (2) the data exchange will be private and (3) data integrity will be checked. On the other way, <strong>device authentication </strong>([<a href="https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#device_authentication">link</a>]) with Cloud IoT Core is performed with a per-device public/private key authentication using <strong>JSON Web Token (JWT)</strong>. The device performs the signature part of the JWT with its private key and Cloud IoT Core validates it using the related public key. Mongoose OS tools handles this keys generation and distribution, we’ll see that soon in the section called “Device registration within the Cloud IoT Core project” lying a few paragraphs below. In this section, we’ll see also how to store securely the private key on the device by performing memory encryption (preventing as well reverse engineering).</p><p><em>Note:</em> Beyond JWT device authentication, for additional security, it’s possible to impose TLS from Cloud IoT Core to devices (so each device has also a public key certificate, etc.). It is an option we won’t use but it’s described <a href="https://mongoose-os.com/docs/mongoose-os/api/net/mqtt.md">here</a> for Mongoose OS side (see “mutual TLS”) and <a href="https://cloud.google.com/iot/docs/how-tos/credentials/verifying-credentials">here</a> for Cloud Iot Core side. It’s good to know that AWS IoT imposes this mutual TLS, unconditionally ([<a href="https://docs.aws.amazon.com/iot/latest/developerguide/iot-security-identity.html">link</a>]).</p><ul><li><em>Registry</em></li></ul><p>Devices sharing the same purpose are regrouped within a <strong>registry</strong>.</p><ul><li><em>Cloud Pub/Sub</em></li></ul><p><strong>Telemetry data from all devices belonging to the same registry is then <em>forwarded </em>to a Cloud Pub/Sub topic </strong>(Cloud Pub/Sub is a GCP product [<a href="https://cloud.google.com/pubsub/">link</a>], not specifically a Cloud IoT Core one). The name of the Cloud Pub/Sub topic follows this pattern:</p><pre>projects/<strong>id-of-google-cloud-project</strong>/topics/<strong>name-of-telemetry-topic</strong></pre><p>So, if we call our Google Cloud project hello-cloud-iot-core, if we choose weather-telemetry-topic for the name of our Pub/Sub telemetry topic and if finally our registry is called weather-devices-registry, we’ll get sooner or later that kind of view in <strong>Google Cloud Console</strong> :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/936/1*BeVR0exU6l-rXg8LqJvfeQ.jpeg" /><figcaption>Project ID, registry ID and telemetry Pub/Sub topic name in Google Cloud Console</figcaption></figure><p>But no stress, everything will be explained step by step to reach that.</p><p><em>Note:</em> As it is said here ([<a href="https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#publishing_telemetry_events">link</a>]), each message in the Cloud Pub/Sub topic contains a copy of the telemetry message published by the device but also some <strong>message attributes</strong>, the most important being probably deviceID, allowing us to match some received data with the device that published it.</p><p><em>Note:</em> We talk a lot about <strong>Pub(lish)</strong>, but where is the <strong>Sub(scribe)</strong>? In fact, we’ll create quickly with Google Cloud Command Line Interface a Cloud Pub/Sub subscription (a “pull” one) in order to view the messages published to the telemetry topic. Later in this post, we’ll create a Firebase Cloud Function reacting to each publication and this will automatically create another subscription (a “push” one this time).</p><p><strong>From Cloud Pub/Sub to data storage and visualization</strong></p><p>We’re following the right part of the project architecture diagram given at the beginning of this post:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/571/1*aN_fNiSZXWfgoNrHPmNXeQ.png" /><figcaption>Project Architecture — Weather data storage and visualization</figcaption></figure><p>A publication to the Cloud Pub/Sub topic will <strong>trigger a Firebase Cloud Function</strong> that will itself <strong>fulfill a Firebase Realtime Database</strong> with the new data. A web app hosted by<strong> Firebase Hosting </strong>will lively plot data from the Firebase Realtime Database, in the same way as we did in a previous post: [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4">link</a>].</p><p>There are other options in the Google ecosystem to store/treat/visualize data. <a href="https://medium.com/u/135b0794ddc5">Alvaro Viebrantz</a>’s really good post [<a href="https://medium.com/google-cloud/build-a-weather-station-using-google-cloud-iot-core-and-mongooseos-7a78b69822c5">link</a>] that helped us uses <strong>Big Query</strong> ([<a href="https://cloud.google.com/bigquery/">link</a>]) and <strong>Data Studio</strong> ([<a href="https://datastudio.google.com/">link</a>]).</p><p><strong>Additional “config” and “state” topics</strong></p><p>On the project architecture diagram given at the beginning of this post, we see besides telemetry two other data flows: <strong>Config </strong>([<a href="https://cloud.google.com/iot/docs/how-tos/config/configuring-devices">link</a>]) and <strong>State </strong>([<a href="https://cloud.google.com/iot/docs/how-tos/config/getting-state">link</a>]):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/249/1*kBpmaNkEksBh_SAju-XpxA.png" /><figcaption>Config and State data flows</figcaption></figure><p>Indeed, the Cloud IoT Core service may publish <strong>configuration update messages</strong> to a special topic the device has subscribed to ([<a href="https://cloud.google.com/iot/docs/how-tos/config/configuring-devices">link</a>]). It is useful when we need the device to go to a new state, <em>e.g.</em> by updating a parameter of its associated sensor, by changing a deep sleep period, moving a servomotor, etc.</p><p>For efficiency, there shouldn’t be more than one message of that type per second per device. Such a message is an arbitrary user-defined blob (we’ll use JSON), up to 64 kiB. At last, the name of this special MQTT topic is imperatively:</p><pre>/devices/{device-id}/config</pre><p>On the other hand, a device may publish to a special topic — that Cloud IoT Core has automatically subscribed to — <strong>messages concerning its state </strong>([<a href="https://cloud.google.com/iot/docs/how-tos/config/getting-state">link</a>])<strong>, </strong><em>e.g.</em> quantity of RAM available, state of a button, etc. It is often used to see if the previous config message sent to the device had the desired effect.</p><p>For efficiency, this kind of publication shouldn’t be done more than once per second per device. Such a message is an arbitrary user-defined blob (we’ll use JSON), up to 64 kiB. At last, the topic to which the device publishes its state data has imperatively this name:</p><pre>/devices/{device-id}/state</pre><p><em>Note:</em> Sending<strong> commands </strong>to devices is also possible from Cloud IoT Core: see [<a href="https://cloud.google.com/iot/docs/how-tos/commands">link</a>] but we won’t illustrate it.</p><blockquote>But for the moment, we will focus on telemetry. After this journey, in a “coming soon” post we will show how to handle <em>config</em> and <em>state</em> special topics.</blockquote><p>UPDATE March 29, 2019: This post about config and state special topics is out: [<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-2nd-config-state-encrypt-7c5e937e5be9">link</a>].</p><h3><strong>Mongoose OS installation on devices</strong></h3><h4>1) A short description of Mongoose OS</h4><p><strong>Mongoose OS</strong> ([<a href="https://mongoose-os.com/">link</a>], [<a href="https://lwn.net/Articles/733297/">link</a>]) is a smart IoT-oriented OS, runnable on several chips, including ESP8266 and ESP32. Mongoose OS is in partnership with the major actors in IoT ([<a href="https://mongoose-os.com/about.html">link</a>]). It comes with a development tool called <strong>mos</strong>, really useful to set up the device and then provision it with the IoT platform, working either within a UI or within a Command Line Terminal. In either cases, we’ll write mos commands. There is also a device management app called mDash but we didn’t try it. <strong>Numerous APIs dealing with most of the network and sensor protocols are provided.</strong> Programs can be written in both C/C++ and JS.</p><p>At last, there is a 12-tutorial series on YouTube, really useful:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fvideoseries%3Flist%3DPLNOffh-6mSoRfxD4wTvRziUDUiSLSyJKE&amp;url=https%3A%2F%2Fwww.youtube.com%2Fplaylist%3Flist%3DPLNOffh-6mSoRfxD4wTvRziUDUiSLSyJKE&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FbDsqR6HBseY%2Fhqdefault.jpg%3Fsqp%3D-oaymwEWCKgBEF5IWvKriqkDCQgBFQAAiEIYAQ%3D%3D%26rs%3DAOn4CLCW9F5TIZ2LgpNrrADpInVGbH3_eg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="853" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/429bbb9f37fb2c90f18fa63057cb88e3/href">https://medium.com/media/429bbb9f37fb2c90f18fa63057cb88e3/href</a></iframe><p><em>Note:</em> We used Mongoose OS Community Edition, which is free, licensed under Apache 2.0.</p><h4>2) Mongoose OS installation on ESP32</h4><p>This installation has to be performed on each device.</p><p>We head to the <strong>developers section</strong> of Mongoose OS web site ([<a href="https://mongoose-os.com/docs/quickstart/setup.md">link</a>]) in order to perform the <strong>first seven steps</strong> of the list given in this resource:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1022/1*LZbBhMBqdngkZwdJrmtANg.png" /><figcaption>Mongoose OS setup steps</figcaption></figure><p><strong>Step #1</strong>, <strong>Step #2</strong> and <strong>Step #3</strong> are trivial. At Step #3 don’t forget to connect the device to the host machine via a USB cable.</p><p>For <strong>Step #4 </strong>“Create new app”, we choose to call the app app1. When mos clone https://github.com/mongoose-os-apps/demo-js app1 indicated on the web site is completed, mos tool automatically goes to the just created app1/ folder.</p><p>In app1/fs/ folder, there is a source file called init.js. It is a demo file capable to communicate with different IoT platforms (if they are configured of course). We will basically test it and soon simplify it for our purposes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5GYs7d1Ws_km6oDnWPaa6Q.png" /><figcaption><strong>mos tool</strong> launched in a UI ; ESP32 selected; Serial console (on the right) is by default at 115200 bds, ESP32’s default speed.</figcaption></figure><p><strong>Step #5</strong> “Build app firmware” is launched with mos build command (add --arch esp32 to this command if you launch it from a Command Line Terminal, not from mos tool). It may take a while but normally we have to perform this build only once. After it, we have many more files. One called app1/build/fw.zip contains the binaries of the OS and init.js. It will be flashed to ESP32 in the next step.</p><p><strong>Step #6</strong> “Flash firmware” is launched with mos flash command. It has normally to be done just once. Even if later we change some files (like init.js for instance), we will use a mos put command to upload a file from the host machine to the <strong>local device’s file system</strong>. Of course this command is only available after the flash process.</p><p><em>Note:</em> Firmware flash step can be tricky with a brand new ESP32. With our ESP32 DEVKIT V1, we had messages in console (that’s a first good point!) reporting issues about failing to connect to ESP32 ROM. Retrying to flash by pressing the BOOT button (closed to USB connector) finally turned out to a successful flash. Though, be ready to wait for one minute or two.</p><p>Then, the device automatically reboots and executes init.js. We obtained every second the following information in mos console (or in any serial terminal @115200 bds) :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/884/1*0i3bn3fhEkAolrkfvBjQVg.png" /><figcaption>Console after initial ESP32 flash firmware with Mongoose OS</figcaption></figure><p>In <strong>Step #7</strong> we connect ESP32 to our Wi-Fi network (we use mos tool):</p><pre>mos wifi WIFI_NETWORK_NAME WIFI_PASSWORD</pre><p>The device will reboot by itself after getting an IP address and synchronizing time by contacting a SNTP server. We then ping our device to check its internet connexion.</p><p><em>Note: </em>We get device information (IP address for instance) by hitting <strong>CTRL+i </strong>in mos tool, or by typing mos call Sys.GetInfo.</p><p><em>Note: </em>We reset the device by hitting <strong>CTRL+u</strong> in mos tool, or by typing mos call Sys.Reboot.</p><p><em>Note: </em>Steps #5, #6 and #7 could be the beginning of a “provisioning script”, useful if we have many devices to setup. It is optional to rerun Step #5 if all devices are the same, <em>e.g.</em> only ESP32.</p><h4>3) ESP32 “Hello, World!” program with Mongoose OS</h4><p>To get used to Mongoose OS JS programming style and mos tool, let’s write a small program whose aim is to make the blue built-in LED blink and print messages on console. <strong>This led is connected to GPIO2 pin</strong> of ESP32 DEVKIT V1 (see Assembly Diagram at the beginning of this post). On our host machine, let’s replace the content of app1/fs/init.js by this one:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7588ba61b732872a9a5f00c76017b662/href">https://medium.com/media/7588ba61b732872a9a5f00c76017b662/href</a></iframe><p>From mos tool or from a Command Line Terminal, we upload this file to Mongoose OS file system and finally we reboot the device:</p><pre>mos put fs/init.js<br>mos call Sys.Reboot</pre><p>The blue led should blink and we should see alternatively Tick and Tock printed on console.</p><h4>4) DHT22 test with Mongoose OS</h4><p>At the beginning of this post, there is an Assembly Diagram showing how to connect DHT22 sensor with ESP32 DEVKIT V1. We chose to connect <strong>DHT22 data pin</strong> <strong>to GPIO0 of ESP32 DEVKIT V1</strong>.</p><p>So, here is another short init.js program. This one prints periodically to serial console DHT22 measures (temperature and humidity - as an object in JSON, no MQTT publication yet):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1a5ddf7eee10ee76e77a01ee189ae780/href">https://medium.com/media/1a5ddf7eee10ee76e77a01ee189ae780/href</a></iframe><p>Then:</p><pre>mos put fs/init.js<br>mos call Sys.Reboot</pre><p>And this is the related console we get after uploading the init.js program and rebooting the device. Humidity is in % and temperature is in Celsius degrees:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/626/1*2xr980fPqZCYC84iUq4qEw.png" /><figcaption>DHT22 measures as printed to console. A bit too accurate, isn’t it ?</figcaption></figure><p>Numbers seem to have a long decimal part but this will be fixed later within a Cloud Function.</p><p><em>Note:</em> For pedagogical purposes, we chose all over this post explicit long key names like temperature or humidity. This will have consequences on the volume of data stored later in a NoSQL database (Firebase Realtime Database) as those keys will be repeated for each measure. Shorter key names could be a good idea.</p><h4>5) Let’s publish data to the MQTT telemetry topic</h4><p><strong>This is our last program, the one ready to work with Cloud IoT Core!</strong> On the previous program, we just add a publication to the telemetry topic we already talked about: /devices/{device-id}/events.</p><p>Note that messages are published in JSON as it will facilitate later their content retrieval with the Firebase Cloud Function reacting to messages publication.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3e9fd42be8ae0ab9d396271443eec67a/href">https://medium.com/media/3e9fd42be8ae0ab9d396271443eec67a/href</a></iframe><p>We name this file init.js, upload it to Mongoose file system, then provoke a reset:</p><pre>mos put fs/init.js<br>mos call Sys.Reboot</pre><p><em>Note: </em>These commands could be appended to the “provisioning script” we mentioned earlier.</p><p>When running, this last program prints data to console but it fails to publish data to the MQTT bridge of Cloud IoT Core (MQTT.pub() returns 0):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/646/1*Q-FIqugYuMQGd5rjjeu56Q.png" /><figcaption>Telemetry data can still not be published as we haven’t set up a Google Cloud project yet.</figcaption></figure><p>Indeed, we haven’t set up any Google Cloud project yet, neither <em>a fortiori </em>registered a single device to it. Let’s do it now!</p><h3>Cloud IoT Core project setup</h3><h4>1) Google Cloud SDK installation</h4><p>Firstly we need to <strong>install Google Cloud SDK</strong> because we will have to type some <strong>gcloud commands</strong> in a Command Line Terminal. At the time of writing, it requires Python 2.7. It won’t work with Python 3.5. The Google Cloud SDK download page ([<a href="https://cloud.google.com/sdk/downloads">link</a>]) offers versions of the SDK with Python bundled inside (if you’re sure you don’t have Python already installed and don’ t want to handle this Python point).</p><p>Then, Cloud IoT Core requires some <strong>Beta versions of </strong><strong>gcloud commands</strong>. So in a Command Line Terminal, from any folder, we type:</p><pre>gcloud components install beta</pre><p>These two previous steps have to be done just one time!</p><p><em>Note:</em> Most of the following actions on Google IoT Core can be performed in three ways:</p><ul><li>with <strong>Google Cloud Console</strong> (on the web)</li><li>with <strong>some APIs</strong> in different languages, and</li><li>with <strong>Command Line Interface</strong> in a terminal, typing gcloud commands.</li></ul><p>We will use the latter to configure things and we’ll check facts with Google Cloud Console (on the web).</p><h4>2) Google Cloud project setup</h4><p>We follow now this guide from Mongoose OS web site : [<a href="https://mongoose-os.com/docs/quickstart/cloud/google.md">link</a>].</p><pre><strong># Commands indicated in this grey frame have to be done just once to configure the Google Cloud project! They can be performed from any folder.</strong></pre><pre><strong># Get authenticated with Google Cloud</strong><br>gcloud auth login</pre><pre><strong># Create cloud project. We chose <em>hello-cloud-iot-core</em> as PROJECT_ID</strong><br>gcloud projects create <em>hello-cloud-iot-core</em></pre><pre><strong># Give Cloud IoT Core permission to publish to Pub/Sub topics</strong><br>gcloud projects add-iam-policy-binding <em>hello-cloud-iot-core</em> --member=serviceAccount:cloud-iot@system.gserviceaccount.com --role=roles/pubsub.publisher</pre><pre><strong># Set default project for gcloud</strong><br>gcloud config set project <em>hello-cloud-iot-core</em></pre><pre><strong># Create Pub/Sub topic for device telemetry<br></strong>gcloud beta pubsub topics create <em>weather-telemetry-topic</em></pre><pre><strong># Create a Pub/Sub subscription to the just created topic</strong><br>gcloud beta pubsub subscriptions create --topic <em>weather-telemetry-topic</em> <em>weather-telemetry-subscription</em></pre><pre><strong># Create devices registry (we call it <em>weather-devices-registry</em>)<br># Precise Pub/Sub topic name for event notifications</strong><br><strong># Disallow device connections to the HTTP bridge</strong><br>gcloud beta iot registries create <em>weather-devices-registry</em> --region europe-west1 --no-enable-http-config --event-notification-config=topic=<em>weather-telemetry-topic<br></em><strong># Say &#39;yes&#39; to enable API (if prompted).<br># But the last command may however not work<br># if you don&#39;t enable billing.<br># So, follow the link to enable billing and retry last command.<br># It should end up to &quot;</strong>Created registry [weather-devices-registry].&quot;</pre><h4>3) Device registration within the Cloud IoT Core project</h4><p>Let’s now register the devices to the project! One at a time of course. <strong>mos tool is really helpful for this task. </strong>From mos tool launched in its UI or from Command Line Terminal, placed in our app1 folder, we type the following command (project id and registry name are involved, as you see):</p><pre><strong># Register device with Cloud IoT Core (do it for each device!)</strong><br>mos gcp-iot-setup --gcp-project <em>hello-cloud-iot-core</em> --gcp-region europe-west1 --gcp-registry <em>weather-devices-registry</em></pre><p><em>Note: </em>This command could be the last one of the “provisioning script” we mentioned already twice.</p><p>This command is a mos command that will itself use gcloud commands. The device about to be registered must be connected via the serial port to our host computer because some information will be uploaded to it just like a private key, MQTT bridge address, etc.</p><p>Indeed, we see on mos console that <strong>two keys (one private, one public) are generated</strong>. We can inspect them in app1 project folder. The private one is for ESP32 and the public one is for Google IoT Core. They are used during the authentication process involving the JSON Web Token we mentioned earlier.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/354/1*iVJ-dbpnqmQJqwuGFC917A.png" /><figcaption>Pair of keys just generated (private and public)</figcaption></figure><p><em>Note concerning security: </em><strong>The private key shouldn’t be stored in plain text in ESP32 flash memory</strong>. This is why we describe in the post following this one ([<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-2nd-config-state-encrypt-7c5e937e5be9">link</a>]) how to encrypt this memory. Also, <strong>the private key file shouldn’t be stored in plain text on the host development computer</strong>. At least, protect access to its content with a password.</p><p>When the device reboots, we see in the console that it successfully connects to the Google MQTT bridge and publishes telemetry messages (MQTT.pub() returns 1):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/646/1*H9T-zF4B-HwYgO_ZdratEw.png" /><figcaption>Publications to MQTT bridge are successful. Nice job!</figcaption></figure><h4>4) Checking the project setup in Google Cloud Console</h4><p>We head to <a href="https://console.cloud.google.com/iot/">https://console.cloud.google.com/iot/</a> to check that everything was well configured:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/936/1*BeVR0exU6l-rXg8LqJvfeQ.jpeg" /><figcaption>Project ID, registry ID and telemetry Pub/Sub topic name in Google Cloud Console</figcaption></figure><p>Clicking on the <strong>Registry ID</strong> weather-devices-registry reaches another screen. Clicking on “Devices” on this new screen lists provisioned devices and gives details like the last time they were seen (but this is not live updated, we have to refresh the page):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sfa7ErglL4OqCsk2jIZqUA.png" /><figcaption>Devices View in Google Cloud Console</figcaption></figure><p>Otherwise, if we click on the <strong>Telemetry Pub/Sub topic</strong> name (here: projects/hello-cloud-iot-core/topics/weather-telemetry-topic), we reach the <strong>Pub/Sub console</strong>, that shows the subscription we created before, <em>i.e.</em> the one related to the telemetry topic:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/760/1*EQ1r5SozuzjM5Jrbl4vdVg.png" /><figcaption>Google Cloud Console (Pub/Sub) — names of topic and related subscription</figcaption></figure><h4>5) Viewing at last some telemetry data</h4><p>Now it would be nice to see the data that devices are publishing. For this, we have the subscription we already created. From any folder of the host computer, we type:</p><pre>gcloud beta pubsub subscriptions pull --auto-ack <em>weather-telemetry-subscription </em>--limit=<strong><em>2</em></strong></pre><p>This command ([<a href="https://cloud.google.com/sdk/gcloud/reference/beta/pubsub/subscriptions/pull">link</a>]) pulls until <strong><em>2</em></strong> Pub/Sub messages from our weather-telemetry-subscription subscription. We can see data in JSON, messages ids and a list of attributes for each message. Among them the deviceId attribute is present. Unfortunately there are no timestamps, we’ll see how to get them later.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/946/1*78OYVPPUeKZWRRvlWdI4Mg.png" /><figcaption>Result of pulling telemetry messages from a subscription</figcaption></figure><blockquote>If you have reached this milestone, congrats! We’re now ready to write a Firebase Cloud Function that subscribes to the Pub/Sub telemetry topic!</blockquote><h3>Logging, storing and visualizing weather data with Firebase</h3><h4>1) Introduction</h4><p>We’re now tackling this part of the project:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/503/1*UwR_qn8GX1b2CkMA62kT3w.png" /><figcaption>The part we study now</figcaption></figure><p>On that diagram, we see that our project needs 3 Firebase products :</p><p>A <strong>Firebase Cloud Function</strong> (more exactly “a Cloud Function for Firebase”) must react to any publication to the telemetry topic in order to store the weather data of this publication to a <strong>Firebase Realtime Database</strong>. This storage allows weather data persistence and is used to feed a web app hosted by <strong>Firebase Hosting</strong>. This web app draws live plots of this weather data across time.</p><p>The good new is that it’s possible to configure all these products with one command.</p><h4><strong>2) Firebase configuration, GitHub repository</strong></h4><p>We are still working on the same Google Cloud project called hello-cloud-iot-core. Firebase will just “enhance” this project with its products.</p><p>We made a GitHub repository for the Firebase aspects of our project:</p><p><a href="https://github.com/olivierlourme/iot-store-display">olivierlourme/iot-store-display</a></p><p>Clone this repository in your favorite development folder and head to the newly created directory:</p><pre><strong>c:\_app&gt;</strong>git clone https://github.com/olivierlourme/iot-store-display<br><strong>c:\_app&gt;</strong>cd iot-store-display</pre><p><strong>Global Firebase configuration</strong></p><p><em>Note:</em> We suppose you have <strong>Firebase tools</strong> installed (<em>i.e. </em>Node.js was installed and then npm install -g firebase-tools was run, see [<a href="https://firebase.google.com/docs/functions/get-started">link</a>] for details).</p><p>Let’s perform the Firebase initializations:</p><pre><strong>c:\_app\iot-store-display&gt;</strong>firebase init </pre><p>First step is to choose Firebase products we want to use:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*FYoZkLMMrQBQDflK8Z46fQ.png" /><figcaption>Choosing Firebase products</figcaption></figure><p>We are then prompted to associate the current directory (iot-store-display) with one of the listed Firebase projects. The problem is that our project hello-cloud-iot-core doesn’t appear in the list because before being a Firebase project it’s also a Google Cloud project! Read <a href="https://medium.com/u/6a53613f4e6d">Doug Stevenson</a>’s posts for relationships between Firebase and Google Cloud: [<a href="https://medium.com/google-developers/whats-the-relationship-between-firebase-and-google-cloud-57e268a7ff6f">link</a>] and [<a href="https://medium.com/google-developers/firebase-google-cloud-whats-different-with-cloud-functions-612d9e1e89cb">link</a>].</p><p>To overcome this, first we hit CTRL+C to stop this initialization process and then we go to<strong> Firebase Console</strong> at <a href="https://console.firebase.google.com/">https://console.firebase.google.com</a>. We choose “Add a project”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/606/1*nOcFfL_ZwGUKGe-PDnsZUQ.png" /><figcaption>Firebase Console — Add a project</figcaption></figure><p>And we can see our project (with Google Cloud logo) and choose it:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/392/1*QqI3k8bH5P348eAInetTOQ.png" /><figcaption>Firebase Console — Even Google Cloud projects are listed.</figcaption></figure><p><em>Note:</em> You might then be asked to confirm Firebase billing plan if the Google Cloud project itself has a billing plan.</p><p>Great! We restart the Firebase initialization with firebase init command and this time our Google Cloud project hello-cloud-iot-core is listed. We choose it:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/513/1*qr4CKgpdnEG9UorzVv3yrw.png" /><figcaption>Our <strong>iot-store-display</strong> directory is associated with <strong>hello-cloud-iot-core </strong>project.</figcaption></figure><p><em>Note:</em> If you still don’t see your project you might be logged to Firebase without the correct Google account. In this case, type firebase logout followed by firebase login.</p><p><strong>Realtime Database configuration</strong></p><p>Then the wizard asks a single question about the Realtime Database and its rules: the name of the file where they will be saved. We opt for the default proposed name database.rules.json. It’s more practical to have these rules in a file lying in the project directory than to go to Firebase Console as we did in past posts. We will detail these rules later.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*YtlGoKNyjspvirVxSoXYNg.png" /><figcaption>Name of the file storing Realtime Database rules</figcaption></figure><p><strong>Cloud Functions configuration</strong></p><p>Here are the answers we made to the wizard concerning Functions Setup:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/733/1*ml7Pc1OSEgqi6dRsy5J_aA.png" /><figcaption>Cloud Functions setup</figcaption></figure><p>Of course, we choose not to overwrite the functions/index.js file obtained from <a href="https://github.com/olivierlourme/iot-store-display">GitHub</a>.</p><p>UPDATE Feb. 21, 2021: Two years after the initial release of this project we had to update the Cloud Function because the version of node.js it used had gone deprecated. For simplicity, we chose not to use Firebase tools but to edit this Cloud Function inline with GCP console. It is summarized here: <a href="https://stackoverflow.com/questions/66279936/from-the-gcp-console-can-we-write-a-gcp-cloud-function-interacting-with-firebas">https://stackoverflow.com/questions/66279936/from-the-gcp-console-can-we-write-a-gcp-cloud-function-interacting-with-firebas</a></p><p><strong>Firebase Hosting configuration</strong></p><p>And here are the answers we made to the wizard concerning Hosting Setup:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/704/1*F_7qI1Norg4qjQfPhouCWw.png" /><figcaption>Hosting setup</figcaption></figure><p>Of course we choose not to overwrite the public/index.html file obtained from <a href="https://github.com/olivierlourme/iot-store-display">GitHub</a>.</p><p><strong>Deploying (not now!)</strong></p><p>Later, if we want to deploy some updates we made to our 3 products, we can type globally:</p><pre><strong>c:\_app\iot-store-display&gt;</strong>firebase deploy</pre><p>But if we want to deploy only, respectively:</p><ul><li>updated database rules,</li><li>updated cloud functions,</li><li>updated web app,</li></ul><p>we type, respectively:</p><pre>firebase deploy --only database<br>firebase deploy --only functions<br>firebase serve --only hosting <em>(local deployment)</em> OR firebase deploy --only hosting <em>(remote deployment)</em></pre><h4>3) Pub/Sub trigger Cloud Function</h4><p><strong>Introduction</strong></p><p>In a past post, we explained that we could write <strong>Firebase Cloud Functions</strong> triggered on some events happening to some of the Google products.</p><p><a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">Post 2 of 3. Our IoT journey through ESP8266, Firebase and Plotly.js</a></p><p><strong>Cloud Pub/Sub</strong> is one of these products and so it is possible to trigger a function each time a message is published to a Pub/Sub topic : [<a href="https://firebase.google.com/docs/functions/pubsub-events">link</a>].</p><p>So if the Firebase Cloud Function is triggered on each publication to the weather-telemetry-topic topic, watching its log will allow us to watch the telemetry topic’s activity.</p><p>The code of the Cloud Function has to store each new published data to the Firebase Realtime Database associated with our project.</p><p><strong>Cloud Function source code</strong></p><p>The beginning of the source code looks like this:</p><pre>exports.detectTelemetryEvents = functions.pubsub.topic(&#39;weather-telemetry-topic&#39;).onPublish(<br>    (message, context) =&gt; {...</pre><p>The full Cloud Function source code lies in the file named index.js. This file is in the functions folder of our iot-store-display directory on <a href="https://github.com/olivierlourme/iot-store-display">GitHub</a>. It is fully commented, so run and study it, it’s short and not complicated.</p><p><strong>Cloud Function deployment</strong></p><p>It’s time to deploy the Cloud Function:</p><pre><strong>c:\_app\iot-store-display&gt;</strong>firebase deploy --only functions</pre><p><strong>Cloud Function validation</strong></p><p>Once Cloud Function is deployed, we can watch the Cloud Function logs and among other things, we’ll see the results of the console.log(`Device=${deviceId}...) we wrote at the end of index.js.</p><p>Where to see those logs? We have two opportunities:</p><ul><li>in Firebase Console (<a href="https://console.firebase.google.com/">https://console.firebase.google.com</a>):</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SH9086pyf8yyuEnyCDu0UQ.png" /><figcaption>Firebase Console — Firebase Cloud Functions logs</figcaption></figure><ul><li>in Google Cloud Console (<a href="https://console.cloud.google.com/functions/">https://console.cloud.google.com/functions/</a>):</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*D3QmCuAsqE5jUkuIyPTB-w.png" /><figcaption>Google Cloud Console — Access to <strong>Cloud Function logs</strong> and to <strong>Cloud Function deletion</strong></figcaption></figure><p>We prefer this latter solution, as logs are clearer:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kgpwdupeMVLKQ2msHpO4cQ.png" /><figcaption>Google Cloud Console- Cloud Functions logs</figcaption></figure><p>Concerning storage, here is what lies in Firebase Realtime Database after each device has made 2 telemetry data publication. Data is of course sorted by device as we specified it in index.js:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1011/1*gJX7raPOkRvRZzAHhQC14Q.png" /><figcaption>Firebase Console — Realtime Database after 2 telemetry data publications per device</figcaption></figure><p><em>Note: </em>Don’t forget to <strong>delete your Cloud Function</strong> on Google servers if you don’t use it, otherwise you might either reach the invocation quota or pay for service you don’t use, as indicated here: [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>]. Function deletion is to be performed on Google Cloud Console (see “Delete”, 3 screenshots above).</p><p><em>Note:</em> The Cloud Function has admin rights over the database, whatever is the content of the database.rules.json file. At this step, the database.rules.json file can still be very restrictive. Don’t forget to deploy them, once edited.</p><pre>{<br>  &quot;rules&quot;: {<br>    &quot;.read&quot;: false,<br>    &quot;.write&quot;: false<br>  }<br>}</pre><h4>4) A web app using Firebase and plotlys.js to visualize weather data</h4><p><strong>Introduction</strong></p><p><em>Note:</em> We’re now building a “homemade” (and satisfying) data visualization solution. For enhanced UI (dashboard, etc.), maybe you should investigate Data Studio we already mentioned elsewhere in this post.</p><p>We focus on <strong>building a small web</strong> app, hosted by <strong>Firebase Hosting</strong>. This web app <strong>lively plots</strong> the data stored in the Firebase Realtime Database. We used <a href="https://medium.com/u/5fdd6522cd45">plotly</a> (<a href="https://plot.ly/javascript/">https://plot.ly/javascript/</a>) for the plotting library. We are familiar with that work as we already undertook a similar one in a previous post:</p><p><a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4">Post 3 of 3. Our IoT journey through ESP8266, Firebase and Plotly.js</a></p><p>What’s different today is that we have to:</p><ul><li>draw several charts: temperature <em>vs</em> time and humidity <em>vs</em> time,</li><li>inside each chart, we have one plot per device.</li></ul><p><strong>Database rules &amp; devices-ids node</strong></p><p>Concerning the database rules, what should be now the database.rules.json file? The device-telemetry node needs to be <strong>read </strong>by the web app. And if you looked attentively at the Realtime Database screenshot given a few screenshots before, there is another node called devices-ids.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/335/1*Si6-O12MUJXpzN3qyZyBVg.png" /><figcaption>Firebase Console — Detail of devices-ids node in Realtime Database</figcaption></figure><p>You need to create <strong>manually in the Firebase Console</strong> this devices-ids node and fill it appropriately for the web app to work properly. It is a simple mean to declare to the web app the devices we want plots for and also to give aliases to the devices. Its role and necessity are fully explained in comments of the public/script.js file given in <a href="https://github.com/olivierlourme/iot-store-display">GitHub</a>.</p><p><em>Note:</em> An improvement could be a form (accessed through authentication) that, once fulfilled, calls a script to generate this devices-ids node.</p><p>This devices-ids node also needs to be read by the web app. So the database.rules.json file should eventually become:</p><pre>{<br>  &quot;rules&quot;: {<br>    &quot;devices-ids&quot;: {<br>      &quot;.read&quot;: true,<br>      &quot;.write&quot;: false<br>    },<br>    &quot;devices-telemetry&quot;: {<br>      &quot;.read&quot;: true,<br>      &quot;.write&quot;: false<br>    }<br>  }<br>}</pre><p>These new rules, once edited and saved, must be deployed with:</p><pre><strong>c:\_app\iot-store-display&gt;</strong>firebase deploy --only database</pre><p><strong>Web app source code</strong></p><p>The web app source code lies in the public directory of our hello-cloud-iot-core folder or in <a href="https://github.com/olivierlourme/iot-store-display">GitHub</a>. The content of the folder, especially script.js, is fully commented so you know where to study (and improve!) it.</p><p><em>Note: </em>we have only two devices for this demo but the source code is okay for <em>x</em> devices as long as you declare them in the devices-ids node.</p><p><strong>Web app local deployment and validation</strong></p><p>For testing purposes, Firebase Hosting can launch a local live server:</p><pre><strong>c:\_app\iot-store-display&gt;</strong>firebase serve --only hosting</pre><p>We head to http://localhost:5000 and we’re happy to get this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/828/1*02UfatBLkuqCD12-JNBgjw.gif" /><figcaption>At last the charts we wanted!</figcaption></figure><p><strong>Web app remote deployment</strong></p><p>At last, Firebase offers us the hosting of our web app and an access to it via https:</p><pre><strong>c:\_app\iot-store-display&gt;</strong>firebase deploy --only hosting</pre><p>We quickly get the public URL of our web app : <a href="https://hello-cloud-iot-core.firebaseapp.com/">https://hello-cloud-iot-core.firebaseapp.com</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/534/1*EZjq0siYgb0K6sMaFHlk4Q.png" /><figcaption>Web app deployment is complete!</figcaption></figure><p><em>Note: </em>If you have your own domain, you can connect your Firebase web app to it. See [<a href="https://firebase.google.com/docs/hosting/custom-domain">link</a>].</p><h3>Conclusion</h3><p>In this post we discovered how to combine <strong>ESP32</strong>, <strong>Mongoose OS</strong> and <strong>Cloud IoT Core, </strong>obtaining a serious, secure and <strong>professional IoT project</strong>. Now that we know, it can go really fast to provision 10, 100… 1000 devices acquiring weather data all over an area, as long as they can get a Wi-Fi connection. Now, devices are centrally managed, it is easy to provision and monitor them. But we can go further!</p><p>Indeed, in addition to this post, there is a second one ([<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-2nd-config-state-encrypt-7c5e937e5be9">link</a>]). Inside it:</p><ul><li>We’ll focus on ESP32 flash <strong>memory encryption</strong>, to achieve a fully secured system.</li><li>We’ll see how to use the config special topic, allowing us to <strong>trig an action on the device from the Google Cloud Console</strong>.</li><li>We’ll see how to use the state special topic, allowing <strong>the device to communicate to Google Cloud Console informations about its current state</strong>.</li></ul><p>We hope you enjoyed this really long post and that you learnt something! Don’t hesitate to ping me if you have any questions or improvement suggestions…</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5c88d8134ac7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/free-code-camp/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7">How to check the weather using GCP-Cloud IoT Core with ESP32 and Mongoose OS</a> was originally published in <a href="https://medium.com/free-code-camp">We’ve moved to freeCodeCamp.org/news</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Post 3 of 3. Our IoT journey through ESP8266, Firebase and Plotly.js]]></title>
            <link>https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4?source=rss-48724cb81b49------2</link>
            <guid isPermaLink="false">https://medium.com/p/644048e90ca4</guid>
            <category><![CDATA[iot]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[esp8266]]></category>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[plotly]]></category>
            <dc:creator><![CDATA[Olivier LOURME]]></dc:creator>
            <pubDate>Wed, 12 Dec 2018 15:08:42 GMT</pubDate>
            <atom:updated>2021-09-14T06:29:43.337Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*akvkk9FZFyIW3JWLXsBgTQ.png" /><figcaption>Science moves forward :-)</figcaption></figure><h3>TL;DR</h3><p>My Medium home page is <a href="https://medium.com/@o.lourme">here</a>.</p><p>This post stands in a series of 3 as detailed below. These 3 posts reflect the Project Architecture we chose to achieve a simple luminosity logging/live plotting project. We hope they will <strong>help developers or students discovering ESP8266 chip and Firebase platform</strong>. Moreover, we believe that the solution developed here can be an interesting alternative to the comprehensive <strong>Google, AWS and Azure IoT solutions</strong> [<a href="https://cloud.google.com/solutions/iot/">link</a>, <a href="https://docs.aws.amazon.com/fr_fr/iot/latest/developerguide/what-is-aws-iot.html">link</a> and <a href="https://docs.microsoft.com/fr-fr/azure/iot-hub/iot-hub-device-management-overview">link</a>] when we have to <strong>manage in a simple way only a few connected devices</strong>. (For instance, we won’t set up a MQTT broker neither deal with a device registry.)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*J0IGNrEAq3n8zxCZsLO5dQ.png" /><figcaption>Project Architecture — Numbers 1, 2, 3 follow posts numerotation</figcaption></figure><p><strong>Post 1</strong> [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>]: We investigate on how an <strong>ESP8266</strong> can regularly make acquisition of an analog data and push its 10-bit equivalent value to a <strong>Firebase Realtime Database</strong>. We finish with considerations on <strong>ESP8266 power saving.</strong></p><p><strong>Post 2</strong> [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>]: We write a <strong>Firebase Cloud Function</strong> in Typescript language to <strong>timestamp </strong>the data just pushed to Firebase Realtime Database.</p><p><strong>Post 3</strong> (this post): With a<strong> </strong>web app using <strong>plotly.js library</strong>, we lively plot in a browser the analog data versus time. The web app is hosted with <strong>Firebase Hosting</strong>.</p><p><strong><em>Post 3. A web app hosted by Firebase Hosting susbscribes to the data stream coming from a Firebase Realtime Database and plot it.</em></strong></p><h3>A) Where we left</h3><p>At the end of Post 1 [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>], an ESP8266 regularly pushed the 10-bit luminosity measure it just made to the measures node of a Firebase Realtime Database:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/466/1*6aFAQyXJo3nQ-0BUjf45Rw.gif" /><figcaption>Firebase Console — Each pushed value of luminosity is associated with a unique PushID</figcaption></figure><p>At the end of Post 2 [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>], each time a push was made to measures node, a Firebase Cloud Function associated a timestamp to that push. The obtained object was then pushed to timestamped_measures node of the Firebase Realtime Databse:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/436/1*MSioPaOnDex_OP_0qWbS0w.gif" /><figcaption>Firebase Console — Cloud Function at work!</figcaption></figure><p>Now, that would be nice if a <strong>web app</strong>, each time a timestamped measure is pushed to timestamped_measures node, could get the last 200 (for instance) timestamped measures in that node in order to replot measures versus timestamps. <strong>Firebase SDK</strong> makes that subscription really easy and <a href="https://medium.com/u/5fdd6522cd45">plotly</a> ( <a href="https://plot.ly/javascript/">https://plot.ly/javascript/</a>) plots data with no pain!</p><p>Indeed, at the end of this third and last post describing our ESP8266-based project, we will get this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/898/1*VqqpujaI-nPgRzWCquzO5w.gif" /><figcaption>What we will achieve at the end of this post!</figcaption></figure><h3>B) Angular web app or “classical” web app?</h3><p>When we hacked this small project (5 months ago), before writing the 3 related Medium posts, we used <strong>Angular</strong> framework [<a href="https://angular.io/">link</a>] to write the web app. We believed we would use it in this last post of the series, that’s why it is mentioned in the 3 posts URLs. But, as we published our first (4 months ago) and second (2 months ago) Medium posts [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>, <a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>], it turned out that this project could be <strong>a basis for students discovering IoT</strong>, even if they were not initially developers. In that context, we cannot ask them to learn Angular before diving into the IoT topic, that would really be discouraging. So, as our project went eventually more newbies oriented, we will explain here how to write the web app “classically”, <em>i.e. </em>with <strong>html</strong>, <strong>javascript</strong> and <strong>css</strong> files. It’s not possible to change Medium posts URLs afterwards, that’s why “Angular” remains in them and we’re sorry for that. That’s not bad marketing!</p><p><em>Note: </em>If you want to write the web app with Angular all the same, follow the excellent resource mentioned in the <strong>Acknowledgments</strong> section at the end of this post. We ourselves started with it.</p><h3>C) Project description and setup</h3><p><em>Note:</em> Each time there is an action to perform, it is preceeded by a lowercase letter like <strong>a. b. c. </strong>etc.</p><p><strong>a.</strong> Head to the <strong>project GitHub repository</strong> to see the full source code of our web app: <a href="https://github.com/olivierlourme/esp8266webapp">https://github.com/olivierlourme/esp8266webapp</a>. There is even a link to a live demo.</p><p><strong>b.</strong> Clone the repository in your development folder (or download it if you don’t have git installed):</p><pre><strong>c:\_APP&gt;</strong>git clone https://github.com/olivierlourme/esp8266webapp.git</pre><p><strong>c. </strong>Move to the just generated project directory and launch VS code over it:</p><pre><strong>c:\_APP&gt;</strong>cd esp8266webapp<br><strong>c:\_APP\esp8266webapp&gt;</strong>code .</pre><p><em>Note:</em> In Post 2 [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>], we had developed the cloud function in a esp8266 folder. We could develop our web app in the same folder as it is just another feature of the project. But to keep presentation clear and posts independent, we chose another folder for the web app.</p><p><em>Note: </em>The files of the web app are all in a public folder in order to prepare <strong>Firebase Hosting</strong> detailed at the end of this post.</p><p>Let’s briefly explain the role of index.html and script.js files present in the public folder. We won’t go much into details as <strong>the source code is fully commented on the github repository</strong>.</p><p>index.html:</p><ul><li>index.html includes the <strong>Firebase SDK</strong> scripts that allows manipulation of the Firebase Realtime Database of the project. For details, see <a href="https://firebase.google.com/docs/web/setup">https://firebase.google.com/docs/web/setup</a>.</li></ul><pre>&lt;!-- Firebase App is always required and must be first --&gt;<br>&lt;script src=&quot;<a href="https://www.gstatic.com/firebasejs/5.5.9/firebase-app.js">https://www.gstatic.com/firebasejs/5.5.9/firebase-app.js</a>&quot;&gt;&lt;/script&gt;<br>&lt;!-- Add additional services that you want to use --&gt;<br>&lt;script src=&quot;<a href="https://www.gstatic.com/firebasejs/5.5.9/firebase-database.js">https://www.gstatic.com/firebasejs/5.5.9/firebase-database.js</a>&quot;&gt;&lt;/script&gt;</pre><ul><li>index.html includes the <strong>javascript plotting library</strong> named <strong>plotly.js</strong>. This powerful library, built on top of <a href="https://d3js.org/">d3.js</a> and <a href="https://github.com/stackgl">stack.gl</a>, makes insertion of sophisticated charts inside webpages really easy. See <a href="https://plot.ly/javascript/">https://plot.ly/javascript/</a></li></ul><pre>&lt;!-- Include Plotly.js --&gt;<br>&lt;script src=&quot;<a href="https://cdn.plot.ly/plotly-latest.min.js">https://cdn.plot.ly/plotly-latest.min.js</a>&quot;&gt;&lt;/script&gt;</pre><ul><li>index.html includes <strong>moment.js library</strong>. This library can convert timestamps expressed in Epoch time (milliseconds) to human readable dates. See <a href="https://momentjs.com/">https://momentjs.com</a>. For example: moment(1543658683000).format(&#39;YYYY-MM-DD HH:mm:ss&#39;) would produce <br> &#39;2018–12–01 11:04:43&#39; for a computer with a GMT+01:00 timezone.</li></ul><pre>&lt;!-- Include the moment.js library --&gt;<br>&lt;script src=&quot;<a href="https://momentjs.com/downloads/moment.js">https://momentjs.com/downloads/moment.js</a>&quot;&gt;&lt;/script&gt;</pre><ul><li>index.html has then in its &lt;body&gt; section an identified &lt;div&gt; where the plot will be placed.</li></ul><pre>&lt;!-- Plotly chart will be drawn inside this div. --&gt;<br>&lt;div id=&quot;myPlot&quot; style=&quot;width: 100vw; max-height:75vh&quot;&gt;&lt;/div&gt;</pre><ul><li>index.html includes at last the script.js script containing the essential part of the work.</li></ul><pre>&lt;!-- Include the script describing the work to do --&gt;<br>&lt;script src=&quot;script.js&quot;&gt;&lt;/script&gt;</pre><p>script.js:</p><ul><li>script.js defines in a const named config the <strong>Firebase Project Configuration</strong>. It doesn’t contain any sensitive information, it is a way for the web app to identify the Firebase project on Google servers. Anyway, it shouldn’t be exposed unnecessarily (for instance, if we use git, we place this const in a file named config.js, we reference it from script.js and we add config.jsto .gitignore).</li></ul><p><strong>d.</strong> To grab this Firebase Project Configuration, follow the 4 steps below and copy what’s in “5”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/540/1*MbKLLdH9Uus_BT79UV4hxQ.png" /><figcaption>Firebase Console — Obtaining Firebase Project Configuration</figcaption></figure><p><strong>e.</strong> Paste these informations to the beginning of script.js. You should end up with something like this:</p><pre>const config = {<br>  apiKey: &quot;&lt;API_KEY&gt;&quot;,<br>  authDomain: &quot;&lt;PROJECT_ID&gt;.firebaseapp.com&quot;,<br>  databaseURL: &quot;https://&lt;DATABASE_NAME&gt;.firebaseio.com&quot;,<br>  projectId: &quot;&lt;PROJECT_ID&gt;&quot;,<br>  storageBucket: &quot;&lt;BUCKET&gt;.appspot.com&quot;,<br>  messagingSenderId: &quot;&lt;SENDER_ID&gt;&quot;,<br>};</pre><ul><li>script.js then “subscribes” to the value changes in the Firebase Realtime Database node we want to plot: When a change occurs (<em>i.e.</em> a push to the node), an array of the nbOfElts <strong>last values</strong> of timestamp is made and also an array of the nbOfElts <strong>last values</strong> of luminosity. Those arrays then feed the x and y part of the plotly trace.</li></ul><pre>firebase.database()<br>  .ref(&#39;timestamped_measures&#39;)<br>  .limitToLast(nbOfElts) // gives the sliding effect!<br>  .on(&#39;value&#39;, ts_measures =&gt; {...</pre><p><em>Note: </em>The value of nbOfElts is up to you. For instance, if you have a delay of 5 minutes between measures, it makes 12 measures per hour. If you want a sliding plot covering a whole day, you need to assign to nbOfElts the value 24*12 = 288.</p><p><em>Note:</em> Our Firebase web app is made synced with the database since it connects to it through what we call <strong>WebSockets </strong>[<a href="https://en.wikipedia.org/wiki/WebSocket">link</a>]<strong> </strong>and not normal HTTP.</p><p><strong>f. </strong>Adapt <strong>Firebase Realtime Database rules</strong></p><p>It’s time to adapt rules that grant access to nodes of our database. At the end of Post 2 [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>], we had this:</p><pre>{<br>  &quot;rules&quot;: {<br>    &quot;measures&quot;: {<br>      &quot;.read&quot;: &quot;false&quot;,<br>      &quot;.write&quot;: &quot;false&quot; <br>    },<br>    &quot;timestamped_measures&quot;: {<br>      &quot;.read&quot;: &quot;false&quot;,<br>      &quot;.write&quot;: &quot;false&quot; <br>    }<br>  }<br>}</pre><p>But now, as we want our web app to read timestamped_measures node, with no kind of authentication, the rules have to be changed to this:</p><pre>{<br>  &quot;rules&quot;: {<br>    &quot;measures&quot;: {<br>      &quot;.read&quot;: &quot;false&quot;,<br>      &quot;.write&quot;: &quot;false&quot; <br>    },<br>    &quot;timestamped_measures&quot;: {<br>     <strong> &quot;.read&quot;: &quot;true&quot;,</strong><br>      &quot;.write&quot;: &quot;false&quot; <br>    }<br>  }<br>}</pre><h3>D) Starting a development server, configuring Firebase Hosting</h3><h4>D) 1) Description</h4><p>We’ll cover two topics here:</p><ul><li>start a <strong>development server</strong> to test locally our web app while improving it,</li><li>configure <strong>Firebase Hosting</strong> in order to have quickly our app hosted on a Google server.</li></ul><p>In fact, these topics are linked: As we will configure the use of a Firebase service (here the hosting one), we will benefit from the development server.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/649/1*0QDB-Fz8wElUwT41nSRLQQ.png" /><figcaption>Firebase Hosting logo</figcaption></figure><p><strong>a. </strong>To be sure to log-in to Firebase with the right account (<em>i.e. </em>the one who created the esp8266-rocksproject), we type first:</p><pre><strong>c:\_APP\esp8266webapp&gt;</strong>firebase logout</pre><p>Followed by:</p><pre><strong>c:\_APP\esp8266webapp&gt;</strong>firebase login</pre><p><strong>b.</strong> Once logged-in, we associate esp8266webapp folder with the Firebase services we want to use. Here we just want Firebase Hosting. Of course, we use also Firebase Realtime Database in this project, but it has already been included in index.html. So the command is:</p><pre><strong>c:\_APP\esp8266webapp&gt;</strong>firebase init hosting</pre><p><strong>c.</strong> A few questions are asked. Below, we put our responses in <strong>bold</strong>:</p><pre>? Are you ready to proceed? <strong>Yes<br></strong>? Select a default Firebase project for this directory: <strong>esp8266-rocks<br></strong>? What do you want to use as your public directory? <strong>public<br></strong>? Configure as a single-page app (rewrite all urls to /index.html)? <strong>No<br></strong>? File public/index.html already exists. Overwrite? <strong>No</strong></pre><p>A few files are generated (and a 404 page as well):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/448/1*BtZts2frIrFMEpRGOX7Pig.png" /></figure><h4>D) 2) Use of Firebase development server</h4><p><strong>d.</strong> Having initiated Firebase allows us to launch a <strong>local development server</strong>. We do it that way:</p><pre><strong>c:\_APP\esp8266webapp&gt;</strong>firebase serve --only hosting</pre><p><strong>e.</strong> We get the URL to test our web app and we paste it in a browser.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/437/1*IZGgyD7yhTPCGKlNUSVvPQ.png" /></figure><p>Fantastic! The app works! And each time a new measure arrives, the plot moves to the left.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/701/1*-hwA13v8hz0xnk8RjFEf6g.png" /><figcaption>The web app, locally tested</figcaption></figure><p><em>Note:</em> Now, we cannot have access anymore to the terminal that launched the Firebase development server because it is monopolized by this latter, displaying messages about the incoming connections and requests. If we need to stop the server, we hit CTRL + C. We can also open another terminal if we still need the server to work.</p><p><em>Note:</em> <strong>After saving a change made in the source code, we have to refresh the browser to test it</strong> because Firebase development server is not a live server like this one : [<a href="https://www.npmjs.com/package/live-server">link</a>].</p><h4>D) 3) Use of Firebase Hosting</h4><p>When we’re satisfied with our development, it’s time to host the web app.</p><p><strong>f. </strong>After hitting CTRL+C to stop Firebase development server, we just have to type this command:</p><pre><strong>c:\_APP\esp8266webapp&gt;</strong>firebase deploy --only hosting</pre><p>After a few seconds, deploy is complete and we get the public URL of our web app: <a href="https://esp8266-rocks.firebaseapp.com/">https://esp8266-rocks.firebaseapp.com</a> . We test it in a browser (you too!), it works perfectly!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/373/1*77Q0WEWSfKYKJJNOdrcUig.png" /><figcaption>Hosting URL of the web app</figcaption></figure><p><em>Note: </em>If you have your own domain, you can connect your Firebase web app to it. See [<a href="https://firebase.google.com/docs/hosting/custom-domain">link</a>].</p><h4>D) 4 ) How much data can be downloaded from the database?</h4><p>With <strong>Firebasebase “Spark” pricing plan</strong> (the free one), up to 10 GB/month can be downloaded. This can be quickly reached if:</p><ul><li>We have many points in the plot, <em>i.e.</em> if nbOfElts is high.</li><li>We have a high refresh rate for it.</li><li>Many people are connected to our web app!</li></ul><p>To know the current downloaded amount of data, we hit <strong>Project Overview</strong> in Firebase Console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/214/1*iJHD5-c9eccbYKSC_B-tXQ.png" /><figcaption>Firebase Console — Project Overview</figcaption></figure><h3>Conclusion</h3><p><strong>About this post</strong></p><p>That’s all for today! We now have a web app basis to monitor data. But it can be improved in many ways. The first thing to do is to implement <strong>Firebase Authentication</strong> [<a href="https://firebase.google.com/docs/auth/">link</a>] and roles to handle user/admin access to the web app. Database rules should then be updated adequatly. With authentication feature, the web app could:</p><ul><li>have a form element for the <strong>admin </strong>to <strong>choose the refresh period</strong> (that could be a Firebase Realtime Database node written by the web app and read by ESP8266 after each push),</li><li>have a button for the <strong>admin</strong> to <strong>delete the</strong> measures <strong>and </strong>timestamped_measures <strong>nodes</strong>,</li><li>have a form element for <strong>users </strong>to <strong>set the number of last elements to plot.</strong></li></ul><p>Then we could consider the <strong>sending of notifications </strong>to some registered users. For instance a user could receive a message if luminosity goes below a personalized threshold. This is possible with <strong>Firebase Cloud Messaging</strong>.</p><p>We have already implemented both aspects (authentication/notifications) in other contexts and this was really immediate.</p><p><strong>Acknowledgments for this post: </strong>We’d like to thank here @angularfirebase (<a href="https://medium.com/u/be68cb994bb8">Jeff Delaney</a>) whose videos-lessons are great quality content. Especially, <strong>Episode #39 “Realtime Charts With Plot.ly”</strong> [<a href="https://angularfirebase.com/lessons/realtime-charts-with-plot-ly/">link</a>] made us discover plotly.js in an Angular context and gave us the idea to lively plot measures made by an ESP8266.</p><p><strong>About this 3-post series</strong></p><p>With this third and last post about ESP8266-Firebase topic, we now have the full picture…</p><ul><li>Personally, our system (ESP8266 — Cloud Function — Web App) has been working like a charm for days and days. ESP8266 is supplied with a 10.000 mAh powerbank and just pushes a measure once in a while. It remains in deep sleep mode the rest of the time. Moreover, as timestamps are delegated to a cloud function, at the end ESP8266 <strong>consumes really little power</strong>.</li><li>Concerning <strong>security</strong>, though “secret” authentication to Firebase is not perfect, it does the job. The absence of an easy flash memory encryption is the only serious drawback we will regret (cf. post 1, [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>]).</li><li>UPDATE (March 15, 2019). To go further and build a more professional, scalable and secure solution, read our next Medium post called <a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7?source=---------4------------------"><strong>GCP-Cloud IoT Core with ESP32 and Mongoose OS</strong></a>.</li></ul><p><strong>About writing for Medium</strong></p><p><strong>Writing for Medium </strong>for the first time was a positive experience. We didn’t realize at first the long process it was to write, choose pictures, refactor source code and comments, etc. to seamlessly present our project. Hacking the whole project took us less than one day. Writing just <strong>one </strong>post for Medium was a matter of at least 2 full days! But it’s really rewarding when you see that people from many countries, even France :-), enjoyed it and give you positive feedback. And it opened interesting discussions with our job colleagues as well. So, for sure we’ll write some other posts in 2019. Stay tuned, and try yourself writing!</p><p><em>Tip: </em>By default your Medium post title will influence the post URL. If your title is long, you’ll have a long URL for your post provoking sometimes display disagreements due to long URLs. To avoid that, before publishing you can personalize your post URL by selecting <strong>Customize story link </strong>after clicking on the 3 dots … (close to the bell).</p><p>We’ve been really happy to share this newly learned knowledge with you.</p><p><strong>Links to the posts of this series: </strong><a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">Post 1</a>, <a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">Post 2</a>, Post 3, <a href="https://github.com/olivierlourme/esp8266webapp">GitHub</a> and <a href="https://esp8266-rocks.firebaseapp.com/">Live Demo</a>.</p><p><strong>Check also this post:</strong> <a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7?source=---------4------------------">GCP-Cloud IoT Core with ESP32 and Mongoose OS</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=644048e90ca4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Post 2 of 3. Our IoT journey through ESP8266, Firebase and Plotly.js]]></title>
            <link>https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e?source=rss-48724cb81b49------2</link>
            <guid isPermaLink="false">https://medium.com/p/14b0609d3f5e</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[iot]]></category>
            <category><![CDATA[esp8266]]></category>
            <category><![CDATA[firebase-cloud-functions]]></category>
            <category><![CDATA[firebase]]></category>
            <dc:creator><![CDATA[Olivier LOURME]]></dc:creator>
            <pubDate>Mon, 22 Oct 2018 20:31:21 GMT</pubDate>
            <atom:updated>2021-09-14T06:29:07.341Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KuQW_Ki39RaP8ASRcGEJNg.jpeg" /><figcaption>Sunrise at Lac du Héron</figcaption></figure><h3>TL;DR</h3><p>My Medium home page is <a href="https://medium.com/@o.lourme">here</a>.</p><p>This post stands in a series of 3 as detailed below. These 3 posts reflect the Project Architecture we chose to achieve a simple luminosity logging/live plotting project. We hope they will <strong>help developers or students discovering ESP8266 chip and Firebase platform</strong>. Moreover, we believe that the solution developped here can be an interesting alternative to the comprehensive <strong>Google, AWS and Azure IoT solutions</strong> [<a href="https://cloud.google.com/solutions/iot/">link</a>, <a href="https://docs.aws.amazon.com/fr_fr/iot/latest/developerguide/what-is-aws-iot.html">link</a> and <a href="https://docs.microsoft.com/fr-fr/azure/iot-hub/iot-hub-device-management-overview">link</a>] when we have to <strong>manage in a simple way only a few connected devices</strong>. (For instance, we won’t set up a MQTT broker neither deal with a device registry.)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*J0IGNrEAq3n8zxCZsLO5dQ.png" /><figcaption>Project Architecture — Numbers 1, 2, 3 follow articles numerotation</figcaption></figure><p><strong>Post 1</strong> [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>]: We investigate on how an <strong>ESP8266</strong> can regularly make acquisition of an analog data and push its 10-bit equivalent value to a <strong>Firebase Realtime Database</strong>. We finish with considerations on <strong>ESP8266 power saving.</strong></p><p><strong>Post 2</strong> (this article): We write a <strong>Firebase Cloud Function</strong> in Typescript language to <strong>timestamp </strong>the data just pushed to Firebase Realtime Database.</p><p><strong>Post 3</strong> [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4">link</a>]: With a<strong> </strong>web app using <strong>plotly.js library</strong>, we lively plot in a browser the analog data versus time. The web app is hosted with <strong>Firebase Hosting</strong>.</p><p><strong><em>Post 2. A Firebase Cloud Function appends a timestamp to each value pushed to a Firebase Realtime Database.</em></strong></p><h3>A) The options we had for timestamping data</h3><h4>A) 1) In the previous episode…</h4><p>At the end of Post 1 [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>] of this terrific project, we regularly had a new 10-bit value of luminosity that was pushed into a Firebase RealTime Database — all done by an ESP8266:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/466/1*6aFAQyXJo3nQ-0BUjf45Rw.gif" /><figcaption>Firebase Console — Each pushed value of luminosity is associated with a unique push ID</figcaption></figure><p>As we want to plot luminosity vs time, <strong>a timestamp associated with each measured value is necessary</strong>. Indeed, we would like something like in the example below:</p><pre>{<br>  &quot;timestamped_measures&quot; : {<br>    &quot;-LHmx0njIsZ3hkCFzjSC&quot; : {<br>      &quot;timestamp&quot; : 1532010700350,<br>      &quot;value&quot; : 910<br>    },<br>    &quot;-LHmx1PcieyEm04aOo2a&quot; : {<br>      &quot;timestamp&quot; : 1532010702641,<br>      &quot;value&quot; : 907<br>    },<br>    &quot;-LHmx1leagyrTQxa9zii&quot; : {<br>      &quot;timestamp&quot; : 1532010703986,<br>      &quot;value&quot; : 840<br>    },<br>    ...<br>}</pre><p>Each measure should now be an object (described in JSON) having two key/val. pairs, the keys being &quot;timestamp&quot; and &quot;value&quot;. And, at an upper level, this object is the value associated with the key called a “Firebase push ID”, for instance &quot;-LHmx0njIsZ3hkCFzjSC&quot; for the first record in the above example.</p><p>The timestamp of a measure should ideally corresponds to the <strong>Unix Epoch time</strong> of the instant the measure was made.</p><p><em>Note:</em> The Epoch time is the number of <strong>seconds</strong> that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970 [<a href="https://en.wikipedia.org/wiki/Unix_time">link</a>]. Manual conversions from Epoch time to human time (or vice versa) can be made here [<a href="https://www.epochconverter.com/">link</a>] for instance. As you may have guessed it in the above example, we will use Epoch time expressed in <strong>milliseconds</strong> (not seconds) as the tools we’ll use supply timestamps within this unit.</p><p>We investigate now two options to associate a timestamp to a 10-bit value just obtained.</p><h4>A) 2) First option: ESP8266 generates a timestamp and associates it to the just obtained value of luminosity</h4><p>With this option, ESP8266 should be aware of time, <em>i.e.</em> have a <strong>Real Time Clock</strong> (RTC, hardware or software recreated). It should loop over the following actions:</p><ol><li>get the 10-bit luminosity measure.</li><li>get Epoch time.</li><li><strong>create an object</strong> with &quot;value&quot; and &quot;timestamp&quot; populated with the measure and the Epoch time. The <strong>ArduinoJson library</strong> we already installed in our previous article [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>] can deal with that [<a href="https://github.com/bblanchon/ArduinoJson#serialization">link</a>].</li><li><strong>push this object </strong>to our Firebase Realtime Database. This is possible with the <strong>FirebaseArduino library</strong> [<a href="https://github.com/firebase/firebase-arduino">link</a>, <a href="https://firebase-arduino.readthedocs.io/en/latest/#_CPPv2N15FirebaseArduino4pushERK6StringRK11JsonVariant">link</a>] we already know from our previous article [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>]. The function for that purpose has this prototype:</li></ol><pre>String push(<em>const</em> String &amp;<em>path</em>, <em>const</em> JsonVariant &amp;<em>value</em>)</pre><p>Steps 1, 3 and 4 should be okay but step 2 is the tricky point. Indeed, when we read this <strong>NodeMCU Documentation</strong> at <strong>RTC Time Module</strong> page [<a href="https://nodemcu.readthedocs.io/en/master/en/modules/rtctime/">link</a>], we realize that RTC in ESP8266:</p><ul><li>is a software module,</li><li>has an accuracy depending on chip temperature,</li><li>needs to synchronize via SNTP or NTP (thus consuming power),</li><li>will lose time in case of an unexpected reset.</li></ul><p>Okay! Too much drawbacks! Let’s forget this option and let’s dive into a more realistic one…</p><p><em>Note:</em> Using NTP with ESP8266 is nonetheless described here: [<a href="https://tttapa.github.io/ESP8266/Chap15%20-%20NTP.html">link</a>].</p><h4>A) 3) Second option: A Firebase Cloud Function issues the timestamp when a value is pushed to the Firebase Realtime Database.</h4><p>Firstly, what are Firebase Cloud Functions?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*GnWThKAgUSof2W4jUBiuyw.png" /><figcaption>Cloud Functions for Firebase logo</figcaption></figure><p><strong>Firebase Cloud Functions</strong> (or “Cloud Functions for Firebase”, [<a href="https://firebase.google.com/docs/functions/">link</a>]) are part of <strong>Google Cloud Platform</strong> and are <strong>functions executed in a Node environment </strong>on Google servers. A Firebase Cloud Function can be:</p><ul><li>called from an app involving Firebase (directly or via a HTTP request),</li><li>automatically triggered upon an event on Firebase products:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*KFCG8rn6hoiFbCit5vihqA.jpeg" /><figcaption>Means to invoke a Firebase Cloud Function. The one we’ll use is underlined.</figcaption></figure><p>You might have already guessed it, what we need is a <strong>Realtime Database trigger</strong>. Each time a measure is pushed to Firebase Realtime Database by ESP8266, a Firebase Cloud Function will be triggered in order to timestamp the measure. With that solution,<strong> we maintain the work done by ESP8266 to the minimum (and thus its power consumption).</strong></p><p>The <strong>small drawback</strong> of this option is that we will timestamp the push to Firebase Realtime Database, not the measure. But the temporal gap between them is only about seconds, depending on network latency. In our previous article [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>], we used to make a measure every 5 minutes ; a delay of 1 or 2 seconds on the timestamp is therefore not an issue here.</p><p><em>Note: </em>Firebase Cloud Functions are part of what is sometimes called <strong>Functions as a Service</strong> (FaaS) and are one aspect of the famous <strong>serverless architecture</strong>, <em>i.e.</em> we don’t need to provide our own servers to host and run them.</p><h3>B) Writing our Cloud Function</h3><p>As written in <a href="https://firebase.google.com/docs/functions/">https://firebase.google.com/docs/functions/</a> we should:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/766/1*EpQ-zjvWf49XmMFfe3_EnQ.jpeg" /><figcaption>Firebase Cloud Functions workflow</figcaption></figure><p>So let’s follow these steps! But before let’s give <strong>a few documentation links</strong>:</p><p><a href="https://firebase.google.com/docs/functions/get-started">Get started: write, test, and deploy your first functions | Cloud Functions for Firebase</a></p><p>This page ↑ and its links often include videos from <a href="https://medium.com/u/6a53613f4e6d">Doug Stevenson</a>. We can find them on YouTube under the following list. It is worth watching all them, Cloud Functions are nicely explained and fundamental concepts like <strong>Promises</strong> too!</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fvideoseries%3Flist%3DPLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&amp;url=https%3A%2F%2Fwww.youtube.com%2Fplaylist%3Flist%3DPLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FDYfP-UIKxH0%2Fhqdefault.jpg%3Fsqp%3D-oaymwEWCKgBEF5IWvKriqkDCQgBFQAAiEIYAQ%3D%3D%26rs%3DAOn4CLBa3tAKq8d0gHqldcqkFk-QLAaCOg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="853" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/146d44242ba699f445d662e29b94e15f/href">https://medium.com/media/146d44242ba699f445d662e29b94e15f/href</a></iframe><p>And finally, if you want to become a master in Firebase Cloud Functions 😃, head to this impressive Github repo of Cloud Functions samples (mostly in JavaScript):</p><p><a href="https://github.com/firebase/functions-samples">firebase/functions-samples</a></p><h4>B) 1) Setting up the tools managing Firebase Cloud Functions</h4><p>To sum up :</p><p><em>Note:</em> Each time there is an action to perform, it is preceeded by a lowercase letter like <strong>a. b. c. </strong>etc.</p><p><strong>a. </strong>If not installed yet on our computer, we install <strong>Node.js</strong> [<a href="https://nodejs.org/en/">link</a>]. It will also install Node Package Manager (<strong>NPM</strong>). Once done, we check version in command line. At the time of writing, it should be ≥8 for Node.js and ≥6 for NPM. To do so, open a terminal. Personnaly, as we develop on a Windows 10 computer, the terminal is cmd.exe. Do it right now with <strong>admin rights</strong> as some of the future commands will require it. Then, to check installed versions, run from any folder:</p><p>node --version</p><p>npm --version</p><p><strong>b. </strong>We install <strong>Firebase Command Line Interface</strong> (CLI, a necessary set of Firebase command line tools) by running, from any folder:</p><p>npm install -g firebase-tools</p><p>Again, firebase --version will give the installed version. At the time of writing, it should be ≥4.</p><p>-g installs Firebase tools “globally” <em>i.e.</em> we will be able to use the Firebase tools from any <strong>project directory</strong>. A project directory is a directory on our computer that hosts during its edition the Cloud Function(s) related to the Firebase project we’re working on.</p><p><strong>c. </strong>We authenticate with Firebase services by running (a few permissions will be asked):</p><p>firebase login</p><p><em>Note:</em> Here, we have to authenticate with the same account than the one we used while setting up esp8266-rocks Firebase project in our previous article [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">link</a>].</p><p><em>Note:</em> Use first firebase logout if you were logged-in with another account.</p><p>It should result in this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/432/1*tXmTWUE8RzzbSqkCj3BTPw.jpeg" /><figcaption>Successful Firebase CLI Login</figcaption></figure><p><strong>d.</strong> In our computer development directory (<strong>c:\_APP</strong> for us), we create <strong>a project directory</strong> that we call esp8266:</p><p><strong>c:\_APP&gt;</strong>md esp8266 on Windows (or mkdir esp8266 on Linux).</p><p>We navigate to it and run the command to set up the “functions” purpose of the project (same commands for Windows/Linux):</p><pre><strong>c:\_APP&gt;</strong>cd esp8266<br><strong>c:\_APP\esp8266&gt;</strong>firebase init functions</pre><p>This is what we get:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*CAo0B7eo3VV_4a8HXmKLDg.jpeg" /><figcaption>“firebase init functions” command</figcaption></figure><p><strong>e.</strong> A few questions are asked after we respond <strong>Yes </strong>to proceed:</p><ul><li>Of course, we choose to <strong>associate </strong>the esp8266 project directory with the esp8266-rocksFirebase project:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/641/1*CPR-pZ7LjcI8kB43uWLGkA.jpeg" /><figcaption>Project Setup</figcaption></figure><ul><li>We then choose <strong>TypeScript language</strong>. Usually programs for Node environment are written in JavaScript but TypeScript has a lot of advantages over JavaScript, the first one being likely <strong>(optional) static typing</strong>. In fact, it handles the pillars of Object Oriented Programming. However we have to confess that our function will be so simple today that using TypeScript will provide no real benefit... But the scaffolding for writing later more sophisticated functions in Typescript will have been set up. A short and nice introduction to TypeScript is here: [<a href="http://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html">link</a>].</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/642/1*0jc5JzG35ol_V2fmYTXpDQ.jpeg" /><figcaption>Functions Setup (1)</figcaption></figure><p><em>Note:</em> Check later this blog post [<a href="https://firebase.googleblog.com/2018/01/why-you-should-use-typescript-for.html">link</a>] from <a href="https://medium.com/u/6a53613f4e6d">Doug Stevenson</a> for TypeScript pros while writing Cloud Functions. Read also [<a href="https://github.com/firebase/functions-samples/tree/Node-8/typescript-getting-started">link</a>] for additional workflow details while using TypeScript with Cloud Functions. You will also learn the key differences between a file in TypeScript and its equivalent in JavaScript ES6 (import &lt;-&gt; require, export const &lt;-&gt; exports.)</p><ul><li>We answer <strong>Yes</strong> to the next question concerning the use of <strong>TSLint</strong>. It is a powerful debug tool but unfortunately we won’t have time to tackle with it in this article! At least it will have been set up.</li><li>At last, we accept to install dependencies with NPM: (be prepared to have a bunch of files installed!)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/678/1*ihNvCFijVN1VGwJ_XsQhxw.jpeg" /><figcaption>Function Setup (2)</figcaption></figure><p><strong>f.</strong> Now we’re done! On the graph below we have an (incomplete) tree of the project directory. What’s important to us is that inside the esp8266 project directory, a functions directory was created. In this one we find a src directory that hosts index.ts , the file where we will write our Cloud Function in TypeScript. At the time of deploying the Cloud Function on Google servers, the index.ts file will be <strong>transpiled </strong>to JavaScript, by a <strong>transpiler </strong>program called tsc, resulting in the index.js file stored in the lib directory. It’s index.js that will be run by Node.js on Google servers.</p><p>The node_modules directory hosts the dependencies (as Node packages/modules) indicated in package.json: firebase-admin and firebase-functions. But it also stores the dependencies of these dependencies… That’s why it is so huge.</p><pre>esp8266/<br> |<br> +- .firebaserc<br> |<br> +- firebase.json<br> |<br> +- functions/<br>     |<br>     +- package.json<br>     |<br>     +- src/<br>     |   |<br>     |   +- index.ts   # where we will write our Cloud Function<br>     |<br>     +- lib/ <br>     |   |<br>     |   +- index.js   # result of index.ts transpilation<br>     |<br>     +- node_modules/  # directory where dependencies (declared in<br>                       # package.json) are installed</pre><h4>B) 2) Writing the Cloud Function</h4><p>We launch an editor on our project directory. For instance, <strong>Visual Studio Code</strong> [<a href="https://code.visualstudio.com/">link</a>] is launched over the esp8266 folder that way:</p><pre><strong>c:\_app\esp8266&gt;</strong>code .</pre><p>This is what we get:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u2rkenS4sJptMzNr8dkfhQ.jpeg" /><figcaption>After we launched VS Code</figcaption></figure><p>There is already some (commented) code in index.ts. This is in fact the code of a <strong>function called on a HTTP request</strong>, not what we need today (but it’s worth testing it along with the first YouTube video embedded above in this post). Remember, we are about to write a <strong>Realtime Database trigger function</strong>.</p><p><em>Note:</em> If we needed to write several Cloud Functions, they would all fit in index.ts, one after one.</p><p>We copy/paste the following code in index.ts. It is fully commented to understand how it proceeds. Of course, we save this file!</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dff56beda91d55f4c1c484e5e3cd2f3d/href">https://medium.com/media/dff56beda91d55f4c1c484e5e3cd2f3d/href</a></iframe><h4>B) 3) Deploy, test and monitor the Cloud Function</h4><p><strong>Cloud Function deployment</strong></p><p>In terminal, we run:</p><pre><strong>c:\_APP\esp8266&gt;</strong>firebase deploy --only functions</pre><p>Unfortunately, there is a <strong>known issue while predeploying (<em>i.e. </em>tslint &amp; tsc execution) with Windows 10 </strong>(cmd.exe):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/917/1*hVp0GNrdNndSQXU3nd0oXQ.jpeg" /><figcaption>Known issue with Windows 10 while deploying Cloud Functions</figcaption></figure><p>This issue is discussed here : [<a href="https://github.com/firebase/firebase-tools/issues/610">link</a>, <a href="https://stackoverflow.com/questions/47756264/cloud-functions-firebase-cli-predeploy-error-typescript">link</a>]. We used this sustainable workaround:</p><ul><li>Replace firebase.json current content:</li></ul><pre>{<br>  &quot;functions&quot;: {<br>    &quot;predeploy&quot;: [<br>      &quot;npm --prefix \&quot;$RESOURCE_DIR\&quot; run lint&quot;,<br>      &quot;npm --prefix \&quot;$RESOURCE_DIR\&quot; run build&quot;<br>    ]<br>  }<br>}</pre><p>by:</p><pre>{<br>  &quot;functions&quot;: {<br>  &quot;predeploy&quot;: &quot;npm --prefix functions run lint &amp;&amp; npm --prefix functions run build&quot;<br>  }<br>}</pre><ul><li>Then, replace in the &quot;scripts&quot; part of package.json the lines:</li></ul><pre>&quot;lint&quot;: &quot;tslint --project tsconfig.json&quot;,<br>&quot;build&quot;: &quot;tsc&quot;,</pre><p>by:</p><pre>&quot;lint&quot;: &quot;./node_modules/.bin/tslint -p tslint.json&quot;,<br>&quot;build&quot;: &quot;./node_modules/.bin/tsc&quot;,</pre><p>We try again firebase deploy --only functions and this time it’s ok! By curiosity, you can have a look at the obtained index.js file.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/621/1*UCQ_aJeeusncG84UqdUvSg.jpeg" /><figcaption>Successful Cloud Function deploy</figcaption></figure><p><em>Note:</em> It takes about 30 seconds for Cloud Functions to be deployed on Google servers. As we will repeat many times the write-deploy-test process, deploying Cloud Functions locally during development could be an interesting option. We can find more information on <strong>Cloud Functions emulator </strong>here: [<a href="https://firebase.google.com/docs/functions/local-emulator">link</a>].</p><p><strong>Cloud Function test</strong></p><p>In the animation below, we trigger the Cloud Function. To achieve this, we simulate in Firebase Console a new measure pushed to Firebase Realtime Databasemeasures node. Instantly, the Cloud Function detects this creation and push to the timestamped_measures node the object with value and timestamp keys we talked about before. It also assign it a unique push ID. The value of the timestamp is the Epoch time in ms provided by Google servers, it should be accurate.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/436/1*MSioPaOnDex_OP_0qWbS0w.gif" /><figcaption>Firebase Console — Cloud Function at work!</figcaption></figure><p><strong>Cloud Function monitoring</strong></p><p>While debugging, it is useful to monitor the execution of the Cloud Function and to console.log() a few informations as we did at the end of our index.ts file:</p><pre>console.log(`Detected new measure ${original} with pushId ${pushId}`);</pre><p>Where can we see those logs? In Firebase Console (<a href="https://console.firebase.google.com/">https://console.firebase.google.com</a>):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yJolVpBoF_1_m0w8V2KYyg.jpeg" /><figcaption>Firebase Console — Monitoring the Cloud Function</figcaption></figure><p><strong>How to undeploy a Cloud Function?</strong></p><p>Curiously, it’s not possible to delete a Cloud Function from Firebase Console. We have to go to <strong>Google Cloud Platform Console</strong> (<a href="https://console.cloud.google.com/">https://console.cloud.google.com</a>), then to choose “Cloud Functions” and then to select the Cloud Function we want to delete:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iuLPD1i0l5twYrOH3CgNpg.jpeg" /><figcaption>GCP Console — Undeploying a Cloud Function</figcaption></figure><p><strong>How many times can we invoke our Cloud Functions per month?</strong></p><p>With <strong>Firebase “Spark pricing plan”</strong> (the free one), we can make up to 125K invocations per month in the limits of 5K invocation per day and 50 invocation per 100 seconds [<a href="https://stackoverflow.com/questions/42905204/function-killed-error-quota-exceeded">link</a>]. <strong>This thresholds can be quickly reached! </strong>To know the current number of invocations (it’s easy to estimate it), we hit <strong>Project Overview</strong> in Firebase Console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/214/1*iJHD5-c9eccbYKSC_B-tXQ.png" /><figcaption>Firebase Console — Project Overview</figcaption></figure><p><em>Note: </em>When the invocation quota is exceeded, the function execution is paused and timestamps will be the ones when the function execution resumes! We should detect the “quota exceeded” event and /or consider the <strong>“Blaze pricing plan”</strong>.</p><p><strong>Hmmh… wait! Do we have to change database access rules ?</strong></p><p>First, remember that the Cloud Function we wrote has admin rights and can thus do anything with the database regardless of the rules we’ll set up.</p><p>But it’s good practice to set access rules for each node we have in the database, knowing also that .read and .write rules cascade to deeper paths (see [<a href="https://firebase.google.com/docs/database/security/">link</a>]).</p><p>So, for our new node named timestamped_measures, we set .read and .write to false as, for the moment, no third party needs to access this node. But this will change in the next episode [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4">link</a>].</p><pre>{<br>  &quot;rules&quot;: {<br>    &quot;measures&quot;: {<br>      &quot;.read&quot;: &quot;false&quot;,<br>      &quot;.write&quot;: &quot;false&quot; <br>    },<br>    &quot;timestamped_measures&quot;: {<br>      &quot;.read&quot;: &quot;false&quot;,<br>      &quot;.write&quot;: &quot;false&quot; <br>    }<br>  }<br>}</pre><h3>Conclusion</h3><p>In this article, we wrote our first <strong>Firebase Cloud Function</strong> to timestamp measures made by ESP8266. No doubt you will adopt them in your own projects as it is an easy way to run code that cannot be run by client side.</p><p>As live data is now presented in a good shape, we will plot it dynamically with a <strong>web app </strong>using <strong>plotly.js </strong>in the third and last article of this series. Hopefully we’ll post it before Christmas 2018 🎄 🎁! So stay tuned!</p><p><strong>Links to the posts: </strong><a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f">Post 1</a>, Post 2, <a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4">Post 3</a>, <a href="https://github.com/olivierlourme/esp8266webapp">GitHub</a> and <a href="https://esp8266-rocks.firebaseapp.com/">Live Demo</a>.</p><p><strong>Check also this post:</strong> <a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7?source=---------4------------------">GCP-Cloud IoT Core with ESP32 and Mongoose OS</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=14b0609d3f5e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Post 1 of 3. Our IoT journey through ESP8266, Firebase and Plotly.js]]></title>
            <link>https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-1-a07db495ac5f?source=rss-48724cb81b49------2</link>
            <guid isPermaLink="false">https://medium.com/p/a07db495ac5f</guid>
            <category><![CDATA[iot]]></category>
            <category><![CDATA[esp8266]]></category>
            <category><![CDATA[arduino]]></category>
            <category><![CDATA[firebaserealtimedatabase]]></category>
            <category><![CDATA[firebase]]></category>
            <dc:creator><![CDATA[Olivier LOURME]]></dc:creator>
            <pubDate>Thu, 09 Aug 2018 12:26:46 GMT</pubDate>
            <atom:updated>2021-09-14T06:30:40.797Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/898/1*VqqpujaI-nPgRzWCquzO5w.gif" /><figcaption>What we will achieve… at the end of this 3-post series</figcaption></figure><h3>TL;DR</h3><p>My Medium home page is <a href="https://medium.com/@o.lourme">here</a>.</p><p>This post stands in a series of 3 as detailed below. These 3 posts reflect the Project Architecture we elected in order to achieve a simple luminosity logging/live plotting project. We hope they will <strong>help developers or students discovering ESP8266 chip and Firebase platform</strong>. Moreover, we believe that the solution developped here can be an interesting alternative to the comprehensive <strong>Google, AWS and Azure IoT solutions</strong> [<a href="https://cloud.google.com/solutions/iot/">link</a>, <a href="https://docs.aws.amazon.com/fr_fr/iot/latest/developerguide/what-is-aws-iot.html">link</a> and <a href="https://docs.microsoft.com/fr-fr/azure/iot-hub/iot-hub-device-management-overview">link</a>] when we have to <strong>manage in a simple way only a few connected devices</strong>. (For instance, we won’t set up a MQTT broker neither deal with a device registry.)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*J0IGNrEAq3n8zxCZsLO5dQ.png" /><figcaption>Project Architecture — Numbers 1, 2, 3 follow post numerotation</figcaption></figure><p><strong>Post 1</strong> (this post): We investigate on how an <strong>ESP8266</strong> can regularly make acquisition of an analog data and push its 10-bit equivalent value to a <strong>Firebase Realtime Database</strong>. We finish with considerations on <strong>ESP8266 power saving.</strong></p><p><strong>Post 2</strong> [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>]: We write a <strong>Firebase Cloud Function</strong> in Typescript language to <strong>timestamp </strong>the data just pushed to Firebase Realtime Database.</p><p><strong>Post 3</strong> [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4">link</a>]: With a<strong> </strong>web app using <strong>plotly.js library</strong>, we lively plot in a browser the analog data versus time. The web app is hosted with <strong>Firebase Hosting</strong>.</p><p><strong><em>Post 1. An ESP8266 pushes luminosity measures to a Firebase Realtime Database.</em></strong></p><h3>General introduction</h3><p>It’s been a while since we heard about the ESP8266 component for the first time, its low-cost and its Wi-Fi features. Willing to master it and having at last a little free time, we built a small <strong>IoT (Internet of Things) project whose aim is to lively plot an analog data to a web app</strong>. Which analog data? Hmmmh, let’s say luminosity in North of France!</p><h3>A) Hardware considerations</h3><h4>A) 1) ESP8266: a short introduction</h4><p>ESP8266 [<a href="https://en.wikipedia.org/wiki/ESP8266">link</a>] is a <strong>low cost and low power Wi-Fi SoC</strong> integrating a 32-bit Tensilica microcontroller running at 80 MHz. It is designed by ESPRESSIF chinese company and manufactured by companies such as ESPRESSIF, AI-THINKER or DOIT. Due to its embedded Wi-Fi capability, it is widely used in IoT projects and products (in <strong>Sonoff or Shelly switches </strong>for instance : [<a href="https://sonoff.itead.cc/en/products/sonoff/sonoff-basic">link</a>, <a href="https://shelly.cloud/">link</a>]). Until now, ESP8266 is declined in many versions but we use here the widespread one called ESP-12E [<a href="https://www.kloppenborg.net/images/blog/esp8266/esp8266-esp12e-specs.pdf">link to specs as a pdf</a>].</p><p><em>Note:</em> What do we mean by low cost ? We’ll use a <strong>NodeMCU DEVKIT v1.0 </strong>board integrating an ESP8266 and many items for development purpose (see a few lines below). It costs between $3 and $4 from classical chinese web sites. A device dedicated to production costs even less.</p><p><em>Note:</em> An ESP8266 successor is ESP32 [<a href="https://en.wikipedia.org/wiki/ESP32">link</a>]. Compared to ESP8266, everything is enhanced: speed, memory, peripherics, presence of BLE, memory encryption capability, etc. But it costs about twice.</p><p>Besides Wi-Fi, ESP-12E is equipped with <strong>all classical peripherals</strong> : GPIOs, UART, a single ADC (Analog To Digital Converter), PWMs, I2C, SPI, and so on. It also comes with a 4 MiB SPI Flash memory which we’ll discuss later.</p><p>It is important to note that, though ESP-12E is 3.3 V powered, the ADC input (pin #2 on the pinout just below) voltage range is from 0 V to 1 V. The ADC is a 10-bit one so its quantum is about 1 mV (exactly: 1 V /(2¹⁰-1)).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*WsCz-gCf0W2sr-mgGfTImg.jpeg" /><figcaption>ESP-12E pinout [<a href="http://ha2eqd.com/arduino/021_1st_ket_ESP_modulom/1st_ESP.html">link</a>]</figcaption></figure><p>Of course, you can’t use ESP-12E out of the box, a lot of things are missing (at least a supply). So read next paragraph…</p><h4>A) 2) NodeMCU DEVKIT v1.0 to immediately start development</h4><p>Really soon (2014) after ESP8266 was released (2013) some people developped (in C and LUA languages) a <strong>firmware called NodeMCU</strong> [<a href="https://en.wikipedia.org/wiki/NodeMCU">link</a>]. It allows to write scripts for ESP8266 in LUA language. A few months later, an <strong>open-hardware platform </strong>called NodeMCU DEVKIT v0.9<strong> </strong>was added to this project. Now outdated, we used in our project its successor <strong>NodeMCU DEVKIT v1.0 </strong>[<a href="https://github.com/nodemcu/nodemcu-devkit-v1.0/blob/master/NODEMCU_DEVKIT_V1.0.PDF">link to schematic as a pdf in github</a>] on which we can find everything to immediately start IoT development:</p><ol><li>An ESP-12E.</li><li>A USB to Serial Converter to communicate with a computer (for console and program flashing purposes); most of the time it’s a CP2102 chip but sometimes it’s a CH340. Installing a driver is sometimes needed.</li><li>A MicroUSB-B connector to connect our NodeMCU DEVKIT v1.0 to our computer during development/debug. You will need a cable.</li><li>A 3.3 V regulator to make 3.3 V from 5 V USB (typical reference: AMS1117).</li><li>A “flash” button (we didn’t have to use it) and a useful reset button.</li><li>An <strong>active low</strong> built-in blue LED, connected to D0 (GPIO16) (see pinout below, after NodeMCU DEVKIT v1.0 photo)</li><li>A voltage divider (not referenced on image below) whose role is explained just after.</li><li>…</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pqruSzABNlOd60QRpDie9Q.jpeg" /><figcaption>NodeMCU DEVKIT v1.0 [<a href="https://github.com/nodemcu/nodemcu-devkit-v1.0/tree/master/Documents">link</a>]</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/469/1*9SeLUvl8eKo66k7ltcRfVg.jpeg" /><figcaption>NodeMCU DEVKIT v1.0 pinout [<a href="https://e.banana-pi.fr/esp8266/389-nodemcu-10-wifi-esp8266-esp-12e.html">link</a>]</figcaption></figure><p>On the above pinout, A0 is the (upper left) pin where you connect the analog input you want to measure. A0 is not directly connected to pin #2 of ESP-12E, there is a 100k/(100k+220k) = (1/3.2) <strong>voltage divider</strong> between them [<a href="https://github.com/nodemcu/nodemcu-devkit-v1.0/blob/master/NODEMCU_DEVKIT_V1.0.PDF">link to schematic as a pdf in github</a>, see part called “ADC”]. So, <strong>on A0 of NodeMCU v1.0, the input voltage range can be from 0 V to 3.2 V</strong>.</p><p>To conclude this hardware presentation, let’s say it is sometimes confusing to deal with the numerous NodeMCU DEVKIT versions and manufacturers. This post [<a href="https://frightanic.com/iot/comparison-of-esp8266-nodemcu-development-boards/">link</a>] explains things well and also presents <strong>ESP8266 alternative developpement boards</strong> like <strong>Adafruit Feather HUZZAH with ESP8266</strong> (supplied by a 3.7 V LiPo battery or 5 V USB + power management included) or <strong>WeMos mini</strong>. It also gives links to at last buy our first NodeMCU DEVKIT v1.0!</p><h3>B) Software choice: Arduino language and environment</h3><p>LUA is without doubt an interesting language but what if we could program ESP8266 with <strong>a language and an IDE </strong>we all already know, eliminating long learning hours ? Let’s say something like Arduino. This is possible thanks to “<strong>Arduino core for ESP8266”</strong>! And it has a fantastic network library!</p><p><em>Note:</em> There are numerous other development options than NodeMCU and Arduino. See “SDKs” and “See also” parts in [<a href="https://en.wikipedia.org/wiki/ESP8266">link</a>].</p><h4>B) 1) Installation</h4><p>The official “Arduino core for ESP8266<strong>” </strong>github repo is here : [<a href="https://github.com/esp8266/Arduino#installing-with-boards-manager">link</a>]. We follow the part called <strong>Installing with Boards Manager</strong>. At the end, when everything is installed and the NodeMCU DEVKIT v1.0 is selected as our development board, we get something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/812/1*9FyQ0JNIyGMDz9zDvmdB3A.png" /><figcaption>Arduino IDE after NodeMCU DEVKIT v1.0 is selected</figcaption></figure><p><em>Note:</em> There is no Arduino firmware flash to care about. And if there is already a firmware installed on our NodeMCU DEVKIT v1.0 when we get it, it will be deleted the first time we upload an Arduino program.</p><h4>B) 2) Time for “Hello, World!” program</h4><p>In this <strong>“Hello, World!” program</strong> (a program is called a “sketch” in the Arduino world), we will make the NodeMCU DEVKIT v1.0 built-in blue <strong>LED blink and print a message</strong> <strong>to Arduino IDE Serial Monitor</strong> each time this LED is about to change its state. This program is inspired from:[<a href="https://github.com/esp8266/Arduino/blob/master/libraries/esp8266/examples/Blink/Blink.ino">link</a>] (or we can reach it by: <strong>Arduino_IDE&gt;File&gt;Examples&gt;ESP8266&gt;Blink</strong>).</p><p><em>Note:</em> Each time there is an action to perform, it is preceeded by a lowercase letter like <strong>a. b. c. </strong>etc.</p><p><strong>a.</strong> With <strong>Arduino_IDE&gt;File&gt;New</strong>, we create a new program and copy/paste the following code. We save it.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/66d09c3741f423d982f052ab43578b19/href">https://medium.com/media/66d09c3741f423d982f052ab43578b19/href</a></iframe><p><strong>b.</strong> If not done yet, we connect via USB our NodeMCU DEVKIT v1.0 to our computer.</p><p><strong>c.</strong> With <strong>Arduino_IDE&gt;Tools&gt;Port</strong>, we choose the (emulated via USB) serial port we think our computer uses to communicate with NodeMCU DEVKIT v1.0, for instance COM6 on Windows.</p><p>d. Select <strong>Arduino_IDE&gt;Sketch&gt;Upload</strong> (or hit the famous Arduino right arrow icon). If the LED is not blinking after several seconds, we should change serial port and retry.</p><p>If the LED remains in the same state, we try changing upload speed with <strong>Arduino_IDE&gt;Tools&gt;Upload Speed</strong> and retry. Normally it’s 115200 Bd but it depends on the firmware our NodeMCU DEVKIT v1.0 is shipped with.</p><p>At this point, the LED should blink!</p><h4>B) 3) Memory</h4><p>Let’s say a word about <strong>ESP-12E memory</strong>. On Arduino IDE status bar, we have this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/457/1*qWKeXXQ4xhSGpELuvmPKmg.jpeg" /><figcaption>Arduino IDE status bar</figcaption></figure><ul><li>“NodeMCU 1.0 (ESP-12E Module)” is the board we work with.</li><li>“115200” is the program’s upload speed, here 115200 Bd.</li><li>“4M” is the size of SPI flash memory in ESP-12E, i.e. 4 MiB.</li><li>“(3M SPIFFS)”: From the 4 MiB mentionned before, 3 are here reserved (this can be changed) to be handled by <strong>SPI Flash File System</strong> (SPIFFS). For instance, if we plan to use ESP8266 as a web server, our web site would be stored somewhere in those 3 MiB. So we have 1 MiB left to store our Arduino program and libraries.</li><li>“COM6” is the serial port our computer uses to communicate with NodeMCU DEVKIT v1.0.</li></ul><p>After uploading we have also these sentences in Arduino IDE:</p><pre>Sketch uses 224281 bytes (21%) of program storage space. Maximum is 1044464 bytes.<br>Global variables use 31768 bytes (38%) of dynamic memory, leaving 50152 bytes for local variables. Maximum is 81920 bytes.</pre><ul><li>The first and second sentences effectively show that we have 1 MiB for our program and libraries. We learn that we used 21% of this.</li><li>The third and fourth sentences show that we used 38% of the 80 KiB available RAM.</li></ul><p><em>Note: </em>Some memory can be EEPROM for sketches to store data.</p><h4>B) 4) End of “Hello, World!” test</h4><p>Now, let’s see the messages ESP8266 is sending us.</p><p><strong>e. </strong>We select <strong>Arduino_IDE&gt;Tools &gt; Serial Monitor</strong>. When the Serial Monitor appears, we set its serial speed at 115200 Bd:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/354/1*L5sAVsRew5tiubrA_JJypg.png" /><figcaption>Serial Monitor: Speed setting</figcaption></figure><p>This Serial Monitor speed is of course the same that the one we set for ESP8266 in this line of our program:</p><pre>Serial.begin(115200);</pre><p><strong>f. </strong>And this is eventually the scroll we get in Serial Monitor:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/766/1*0adTXweN_JYp_2gZUbRG5g.png" /><figcaption>Serial Monitor as program is running</figcaption></figure><h3>C) Measuring an analog data like luminosity</h3><p>Let’s go a step further by measuring an analog data with our NodeMCU DEVKIT v1.0.</p><p>The analog data wire should be connected to pin A0 of NodeMCU DEVKIT v1.0. Thanks to the voltage divider we mentionned in A)2), the analog data should be between 0 V and 3.2 V:</p><ul><li>0 V produces the minimal integer 10-bit value, <em>i.e.</em> 0.</li><li>3.2 V produces the maximum integer 10-bit value <em>i.e.</em> 1023.</li></ul><p>For instance, 2.5 V produces: 2.5 * (1023/3.2) = 799.</p><p>As we said before, we want to measure luminosity (or, more accurately, the voltage that is an image of it).</p><p>This document from Adafruit [<a href="https://cdn-learn.adafruit.com/downloads/pdf/photocells.pdf">link to pdf</a>] explains how a <strong>photo cell</strong> (or Light Dependent Resistor, <strong>LDR</strong>) can be used to measure luminosity (<em>i.e.</em> how you can relate its ohm or voltage values to luminosity) and how you can connect it to a microcontroller analog input. It even gives Arduino program examples.</p><p>So this is the assembly we will adopt (no need of a voltage follower between LDR and NodeMCU DEVKIT v1.0, we checked that point):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/747/1*bG-67j9rY2NYMmeKRGZRFA.jpeg" /><figcaption>Luminosity measurement with a LDR and NodeMCU DEVKIT v1.0</figcaption></figure><ul><li>Total darkness should produce a 10-bit equivalent value close to 0.</li><li>Direct strong sunlight should produce a 10-bit equivalent value close to 1023.</li></ul><p>With a small breadbord, we can get this compact installation (in fact we’ve been given the whole hardware in a <a href="http://twitter.com/RedisLabs">@RedisLabs</a><strong> </strong>meetup [<a href="https://www.meetup.com/fr-FR/Redis-Lille/events/247121494/">link</a>] hosted by <a href="https://twitter.com/ZenikaLille"><strong>@</strong>ZenikaLille</a>, we thank both of them here!):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*iHX6NLG9_v7LXJzbIvXD5w.jpeg" /><figcaption>NodeMCU DEVKIT v1.0 with LDR and a 10k resistor</figcaption></figure><p><em>Note: </em>A LDR is not the best luminosity sensor in town! But for sure, it’s the cheapest!</p><p><strong>g. </strong>The program can be as simple as that:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e479936c3800f3a9c22db543f52eef53/href">https://medium.com/media/e479936c3800f3a9c22db543f52eef53/href</a></iframe><p><strong>h.</strong> And eventually, after we upload this program to NodeMCU DEVKIT v1.0, we get the following sreenshot of Arduino IDE Serial Monitor (we produced different luminosity environments - covering LDR, adding light, … - to get this values):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/766/1*eNDIe3anhUhdUtaCoYYdVA.png" /><figcaption>Serial Monitor: Different values of luminosity image</figcaption></figure><h3>D) Connecting NodeMCU DEVKIT v1.0 to our LAN and Internet</h3><h4>D) 1) Procedure</h4><p>Serious things begin now! To connect our NodeMCU DEVKIT v1.0 to our LAN, this latter should of course have a Wi-Fi access point. Also, our LAN gateway should run a DHCP server to give an IPv4 address to our component when it asks for one. And if we want our component to go to Internet though we have only one public IP address, our gateway should implement NAT. Nothing to worry about, almost all domestic Fiber/ADSL boxes do that naturally.</p><p>To get connected to our LAN, we just have to copy the <strong>void setup()</strong> function of one of the “Arduino core for ESP8266” examples, for instance: [<a href="https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino">link</a>] (or you can reach it by: <strong>Arduino_IDE&gt;File&gt;Examples&gt;ESP8266Wifi&gt;WifiClient</strong>).</p><p>The short program looks like this, don’t forget to replace the values of WIFI_SSID and WIFI_PASSWORD by yours:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c2f333962fdc9c7a4e172c8276d613c5/href">https://medium.com/media/c2f333962fdc9c7a4e172c8276d613c5/href</a></iframe><p>And this is the kind of screenshot we get on Serial Monitor:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/329/1*-Mt3uxPxnp8J2s-kJfPtiQ.png" /><figcaption>NodeMCU DEVKIT v1.0 got connected and obtained an IP address by DHCP</figcaption></figure><p>Now, we encourage you to continue this example and implement totally a TCP client or even a web server, finding help in “Arduino core for ESP8266” examples and Internet. By lack of time, we won’t do it here (but again, do it!). We prefer focussing on a client that connects to a Firebase RealTime Database…</p><h4>D) 2) Security considerations</h4><p>Hard coding Wi-Fi SSID and password in the sketch might be a problem:</p><ul><li>if we want to communicate the sketch to others, we have to mask these informations,</li><li>if the Wi-Fi configuration changes, we have to reprogram the device.</li></ul><p>To avoid these drawbacks, there is a solution called <strong>WifiManager</strong> [<a href="https://github.com/tzapu/WiFiManager">link</a>], we didn’t personally test it but it has many stars on github.</p><p>Anyway, whatever the manner <strong>Wi-Fi SSID and password</strong> are specified with, at the end they <strong>lie in plain text in the flash memory</strong>. If a person with bad intention has <strong>physical access to the chip</strong>, it is really easy for it to get all credentials.</p><p>For instance, we dumped our 4MiB flash memory to a file with the use of <strong>esptool </strong>[<a href="https://github.com/espressif/esptool">link</a>], an official Espressif tool:</p><pre>esptool.py -p COM6 read_flash 0 0x400000 flash_contents.bin</pre><p>Then, searching in an editor the Wi-Fi SSID, we find close to it the Wi-Fi password:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/625/1*VQ5XcrTjfo9MML-vAESqOQ.png" /><figcaption>Searching for Wi-Fi password once flash memory is dumped</figcaption></figure><p>Later, we will also have to store credentials that give access to a Firebase database. The problem will be the same as here… they will be easily discoverable.</p><p><strong>How can we protect credentials from hackers having physical access to the chip ?</strong></p><ul><li>ESP8266 doesn’t support native flash encryption. A possibility is to make it work with an encrypting device like <strong>ATECC508A</strong> or <strong>ATECC608A </strong>[<a href="https://www.microchip.com/wwwproducts/en/ATECC608A">link</a>] from Microchip/Atmel. <strong>Mongoose OS</strong> (a step further from this present post) uses this solution to encrypt sensitive information when dealing with ESP8266 [<a href="https://mongoose-os.com/docs/mongoose-os/userguide/security.md#atecc608a-crypto-chip">link</a>].</li><li>But maybe it would be simpler to upgrade to a <strong>ESP32 chip</strong> (we talked about this ESP8266 successor at the beginning of this post), a device with native encryption capability. Still with Mongoose OS, we explain in this post [<a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-2nd-config-state-encrypt-7c5e937e5be9">link</a>] how to encrypt an ESP32 SPI flash memory.</li></ul><h3>E) Connecting and pushing to a Firebase Realtime Database</h3><h4>E) 1) What is Firebase Realtime Database?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ILPd9z7VdKnDWJklf3lpPg.png" /><figcaption>Firebase Reatime Database logo</figcaption></figure><p><strong>Firebase</strong> [<a href="https://firebase.google.com/">link</a>] is a huge Google platform to help build sophisticated, mobile and web realtime apps. Each Firebase project has one online NoSQL databases (to chose between <strong>Firebase Realtime Database</strong>, a simple yet powerful database,<strong> </strong>or <strong>Cloud Firestore</strong>, a more sophisticated, document oriented database), handles authentication, cloud messaging, cloud storage, cloud functions, etc.</p><p><em>Note:</em> Firebase is deeply linked to <strong>Google Cloud</strong>. To learn more about their relationship, read this post from <a href="https://medium.com/u/6a53613f4e6d">Doug Stevenson</a> : [<a href="https://medium.com/@CodingDoug/whats-the-relationship-between-firebase-and-google-cloud-57e268a7ff6f">link</a>].</p><p>What interests us here is the first online NoSQL database called Firebase Realtime Database because we will push into it each new (10-bit equivalent) analog data NodeMCU DEVKIT v1.0 has just measured.</p><p>For the moment, this is a basic usage of this database (it is capable of much more!) but the good point is that new data won’t be stored in NodeMCU DEVKIT v1.0. Thus, we can have a really <strong>big measurement history </strong>without being concerned by our component memory limitation.</p><p>Another good point is that we will use later the “real time” functionality of this database to :</p><ul><li>add a timestamp to each new pushed value. This is discussed in a second post dealing with Firebase Cloud Functions [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>].</li><li>plot to a web app data as it arrives. This is discussed in a third post dealing with Firebase SDK [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4">link</a>].</li></ul><h4>E) 2) Let’s store data!</h4><p>After NodeMCU DEVKIT v1.0 obtained an Internet connection, it will connect <strong>over a secure connection</strong> and <strong>with credentials</strong> to our Firebase Realtime Database.</p><p>Then, for each captured value of luminosity, it will <strong>push it to the Firebase Realtime Database</strong> with the following process: In the database, each incoming <strong>value </strong>is associated with a unique <strong>key</strong>, called a <strong>push ID</strong>. Then, this key/value pair is stored in a <strong>node</strong> of the database.</p><p>Each key is unique, has 20 characters and keys are chronological. If you’re curious, this post [<a href="https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html">link</a>] describes how push IDs are generated.</p><p>For instance, after NodeMCU DEVKIT v1.0 made 3 pushes in the node named measures in the database, the latter looks like this, in JSON:</p><pre>{<br>  &quot;measures&quot; : {<br>    &quot;-LH2fJPeouqr_JPE6XXZ&quot; : 852,<br>    &quot;-LH2gSuEplF4sAHWaGaE&quot; : 801,<br>    &quot;-LH2hbPTIfpIj0Ta6OsK&quot; : 728<br>  },<br>  &quot;another_node&quot; : {<br>    ...<br>  }<br>}</pre><p>Of course, push is not the only avalaible operation in Firebase Realtime Database. You can update a node, listen to events on it (<em>e.g.</em> child added), delete it... There is a <strong>Firebase SDK</strong> to perform all these actions for several languages (JavaScript, C++ for instance) and operating systems (Android, iOS).</p><p>Unfortunately, in Firebase documentation, there is no mention of something like “Firebase SDK for Arduino core for ESP8266<strong>”</strong>. But, but… a library called <strong>FirebaseArduino </strong>exists and its github repo is here [<a href="https://github.com/firebase/firebase-arduino">link</a>]!</p><p>Nevertheless, it’s written:</p><blockquote>“ The Arduino library is <a href="https://github.com/googlesamples/firebase-arduino/issues">under heavy development</a>, experimental, unversioned and its API is not stable.”</blockquote><p>Ok! That’s why experimental projects are for! Let’s go ahead.</p><h4>E) 3) Setting up a Firebase project and its Realtime Database</h4><p><em>Note:</em> We won’t do it here but it is good practice to have a Firebase project for development and another one for production.</p><p>Below are detailed the steps we went through:</p><p><strong>a.</strong> Create a Firebase project by going to <strong>Firebase console</strong>: <a href="https://console.firebase.google.com/">https://console.firebase.google.com</a></p><p><strong>b.</strong> Click the <strong>Add project</strong> blue icon and then give a name to it, for us, this will be esp8266-rocks:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/613/1*5_sokPgnuYyrJ_TDZI4cTg.jpeg" /><figcaption>Firebase console — Creating a Firebase project</figcaption></figure><p><strong>c. </strong>Click on <strong>Database</strong> on the aside menu:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/510/1*cfStXjP9jVPehE46nJN3zw.jpeg" /><figcaption>Firebase console — Selecting Database</figcaption></figure><p><strong>d.</strong> Choose <strong>Realtime Database</strong>, not <strong>Cloud Firestore</strong>. Then <strong>Create database</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/354/1*XmWZAJ54zjt0skiv6ly0jg.jpeg" /><figcaption>Firebase Console — Creating the Realtime Database for our project</figcaption></figure><p><strong>e. </strong>Set <strong>read/write rules</strong> to true for the moment. It’s not really important as we will come back later to this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/812/1*R3gxtzejCAlx1WM80nG_kA.jpeg" /><figcaption>Firebase Console — Setting temporary read/write rules</figcaption></figure><p><strong>f. </strong>We end up with a graphical view of our (still empty) database:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/429/1*GA79EHXhkOxXWNmzKvzBqA.jpeg" /><figcaption>Firebase Console — Graphical view of Firebase Realtime Database after creation</figcaption></figure><p><em>Note:</em> We can discover our database by adding key/value pairs clicking “+” in the above screen. We can also nest data, have objects, arrays, etc. If we export this database we’ll see that it is in fact a Javascript object described in JSON.</p><p><em>Note:</em> With <strong>Firebasebase “Spark” pricing plan</strong> (the free one), we can store up to 1 GB in a Firebase Realtime Database. To know the currently used storage , we hit <strong>Project Overview</strong> in Firebase Console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/214/1*iJHD5-c9eccbYKSC_B-tXQ.png" /><figcaption>Firebase Console — Project Overview</figcaption></figure><p><strong>g. </strong>Let’s fix the read/write rules now by clicking on <strong>Rules</strong> tab.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/537/1*N0uuGs86lVceXkJSTXLNBA.png" /><figcaption>Firebase Console — Setting Firebase Realtime Database read/write rules (We hit Publish button when done.)</figcaption></figure><pre>{<br>  &quot;rules&quot;: {<br>    &quot;measures&quot;: {<br>        &quot;.read&quot;: &quot;false&quot;,<br>        &quot;.write&quot;: &quot;false&quot;<br>    }<br>  }<br>}</pre><p><em>What does this mean?</em></p><p>Those rules mean that a third party with no admin privileges, <em>e.g. </em>a script on a website, an Android app… trying to write to/read from measures node in the database will be denied. On the contrary, with admin privileges, all write to/read from any database node are permitted!</p><p><em>So, who has admin privileges?</em></p><ul><li>The owner of the Firebase Project (us!) manipulating the database from the Firebase Console.</li><li>Some Cloud Function like the one we’ll write in Post 2 [<a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">link</a>].</li><li>An entity accessing the database with a <strong>“secret” type authentication</strong>. This is the case of an ESP8266 using <strong>FirebaseArduino library</strong> (described below).</li></ul><p><strong>h. </strong>At least, it’s time to get authentication credentials for our NodeMCU DEVKIT v1.0. We adapt here the (outdated) “configuration” in <strong>FirebaseDemo</strong> example from <strong>FirebaseArduino</strong> github repository [<a href="https://github.com/firebase/firebase-arduino/tree/master/examples/FirebaseDemo_ESP8266">link</a>].</p><ul><li>What we will call later in Arduino program FIREBASE_HOST corresponds to the Project Id appended by .firebaseio.com , for example esp8266-rocks.firebaseio.com. It’s the URL to the database.</li><li>What we will call later in Arduino program FIREBASE_AUTH corresponds to the <strong>“secret”</strong> we obtain by the 5-step sequence below:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/655/1*OwlSWHtk-qbkiwt7O_MrXg.jpeg" /><figcaption>Firebase Console — Towards obtaining a “secret”</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vpWwKf7Er3NKEsJZpVg0tA.jpeg" /><figcaption>Firebase Console — The “secret” is 40-char long string. It can be revealed and copied to clipboard by clicking Show button</figcaption></figure><p>As indicated, <strong>getting authenticated by a Project ID and a secret is deprecated</strong>. The reason is that when a device gets authenticated that way, it has admin privleges on the database and <strong>this is not a good practice</strong>. Moreover, using the “secret” authentication technique deprives us from the subtility of the Firebase Security Rules feature (see [<a href="https://firebase.google.com/docs/database/security/">link</a>]).</p><p>But at the time of writing, it seems that there is no other such ready-made solution for authenticating an ESP8266 Arduino to Firebase. On the <strong>FirebaseArduino API Reference </strong>[<a href="https://firebase-arduino.readthedocs.io/en/latest/">link</a>], the only function to connect to a Firebase project is Firebase.begin(..., ...) and it requires two parameters like the ones we’ve seen before:FIREBASE_HOST (a URL) and FIREBASE_AUTH (a secret). It is said however that this latter can also be a <strong>token</strong> (and so we wouldn’t use anymore this deprecated solution) but its management is not so easy, given our project.</p><p><a href="http://firebase-arduino.readthedocs.io/en/latest/">Class Documentation - firebase-arduino 1.0 documentation</a></p><p>Discussion about updating the authentication process in FirebaseArduino (<em>i.e.</em> no more use of a secret) is active on github [<a href="https://github.com/firebase/firebase-arduino/issues/224">link</a>]. Informations on this topic are welcomed.</p><p><em>Note: </em>We can have several secrets for one database (thanks to “Add secret” button on the view above), for instance one per ESP8266 device connected. In that case, the database should then be managed to have a supplementary nesting level, just like in the view below. But, one more time, with “secret” authentication, device #1 has access to device #2 data and <em>vice versa</em>.</p><pre>{<br>  &quot;measures&quot; : {<br>    &quot;device01&quot;: {<br>      &quot;-LH2fJPeouqr_JPE6XXZ&quot; : 852,<br>      &quot;-LH2gSuEplF4sAHWaGaE&quot; : 801,<br>      &quot;-LH2hbPTIfpIj0Ta6OsK&quot; : 728<br>    },<br>    &quot;device02&quot;: {<br>      &quot;-LTOa64c9TKkr9s3_3Xn&quot; : 16,<br>      &quot;-LTObDyJrL_dsHw6mZ4k&quot; : 13,<br>      &quot;-LTOcLvAP49gBd6U9OhE&quot; : 18,<br>      &quot;-LTOdTsrDe_SEybwoXTI&quot; : 14<br>    }<br>  }<br>}</pre><h4>E) 4) Setting up Arduino IDE to use FirebaseArduino library</h4><p>We adapt here the (outdated) “software setup” documentation in <strong>FirebaseDemo</strong> example from <strong>FirebaseArduino</strong> github repository [<a href="https://github.com/firebase/firebase-arduino/tree/master/examples/FirebaseDemo_ESP8266">link</a>].</p><p><strong>a.</strong> First we download FirebaseArduino library:</p><p><a href="https://github.com/googlesamples/firebase-arduino/archive/master.zip">https://github.com/googlesamples/firebase-arduino/archive/master.zip</a></p><p><strong>b. </strong>Then we install it in Arduino IDE: <strong>Arduino_IDE&gt;Sketch&gt;Include Library&gt;Add .ZIP Library…</strong> and we choose the zip we just downloaded.</p><p>But Firebase Arduino has a dependency called <strong>ArduinoJson library</strong> [<a href="https://github.com/bblanchon/ArduinoJson">link</a>]. We also need to install it in Arduino IDE.</p><p><strong>c.</strong> First we download ArduinoJson library:</p><p><a href="http://downloads.arduino.cc/libraries/github.com/bblanchon/ArduinoJson-5.13.2.zip">http://downloads.arduino.cc/libraries/github.com/bblanchon/ArduinoJson-5.13.2.zip</a></p><p>(Another possible link for this library is [<a href="https://github.com/bblanchon/ArduinoJson/releases">link</a>].)</p><p><strong>d. </strong>Then we install it in Arduino IDE: <strong>Arduino_IDE&gt;Sketch&gt;Include Library&gt;Add .ZIP Library…</strong> and we choose the zip we just downloaded.</p><h4>E) 5) NodeMCU DEVKIT v1.0 program to push values to Firebase Realtime Database</h4><p>In FirebaseArduino github page, there is several example and one of them is called FirebaseDemo [<a href="https://github.com/firebase/firebase-arduino/tree/master/examples/FirebaseDemo_ESP8266">link</a>]. It illustrates lot of functions of this FirebaseArduino library. We encourage you to explore theses functions (and see lively their effects in Firebase console) as we will only focus on the one we need in our project.</p><p>Indeed, among these functions we will just use the one called pushInt(). For example, to push the value of the int (integer) variable named sensorValue to the node &quot;measures&quot; of the Firebase Realtime Database, it is a simple as that:</p><pre>Firebase.pushInt(&quot;measures&quot;, sensorValue);<br>if (Firebase.failed()) {<br>  // Do something if push went wrong<br>}</pre><p>We can thus complete our luminosity measurement program:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/74cb82ce9e9e5a7bbc11dece16f57ce1/href">https://medium.com/media/74cb82ce9e9e5a7bbc11dece16f57ce1/href</a></iframe><p>WAAO! Look what we get in Firebase Realtime Database Console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/466/1*6aFAQyXJo3nQ-0BUjf45Rw.gif" /><figcaption>Firebase Console — Each pushed value of luminosity is associated with a unique PushID</figcaption></figure><p>So, it seems that luminosity in North of France isn’t so bad, no ?</p><p><strong><em>Troubleshooting</em></strong></p><p>If things don’t work, you will get the message &quot;pushing failed:...&quot; in Arduino IDE Serial Monitor.</p><ul><li>In Arduino program, check your credentials FIREBASE_HOST and FIREBASE_AUTH.</li><li>Try setting temporarily your database rules .&quot;read&quot; and .”write&quot; to &quot;true&quot;.</li><li>UPDATE (November 27, 2018 - three months after this post was initially released) : Today we wanted to make our NodeMCU DEVKIT v1.0 work again. But, although everything was set up like before,we only got tons of &quot;pushing failed:...&quot;! Searching on the web, we managed to solve this issue. It was due to a <strong>Firebase certificate</strong> <strong>fingerprint </strong>that had changed. We can find this latter by typing our project URL appended by /.json in a browser and hit the lock icon to access certificate details. On the other side, in our FirebaseArduino library folder firebase-arduino-master/src, there is a file called FirebaseHttpClient.h. Inside it, there is a line where the fingerprint should be declared (hexadecimal digits by pairs). It has to match the one seen in the certificate details. That was no longer the case!</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/555/1*sHZzyDUxNfBIiJpBppQ4iA.jpeg" /><figcaption>Firebase fingerprint and its match in FirebaseHttpClient.h</figcaption></figure><h3>F) Let’s save power with ESP8266 deep sleep mode</h3><p>When we need to push a new measure every 3 seconds (to be exact : measure <em>then</em> push <em>then </em>delay 3 seconds), it’s not worth putting ESP8266 Wi-Fi off after the push is done. ESP8266 would lose seconds to reconnect and we would miss some measures. But we have to be aware that Wi-Fi draws a lot of power. For instance, ESP-12E consumes <strong>120 mA</strong> while transmitting <em>via</em> Wi-Fi N. In such a situation we can’t run in an autonomous way for days and days with a <strong>USB (solar) power bank</strong>.</p><p>Things are different when we need a new measure every 5 minutes (for instance). In this case it is worth putting ESP-12E in <strong>deep sleep mode</strong> (consumption: <strong>10 µA</strong>) after the push to database is done:</p><pre>// Measure analog value:<br>// ...<br>// Push value to database:<br>// ...<br>// Now let&#39;s go in deep sleep for 5 minutes:<br>ESP.deepSleep(300e6, WAKE_RF_DEFAULT); // 1st parameter is in µs!</pre><p>ESP.deepSleep() instruction puts ESP-12E in deep sleep mode during a time indicated in µs (first parameter). The WAKE_RF_DEFAULT mode (second parameter) ensures that Wi-Fi will be restarted when the chip wakes from deep sleep.</p><p>Once the deep sleep duration is achieved, <strong>D0 (GPIO16) </strong>pin of NodeMCU DEVKIT v1.0 will issue a high to low transition. So <strong>D0 pin has to be tied to RST pin in order to provoke a chip reset and make the program start again</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/795/1*R4R0PZSDmoCT1hV4C5Cslw.jpeg" /><figcaption>Enabling the chip to reset after deep sleep thanks to the D0 to RST connection</figcaption></figure><p>The overall average current will drop to <strong>mA</strong> and supplying the NodeMCU DEVKIT v1.0 by a power bank is now feasible. If we have time, we will make measures and update this post.</p><p><em>Important note: </em>It’s a shame but D0 (GPIO16) controls as well the built-in LED of NodeMCU DEVKIT v1.0. Due to D0 to RST connection, <strong>we must forget the idea of managing the built-in LED</strong> as we did until now, <strong>otherwise we will provoke a chip reset</strong> when we set the built-in LED on!</p><p><em>Important note:</em> While uploading the program from Arduino IDE to NodeMCU DEVKIT v1.0, the D0 to RST connection has to be removed otherwise upload won’t work.</p><p>One last thing: The code has to be refactored because we regularly provoke a reset. Thus, all code takes place in void setup() function. The void loop() function is an empty one.</p><p>The code is below. Try it now:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e2976806e8ebeace4bcb00034d41414b/href">https://medium.com/media/e2976806e8ebeace4bcb00034d41414b/href</a></iframe><p><em>Note:</em> When concerned with power saving, <strong>Feather HUZZAH development board</strong> (cf. part A) 2)) could be a good choice because it has a 3.7 V supply input. Sadly, we didn’t have time to investigate this solution.</p><h3>Conclusion</h3><p>We’ve travelled a lot to discover different technologies (<strong>ESP8266</strong>, <strong>Arduino IDE</strong>, <strong>Firebase Realtime Database</strong>) and link them together to build the fundations of a low cost ans low power IoT project! And, even if we’re not fully satisfied with the ESP8266 “secret” authentication, it is a secure project… as long as a hacker doesn’t have physical access to the ESP8266 chip.</p><p>There is more to come:</p><ul><li>In a second post we’ll see how to add a timestamp to each measured value of luminosity thanks to a <strong>Firebase Cloud Function</strong>.</li><li>And in a third one we will lively plot luminosity values as they arrive, thanks to <strong>a web app </strong>using <strong>plotly.js</strong>.</li></ul><p>So stay tuned!</p><p><strong>Links to the posts: </strong>Post 1, <a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-2-14b0609d3f5e">Post 2</a>, <a href="https://medium.com/@o.lourme/our-iot-journey-through-esp8266-firebase-angular-and-plotly-js-part-3-644048e90ca4">Post 3</a>, <a href="https://github.com/olivierlourme/esp8266webapp">GitHub</a> and <a href="https://esp8266-rocks.firebaseapp.com/">Live Demo</a>.</p><p><strong>Check also this post:</strong> <a href="https://medium.com/@o.lourme/gcp-cloudiotcore-esp32-mongooseos-1st-5c88d8134ac7?source=---------4------------------">GCP-Cloud IoT Core with ESP32 and Mongoose OS</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a07db495ac5f" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>