tag:blogger.com,1999:blog-75497052155134889452024-03-28T20:30:03.600-07:00IoT SharingInternet Of Things and Machine LearningTech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.comBlogger69125tag:blogger.com,1999:blog-7549705215513488945.post-78090174078730250322023-11-26T22:43:00.000-08:002023-11-26T22:43:56.093-08:00Demo 56: Steps to deploy tinyml (tensorflow lite) on esp32<p><span style="color: var(--color-text); font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal);">Steps to deploy tinyml (tensorflow lite) on esp32:</span></p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);">- Using transfer learning from a pre-trained network</p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);">- Fine-tuning the model to achieve the best result</p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);">- Optional: Quantization</p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);">- Convert the model to CC code</p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);">- Implement inference code on esp32</p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);"><br style="box-sizing: inherit;" /></p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);">Here is a demo that deploys MobileNetV1 on ESP32</p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);">https://github.com/nhatuan84/steps-tinyml-esp32</p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);"><br style="box-sizing: inherit;" /></p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-size: inherit; font-weight: var(--artdeco-reset-typography-font-weight-normal); line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);"><br style="background-color: white; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 20px; white-space-collapse: preserve;" /></p>Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com0tag:blogger.com,1999:blog-7549705215513488945.post-91785660329881742882022-11-28T05:07:00.006-08:002023-11-26T22:42:46.645-08:00Demo 55: Firmware Update Over The Air (FOTA) for ECU (STM32) via ESP32 (HTTP - CAN protocols)<p><b>1. Introduction</b></p><p>FOTA is keeping an important role now a day. It helps to update the Firmware without recalling the product, especially in automotive where recalling costs millions to billions of USD.</p><p>The demo with old firmware will blink the Red Led. The new firmware will blink the Blue Led.</p><p>This demo is setup as below:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Vi7yMixqj2rX5FEzUpk7bwQEw9EIgjQ7llgZsXVZhfNHKcTLGFy8d6pKCNj4uS53KhpXo_i9BPSy7ooMajArs3-IQhqCdSZPKqgt-hzBeYMKzqpz3ITEA-I_6O8YoNaDYuU0-USeGVgOmGUEzpFBnTVcnHNV4stbmd08ap61O0HWIdCeJSf-R5Q/s483/FOTA.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="483" data-original-width="412" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Vi7yMixqj2rX5FEzUpk7bwQEw9EIgjQ7llgZsXVZhfNHKcTLGFy8d6pKCNj4uS53KhpXo_i9BPSy7ooMajArs3-IQhqCdSZPKqgt-hzBeYMKzqpz3ITEA-I_6O8YoNaDYuU0-USeGVgOmGUEzpFBnTVcnHNV4stbmd08ap61O0HWIdCeJSf-R5Q/s16000/FOTA.jpg" /></a></div>This demo reused some demos: <div><a href="http://www.iotsharing.com/2017/09/how-to-use-arduino-esp32-can-interface.html" target="_blank">ESP32 CAN</a></div><div><a href="http://www.iotsharing.com/2018/01/esp32-multipart-upload-file-and-download-via-http.html" target="_blank">ESP32 Download and Upload</a></div><div><a href="http://www.iotsharing.com/2019/07/how-to-turn-esp-with-sdcard-or-spiffs-a-web-file-server.html" target="_blank">ESP32 SPIFFS</a></div><div><br /></div><div>STM32 Firmwares include:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiew8Tw54hhCClnyIg9XLydesjha7ywZ-DC22KwFKBiwBXmPFRzLxodjtJo9wie3x8eieYCHf1iHnPgAjpDXO5eSUTCZdQSgk8FQDltAeSBvXfsdZx0Yk4RfVp6PjRuaWxkT4nMgtnHvajJKDC31MHiTzf9eJrHsNUay9zTa8f32c30k20WAsrMmqc/s351/STM32vsESP32.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="141" data-original-width="351" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiew8Tw54hhCClnyIg9XLydesjha7ywZ-DC22KwFKBiwBXmPFRzLxodjtJo9wie3x8eieYCHf1iHnPgAjpDXO5eSUTCZdQSgk8FQDltAeSBvXfsdZx0Yk4RfVp6PjRuaWxkT4nMgtnHvajJKDC31MHiTzf9eJrHsNUay9zTa8f32c30k20WAsrMmqc/s16000/STM32vsESP32.jpg" /></a></div><br /><div>STM32 Flash layout for this demo:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGY2GQZ0naTZ45fM6ND6H5-g0iCzHkvDDHAhyEIfuhyPyI2Go9R9_sV47n1aUZOVyI9xLEOYxvFCl19RERSd5ECdbXC4xf-6ThBRE82j46VQahpk5vaf7dTEUBGoKSTlL25OD7q-i6e69-57wOz2QtrM7e5uDihJwm22liTTnSOTix61cZ5Va19ec/s421/STM32memory.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="421" data-original-width="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGY2GQZ0naTZ45fM6ND6H5-g0iCzHkvDDHAhyEIfuhyPyI2Go9R9_sV47n1aUZOVyI9xLEOYxvFCl19RERSd5ECdbXC4xf-6ThBRE82j46VQahpk5vaf7dTEUBGoKSTlL25OD7q-i6e69-57wOz2QtrM7e5uDihJwm22liTTnSOTix61cZ5Va19ec/s16000/STM32memory.jpg" /></a></div><div><p><b>2. Hardware</b></p><p>1 ESP32 Dev module</p><p><a href="https://www.amazon.com/SN65HVD230-Transceiver-Communication-Module-Arduino/dp/B01L47TLVQ" target="_blank">2 CAN transceivers</a> </p><p><a href="https://www.st.com/en/evaluation-tools/stm32f4discovery.html" target="_blank">STM32F407 Discovery board</a></p><p>The connection between CAN transceiver and ESP32: <a href="http://www.iotsharing.com/2017/09/how-to-use-arduino-esp32-can-interface.html" target="_blank">ESP32 CAN</a></p><p>The connection between CAN transceiver and STM32: </p><p>- PB8 x CRX</p><p>- PB9 x CTX</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGbf3b0uZQNn855it82CrP5wc-8hwPHpMpwXxf5wKLYE3Iowi0oV0lMAgHZIZoqAcJBJ2Idz8GqUjKO6flicE1CjGCcB4Q02fKu0QgCSZNnp3weN1Il13ymzi63HkluZjiD22wHXXr2_Fob9VAzEfJRTemA0wK17UdqeFu4wIkuTyaN2YxLFJcrCU/s2776/FOTA.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2776" data-original-width="2082" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGbf3b0uZQNn855it82CrP5wc-8hwPHpMpwXxf5wKLYE3Iowi0oV0lMAgHZIZoqAcJBJ2Idz8GqUjKO6flicE1CjGCcB4Q02fKu0QgCSZNnp3weN1Il13ymzi63HkluZjiD22wHXXr2_Fob9VAzEfJRTemA0wK17UdqeFu4wIkuTyaN2YxLFJcrCU/w300-h400/FOTA.jpg" width="300" /></a></div><p><b>3. Software</b></p><p>STM32 Flowchart:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4zmIuwYmi5ddAx4muTlurBvtMUONxVqrBXBWTXFCX7IktRYynik4SE1LUsb-p3flH6pOXBxxvxdDQzVZNAICe4RadmlE8UgE05-q7qipHQKrTbD6g8KX1Zp1vsQZ4WAuUYzoq2P6REIqehIlFepssvjLKJh0sBiI_8SOls2mkOj0JAVpvzGqb42M/s591/STM32flowchart.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="591" data-original-width="406" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4zmIuwYmi5ddAx4muTlurBvtMUONxVqrBXBWTXFCX7IktRYynik4SE1LUsb-p3flH6pOXBxxvxdDQzVZNAICe4RadmlE8UgE05-q7qipHQKrTbD6g8KX1Zp1vsQZ4WAuUYzoq2P6REIqehIlFepssvjLKJh0sBiI_8SOls2mkOj0JAVpvzGqb42M/s16000/STM32flowchart.jpg" /></a></div><div class="separator" style="clear: both; text-align: left;">ESP32 Flowchart:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQNQ2A33k8LxrwPhlFtXJ3skB38OxJP0u3myCAoqZV_IfJvevbSfuOnQ1Q7mAtWhBMZrNOrCWd0xfQ8BVbZ_5AqSePFSl86LI-srwqqe_c-C3NZwM-3HzrLx8YoOU-tjLInGi_vr_xVjzAKLVEcTLCi918zXnEpFiaKd435ckkKyKdAW88agKjbOg/s851/ESP32flowchart.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="851" data-original-width="189" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQNQ2A33k8LxrwPhlFtXJ3skB38OxJP0u3myCAoqZV_IfJvevbSfuOnQ1Q7mAtWhBMZrNOrCWd0xfQ8BVbZ_5AqSePFSl86LI-srwqqe_c-C3NZwM-3HzrLx8YoOU-tjLInGi_vr_xVjzAKLVEcTLCi918zXnEpFiaKd435ckkKyKdAW88agKjbOg/s16000/ESP32flowchart.jpg" /></a></div>CAN Flowchart</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwznmCrxLiK6Srh-3UVPhCwE1hMP35S_T_mEeYnUBkVrMQcMw1MReXu2cxUxUKf-IF3r6HTvZF8d3IhDm3d0MZ8Z9DqSYAyfvaydrgJxLWXlV68XVUSrv5SZQk-jg4ygeC5-lk0M5qF-KzfcOwcpD7T8LUnpYw4aqfaDYBElBvs3k4eb50r3vyU4k/s682/CANflowchart.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="682" data-original-width="401" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwznmCrxLiK6Srh-3UVPhCwE1hMP35S_T_mEeYnUBkVrMQcMw1MReXu2cxUxUKf-IF3r6HTvZF8d3IhDm3d0MZ8Z9DqSYAyfvaydrgJxLWXlV68XVUSrv5SZQk-jg4ygeC5-lk0M5qF-KzfcOwcpD7T8LUnpYw4aqfaDYBElBvs3k4eb50r3vyU4k/s16000/CANflowchart.jpg" /></a></div><br /><div>The format of SW Info file (NSW.txt): <b>version;url</b> (Example: 1.3;http://192.168.1.3:8000/App1.bin)<br /><div class="separator" style="clear: both; text-align: left;"><br /></div>The FW file (.bin) and NSW.txt are put under a directory and a Python3 Simple HTTP is used. Under the SW directory open the Terminal and run the command: <b>python3 -m http.server</b><br /><p>The source code is updated here: </p><p><a href="https://github.com/nhatuan84/Firmware-Update-Over-The-Air-FOTA-for-ECU-STM32-via-ESP32-" target="_blank">https://github.com/nhatuan84/Firmware-Update-Over-The-Air-FOTA-for-ECU-STM32-via-ESP32-</a><br /></p><p><b>4. Result</b></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="360" src="https://www.youtube.com/embed/KuZePXme9r8" width="480" youtube-src-id="KuZePXme9r8"></iframe></div><br /><p><br /></p></div>Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com1tag:blogger.com,1999:blog-7549705215513488945.post-81679029933432174952021-11-06T07:24:00.001-07:002021-11-06T07:26:33.230-07:00Demo 53: ESP32 Camera as a Webcam for Skype/Zoom video call<p><b>1. Introduction</b></p><p>Today I will make a very interseting demo. That is turning your ESP32 Cam into a webcam for Skype/Zoom video call.</p><p>This demo only applies for Linux OS. Since it will use v4l2loopback device.</p><p>This demo can be applied for deep learning projects with ESP32 Camera. You can apply filter before forward the image to Skype/Zoom. For example I will apply A.I to hide eyes by red circle in this demo. <br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv0T-la6sn1Ki_022qkdfaGjWekju1Zrn8IkopQP026iZXqAX7bEq52q4p6x4_2HlUTrhdnl8zo624GlNpxu7ax70ABPAPac-YPQprtBSG19m4je5TOII36rw6Bgje6oDN00cIKEPCOaE/s706/sky1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="677" data-original-width="706" height="307" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv0T-la6sn1Ki_022qkdfaGjWekju1Zrn8IkopQP026iZXqAX7bEq52q4p6x4_2HlUTrhdnl8zo624GlNpxu7ax70ABPAPac-YPQprtBSG19m4je5TOII36rw6Bgje6oDN00cIKEPCOaE/s320/sky1.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-LlKo0xsrLN4WZqSZQef49UpI13AmHdI5A4r7RGQoYypf4his5HaUoj71r3M1Z_515PgEicTMaXAVgp6FRJLUwmd0nEAhZBGabTOckT2Ttj-o_zh_LTTiujl1VSTL1GxyoIMW_MAiGDM/s711/sky3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="674" data-original-width="711" height="303" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-LlKo0xsrLN4WZqSZQef49UpI13AmHdI5A4r7RGQoYypf4his5HaUoj71r3M1Z_515PgEicTMaXAVgp6FRJLUwmd0nEAhZBGabTOckT2Ttj-o_zh_LTTiujl1VSTL1GxyoIMW_MAiGDM/s320/sky3.png" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p><b>2. Hardware</b></p><p>- A Linux (Ubuntu) PC</p><p>- A ESP32 Camera</p><p><b>3. Software</b></p><p>- Install the software on Linux PC:</p><p><b><i>+ sudo apt install python3-pip</i></b></p><p><b><i>+ pip3 install --user cv2 </i></b></p><p><b><i>+ pip3 install --user numpy</i></b></p><p><b><i>+ pip3 install git+https://github.com/antmicro/python3-v4l2 </i></b></p><p><b><i>+ git clone https://github.com/umlaeute/v4l2loopback.git (then </i></b><b><i>make && sudo make install)</i></b></p><p>From Terminal typing: </p><p><b><i>sudo modprobe v4l2loopback video_nr=6</i></b></p><p>This will create virtual <b>/dev/video6</b> device. You can check it by command:</p><p><b><i>ls /dev/video*</i></b></p><p>Skype/Zoom will read <b>/dev/video6</b> device for images</p><p>The communication between ESP32 Cam and PC is TCP Server/Client.</p><p></p><div class="separator" style="clear: both; font-weight: bold; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHD3XjAQ7UcQQH72eXpvzS8evUrLXyyfxiJ70g9-tgG85ipjek7f7dPCo73HfnshHf6Ilb4qYQlNoP7YUPBKY6ageNIW5JF6tnCa51J03OhqPy3PRgSxowLKhceP6Hhu3gzgnyzI7WHvY/s521/sky2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="61" data-original-width="521" height="74" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHD3XjAQ7UcQQH72eXpvzS8evUrLXyyfxiJ70g9-tgG85ipjek7f7dPCo73HfnshHf6Ilb4qYQlNoP7YUPBKY6ageNIW5JF6tnCa51J03OhqPy3PRgSxowLKhceP6Hhu3gzgnyzI7WHvY/w640-h74/sky2.png" width="640" /></a></div><br />The ESP32 Cam Arduino code:
<!--HTML generated using hilite.me--><div style="background: rgb(240, 240, 240); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #007020;">#include "esp_camera.h"</span>
<span style="color: #007020;">#include <WiFi.h></span>
<span style="color: #007020;">#define PWDN_GPIO_NUM 32</span>
<span style="color: #007020;">#define RESET_GPIO_NUM -1</span>
<span style="color: #007020;">#define XCLK_GPIO_NUM 0</span>
<span style="color: #007020;">#define SIOD_GPIO_NUM 26</span>
<span style="color: #007020;">#define SIOC_GPIO_NUM 27</span>
<span style="color: #007020;">#define Y9_GPIO_NUM 35</span>
<span style="color: #007020;">#define Y8_GPIO_NUM 34</span>
<span style="color: #007020;">#define Y7_GPIO_NUM 39</span>
<span style="color: #007020;">#define Y6_GPIO_NUM 36</span>
<span style="color: #007020;">#define Y5_GPIO_NUM 21</span>
<span style="color: #007020;">#define Y4_GPIO_NUM 19</span>
<span style="color: #007020;">#define Y3_GPIO_NUM 18</span>
<span style="color: #007020;">#define Y2_GPIO_NUM 5</span>
<span style="color: #007020;">#define VSYNC_GPIO_NUM 25</span>
<span style="color: #007020;">#define HREF_GPIO_NUM 23</span>
<span style="color: #007020;">#define PCLK_GPIO_NUM 22</span>
WiFiServer <span style="color: #06287e;">server</span>(<span style="color: #40a070;">8088</span>);
<span style="color: #902000;">bool</span> connected <span style="color: #666666;">=</span> <span style="color: #007020;">false</span>;
WiFiClient live_client;
<span style="color: #902000;">void</span> <span style="color: #06287e;">configCamera</span>(){
<span style="color: #902000;">camera_config_t</span> config;
config.ledc_channel <span style="color: #666666;">=</span> LEDC_CHANNEL_0;
config.ledc_timer <span style="color: #666666;">=</span> LEDC_TIMER_0;
config.pin_d0 <span style="color: #666666;">=</span> Y2_GPIO_NUM;
config.pin_d1 <span style="color: #666666;">=</span> Y3_GPIO_NUM;
config.pin_d2 <span style="color: #666666;">=</span> Y4_GPIO_NUM;
config.pin_d3 <span style="color: #666666;">=</span> Y5_GPIO_NUM;
config.pin_d4 <span style="color: #666666;">=</span> Y6_GPIO_NUM;
config.pin_d5 <span style="color: #666666;">=</span> Y7_GPIO_NUM;
config.pin_d6 <span style="color: #666666;">=</span> Y8_GPIO_NUM;
config.pin_d7 <span style="color: #666666;">=</span> Y9_GPIO_NUM;
config.pin_xclk <span style="color: #666666;">=</span> XCLK_GPIO_NUM;
config.pin_pclk <span style="color: #666666;">=</span> PCLK_GPIO_NUM;
config.pin_vsync <span style="color: #666666;">=</span> VSYNC_GPIO_NUM;
config.pin_href <span style="color: #666666;">=</span> HREF_GPIO_NUM;
config.pin_sscb_sda <span style="color: #666666;">=</span> SIOD_GPIO_NUM;
config.pin_sscb_scl <span style="color: #666666;">=</span> SIOC_GPIO_NUM;
config.pin_pwdn <span style="color: #666666;">=</span> PWDN_GPIO_NUM;
config.pin_reset <span style="color: #666666;">=</span> RESET_GPIO_NUM;
config.xclk_freq_hz <span style="color: #666666;">=</span> <span style="color: #40a070;">20000000</span>;
config.pixel_format <span style="color: #666666;">=</span> PIXFORMAT_JPEG;
config.frame_size <span style="color: #666666;">=</span> FRAMESIZE_QVGA;
config.jpeg_quality <span style="color: #666666;">=</span> <span style="color: #40a070;">9</span>;
config.fb_count <span style="color: #666666;">=</span> <span style="color: #40a070;">1</span>;
<span style="color: #902000;">esp_err_t</span> err <span style="color: #666666;">=</span> esp_camera_init(<span style="color: #666666;">&</span>config);
<span style="color: #007020; font-weight: bold;">if</span> (err <span style="color: #666666;">!=</span> ESP_OK) {
Serial.printf(<span style="color: #4070a0;">"Camera init failed with error 0x%x"</span>, err);
<span style="color: #007020; font-weight: bold;">return</span>;
}
}
<span style="color: #60a0b0; font-style: italic;">//continue sending camera frame</span>
<span style="color: #902000;">void</span> <span style="color: #06287e;">liveCam</span>(WiFiClient <span style="color: #666666;">&</span>client){
<span style="color: #60a0b0; font-style: italic;">//capture a frame</span>
<span style="color: #902000;">camera_fb_t</span> <span style="color: #666666;">*</span> fb <span style="color: #666666;">=</span> esp_camera_fb_get();
<span style="color: #007020; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>fb) {
Serial.println(<span style="color: #4070a0;">"Frame buffer could not be acquired"</span>);
<span style="color: #007020; font-weight: bold;">return</span>;
}
client.write(fb<span style="color: #666666;">-></span>buf, fb<span style="color: #666666;">-></span>len);
client.flush();
client.print(<span style="color: #4070a0;">"</span><span style="color: #4070a0; font-weight: bold;">\r\n</span><span style="color: #4070a0;">"</span>);
client.flush();
<span style="color: #60a0b0; font-style: italic;">//return the frame buffer back to be reused</span>
esp_camera_fb_return(fb);
}
<span style="color: #902000;">void</span> <span style="color: #06287e;">setup</span>() {
Serial.begin(<span style="color: #40a070;">115200</span>);
WiFi.begin(<span style="color: #4070a0;">"I3.41"</span>, <span style="color: #4070a0;">"xxx"</span>);
Serial.println(<span style="color: #4070a0;">""</span>);
<span style="color: #007020; font-weight: bold;">while</span> (WiFi.status() <span style="color: #666666;">!=</span> WL_CONNECTED) {
delay(<span style="color: #40a070;">500</span>);
Serial.print(<span style="color: #4070a0;">"."</span>);
}
Serial.println(<span style="color: #4070a0;">""</span>);
String IP <span style="color: #666666;">=</span> WiFi.localIP().toString();
Serial.println(<span style="color: #4070a0;">"IP address: "</span> <span style="color: #666666;">+</span> IP);
server.begin();
configCamera();
}
<span style="color: #902000;">void</span> <span style="color: #06287e;">loop</span>() {
WiFiClient client <span style="color: #666666;">=</span> server.available();
<span style="color: #007020; font-weight: bold;">if</span> (client.connected()) {
live_client <span style="color: #666666;">=</span> client;
connected <span style="color: #666666;">=</span> <span style="color: #007020;">true</span>;
}
<span style="color: #007020; font-weight: bold;">if</span>(live_client.connected() <span style="color: #666666;">==</span> <span style="color: #007020;">false</span>) {
connected <span style="color: #666666;">=</span> <span style="color: #007020;">false</span>;
}
<span style="color: #007020; font-weight: bold;">if</span>(connected) {
liveCam(live_client);
}
}
</pre></div>
The Python code on PC:<div><p>The ".xml" files can be downloaded here:</p><p><a href="https://github.com/opencv/opencv/tree/master/data/haarcascades">https://github.com/opencv/opencv/tree/master/data/haarcascades</a></p></div>
<!--HTML generated using hilite.me--><div style="background: rgb(240, 240, 240); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #007020; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">socket</span>
<span style="color: #007020; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">os</span>
<span style="color: #007020; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">fcntl</span>
<span style="color: #007020; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">numpy</span> <span style="color: #007020; font-weight: bold;">as</span> <span style="color: #0e84b5; font-weight: bold;">np</span>
<span style="color: #007020; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">cv2</span>
<span style="color: #007020; font-weight: bold;">from</span> <span style="color: #0e84b5; font-weight: bold;">v4l2</span> <span style="color: #007020; font-weight: bold;">import</span> <span style="color: #666666;">*</span>
<span style="color: #007020; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">time</span>
ESP32_SERVER_IP <span style="color: #666666;">=</span> <span style="color: #4070a0;">'192.168.1.3'</span>
PORT <span style="color: #666666;">=</span> <span style="color: #40a070;">8088</span>
VID_WIDTH <span style="color: #666666;">=</span> <span style="color: #40a070;">320</span>
VID_HEIGHT <span style="color: #666666;">=</span> <span style="color: #40a070;">240</span>
vd <span style="color: #666666;">=</span> os<span style="color: #666666;">.</span>open(<span style="color: #4070a0;">'/dev/video6'</span>, os<span style="color: #666666;">.</span>O_RDWR)
fmt <span style="color: #666666;">=</span> v4l2_format()
fmt<span style="color: #666666;">.</span>type <span style="color: #666666;">=</span> V4L2_BUF_TYPE_VIDEO_OUTPUT
fcntl<span style="color: #666666;">.</span>ioctl(vd, VIDIOC_G_FMT, fmt)
fmt<span style="color: #666666;">.</span>fmt<span style="color: #666666;">.</span>pix<span style="color: #666666;">.</span>width <span style="color: #666666;">=</span> VID_WIDTH
fmt<span style="color: #666666;">.</span>fmt<span style="color: #666666;">.</span>pix<span style="color: #666666;">.</span>height <span style="color: #666666;">=</span> VID_HEIGHT
fmt<span style="color: #666666;">.</span>fmt<span style="color: #666666;">.</span>pix<span style="color: #666666;">.</span>pixelformat <span style="color: #666666;">=</span> V4L2_PIX_FMT_YUV420
fmt<span style="color: #666666;">.</span>fmt<span style="color: #666666;">.</span>pix<span style="color: #666666;">.</span>sizeimage <span style="color: #666666;">=</span> VID_WIDTH <span style="color: #666666;">*</span> VID_HEIGHT <span style="color: #666666;">*</span> <span style="color: #40a070;">3</span>
fmt<span style="color: #666666;">.</span>fmt<span style="color: #666666;">.</span>pix<span style="color: #666666;">.</span>field <span style="color: #666666;">=</span> V4L2_FIELD_NONE
fcntl<span style="color: #666666;">.</span>ioctl(vd, VIDIOC_S_FMT, fmt)
face_cascade <span style="color: #666666;">=</span> cv2<span style="color: #666666;">.</span>CascadeClassifier(<span style="color: #4070a0;">'haarcascade_frontalface_default.xml'</span>)
eyes_cascade <span style="color: #666666;">=</span> cv2<span style="color: #666666;">.</span>CascadeClassifier(<span style="color: #4070a0;">'haarcascade_eye_tree_eyeglasses.xml'</span>)
<span style="color: #007020; font-weight: bold;">while</span> <span style="color: #007020; font-weight: bold;">True</span>:
buffer <span style="color: #666666;">=</span> <span style="color: #007020;">bytearray</span>()
<span style="color: #007020; font-weight: bold;">with</span> socket<span style="color: #666666;">.</span>socket(socket<span style="color: #666666;">.</span>AF_INET, socket<span style="color: #666666;">.</span>SOCK_STREAM) <span style="color: #007020; font-weight: bold;">as</span> s:
s<span style="color: #666666;">.</span>connect((ESP32_SERVER_IP, PORT))
<span style="color: #007020; font-weight: bold;">while</span> <span style="color: #007020; font-weight: bold;">True</span>:
data <span style="color: #666666;">=</span> s<span style="color: #666666;">.</span>recv(<span style="color: #40a070;">1024</span>)
<span style="color: #007020;">len</span> <span style="color: #666666;">=</span> data<span style="color: #666666;">.</span>find(b<span style="color: #4070a0;">'</span><span style="color: #4070a0; font-weight: bold;">\r\n</span><span style="color: #4070a0;">'</span>)
<span style="color: #007020; font-weight: bold;">if</span>(<span style="color: #007020;">len</span> <span style="color: #666666;">></span> <span style="color: #40a070;">0</span>):
buffer <span style="color: #666666;">+=</span> data[<span style="color: #40a070;">0</span>:<span style="color: #007020;">len</span>]
image_bytes <span style="color: #666666;">=</span> np<span style="color: #666666;">.</span>frombuffer(buffer, dtype<span style="color: #666666;">=</span>np<span style="color: #666666;">.</span>uint8)
frame <span style="color: #666666;">=</span> cv2<span style="color: #666666;">.</span>imdecode(image_bytes, flags<span style="color: #666666;">=</span>cv2<span style="color: #666666;">.</span>IMREAD_COLOR)
frame_gray <span style="color: #666666;">=</span> cv2<span style="color: #666666;">.</span>cvtColor(frame, cv2<span style="color: #666666;">.</span>COLOR_BGR2GRAY)
frame_gray <span style="color: #666666;">=</span> cv2<span style="color: #666666;">.</span>equalizeHist(frame_gray)
<span style="color: #60a0b0; font-style: italic;">#-- Detect faces</span>
faces <span style="color: #666666;">=</span> face_cascade<span style="color: #666666;">.</span>detectMultiScale(frame_gray)
<span style="color: #007020; font-weight: bold;">for</span> (x,y,w,h) <span style="color: #007020; font-weight: bold;">in</span> faces:
center <span style="color: #666666;">=</span> (x <span style="color: #666666;">+</span> w<span style="color: #666666;">//</span><span style="color: #40a070;">2</span>, y <span style="color: #666666;">+</span> h<span style="color: #666666;">//</span><span style="color: #40a070;">2</span>)
faceROI <span style="color: #666666;">=</span> frame_gray[y:y<span style="color: #666666;">+</span>h,x:x<span style="color: #666666;">+</span>w]
<span style="color: #60a0b0; font-style: italic;">#-- In each face, detect eyes</span>
eyes <span style="color: #666666;">=</span> eyes_cascade<span style="color: #666666;">.</span>detectMultiScale(faceROI)
<span style="color: #007020; font-weight: bold;">for</span> (x2,y2,w2,h2) <span style="color: #007020; font-weight: bold;">in</span> eyes:
eye_center <span style="color: #666666;">=</span> (x <span style="color: #666666;">+</span> x2 <span style="color: #666666;">+</span> w2<span style="color: #666666;">//</span><span style="color: #40a070;">2</span>, y <span style="color: #666666;">+</span> y2 <span style="color: #666666;">+</span> h2<span style="color: #666666;">//</span><span style="color: #40a070;">2</span>)
radius <span style="color: #666666;">=</span> <span style="color: #007020;">int</span>(<span style="color: #007020;">round</span>((w2 <span style="color: #666666;">+</span> h2)<span style="color: #666666;">*</span><span style="color: #40a070;">0.25</span>))
frame <span style="color: #666666;">=</span> cv2<span style="color: #666666;">.</span>circle(frame, eye_center, radius, (<span style="color: #40a070;">255</span>, <span style="color: #40a070;">0</span>, <span style="color: #40a070;">0</span> ), <span style="color: #666666;">-</span><span style="color: #40a070;">1</span>)
frame <span style="color: #666666;">=</span> cv2<span style="color: #666666;">.</span>cvtColor(frame, cv2<span style="color: #666666;">.</span>COLOR_RGB2YUV_I420)
os<span style="color: #666666;">.</span>write(vd, frame)
s<span style="color: #666666;">.</span>close()
<span style="color: #007020; font-weight: bold;">break</span>
<span style="color: #007020; font-weight: bold;">else</span>:
buffer <span style="color: #666666;">+=</span> data
</pre></div><b>
4. Result</b><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="480" src="https://www.youtube.com/embed/WIrhZOJVBms" width="640" youtube-src-id="WIrhZOJVBms"></iframe></div><br /><div><br /></div>Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com0tag:blogger.com,1999:blog-7549705215513488945.post-61771656967744451692021-11-01T08:57:00.000-07:002021-11-06T07:41:08.747-07:00Demo 43: How to apply Kalman Filter to ESP to make sensor measurement more accurate<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
Kalman filtering is an algorithm that uses a series of measurements (including statistical noise and other inaccuracies) observed over time to <b>make estimates of unknown variables more accurate than just use a single measurement.</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-xLHT_JHft-s/XQUUeM8PpNI/AAAAAAAAKWI/R72MI8QchVk12JbLMrFKx6iO_1MpGpgYQCPcBGAYYCw/s1600/kalman_result.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="296" data-original-width="1135" height="166" src="https://1.bp.blogspot.com/-xLHT_JHft-s/XQUUeM8PpNI/AAAAAAAAKWI/R72MI8QchVk12JbLMrFKx6iO_1MpGpgYQCPcBGAYYCw/s640/kalman_result.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: Blue line is sensor data from ADC with noise and Brown line is sensor data after applying Kalman Filter</b></div>
In order to understand more about the equations and calculations, please refer <a href="http://bilgin.esme.org/BitsAndBytes/KalmanFilterforDummies">this</a>.</div><div dir="ltr" style="text-align: left;" trbidi="on">In summary, the filter process includes 2 steps: Prediction and Correction.</div><div dir="ltr" style="text-align: left;" trbidi="on">- Prediction step: tries to predict the value based on system model with previous corrected value.</div><div dir="ltr" style="text-align: left;" trbidi="on">- Correction step: tries to correct the predicted value in prediction step by measurement value.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixuIHAQWrrHhC_FrllJUEXe6cCIusr9bBXLBA_byeQC6L-O29E2llVjE6X494DGhN4mD_OtuV2TVmTUMbogFMvMifxjuAbdrk1u0n1ihKgIVDBaO-V4vxQNOpZUBZ8yEJ6KXjMTwcUpFs/s725/Kalman-filter-equations-and-instruction.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="401" data-original-width="725" height="354" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixuIHAQWrrHhC_FrllJUEXe6cCIusr9bBXLBA_byeQC6L-O29E2llVjE6X494DGhN4mD_OtuV2TVmTUMbogFMvMifxjuAbdrk1u0n1ihKgIVDBaO-V4vxQNOpZUBZ8yEJ6KXjMTwcUpFs/w640-h354/Kalman-filter-equations-and-instruction.png" width="640" /></a></div><div dir="ltr" style="text-align: left;" trbidi="on"><br />
This post will make a simple demo of applying Kalman Filter to ESP to make sensor measurement from a <a href="https://www.kitronik.co.uk/blog/how-an-ldr-light-dependent-resistor-works/">LDR</a> (Light Dependent Resistor) more accurate.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_OPjeRFaAAxnLFr53VLtiHq9ef89il4nD9axt2pdcVkm1IFKcd4L3u1SuzXxxhvTn97z2Bxv4Y2zoeMgWHLhN73KIu2ZdK3zZVxvKd2Y3ClyIAl01CtatsLGB3gGrYq2c1ze0P_Y3wac/s1600/ldr_sensor.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="148" data-original-width="430" height="110" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_OPjeRFaAAxnLFr53VLtiHq9ef89il4nD9axt2pdcVkm1IFKcd4L3u1SuzXxxhvTn97z2Bxv4Y2zoeMgWHLhN73KIu2ZdK3zZVxvKd2Y3ClyIAl01CtatsLGB3gGrYq2c1ze0P_Y3wac/s320/ldr_sensor.png" width="320" /></a></div>
<div style="text-align: center;">
<b>Figure: LDR sensor</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWIxnxLFD09V82XPWyZKgv5Cl6G6sSm62ZTc4Wzh2eCT0koDNbHWfHx9XDvFwowVCP4qlixCHZpgnipWg_egZTHZGdou_N4MO4Jc2hOWm4jV53bDsCqsTQExba9IDBBKs8PCRxfs9p-so/s1600/esp32_module.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="311" data-original-width="218" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWIxnxLFD09V82XPWyZKgv5Cl6G6sSm62ZTc4Wzh2eCT0koDNbHWfHx9XDvFwowVCP4qlixCHZpgnipWg_egZTHZGdou_N4MO4Jc2hOWm4jV53bDsCqsTQExba9IDBBKs8PCRxfs9p-so/s1600/esp32_module.png" /></a></div>
<div style="text-align: center;">
<b>Figure: ESP32 module</b></div>
<div style="text-align: center;">
</div>
<b>2. Hardware</b><br />
ESP32 3.3V connect LDR Vcc<br />
ESP32 GND connect LDR GND<br />
ESP32 G34(ADC pin) connect LDR A0<br />
<b>3. Software</b><br />I developed the matrix version of Kalman filter. </div><div dir="ltr" style="text-align: left;" trbidi="on"><a href="https://github.com/nhatuan84/Arduino-KalmanFilter">https://github.com/nhatuan84/Arduino-KalmanFilter</a></div><div dir="ltr" style="text-align: left;" trbidi="on"><br /></div><div dir="ltr" style="text-align: left;" trbidi="on"><div dir="ltr" trbidi="on">It can be applied to Arduino, <b>ESP8266/ESP32/MCUs</b>.</div><div dir="ltr" trbidi="on">There are 3 files that you need to include in your project (ESP8266/ESP32/MCUs):</div><div dir="ltr" trbidi="on"><b>- ArduiKalman.cpp</b></div><div dir="ltr" trbidi="on"><b>- ArduiKalman.h</b></div><div dir="ltr" trbidi="on"><b>- mat.h</b></div><div dir="ltr" trbidi="on">where:</div><div dir="ltr" trbidi="on"><div dir="ltr" trbidi="on"><b>n: number of states</b></div><div dir="ltr" trbidi="on"><b>m: number of measurement values</b></div><div dir="ltr" trbidi="on"><b>xc[n]: correct state vector</b></div><div dir="ltr" trbidi="on"><b>xp[n]: predict state vector</b></div><div dir="ltr" trbidi="on"><b>A(n, n): System dynamics matrix</b></div><div dir="ltr" trbidi="on"><b>H(m, n): Measurement matrix</b></div><div dir="ltr" trbidi="on"><b>Q(n, n): Process noise covariance</b></div><div dir="ltr" trbidi="on"><b>R(m, m): Measurement noise covariance</b></div><div dir="ltr" trbidi="on"><b>P(n, n): Estimate error covariance</b></div><div dir="ltr" trbidi="on"><br /></div><div dir="ltr" trbidi="on">Predict step:</div><div dir="ltr" trbidi="on"> float *predict = m_kf.predict()</div><div dir="ltr" trbidi="on"><br /></div><div dir="ltr" trbidi="on">Correct step:</div><div dir="ltr" trbidi="on"> float *correct = m_kf.correct(measurement)</div><div dir="ltr" trbidi="on"><br /></div><div dir="ltr" trbidi="on">An example when n=4, m=2, and how to initialize the matrices.</div><div dir="ltr" trbidi="on"><br /></div><div dir="ltr" trbidi="on">A[0][0] = 1.0f;</div><div dir="ltr" trbidi="on">A[1][1] = 1.0f;</div><div dir="ltr" trbidi="on">A[2][2] = 1.0f;</div><div dir="ltr" trbidi="on">A[3][3] = 1.0f;</div><div dir="ltr" trbidi="on">H[0][0] = 1.0f;</div><div dir="ltr" trbidi="on">H[1][1] = 1.0f;</div><div dir="ltr" trbidi="on">Q[0][0] = 0.01f;</div><div dir="ltr" trbidi="on">Q[1][1] = 0.01f;</div><div dir="ltr" trbidi="on">Q[2][2] = 0.01f;</div><div dir="ltr" trbidi="on">Q[3][3] = 0.01f;</div><div dir="ltr" trbidi="on">R[0][0] = 0.1f;</div><div dir="ltr" trbidi="on">R[1][1] = 0.1f;</div><div dir="ltr" trbidi="on">P[0][0] = 1.0f;</div><div dir="ltr" trbidi="on">P[1][1] = 1.0f;</div><div dir="ltr" trbidi="on">P[2][2] = 1.0f;</div><div dir="ltr" trbidi="on">P[3][3] = 1.0f;</div><div dir="ltr" trbidi="on">xc[0] = 0.01f;</div><div dir="ltr" trbidi="on">xc[1] = 0.01f;</div><div dir="ltr" trbidi="on">xc[2] = 0.01f;</div><div dir="ltr" trbidi="on">xc[3] = 0.01f;</div><div dir="ltr" trbidi="on"><br /></div></div></div><div dir="ltr" style="text-align: left;" trbidi="on">
Here is the source code. You can read comments to understand.
<!--HTML generated using hilite.me--><div style="background: rgb(248, 248, 248); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800;">#include "ArduiKalman.h"</span>
<span style="color: #008800;">#define ADC_PIN 34</span>
<span style="color: #008800;">#define UPDATE_TIME 100</span>
<span style="color: #00bb00; font-weight: bold;">long</span> current;
<span style="color: #00bb00; font-weight: bold;">int</span> stateNum <span style="color: #666666;">=</span> <span style="color: #666666;">1</span>;
<span style="color: #00bb00; font-weight: bold;">int</span> measureNum <span style="color: #666666;">=</span> <span style="color: #666666;">1</span>;
<span style="color: #008800; font-style: italic;">//init matrix for Kalman</span>
<span style="color: #00bb00; font-weight: bold;">float</span> xc[<span style="color: #666666;">1</span>]; <span style="color: #008800; font-style: italic;">// correct state vector </span>
<span style="color: #00bb00; font-weight: bold;">float</span> xp[<span style="color: #666666;">1</span>]; <span style="color: #008800; font-style: italic;">// predict state vector </span>
<span style="color: #00bb00; font-weight: bold;">float</span> A[<span style="color: #666666;">1</span>][<span style="color: #666666;">1</span>]; <span style="color: #008800; font-style: italic;">// prediction error covariance </span>
<span style="color: #00bb00; font-weight: bold;">float</span> Q[<span style="color: #666666;">1</span>][<span style="color: #666666;">1</span>]; <span style="color: #008800; font-style: italic;">// process noise covariance </span>
<span style="color: #00bb00; font-weight: bold;">float</span> R[<span style="color: #666666;">1</span>][<span style="color: #666666;">1</span>]; <span style="color: #008800; font-style: italic;">// measurement error covariance</span>
<span style="color: #00bb00; font-weight: bold;">float</span> H[<span style="color: #666666;">1</span>][<span style="color: #666666;">1</span>]; <span style="color: #008800; font-style: italic;">// Measurement model</span>
<span style="color: #00bb00; font-weight: bold;">float</span> P[<span style="color: #666666;">1</span>][<span style="color: #666666;">1</span>]; <span style="color: #008800; font-style: italic;">// Post-prediction, pre-update</span>
KalmanFilter m_kf;
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">setup</span>() {
Serial.begin(<span style="color: #666666;">115200</span>);
Serial.print(<span style="color: #666666;">0</span>); <span style="color: #008800; font-style: italic;">// To freeze the lower limit</span>
Serial.print(<span style="color: #bb4444;">" "</span>);
Serial.print(<span style="color: #666666;">3.3</span>); <span style="color: #008800; font-style: italic;">// To freeze the upper limit</span>
Serial.print(<span style="color: #bb4444;">" "</span>);
<span style="color: #008800; font-style: italic;">// put your setup code here, to run once:</span>
m_kf.init(stateNum, measureNum, <span style="color: #666666;">&</span>A[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>], <span style="color: #666666;">&</span>P[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>], <span style="color: #666666;">&</span>Q[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>], <span style="color: #666666;">&</span>H[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>], <span style="color: #666666;">&</span>R[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>], <span style="color: #666666;">&</span>xp[<span style="color: #666666;">0</span>], <span style="color: #666666;">&</span>xc[<span style="color: #666666;">0</span>]);
m_kf.zeros();
A[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>] <span style="color: #666666;">=</span> <span style="color: #666666;">1.0f</span>;
H[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>] <span style="color: #666666;">=</span> <span style="color: #666666;">1.0f</span>;
Q[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>] <span style="color: #666666;">=</span> <span style="color: #666666;">0.01f</span>;
R[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>] <span style="color: #666666;">=</span> <span style="color: #666666;">100.0f</span>;
P[<span style="color: #666666;">0</span>][<span style="color: #666666;">0</span>] <span style="color: #666666;">=</span> <span style="color: #666666;">1.0f</span>;
xc[<span style="color: #666666;">0</span>] <span style="color: #666666;">=</span> analogRead(ADC_PIN)<span style="color: #666666;">/4095.0</span> <span style="color: #666666;">*</span> <span style="color: #666666;">3.3</span>;
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">loop</span>() {
<span style="color: #008800; font-style: italic;">// predict</span>
<span style="color: #00bb00; font-weight: bold;">float</span> <span style="color: #666666;">*</span>predict <span style="color: #666666;">=</span> m_kf.predict();
<span style="color: #008800; font-style: italic;">// correct</span>
<span style="color: #00bb00; font-weight: bold;">float</span> rand_noise <span style="color: #666666;">=</span> random(<span style="color: #666666;">-100</span>,<span style="color: #666666;">100</span>)<span style="color: #666666;">/100.0</span>;
<span style="color: #00bb00; font-weight: bold;">float</span> measured_value <span style="color: #666666;">=</span> analogRead(ADC_PIN)<span style="color: #666666;">/4095.0</span> <span style="color: #666666;">*</span> <span style="color: #666666;">3.3</span> <span style="color: #666666;">+</span> rand_noise;
<span style="color: #00bb00; font-weight: bold;">float</span> measurement[measureNum];
measurement[<span style="color: #666666;">0</span>] <span style="color: #666666;">=</span> measured_value;
<span style="color: #00bb00; font-weight: bold;">float</span> <span style="color: #666666;">*</span>correct <span style="color: #666666;">=</span> m_kf.correct(measurement);
<span style="color: #00bb00; font-weight: bold;">float</span> estimated_value <span style="color: #666666;">=</span> correct[<span style="color: #666666;">0</span>];
<span style="color: #008800; font-style: italic;">//update plotter</span>
<span style="color: #aa22ff; font-weight: bold;">if</span> (millis() <span style="color: #666666;">></span> current) {
Serial.print(measured_value);
Serial.print(<span style="color: #bb4444;">","</span>);
Serial.print(estimated_value);
Serial.println();
current <span style="color: #666666;">=</span> millis() <span style="color: #666666;">+</span> UPDATE_TIME;
}
}
</pre></div>
<b>4. Result</b><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-v1YBXIFGerY/YX4X4wVLkNI/AAAAAAAAP94/C3dRHkTWLa4Kf8O5OBZU3weJfmQuMWGjgCLcBGAsYHQ/s1839/kalman1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="961" data-original-width="1839" height="334" src="https://1.bp.blogspot.com/-v1YBXIFGerY/YX4X4wVLkNI/AAAAAAAAP94/C3dRHkTWLa4Kf8O5OBZU3weJfmQuMWGjgCLcBGAsYHQ/w640-h334/kalman1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>
<div style="text-align: center;">
<b>Figure: Blue line is sensor data from ADC with noise and Red line is sensor data after applying Kalman Filter</b></div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com0tag:blogger.com,1999:blog-7549705215513488945.post-76924226139938082922021-10-31T03:58:00.000-07:002021-11-06T07:44:57.899-07:00Demo 47: Deep learning - Computer vision with ESP32 and tensorflow.js<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: justify;">
<b>1. Introduction</b></div>
<div style="text-align: justify;">
- Deep learning is a hot topic and esp32 is a hot IoT MCU. Recently many applications related to computer vision are deployed on ESP32 (face detection, face recognition, ...). In this post I will show you a new approach to deploy Deep learning - Computer vision applications on ESP32 such as object classification (SqueezeNet), object detection and recognition (YOLOv3). After reading this post I am sure you can deploy hot network such as <b>YOLOv3</b> on ESP32.</div>
<div style="text-align: justify;">
- My approach is using <b>TensorFlow.js </b>is a library for developing and training ML models in JavaScript, and deploying in browser.</div>
<div style="text-align: justify;">
- In this post, I will create a simple Deep learning - Computer vision application that is object classification using SqueezeNet. The esp32 will act as a webserver and when the client connect to it, a slideshow of objects will start and the objects will be classified using SqueezeNet.<br />
You can do similar steps for <b>YOLOv3</b>, but instead of reading pictures from sdcard, you will use esp32-camera module and pass each camera frame to YOLOv3 model created by tensorflow.js.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-zKm8dv7dJ-Q/XTsgMuuG50I/AAAAAAAAKlw/Kf7v6GPHcPQSBNLEouTkpg2jddKE8dY-QCLcBGAs/s1600/esp32-tensorflowjs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="604" height="316" src="https://1.bp.blogspot.com/-zKm8dv7dJ-Q/XTsgMuuG50I/AAAAAAAAKlw/Kf7v6GPHcPQSBNLEouTkpg2jddKE8dY-QCLcBGAs/s400/esp32-tensorflowjs.png" width="400" /></a></div>
<div style="text-align: center;">
<b> Figure: Deep learning - Computer vision with ESP32 and tensorflow.js</b></div>
<b>2. Hardware</b><br />
You need a micro sdcard module as in <a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html">Demo 7: How to use Arduino ESP32 to store data to microsdcard (Software SPI and Hardware SPI)</a><br />
In this demo, I used Hardware SPI so please connect pins as below:<br />
MICROSD CS - ESP32 IO5<br />
MICROSD SCK - ESP32 IO18<br />
MICROSD MOSI - ESP32 IO23<br />
MICROSD MISO - ESP32 IO19<br />
MICROSD Vcc - ESP32 3.3V<br />
MICROSD GND - ESP32 GND<br />
<div style="text-align: justify;">
<b>3. Software</b></div>
- In order to make this demo, you have to review some demos:<br />
<a href="http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html">Demo 12: How to turn the Arduino ESP32 into a Web Server </a><br />
<a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html">Demo 7: How to use Arduino ESP32 to store data to microsdcard (Software SPI and Hardware SPI)</a><br />
- Knowledge of Jquery and Javascript. <br />
- Material for deep learning part make by me: <a href="https://github.com/nhatuan84/tensorflowjs-squeezenet">https://github.com/nhatuan84/tensorflowjs-squeezenet</a> (or you can use the outputs that I generated) <br />
- Knowledge of Deep learning. If you don't know, just follow me. I had another blog about Machine Leaning. It is <a href="http://www.fossreview.com/">here</a>.<br />
- I had to modify the webserver library in <a href="http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html">Demo 12: How to turn the Arduino ESP32 into a Web Server</a> so that It can be used for this demo.<br />
- Here are the steps:<br />
+ Download all the resources <a href="https://github.com/nhatuan84/esp32-computer-vision-tensorflowjs">here</a> and unzip it. <br />
+ Reinstall the <span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="https://github.com/nhatuan84/esp32-computer-vision-tensorflowjs/blob/master/ESP32WebServer.zip" id="c22138ba9dbbbe8aebdf3dcd8e31ceaa-267cdd333de82691dc97eb9e8672670c25d00eef" title="ESP32WebServer.zip">ESP32WebServer.zip</a> (in </span><span class="css-truncate css-truncate-target">resources) for Arduino (you may uninstall old </span><span class="css-truncate css-truncate-target"><span class="css-truncate css-truncate-target">ESP32WebServer library</span>).</span><br />
<span class="css-truncate css-truncate-target"> + Copy files: group1-shard1of2.bin, group1-shard2of2.bin, model.json, index.html, 1.jpg, 2.jpg, 3.jpg </span><span class="css-truncate css-truncate-target"><span class="css-truncate css-truncate-target">(in </span><span class="css-truncate css-truncate-target">resources) </span>to sdcard.</span><br />
<span class="css-truncate css-truncate-target"> + Create an Arduino project with code:</span><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <WiFiClient.h></span>
<span style="color: #557799;">#include <ESP32WebServer.h></span>
<span style="color: #557799;">#include <WiFi.h></span>
<span style="color: #557799;">#include <ESPmDNS.h></span>
<span style="color: #557799;">#include "FS.h"</span>
<span style="color: #557799;">#include <SD.h></span>
<span style="color: #557799;">#include <SPI.h></span>
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> ssid <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"ssid"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> password <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"pass"</span>;
ESP32WebServer <span style="color: #0066bb; font-weight: bold;">server</span>(<span style="color: #0000dd; font-weight: bold;">80</span>);
File root;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">handleRoot</span>() {
root <span style="color: #333333;">=</span> SD.open(<span style="background-color: #5eeb34;">"/index.html"</span>);
<span style="color: #008800; font-weight: bold;">if</span> (root) {
<span style="color: #888888;">/* respond the content of file to client by calling streamFile()*/</span>
<span style="color: #333399; font-weight: bold;">size_t</span> sent <span style="color: #333333;">=</span> server.streamFile(root, <span style="background-color: #5eeb34;">"text/html"</span>);
<span style="color: #888888;">/* close the file */</span>
root.close();
} <span style="color: #008800; font-weight: bold;">else</span> {
Serial.println(<span style="background-color: #5eeb34;">"error opening index"</span>);
}
}
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #0066bb; font-weight: bold;">loadFromSDCARD</span>(String path){
path.toLowerCase();
Serial.println(path);
String dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"text/plain"</span>;
<span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">"/"</span>)) path <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"/index.html"</span>;
<span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".src"</span>)) path <span style="color: #333333;">=</span> path.substring(<span style="color: #0000dd; font-weight: bold;">0</span>, path.lastIndexOf(<span style="background-color: #5eeb34;">"."</span>));
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".jpg"</span>)) dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"image/jpeg"</span>;
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".txt"</span>)) dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"text/plain"</span>;
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".zip"</span>)) dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"application/zip"</span>;
<span style="color: #008800; font-weight: bold;">if</span>(path <span style="color: #333333;">==</span> <span style="background-color: #5eeb34;">"/favicon.ico"</span>)
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">false</span>;
root <span style="color: #333333;">=</span> SD.open((String(<span style="background-color: #5eeb34;">"/"</span>) <span style="color: #333333;">+</span> path).c_str());
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>root){
Serial.println(<span style="background-color: #5eeb34;">"failed to open file"</span>);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">false</span>;
}
<span style="color: #008800; font-weight: bold;">if</span> (server.streamFile(root, dataType) <span style="color: #333333;">!=</span> root.size()) {
Serial.println(<span style="background-color: #5eeb34;">"Sent less data than expected!"</span>);
}
root.close();
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">true</span>;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">handleNotFound</span>(){
<span style="color: #008800; font-weight: bold;">if</span>(loadFromSDCARD(server.uri())) <span style="color: #008800; font-weight: bold;">return</span>;
String message <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"SDCARD Not Detected</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n\n</span><span style="background-color: #5eeb34;">"</span>;
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"URI: "</span>;
message <span style="color: #333333;">+=</span> server.uri();
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">Method: "</span>;
message <span style="color: #333333;">+=</span> (server.method() <span style="color: #333333;">==</span> HTTP_GET)<span style="color: #333333;">?</span><span style="background-color: #5eeb34;">"GET"</span><span style="color: #333333;">:</span><span style="background-color: #5eeb34;">"POST"</span>;
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">Arguments: "</span>;
message <span style="color: #333333;">+=</span> server.args();
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">"</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">uint8_t</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>; i<span style="color: #333333;"><</span>server.args(); i<span style="color: #333333;">++</span>){
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">" NAME:"</span><span style="color: #333333;">+</span>server.argName(i) <span style="color: #333333;">+</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;"> VALUE:"</span> <span style="color: #333333;">+</span> server.arg(i) <span style="color: #333333;">+</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">"</span>;
}
server.send(<span style="color: #0000dd; font-weight: bold;">404</span>, <span style="background-color: #5eeb34;">"text/plain"</span>, message);
Serial.println(message);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>(<span style="color: #333399; font-weight: bold;">void</span>){
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
WiFi.begin(ssid, password);
Serial.println(<span style="background-color: #5eeb34;">""</span>);
<span style="color: #888888;">// Wait for connection</span>
<span style="color: #008800; font-weight: bold;">while</span> (WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED) {
delay(<span style="color: #0000dd; font-weight: bold;">500</span>);
Serial.print(<span style="background-color: #5eeb34;">"."</span>);
}
Serial.println(<span style="background-color: #5eeb34;">""</span>);
Serial.print(<span style="background-color: #5eeb34;">"Connected to "</span>);
Serial.println(ssid);
Serial.print(<span style="background-color: #5eeb34;">"IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #888888;">//use IP or iotsharing.local to access webserver</span>
<span style="color: #008800; font-weight: bold;">if</span> (MDNS.begin(<span style="background-color: #5eeb34;">"iotsharing"</span>)) {
Serial.println(<span style="background-color: #5eeb34;">"MDNS responder started"</span>);
}
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>SD.begin()) {
Serial.println(<span style="background-color: #5eeb34;">"initialization failed!"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
Serial.println(<span style="background-color: #5eeb34;">"initialization done."</span>);
<span style="color: #888888;">//handle uri </span>
server.on(<span style="background-color: #5eeb34;">"/"</span>, handleRoot);
server.onNotFound(handleNotFound);
server.begin();
Serial.println(<span style="background-color: #5eeb34;">"HTTP server started"</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>(<span style="color: #333399; font-weight: bold;">void</span>){
server.handleClient();
}
</pre>
</td></tr>
</tbody></table>
</div>
+ Open web browser and type the IP address from Terminal, you will see:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinK4fkbCJzy8-33J__w7kqt0zN3DpqGobBmAmmBCn6UG9EY7pS6YxMIrjooUACrjWh_6-y71wZ1CWxqhnJR90j6m9JXfwcHFjybjSERSa7xhLCEHY7Pw0vlLiqy3bv1OGcnvIDyxlDmpo/s1600/esp32+tensorflowjs.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="389" data-original-width="487" height="255" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinK4fkbCJzy8-33J__w7kqt0zN3DpqGobBmAmmBCn6UG9EY7pS6YxMIrjooUACrjWh_6-y71wZ1CWxqhnJR90j6m9JXfwcHFjybjSERSa7xhLCEHY7Pw0vlLiqy3bv1OGcnvIDyxlDmpo/s320/esp32+tensorflowjs.PNG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<b>Figure: esp32-tensorflowjs-squeezenet prediction</b></div>
<div class="separator" style="clear: both; text-align: center;">
<b><br /></b><iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/Xo9Hz-G90cc/0.jpg" frameborder="0" height="320" src="https://www.youtube.com/embed/Xo9Hz-G90cc?feature=player_embedded" width="480"></iframe></div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com45tag:blogger.com,1999:blog-7549705215513488945.post-67456049812864539842021-10-26T10:11:00.000-07:002021-11-06T07:45:17.740-07:00Demo 46: How to turn ESP with a sdcard or SPIFFS to a web file server<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
In this post I will show you how to turn ESP with a sdcard or SPIFFS to a web file server.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-FFKZ_Tjv5lY/XSDU29G66dI/AAAAAAAAKg8/LMOrdqu9saM16K3ftG1f0AyYN1IwKZecQCLcBGAs/s1600/web-file-server.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="444" data-original-width="386" height="320" src="https://1.bp.blogspot.com/-FFKZ_Tjv5lY/XSDU29G66dI/AAAAAAAAKg8/LMOrdqu9saM16K3ftG1f0AyYN1IwKZecQCLcBGAs/s320/web-file-server.png" width="278" /></a></div>
<div style="text-align: center;">
<b>Figure: ESP web file server</b></div>
With this file server you can upload data to sdcard or SPIFFS or download data from sdcard or SPIFFS easily.<br />
I am going to reuse the other posts, so you need to review them:<br />
<a href="http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html" target="_blank">Demo 12: How to turn the Arduino ESP32 into a Web Server</a><br />
<a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html" target="_blank">Demo 7: How to use Arduino ESP32 to store data to sdcard</a><br />
<a href="http://www.iotsharing.com/2019/07/copy-data-to-from-spiffs-without-mkspiffs.html">Demo 45: Copy data from/to SPIFFS without using mkspiffs (web file server)</a><br />
<b>2. Hardware</b><br />
If you are using SPIFFS, you can refer <a href="http://www.iotsharing.com/2019/07/copy-data-to-from-spiffs-without-mkspiffs.html">Demo 45: Copy data from/to SPIFFS without using mkspiffs (web file server)</a> <br />
If you are using sdcard, please connect ESP with sdcard module as <a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html" target="_blank">Demo 7: How to use Arduino ESP32 to store data to sdcard</a> <br />
<b>3. Software</b><br />
Here is the full source code with comments:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <WiFiClient.h></span>
<span style="color: #557799;">#include <ESP32WebServer.h></span>
<span style="color: #557799;">#include <WiFi.h></span>
<span style="color: #557799;">#include <ESPmDNS.h></span>
<span style="color: #557799;">#include <SPI.h></span>
<span style="color: #557799;">#include <mySD.h></span>
String serverIndex <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"</span>
<span style="background-color: #5eeb34;">"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"</span>
<span style="background-color: #5eeb34;">"<input type='file' name='update'>"</span>
<span style="background-color: #5eeb34;">"<input type='submit' value='Upload'>"</span>
<span style="background-color: #5eeb34;">"</form>"</span>
<span style="background-color: #5eeb34;">"<div id='prg'>progress: 0%</div>"</span>
<span style="background-color: #5eeb34;">"<script>"</span>
<span style="background-color: #5eeb34;">"$('form').submit(function(e){"</span>
<span style="background-color: #5eeb34;">"e.preventDefault();"</span>
<span style="background-color: #5eeb34;">"var form = $('#upload_form')[0];"</span>
<span style="background-color: #5eeb34;">"var data = new FormData(form);"</span>
<span style="background-color: #5eeb34;">" $.ajax({"</span>
<span style="background-color: #5eeb34;">"url: '/update',"</span>
<span style="background-color: #5eeb34;">"type: 'POST',"</span>
<span style="background-color: #5eeb34;">"data: data,"</span>
<span style="background-color: #5eeb34;">"contentType: false,"</span>
<span style="background-color: #5eeb34;">"processData:false,"</span>
<span style="background-color: #5eeb34;">"xhr: function() {"</span>
<span style="background-color: #5eeb34;">"var xhr = new window.XMLHttpRequest();"</span>
<span style="background-color: #5eeb34;">"xhr.upload.addEventListener('progress', function(evt) {"</span>
<span style="background-color: #5eeb34;">"if (evt.lengthComputable) {"</span>
<span style="background-color: #5eeb34;">"var per = evt.loaded / evt.total;"</span>
<span style="background-color: #5eeb34;">"$('#prg').html('progress: ' + Math.round(per*100) + '%');"</span>
<span style="background-color: #5eeb34;">"}"</span>
<span style="background-color: #5eeb34;">"}, false);"</span>
<span style="background-color: #5eeb34;">"return xhr;"</span>
<span style="background-color: #5eeb34;">"},"</span>
<span style="background-color: #5eeb34;">"success:function(d, s) {"</span>
<span style="background-color: #5eeb34;">"console.log('success!')"</span>
<span style="background-color: #5eeb34;">"},"</span>
<span style="background-color: #5eeb34;">"error: function (a, b, c) {"</span>
<span style="background-color: #5eeb34;">"}"</span>
<span style="background-color: #5eeb34;">"});"</span>
<span style="background-color: #5eeb34;">"});"</span>
<span style="background-color: #5eeb34;">"</script>"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> ssid <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"TRUONG AN"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> password <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"0909505150"</span>;
ESP32WebServer <span style="color: #0066bb; font-weight: bold;">server</span>(<span style="color: #0000dd; font-weight: bold;">80</span>);
File root;
<span style="color: #333399; font-weight: bold;">bool</span> opened <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
String <span style="color: #0066bb; font-weight: bold;">printDirectory</span>(File dir, <span style="color: #333399; font-weight: bold;">int</span> numTabs) {
String response <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">""</span>;
dir.rewindDirectory();
<span style="color: #008800; font-weight: bold;">while</span>(<span style="color: #007020;">true</span>) {
File entry <span style="color: #333333;">=</span> dir.openNextFile();
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span> entry) {
<span style="color: #888888;">// no more files</span>
<span style="color: #888888;">//Serial.println("**nomorefiles**");</span>
<span style="color: #008800; font-weight: bold;">break</span>;
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">uint8_t</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>; i<span style="color: #333333;"><</span>numTabs; i<span style="color: #333333;">++</span>) {
Serial.print(<span style="color: #0044dd;">'\t'</span>); <span style="color: #888888;">// we'll have a nice indentation</span>
}
<span style="color: #888888;">// Recurse for directories, otherwise print the file size</span>
<span style="color: #008800; font-weight: bold;">if</span> (entry.isDirectory()) {
printDirectory(entry, numTabs<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
} <span style="color: #008800; font-weight: bold;">else</span> {
response <span style="color: #333333;">+=</span> String(<span style="background-color: #5eeb34;">"<a href='"</span>) <span style="color: #333333;">+</span> String(entry.name()) <span style="color: #333333;">+</span> String(<span style="background-color: #5eeb34;">"'>"</span>) <span style="color: #333333;">+</span> String(entry.name()) <span style="color: #333333;">+</span> String(<span style="background-color: #5eeb34;">"</a>"</span>) <span style="color: #333333;">+</span> String(<span style="background-color: #5eeb34;">"</br>"</span>);
}
entry.close();
}
<span style="color: #008800; font-weight: bold;">return</span> String(<span style="background-color: #5eeb34;">"List files:</br>"</span>) <span style="color: #333333;">+</span> response <span style="color: #333333;">+</span> String(<span style="background-color: #5eeb34;">"</br></br> Upload file:"</span>) <span style="color: #333333;">+</span> serverIndex;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">handleRoot</span>() {
root <span style="color: #333333;">=</span> SD.open(<span style="background-color: #5eeb34;">"/"</span>);
String res <span style="color: #333333;">=</span> printDirectory(root, <span style="color: #0000dd; font-weight: bold;">0</span>);
server.send(<span style="color: #0000dd; font-weight: bold;">200</span>, <span style="background-color: #5eeb34;">"text/html"</span>, res);
}
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #0066bb; font-weight: bold;">loadFromSDCARD</span>(String path){
path.toLowerCase();
String dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"text/plain"</span>;
<span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">"/"</span>)) path <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"index.htm"</span>;
<span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".src"</span>)) path <span style="color: #333333;">=</span> path.substring(<span style="color: #0000dd; font-weight: bold;">0</span>, path.lastIndexOf(<span style="background-color: #5eeb34;">"."</span>));
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".jpg"</span>)) dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"image/jpeg"</span>;
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".txt"</span>)) dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"text/plain"</span>;
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".zip"</span>)) dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"application/zip"</span>;
Serial.println(dataType);
File dataFile <span style="color: #333333;">=</span> SD.open(path.c_str());
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>dataFile)
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">false</span>;
<span style="color: #008800; font-weight: bold;">if</span> (server.streamFile(dataFile, dataType) <span style="color: #333333;">!=</span> dataFile.size()) {
Serial.println(<span style="background-color: #5eeb34;">"Sent less data than expected!"</span>);
}
dataFile.close();
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">true</span>;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">handleNotFound</span>(){
<span style="color: #008800; font-weight: bold;">if</span>(loadFromSDCARD(server.uri())) <span style="color: #008800; font-weight: bold;">return</span>;
String message <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"SDCARD Not Detected</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n\n</span><span style="background-color: #5eeb34;">"</span>;
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"URI: "</span>;
message <span style="color: #333333;">+=</span> server.uri();
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">Method: "</span>;
message <span style="color: #333333;">+=</span> (server.method() <span style="color: #333333;">==</span> HTTP_GET)<span style="color: #333333;">?</span><span style="background-color: #5eeb34;">"GET"</span><span style="color: #333333;">:</span><span style="background-color: #5eeb34;">"POST"</span>;
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">Arguments: "</span>;
message <span style="color: #333333;">+=</span> server.args();
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">"</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">uint8_t</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>; i<span style="color: #333333;"><</span>server.args(); i<span style="color: #333333;">++</span>){
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">" NAME:"</span><span style="color: #333333;">+</span>server.argName(i) <span style="color: #333333;">+</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;"> VALUE:"</span> <span style="color: #333333;">+</span> server.arg(i) <span style="color: #333333;">+</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">"</span>;
}
server.send(<span style="color: #0000dd; font-weight: bold;">404</span>, <span style="background-color: #5eeb34;">"text/plain"</span>, message);
Serial.println(message);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>(<span style="color: #333399; font-weight: bold;">void</span>){
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
WiFi.begin(ssid, password);
Serial.println(<span style="background-color: #5eeb34;">""</span>);
<span style="color: #888888;">// Wait for connection</span>
<span style="color: #008800; font-weight: bold;">while</span> (WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED) {
delay(<span style="color: #0000dd; font-weight: bold;">500</span>);
Serial.print(<span style="background-color: #5eeb34;">"."</span>);
}
Serial.println(<span style="background-color: #5eeb34;">""</span>);
Serial.print(<span style="background-color: #5eeb34;">"Connected to "</span>);
Serial.println(ssid);
Serial.print(<span style="background-color: #5eeb34;">"IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #888888;">//use IP or iotsharing.local to access webserver</span>
<span style="color: #008800; font-weight: bold;">if</span> (MDNS.begin(<span style="background-color: #5eeb34;">"iotsharing"</span>)) {
Serial.println(<span style="background-color: #5eeb34;">"MDNS responder started"</span>);
}
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>SD.begin(<span style="color: #0000dd; font-weight: bold;">26</span>, <span style="color: #0000dd; font-weight: bold;">14</span>, <span style="color: #0000dd; font-weight: bold;">13</span>, <span style="color: #0000dd; font-weight: bold;">27</span>)) {
Serial.println(<span style="background-color: #5eeb34;">"initialization failed!"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
Serial.println(<span style="background-color: #5eeb34;">"initialization done."</span>);
<span style="color: #888888;">//handle uri </span>
server.on(<span style="background-color: #5eeb34;">"/"</span>, handleRoot);
server.onNotFound(handleNotFound);
<span style="color: #888888;">/*handling uploading file */</span>
server.on(<span style="background-color: #5eeb34;">"/update"</span>, HTTP_POST, [](){
server.sendHeader(<span style="background-color: #5eeb34;">"Connection"</span>, <span style="background-color: #5eeb34;">"close"</span>);
},[](){
HTTPUpload<span style="color: #333333;">&</span> upload <span style="color: #333333;">=</span> server.upload();
<span style="color: #008800; font-weight: bold;">if</span>(opened <span style="color: #333333;">==</span> <span style="color: #007020;">false</span>){
opened <span style="color: #333333;">=</span> <span style="color: #007020;">true</span>;
root <span style="color: #333333;">=</span> SD.open((String("/") + upload.filename).c_str(), FILE_WRITE);
<span style="color: #008800; font-weight: bold;">if</span>(<span style="color: #333333;">!</span>root){
Serial.println(<span style="background-color: #5eeb34;">"- failed to open file for writing"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
}
<span style="color: #008800; font-weight: bold;">if</span>(upload.status <span style="color: #333333;">==</span> UPLOAD_FILE_WRITE){
<span style="color: #008800; font-weight: bold;">if</span>(root.write(upload.buf, upload.currentSize) <span style="color: #333333;">!=</span> upload.currentSize){
Serial.println(<span style="background-color: #5eeb34;">"- failed to write"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(upload.status <span style="color: #333333;">==</span> UPLOAD_FILE_END){
root.close();
Serial.println(<span style="background-color: #5eeb34;">"UPLOAD_FILE_END"</span>);
opened <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
}
});
server.begin();
Serial.println(<span style="background-color: #5eeb34;">"HTTP server started"</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>(<span style="color: #333399; font-weight: bold;">void</span>){
server.handleClient();
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>4. Result</b></div>
<div class="separator" style="clear: both; text-align: left;">
Type "iotsharing.local" in web-browser you will see this.<b> </b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN4Gluo4ujf17b3uDR01g6eyNy5HVzg3FrTVeeJbTTPWG2FEiG0_ufr2bAo1EtmBDGj8-0o8KwQE7QTvCPjbs8R4fD0bsyCrZ-vOxjmrv6nu9XpxHs5O7QCTecuq9UpPkDf17aGPjDM3o/s1600/spiffs.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="362" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN4Gluo4ujf17b3uDR01g6eyNy5HVzg3FrTVeeJbTTPWG2FEiG0_ufr2bAo1EtmBDGj8-0o8KwQE7QTvCPjbs8R4fD0bsyCrZ-vOxjmrv6nu9XpxHs5O7QCTecuq9UpPkDf17aGPjDM3o/s400/spiffs.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: GUI of demo</b></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/KTEFiHIlzJ4/0.jpg" frameborder="0" height="266" src="?feature=player_embedded" width="320"></iframe></div>
<br /></div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com7tag:blogger.com,1999:blog-7549705215513488945.post-12788373542158117672021-10-25T19:43:00.000-07:002021-11-06T07:46:09.779-07:00Demo 39: ESP32/8266 multipart upload a file and download a file via HTTP<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
In previous demos, I showed you how to use MQTT/MQTTS and how to update <a href="http://www.iotsharing.com/2017/11/firmware-update-ota-for-esp32-using-http.html">firmware OTA</a> (TCP/UDP and <a href="http://www.iotsharing.com/2017/11/firmware-update-ota-for-esp32-using-http-sdcard.html">HTTP</a>). In this demo, I will show you another interesting topic. That is how to download and multi-part upload a file via HTTP.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-0ylXiYu0TX4/Wl654XAE7SI/AAAAAAAAGNI/Eg34XFMO3HUmRF5U6LAZuqAHLC6OPwQWgCLcBGAs/s1600/udhttp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="209" data-original-width="271" height="308" src="https://2.bp.blogspot.com/-0ylXiYu0TX4/Wl654XAE7SI/AAAAAAAAGNI/Eg34XFMO3HUmRF5U6LAZuqAHLC6OPwQWgCLcBGAs/s400/udhttp.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: multipart upload and download a file via http</b></div>
Based on this demo, you can build an application that can download the new firmware or the configuration file to memory card that is attached to client board for using later. Or you can upload the log file that records occurred events in run time to a server.<br />
This is the requirement of this demo: a ESP32 will download a file from internet and after finish downloading, upload it to local <a href="http://www.iotsharing.com/2017/06/how-to-turn-the-Orange-Pi-into-an-IoT-node.html">apache server</a>. The downloaded file will be stored in <a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html">sdcard</a>.<br />
In order to make it easy, I created a library <a href="https://github.com/nhatuan84/esp-upload-download-file-http">here</a> in github. You just install and use it.<br />
<b>Note:</b> this library can be apply for ESP8266.<br />
<b>2. Software</b><br />
The library is simple to use. It has 2 APIs: upload() and download() with parameters. The parameters are:<br />
- url of uploading and downloading file.<br />
- progress displaying callback function.<br />
- response processing callback function.<br />
- reading and writing data to storage (sdcard, SPIFFS, ...) callback functions.<br />
You should change them accordingly to your application.<br />
<b>Note</b>: The url parser of this library is quite simple and it will be updated later.<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include "UDHttp.h"</span>
<span style="color: #557799;">#include "mySD.h"</span>
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> ssid <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"dd-wrt"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> password <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"0000000000"</span>;
File root;
<span style="color: #888888;">//these callbacks will be invoked to read and write data to sdcard</span>
<span style="color: #888888;">//and process response</span>
<span style="color: #888888;">//and showing progress </span>
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">responsef</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>buffer, <span style="color: #333399; font-weight: bold;">int</span> len){
Serial.printf(<span style="background-color: #fff0f0;">"%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, buffer);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
//read data callback
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">rdataf</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>buffer, <span style="color: #333399; font-weight: bold;">int</span> len){
<span style="color: #888888;">//read file to upload</span>
<span style="color: #008800; font-weight: bold;">if</span> (root.available()) {
<span style="color: #008800; font-weight: bold;">return</span> root.read(buffer, len);
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
//write data callback
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">wdataf</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>buffer, <span style="color: #333399; font-weight: bold;">int</span> len){
<span style="color: #888888;">//write downloaded data to file</span>
<span style="color: #008800; font-weight: bold;">return</span> root.write(buffer, len);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">progressf</span>(<span style="color: #333399; font-weight: bold;">int</span> percent){
Serial.printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, percent);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
<span style="color: #888888;">// put your setup code here, to run once:</span>
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
WiFi.begin(ssid, password);
<span style="color: #008800; font-weight: bold;">while</span> (WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED) {
delay(<span style="color: #0000dd; font-weight: bold;">500</span>);
Serial.print(<span style="background-color: #fff0f0;">"."</span>);
}
Serial.println(<span style="background-color: #fff0f0;">""</span>);
Serial.println(<span style="background-color: #fff0f0;">"WiFi connected"</span>);
Serial.println(<span style="background-color: #fff0f0;">"IP address: "</span>);
Serial.println(WiFi.localIP());
Serial.print(<span style="background-color: #fff0f0;">"Initializing SD card..."</span>);
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>SD.begin(<span style="color: #0000dd; font-weight: bold;">32</span>, <span style="color: #0000dd; font-weight: bold;">14</span>, <span style="color: #0000dd; font-weight: bold;">12</span>, <span style="color: #0000dd; font-weight: bold;">27</span>)) {
Serial.println(<span style="background-color: #fff0f0;">"initialization failed!"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
Serial.println(<span style="background-color: #fff0f0;">"initialization done."</span>);
SD.remove(<span style="background-color: #fff0f0;">"test.pdf"</span>);
{
UDHttp udh;
<span style="color: #888888;">//open file on sdcard to write</span>
root <span style="color: #333333;">=</span> SD.open(<span style="background-color: #fff0f0;">"test.pdf"</span>, FILE_WRITE);
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>root) {
Serial.println(<span style="background-color: #fff0f0;">"can not open file!"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #888888;">//download the file from url</span>
udh.download(<span style="background-color: #fff0f0;">"http://www.smart-words.org/linking-words/linking-words.pdf"</span>, wdataf, progressf);
root.close();
Serial.printf(<span style="background-color: #fff0f0;">"done downloading</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
}
{
UDHttp udh;
<span style="color: #888888;">//open file on sdcard to read</span>
root <span style="color: #333333;">=</span> SD.open(<span style="background-color: #fff0f0;">"test.pdf"</span>);
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>root) {
Serial.println(<span style="background-color: #fff0f0;">"can not open file!"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #888888;">//upload downloaded file to local server</span>
udh.upload(<span style="background-color: #fff0f0;">"http://192.168.1.107:80/upload/upload.php"</span>, <span style="background-color: #fff0f0;">"test.pdf"</span>, root.size(), rdataf, progressf, responsef);
root.close();
Serial.printf(<span style="background-color: #fff0f0;">"done uploading</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
<span style="color: #888888;">// put your main code here, to run repeatedly:</span>
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>And the php script was used for this demo:</b><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;"><?php</span>
<span style="color: #996633;">$target_path</span> <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"uploads/"</span>;
<span style="color: #996633;">$target_path</span> <span style="color: #333333;">=</span> <span style="color: #996633;">$target_path</span> <span style="color: #333333;">.</span> <span style="color: #007020;">basename</span>( <span style="color: #996633;">$_FILES</span>[<span style="background-color: #fff0f0;">'data'</span>][<span style="background-color: #fff0f0;">'name'</span>]);
<span style="color: #008800; font-weight: bold;">if</span>(<span style="color: #007020;">move_uploaded_file</span>(<span style="color: #996633;">$_FILES</span>[<span style="background-color: #fff0f0;">'data'</span>][<span style="background-color: #fff0f0;">'tmp_name'</span>], <span style="color: #996633;">$target_path</span>)) {
<span style="color: #008800; font-weight: bold;">echo</span> <span style="background-color: #fff0f0;">"The file "</span><span style="color: #333333;">.</span> <span style="color: #007020;">basename</span>( <span style="color: #996633;">$_FILES</span>[<span style="background-color: #fff0f0;">'data'</span>][<span style="background-color: #fff0f0;">'name'</span>])<span style="color: #333333;">.</span>
<span style="background-color: #fff0f0;">" has been uploaded"</span>;
} <span style="color: #008800; font-weight: bold;">else</span>{
<span style="color: #008800; font-weight: bold;">echo</span> <span style="background-color: #fff0f0;">"There was an error uploading the file, please try again!"</span>;
}
<span style="color: #557799;">?></span>
</pre>
</td></tr>
</tbody></table>
</div>
<b>Note: </b>The variable<b> </b><span style="color: #996633;">$_FILES</span>[<span style="background-color: #fff0f0;">'data'</span>][<span style="background-color: #fff0f0;">'name'</span>] has fixed '<b>data</b>' field name (similar to html form "<b><input id="data" name="data" type="file" /></b>"). The downloaded file will be stored in sub-folder 'uploads' which is relative to folder where the php script located. Reference this <a href="http://www.iotsharing.com/2017/06/how-to-turn-the-Orange-Pi-into-an-IoT-node.html">post</a> to install local apache server.<b> </b><br />
<b>3. Hardware</b><br />
For harware connection please refer <a href="http://www.iotsharing.com/2017/11/firmware-update-ota-for-esp32-using-http-sdcard.html">here</a>. <b><br /></b><br />
<b>4. Result</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-EVSAe3FHifM/Wl4Zv-Ejq5I/AAAAAAAAGM4/ovax0H2YmG8_0S79JeUzqERiEObbVRHIQCLcBGAs/s1600/udhttp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="744" data-original-width="505" height="400" src="https://4.bp.blogspot.com/-EVSAe3FHifM/Wl4Zv-Ejq5I/AAAAAAAAGM4/ovax0H2YmG8_0S79JeUzqERiEObbVRHIQCLcBGAs/s400/udhttp.png" width="271" /></a></div>
<div style="text-align: center;">
<b>Figure: start downloading with progress displaying</b></div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com12tag:blogger.com,1999:blog-7549705215513488945.post-61653239632659415012021-10-24T03:38:00.000-07:002021-11-06T07:46:22.550-07:00Demo 31: How to use Arduino ESP32 CAN interface<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
- CAN stands for Controller Area Network (CAN bus). This protocol is very popular in automotive domain. In order to understand more about history, benefits, characteristics, message format of CAN, you can refer:<br />
<a href="http://www.ni.com/white-paper/2732/en/">http://www.ni.com/white-paper/2732/en/</a><br />
<a href="http://www.ti.com/lit/an/sloa101b/sloa101b.pdf">http://www.ti.com/lit/an/sloa101b/sloa101b.pdf</a><br />
- As you knew in <a href="http://www.iotsharing.com/2017/05/introduction-to-esp32.html">Introduction to ESP32</a>, ESP32 also supports CAN interface. So I am going to make a demo for this with Arduino.<br />
- In this demo, 2 ESP32 modules will be used: first module will send the string "hellocan" to second module. The second module will convert the string to upper case and respond it back to first module and first module will show the result in theTerminal.<br />
<b>2. Hardware</b><br />
- ESP32 only supplies CAN controller. So you need CAN transceiver for this demo. I bought 2 CAN trasceivers <a href="https://vi.aliexpress.com/item/SN65HVD230-CAN-bus-transceiver-communication-module-for-arduino/32687564210.html?spm=a2g14.search0303.3.28.TRuG6q">here</a>.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-nuM3-7ENLbE/WaqHAVw-vjI/AAAAAAAAEPk/HsVOT7jnwdkSv9iFcQOgCIfjSmYJ3xuQQCEwYBhgL/s1600/esp32_CAN_1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1334" data-original-width="1000" height="320" src="https://1.bp.blogspot.com/-nuM3-7ENLbE/WaqHAVw-vjI/AAAAAAAAEPk/HsVOT7jnwdkSv9iFcQOgCIfjSmYJ3xuQQCEwYBhgL/s320/esp32_CAN_1.jpg" width="239" /></a></div>
<div style="text-align: center;">
<b> Figure: ESP32 CAn transceiver</b></div>
- ESP32 GPIO5 will act as CAN_Tx.<br />
- ESP32 GPIO4 will act as CAN_Rx.<br />
- So you can connect pins belows (ESP32_X: module ESP32 X, CAN_X: module CAN X, where X is 1 or 2 since we have 2 modules):<br />
<b>ESP32_1 IO5 - CAN_1 CTX </b><br />
<b>ESP32_1 IO4 - CAN_1 CRX</b><br />
<b>CAN_1 CANH - CAN_2 CANH</b><br />
<b>CAN_1 CANL - CAN_2 CANL</b><br />
<b>ESP32_2 IO5 - CAN_2 CTX </b><br />
<b>ESP32_2 IO4 - CAN_2 CRX</b><br />
<b></b>
<b></b>
<b>3. Software</b><br />
- In order to make this demo, I used CAN driver which is made by <a href="https://github.com/ThomasBarth/ESP32-CAN-Driver/tree/master/components/can">Thomas Barth (Thanks Thomas :))</a><br />
- Download the CAN library for ESP32 <a href="https://github.com/nhatuan84/arduino-esp32-can-demo">here</a>. Unzip it and copy to <b>"Arduino/libraries"</b> folder.<br />
- Source code for first ESP32 module: receiving string, converting to upper case and respond back:<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <ESP32CAN.h></span>
<span style="color: #557799;">#include <CAN_config.h></span>
<span style="color: #888888;">/* the variable name CAN_cfg is fixed, do not change */</span>
CAN_device_t CAN_cfg;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
Serial.println(<span style="background-color: #fff0f0;">"iotsharing.com CAN demo"</span>);
<span style="color: #888888;">/* set CAN pins and baudrate */</span>
CAN_cfg.speed<span style="color: #333333;">=</span>CAN_SPEED_1000KBPS;
CAN_cfg.tx_pin_id <span style="color: #333333;">=</span> GPIO_NUM_5;
CAN_cfg.rx_pin_id <span style="color: #333333;">=</span> GPIO_NUM_4;
<span style="color: #888888;">/* create a queue for CAN receiving */</span>
CAN_cfg.rx_queue <span style="color: #333333;">=</span> xQueueCreate(<span style="color: #0000dd; font-weight: bold;">10</span>,<span style="color: #008800; font-weight: bold;">sizeof</span>(CAN_frame_t));
<span style="color: #888888;">//initialize CAN Module</span>
ESP32Can.CANInit();
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
CAN_frame_t rx_frame;
<span style="color: #888888;">//receive next CAN frame from queue</span>
<span style="color: #008800; font-weight: bold;">if</span>(xQueueReceive(CAN_cfg.rx_queue,<span style="color: #333333;">&</span>rx_frame, <span style="color: #0000dd; font-weight: bold;">3</span><span style="color: #333333;">*</span>portTICK_PERIOD_MS)<span style="color: #333333;">==</span>pdTRUE){
<span style="color: #888888;">//do stuff!</span>
<span style="color: #008800; font-weight: bold;">if</span>(rx_frame.FIR.B.FF<span style="color: #333333;">==</span>CAN_frame_std)
printf(<span style="background-color: #fff0f0;">"New standard frame"</span>);
<span style="color: #008800; font-weight: bold;">else</span>
printf(<span style="background-color: #fff0f0;">"New extended frame"</span>);
<span style="color: #008800; font-weight: bold;">if</span>(rx_frame.FIR.B.RTR<span style="color: #333333;">==</span>CAN_RTR)
printf(<span style="background-color: #fff0f0;">" RTR from 0x%08x, DLC %d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\r\n</span><span style="background-color: #fff0f0;">"</span>,rx_frame.MsgID, rx_frame.FIR.B.DLC);
<span style="color: #008800; font-weight: bold;">else</span>{
printf(<span style="background-color: #fff0f0;">" from 0x%08x, DLC %d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,rx_frame.MsgID, rx_frame.FIR.B.DLC);
<span style="color: #888888;">/* convert to upper case and respond to sender */</span>
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">8</span>; i<span style="color: #333333;">++</span>){
<span style="color: #008800; font-weight: bold;">if</span>(rx_frame.data.u8[i] <span style="color: #333333;">>=</span> <span style="color: #0044dd;">'a'</span> <span style="color: #333333;">&&</span> rx_frame.data.u8[i] <span style="color: #333333;"><=</span> <span style="color: #0044dd;">'z'</span>){
rx_frame.data.u8[i] <span style="color: #333333;">=</span> rx_frame.data.u8[i] <span style="color: #333333;">-</span> <span style="color: #0000dd; font-weight: bold;">32</span>;
}
}
}
<span style="color: #888888;">//respond to sender</span>
ESP32Can.CANWriteFrame(<span style="color: #333333;">&</span>rx_frame);
}
}
</pre>
</td></tr>
</tbody></table>
</div>
- Source code for second ESP32 module: sending the string that need to be converted to upper case, receiving response and show it to Terminal<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <ESP32CAN.h></span>
<span style="color: #557799;">#include <CAN_config.h></span>
<span style="color: #888888;">/* the variable name CAN_cfg is fixed, do not change */</span>
CAN_device_t CAN_cfg;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
Serial.println(<span style="background-color: #fff0f0;">"iotsharing.com CAN demo"</span>);
<span style="color: #888888;">/* set CAN pins and baudrate */</span>
CAN_cfg.speed<span style="color: #333333;">=</span>CAN_SPEED_1000KBPS;
CAN_cfg.tx_pin_id <span style="color: #333333;">=</span> GPIO_NUM_5;
CAN_cfg.rx_pin_id <span style="color: #333333;">=</span> GPIO_NUM_4;
<span style="color: #888888;">/* create a queue for CAN receiving */</span>
CAN_cfg.rx_queue <span style="color: #333333;">=</span> xQueueCreate(<span style="color: #0000dd; font-weight: bold;">10</span>,<span style="color: #008800; font-weight: bold;">sizeof</span>(CAN_frame_t));
<span style="color: #888888;">//initialize CAN Module</span>
ESP32Can.CANInit();
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
CAN_frame_t rx_frame;
<span style="color: #888888;">//receive next CAN frame from queue</span>
<span style="color: #008800; font-weight: bold;">if</span>(xQueueReceive(CAN_cfg.rx_queue,<span style="color: #333333;">&</span>rx_frame, <span style="color: #0000dd; font-weight: bold;">3</span><span style="color: #333333;">*</span>portTICK_PERIOD_MS)<span style="color: #333333;">==</span>pdTRUE){
<span style="color: #888888;">//do stuff!</span>
<span style="color: #008800; font-weight: bold;">if</span>(rx_frame.FIR.B.FF<span style="color: #333333;">==</span>CAN_frame_std)
printf(<span style="background-color: #fff0f0;">"New standard frame"</span>);
<span style="color: #008800; font-weight: bold;">else</span>
printf(<span style="background-color: #fff0f0;">"New extended frame"</span>);
<span style="color: #008800; font-weight: bold;">if</span>(rx_frame.FIR.B.RTR<span style="color: #333333;">==</span>CAN_RTR)
printf(<span style="background-color: #fff0f0;">" RTR from 0x%08x, DLC %d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\r\n</span><span style="background-color: #fff0f0;">"</span>,rx_frame.MsgID, rx_frame.FIR.B.DLC);
<span style="color: #008800; font-weight: bold;">else</span>{
printf(<span style="background-color: #fff0f0;">" from 0x%08x, DLC %d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,rx_frame.MsgID, rx_frame.FIR.B.DLC);
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">8</span>; i<span style="color: #333333;">++</span>){
printf(<span style="background-color: #fff0f0;">"%c</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\t</span><span style="background-color: #fff0f0;">"</span>, (<span style="color: #333399; font-weight: bold;">char</span>)rx_frame.data.u8[i]);
}
printf(<span style="background-color: #fff0f0;">"</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
}
}
<span style="color: #008800; font-weight: bold;">else</span>
{
rx_frame.FIR.B.FF <span style="color: #333333;">=</span> CAN_frame_std;
rx_frame.MsgID <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
rx_frame.FIR.B.DLC <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">8</span>;
rx_frame.data.u8[<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> <span style="color: #0044dd;">'h'</span>;
rx_frame.data.u8[<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> <span style="color: #0044dd;">'e'</span>;
rx_frame.data.u8[<span style="color: #0000dd; font-weight: bold;">2</span>] <span style="color: #333333;">=</span> <span style="color: #0044dd;">'l'</span>;
rx_frame.data.u8[<span style="color: #0000dd; font-weight: bold;">3</span>] <span style="color: #333333;">=</span> <span style="color: #0044dd;">'l'</span>;
rx_frame.data.u8[<span style="color: #0000dd; font-weight: bold;">4</span>] <span style="color: #333333;">=</span> <span style="color: #0044dd;">'o'</span>;
rx_frame.data.u8[<span style="color: #0000dd; font-weight: bold;">5</span>] <span style="color: #333333;">=</span> <span style="color: #0044dd;">'c'</span>;
rx_frame.data.u8[<span style="color: #0000dd; font-weight: bold;">6</span>] <span style="color: #333333;">=</span> <span style="color: #0044dd;">'a'</span>;
rx_frame.data.u8[<span style="color: #0000dd; font-weight: bold;">7</span>] <span style="color: #333333;">=</span> <span style="color: #0044dd;">'n'</span>;
ESP32Can.CANWriteFrame(<span style="color: #333333;">&</span>rx_frame);
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>4. Result</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-aoKC-qLvmxA/WaqHBfTtfCI/AAAAAAAAEPo/Rj9ecF_g1msfqKJeYWiQnZs-um-p3ReuQCLcBGAs/s1600/esp32_CAN.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1440" height="400" src="https://1.bp.blogspot.com/-aoKC-qLvmxA/WaqHBfTtfCI/AAAAAAAAEPo/Rj9ecF_g1msfqKJeYWiQnZs-um-p3ReuQCLcBGAs/s640/esp32_CAN.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: ESP32 CAN demo</b><br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/6FpKE_lyABk/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/6FpKE_lyABk?feature=player_embedded" width="480"></iframe></div>
</div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com54tag:blogger.com,1999:blog-7549705215513488945.post-16048174531556420472021-10-22T03:51:00.000-07:002021-11-06T07:46:49.838-07:00Demo 26: How to use Arduino ESP32 I2S (external DAC and built-in DAC) to play wav music file from sdcard<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
- ESP32 has two I2S peripherals. They can be configured to input and output sample data. They also supports <a href="https://en.wikipedia.org/wiki/Direct_memory_access" target="_blank">DMA</a> to stream sample data
without needing CPU operations. I2S output can also be routed directly to the Digital to Analog
Converter output (GPIO25 and GPIO26) without needing <a href="https://vi.aliexpress.com/item/PCM5102-DAC-Decoder-I2S-Player-Assembled-Board-32Bit-384K-Beyond-ES9023-PCM1794-compatible-Raspberry-Pi/32678406932.html?spm=2114.55010608.4.2.jU683C" target="_blank">external I2S codec</a>.<br />
- In this demo I will show you how to use Arduino ESP32 I2S to play <b>wav</b> music file from sdcard. I chose wav file because it is not compressed like mp3 file. So we need not to de-compress it.<br />
- There are 2 demos for this post: <br />
1. I used <a href="https://vi.aliexpress.com/item/PCM5102-DAC-Decoder-I2S-Player-Assembled-Board-32Bit-384K-Beyond-ES9023-PCM1794-compatible-Raspberry-Pi/32678406932.html?spm=2114.55010608.4.2.jU683C" target="_blank">external I2S codec</a>, 2 speakers and 1 module <a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html" target="_blank">micro sdcard</a>.<br />
2. I Used internal DAC, 2 speakers and 1 module micro sdcard.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-0HAUwtfwAN0/WWIGfUgvaOI/AAAAAAAAEHU/a2L05ocwOsImQJHCxGt2H8q-ZDahPMfhgCLcBGAs/s1600/esp32_i2s_2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="570" data-original-width="490" height="400" src="https://2.bp.blogspot.com/-0HAUwtfwAN0/WWIGfUgvaOI/AAAAAAAAEHU/a2L05ocwOsImQJHCxGt2H8q-ZDahPMfhgCLcBGAs/s400/esp32_i2s_2.jpg" width="343" /></a></div>
<div style="text-align: center;">
<b> Figure: <a href="https://vi.aliexpress.com/item/PCM5102-DAC-Decoder-I2S-Player-Assembled-Board-32Bit-384K-Beyond-ES9023-PCM1794-compatible-Raspberry-Pi/32678406932.html?spm=2114.55010608.4.2.jU683C" target="_blank">external I2S codec</a></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-zrYW161XJYY/WWIGgYKIxBI/AAAAAAAAEHY/_J9i7tJxQkwt6MBxSWFK-T8E_onIHoOYwCLcBGAs/s1600/esp32_i2s_1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="960" height="480" src="https://3.bp.blogspot.com/-zrYW161XJYY/WWIGgYKIxBI/AAAAAAAAEHY/_J9i7tJxQkwt6MBxSWFK-T8E_onIHoOYwCLcBGAs/s640/esp32_i2s_1.jpg" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: I used <a href="https://vi.aliexpress.com/item/PCM5102-DAC-Decoder-I2S-Player-Assembled-Board-32Bit-384K-Beyond-ES9023-PCM1794-compatible-Raspberry-Pi/32678406932.html?spm=2114.55010608.4.2.jU683C" target="_blank">external I2S codec</a> for this demo, 2 speakers and 1 module micro sdcard</b></div>
<div style="text-align: left;">
<b>2. Hardware</b></div>
<div style="text-align: left;">
Connect hardware like below:</div>
[ESP32 IO32 – CS MICROSD]<br />
[ESP32 IO14 – MOSI MICROSD]<br />
[ESP32 IO13 – MISO MICROSD]<br />
[ESP32 IO27 – SCK MICROSD]<br />
[ESP32 IO26 – I2S codec BCK]<br />
[ESP32 IO22 – I2S codec DATA]<br />
[ESP32 IO25 – I2S codec LRCK]<br />
[ESP32 GND – I2S codec GND]<br />
[ESP32 GND – GND MICROSD]<br />
[5V – VCC MICROSD]<br />
[5V – I2S codec]<br />
<b>3. Software</b><br />
- We will re-use <a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html" target="_blank">Demo 7</a> for sdcard reading and I2S driver <a href="http://esp-idf.readthedocs.io/en/latest/api-reference/peripherals/i2s.html" target="_blank">here</a>. You can download the document about the wav file format <a href="http://tiny.systems/software/soundProgrammer/WavFormatDocs.pdf" target="_blank">here</a>.<br />
<b>Note</b>: You can down full project including wav file sample : <a href="https://github.com/nhatuan84/esp32-i2s-sdcard-wav-player">https://github.com/nhatuan84/esp32-i2s-sdcard-wav-player</a><br />
<b>3.1 The code with external DAC </b> <br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <mySD.h></span>
<span style="color: #557799;">#include "driver/i2s.h"</span>
<span style="color: #557799;">#include "freertos/queue.h"</span>
<span style="color: #557799;">#define CCCC(c1, c2, c3, c4) ((c4 << 24) | (c3 << 16) | (c2 << 8) | c1)</span>
<span style="color: #888888;">/* these are data structures to process wav file */</span>
<span style="color: #008800; font-weight: bold;">typedef</span> <span style="color: #008800; font-weight: bold;">enum</span> headerState_e {
HEADER_RIFF, HEADER_FMT, HEADER_DATA, DATA
} headerState_t;
<span style="color: #008800; font-weight: bold;">typedef</span> <span style="color: #008800; font-weight: bold;">struct</span> wavRiff_s {
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkID;
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkSize;
<span style="color: #333399; font-weight: bold;">uint32_t</span> format;
} wavRiff_t;
<span style="color: #008800; font-weight: bold;">typedef</span> <span style="color: #008800; font-weight: bold;">struct</span> wavProperties_s {
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkID;
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkSize;
<span style="color: #333399; font-weight: bold;">uint16_t</span> audioFormat;
<span style="color: #333399; font-weight: bold;">uint16_t</span> numChannels;
<span style="color: #333399; font-weight: bold;">uint32_t</span> sampleRate;
<span style="color: #333399; font-weight: bold;">uint32_t</span> byteRate;
<span style="color: #333399; font-weight: bold;">uint16_t</span> blockAlign;
<span style="color: #333399; font-weight: bold;">uint16_t</span> bitsPerSample;
} wavProperties_t;
<span style="color: #888888;">/* variables hold file, state of process wav file and wav file properties */</span>
File root;
headerState_t state <span style="color: #333333;">=</span> HEADER_RIFF;
wavProperties_t wavProps;
<span style="color: #888888;">//i2s configuration </span>
<span style="color: #333399; font-weight: bold;">int</span> i2s_num <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; <span style="color: #888888;">// i2s port number</span>
<span style="color: #333399; font-weight: bold;">i2s_config_t</span> i2s_config <span style="color: #333333;">=</span> {
.mode <span style="color: #333333;">=</span> (<span style="color: #333399; font-weight: bold;">i2s_mode_t</span>)(I2S_MODE_MASTER <span style="color: #333333;">|</span> I2S_MODE_TX),
.sample_rate <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">36000</span>,
.bits_per_sample <span style="color: #333333;">=</span> I2S_BITS_PER_SAMPLE_16BIT,
.channel_format <span style="color: #333333;">=</span> I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format <span style="color: #333333;">=</span> (<span style="color: #333399; font-weight: bold;">i2s_comm_format_t</span>)(I2S_COMM_FORMAT_I2S <span style="color: #333333;">|</span> I2S_COMM_FORMAT_I2S_MSB),
.intr_alloc_flags <span style="color: #333333;">=</span> ESP_INTR_FLAG_LEVEL1, <span style="color: #888888;">// high interrupt priority</span>
.dma_buf_count <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">8</span>,
.dma_buf_len <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">64</span> <span style="color: #888888;">//Interrupt level 1</span>
};
<span style="color: #333399; font-weight: bold;">i2s_pin_config_t</span> pin_config <span style="color: #333333;">=</span> {
.bck_io_num <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">26</span>, <span style="color: #888888;">//this is BCK pin</span>
.ws_io_num <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">25</span>, <span style="color: #888888;">// this is LRCK pin</span>
.data_out_num <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">22</span>, <span style="color: #888888;">// this is DATA output pin</span>
.data_in_num <span style="color: #333333;">=</span> <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #888888;">//Not used</span>
};
<span style="color: #888888;">//</span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">debug</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>buf, <span style="color: #333399; font-weight: bold;">int</span> len){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>len;i<span style="color: #333333;">++</span>){
Serial.print(buf[i], HEX);
Serial.print(<span style="background-color: #fff0f0;">"</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\t</span><span style="background-color: #fff0f0;">"</span>);
}
Serial.println();
}
<span style="color: #888888;">/* write sample data to I2S */</span>
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">i2s_write_sample_nb</span>(<span style="color: #333399; font-weight: bold;">uint32_t</span> sample){
<span style="color: #008800; font-weight: bold;">return</span> i2s_write_bytes((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num, (<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)<span style="color: #333333;">&</span>sample, <span style="color: #008800; font-weight: bold;">sizeof</span>(<span style="color: #333399; font-weight: bold;">uint32_t</span>), <span style="color: #0000dd; font-weight: bold;">100</span>);
}
<span style="color: #888888;">/* read 4 bytes of data from wav file */</span>
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">read4bytes</span>(File file, <span style="color: #333399; font-weight: bold;">uint32_t</span> <span style="color: #333333;">*</span>chunkId){
<span style="color: #333399; font-weight: bold;">int</span> n <span style="color: #333333;">=</span> file.read((<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>)chunkId, <span style="color: #008800; font-weight: bold;">sizeof</span>(<span style="color: #333399; font-weight: bold;">uint32_t</span>));
<span style="color: #008800; font-weight: bold;">return</span> n;
}
<span style="color: #888888;">/* these are function to process wav file */</span>
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">readRiff</span>(File file, wavRiff_t <span style="color: #333333;">*</span>wavRiff){
<span style="color: #333399; font-weight: bold;">int</span> n <span style="color: #333333;">=</span> file.read((<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>)wavRiff, <span style="color: #008800; font-weight: bold;">sizeof</span>(wavRiff_t));
<span style="color: #008800; font-weight: bold;">return</span> n;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">readProps</span>(File file, wavProperties_t <span style="color: #333333;">*</span>wavProps){
<span style="color: #333399; font-weight: bold;">int</span> n <span style="color: #333333;">=</span> file.read((<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>)wavProps, <span style="color: #008800; font-weight: bold;">sizeof</span>(wavProperties_t));
<span style="color: #008800; font-weight: bold;">return</span> n;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>()
{
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
Serial.print(<span style="background-color: #fff0f0;">"Initializing SD card..."</span>);
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>SD.begin(<span style="color: #0000dd; font-weight: bold;">32</span>, <span style="color: #0000dd; font-weight: bold;">14</span>, <span style="color: #0000dd; font-weight: bold;">13</span>, <span style="color: #0000dd; font-weight: bold;">27</span>)) {
Serial.println(<span style="background-color: #fff0f0;">"initialization failed!"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
Serial.println(<span style="background-color: #fff0f0;">"initialization done."</span>);
delay(<span style="color: #0000dd; font-weight: bold;">1000</span>);
<span style="color: #888888;">/* open wav file and process it */</span>
root <span style="color: #333333;">=</span> SD.open(<span style="background-color: #fff0f0;">"T.WAV"</span>);
<span style="color: #008800; font-weight: bold;">if</span> (root) {
<span style="color: #333399; font-weight: bold;">int</span> c <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int</span> n;
<span style="color: #008800; font-weight: bold;">while</span> (root.available()) {
<span style="color: #008800; font-weight: bold;">switch</span>(state){
<span style="color: #008800; font-weight: bold;">case</span> HEADER_RIFF:
wavRiff_t wavRiff;
n <span style="color: #333333;">=</span> readRiff(root, <span style="color: #333333;">&</span>wavRiff);
<span style="color: #008800; font-weight: bold;">if</span>(n <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">sizeof</span>(wavRiff_t)){
<span style="color: #008800; font-weight: bold;">if</span>(wavRiff.chunkID <span style="color: #333333;">==</span> CCCC(<span style="color: #0044dd;">'R'</span>, <span style="color: #0044dd;">'I'</span>, <span style="color: #0044dd;">'F'</span>, <span style="color: #0044dd;">'F'</span>) <span style="color: #333333;">&&</span> wavRiff.format <span style="color: #333333;">==</span> CCCC(<span style="color: #0044dd;">'W'</span>, <span style="color: #0044dd;">'A'</span>, <span style="color: #0044dd;">'V'</span>, <span style="color: #0044dd;">'E'</span>)){
state <span style="color: #333333;">=</span> HEADER_FMT;
Serial.println(<span style="background-color: #fff0f0;">"HEADER_RIFF"</span>);
}
}
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">case</span> HEADER_FMT:
n <span style="color: #333333;">=</span> readProps(root, <span style="color: #333333;">&</span>wavProps);
<span style="color: #008800; font-weight: bold;">if</span>(n <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">sizeof</span>(wavProperties_t)){
state <span style="color: #333333;">=</span> HEADER_DATA;
}
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">case</span> HEADER_DATA:
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkId, chunkSize;
n <span style="color: #333333;">=</span> read4bytes(root, <span style="color: #333333;">&</span>chunkId);
<span style="color: #008800; font-weight: bold;">if</span>(n <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">4</span>){
<span style="color: #008800; font-weight: bold;">if</span>(chunkId <span style="color: #333333;">==</span> CCCC(<span style="color: #0044dd;">'d'</span>, <span style="color: #0044dd;">'a'</span>, <span style="color: #0044dd;">'t'</span>, <span style="color: #0044dd;">'a'</span>)){
Serial.println(<span style="background-color: #fff0f0;">"HEADER_DATA"</span>);
}
}
n <span style="color: #333333;">=</span> read4bytes(root, <span style="color: #333333;">&</span>chunkSize);
<span style="color: #008800; font-weight: bold;">if</span>(n <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">4</span>){
Serial.println(<span style="background-color: #fff0f0;">"prepare data"</span>);
state <span style="color: #333333;">=</span> DATA;
}
<span style="color: #888888;">//initialize i2s with configurations above</span>
i2s_driver_install((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num, <span style="color: #333333;">&</span>i2s_config, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #007020;">NULL</span>);
i2s_set_pin((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num, <span style="color: #333333;">&</span>pin_config);
<span style="color: #888888;">//set sample rates of i2s to sample rate of wav file</span>
i2s_set_sample_rates((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num, wavProps.sampleRate);
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #888888;">/* after processing wav file, it is time to process music data */</span>
<span style="color: #008800; font-weight: bold;">case</span> DATA:
<span style="color: #333399; font-weight: bold;">uint32_t</span> data;
n <span style="color: #333333;">=</span> read4bytes(root, <span style="color: #333333;">&</span>data);
i2s_write_sample_nb(data);
<span style="color: #008800; font-weight: bold;">break</span>;
}
}
root.close();
} <span style="color: #008800; font-weight: bold;">else</span> {
Serial.println(<span style="background-color: #fff0f0;">"error opening test.txt"</span>);
}
i2s_driver_uninstall((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num); <span style="color: #888888;">//stop & destroy i2s driver </span>
Serial.println(<span style="background-color: #fff0f0;">"done!"</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>()
{
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>3.2 The code with built-in DAC</b><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <mySD.h></span>
<span style="color: #557799;">#include "driver/i2s.h"</span>
<span style="color: #557799;">#include "freertos/queue.h"</span>
<span style="color: #557799;">#define CCCC(c1, c2, c3, c4) ((c4 << 24) | (c3 << 16) | (c2 << 8) | c1)</span>
<span style="color: #888888;">/* these are data structures to process wav file */</span>
<span style="color: #008800; font-weight: bold;">typedef</span> <span style="color: #008800; font-weight: bold;">enum</span> headerState_e {
HEADER_RIFF, HEADER_FMT, HEADER_DATA, DATA
} headerState_t;
<span style="color: #008800; font-weight: bold;">typedef</span> <span style="color: #008800; font-weight: bold;">struct</span> wavRiff_s {
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkID;
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkSize;
<span style="color: #333399; font-weight: bold;">uint32_t</span> format;
} wavRiff_t;
<span style="color: #008800; font-weight: bold;">typedef</span> <span style="color: #008800; font-weight: bold;">struct</span> wavProperties_s {
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkID;
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkSize;
<span style="color: #333399; font-weight: bold;">uint16_t</span> audioFormat;
<span style="color: #333399; font-weight: bold;">uint16_t</span> numChannels;
<span style="color: #333399; font-weight: bold;">uint32_t</span> sampleRate;
<span style="color: #333399; font-weight: bold;">uint32_t</span> byteRate;
<span style="color: #333399; font-weight: bold;">uint16_t</span> blockAlign;
<span style="color: #333399; font-weight: bold;">uint16_t</span> bitsPerSample;
} wavProperties_t;
<span style="color: #888888;">/* variables hold file, state of process wav file and wav file properties */</span>
File root;
headerState_t state <span style="color: #333333;">=</span> HEADER_RIFF;
wavProperties_t wavProps;
<span style="color: #888888;">//i2s configuration </span>
<span style="color: #333399; font-weight: bold;">int</span> i2s_num <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; <span style="color: #888888;">// i2s port number</span>
<span style="color: #333399; font-weight: bold;">i2s_config_t</span> i2s_config <span style="color: #333333;">=</span> {
.mode <span style="color: #333333;">=</span> (<span style="color: #333399; font-weight: bold;">i2s_mode_t</span>)(I2S_MODE_MASTER <span style="color: #333333;">|</span> I2S_MODE_TX <span style="color: #333333;">|</span> I2S_MODE_DAC_BUILT_IN),
.sample_rate <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">44100</span>,
.bits_per_sample <span style="color: #333333;">=</span> I2S_BITS_PER_SAMPLE_16BIT, <span style="color: #888888;">/* the DAC module will only take the 8bits from MSB */</span>
.channel_format <span style="color: #333333;">=</span> I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format <span style="color: #333333;">=</span> (<span style="color: #333399; font-weight: bold;">i2s_comm_format_t</span>)I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #888888;">// default interrupt priority</span>
.dma_buf_count <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">8</span>,
.dma_buf_len <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">64</span>,
.use_apll <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>
};
<span style="color: #888888;">//</span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">debug</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>buf, <span style="color: #333399; font-weight: bold;">int</span> len){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>len;i<span style="color: #333333;">++</span>){
Serial.print(buf[i], HEX);
Serial.print(<span style="background-color: #fff0f0;">"</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\t</span><span style="background-color: #fff0f0;">"</span>);
}
Serial.println();
}
<span style="color: #888888;">/* write sample data to I2S */</span>
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">i2s_write_sample_nb</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span> sample){
<span style="color: #008800; font-weight: bold;">return</span> i2s_write_bytes((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num, (<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)<span style="color: #333333;">&</span>sample, <span style="color: #008800; font-weight: bold;">sizeof</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span>), <span style="color: #0000dd; font-weight: bold;">100</span>);
}
<span style="color: #888888;">/* read 4 bytes of data from wav file */</span>
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">read4bytes</span>(File file, <span style="color: #333399; font-weight: bold;">uint32_t</span> <span style="color: #333333;">*</span>chunkId){
<span style="color: #333399; font-weight: bold;">int</span> n <span style="color: #333333;">=</span> file.read((<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>)chunkId, <span style="color: #008800; font-weight: bold;">sizeof</span>(<span style="color: #333399; font-weight: bold;">uint32_t</span>));
<span style="color: #008800; font-weight: bold;">return</span> n;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">readbyte</span>(File file, <span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>chunkId){
<span style="color: #333399; font-weight: bold;">int</span> n <span style="color: #333333;">=</span> file.read((<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>)chunkId, <span style="color: #008800; font-weight: bold;">sizeof</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span>));
<span style="color: #008800; font-weight: bold;">return</span> n;
}
<span style="color: #888888;">/* these are function to process wav file */</span>
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">readRiff</span>(File file, wavRiff_t <span style="color: #333333;">*</span>wavRiff){
<span style="color: #333399; font-weight: bold;">int</span> n <span style="color: #333333;">=</span> file.read((<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>)wavRiff, <span style="color: #008800; font-weight: bold;">sizeof</span>(wavRiff_t));
<span style="color: #008800; font-weight: bold;">return</span> n;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">readProps</span>(File file, wavProperties_t <span style="color: #333333;">*</span>wavProps){
<span style="color: #333399; font-weight: bold;">int</span> n <span style="color: #333333;">=</span> file.read((<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>)wavProps, <span style="color: #008800; font-weight: bold;">sizeof</span>(wavProperties_t));
<span style="color: #008800; font-weight: bold;">return</span> n;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>()
{
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
Serial.print(<span style="background-color: #fff0f0;">"Initializing SD card..."</span>);
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>SD.begin(<span style="color: #0000dd; font-weight: bold;">32</span>, <span style="color: #0000dd; font-weight: bold;">14</span>, <span style="color: #0000dd; font-weight: bold;">13</span>, <span style="color: #0000dd; font-weight: bold;">27</span>)) {
Serial.println(<span style="background-color: #fff0f0;">"initialization failed!"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
Serial.println(<span style="background-color: #fff0f0;">"initialization done."</span>);
delay(<span style="color: #0000dd; font-weight: bold;">1000</span>);
<span style="color: #888888;">/* open wav file and process it */</span>
root <span style="color: #333333;">=</span> SD.open(<span style="background-color: #fff0f0;">"T.WAV"</span>);
<span style="color: #008800; font-weight: bold;">if</span> (root) {
<span style="color: #333399; font-weight: bold;">int</span> c <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int</span> n;
<span style="color: #008800; font-weight: bold;">while</span> (root.available()) {
<span style="color: #008800; font-weight: bold;">switch</span>(state){
<span style="color: #008800; font-weight: bold;">case</span> HEADER_RIFF:
wavRiff_t wavRiff;
n <span style="color: #333333;">=</span> readRiff(root, <span style="color: #333333;">&</span>wavRiff);
<span style="color: #008800; font-weight: bold;">if</span>(n <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">sizeof</span>(wavRiff_t)){
<span style="color: #008800; font-weight: bold;">if</span>(wavRiff.chunkID <span style="color: #333333;">==</span> CCCC(<span style="color: #0044dd;">'R'</span>, <span style="color: #0044dd;">'I'</span>, <span style="color: #0044dd;">'F'</span>, <span style="color: #0044dd;">'F'</span>) <span style="color: #333333;">&&</span> wavRiff.format <span style="color: #333333;">==</span> CCCC(<span style="color: #0044dd;">'W'</span>, <span style="color: #0044dd;">'A'</span>, <span style="color: #0044dd;">'V'</span>, <span style="color: #0044dd;">'E'</span>)){
state <span style="color: #333333;">=</span> HEADER_FMT;
Serial.println(<span style="background-color: #fff0f0;">"HEADER_RIFF"</span>);
}
}
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">case</span> HEADER_FMT:
n <span style="color: #333333;">=</span> readProps(root, <span style="color: #333333;">&</span>wavProps);
<span style="color: #008800; font-weight: bold;">if</span>(n <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">sizeof</span>(wavProperties_t)){
state <span style="color: #333333;">=</span> HEADER_DATA;
}
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">case</span> HEADER_DATA:
<span style="color: #333399; font-weight: bold;">uint32_t</span> chunkId, chunkSize;
n <span style="color: #333333;">=</span> read4bytes(root, <span style="color: #333333;">&</span>chunkId);
<span style="color: #008800; font-weight: bold;">if</span>(n <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">4</span>){
<span style="color: #008800; font-weight: bold;">if</span>(chunkId <span style="color: #333333;">==</span> CCCC(<span style="color: #0044dd;">'d'</span>, <span style="color: #0044dd;">'a'</span>, <span style="color: #0044dd;">'t'</span>, <span style="color: #0044dd;">'a'</span>)){
Serial.println(<span style="background-color: #fff0f0;">"HEADER_DATA"</span>);
}
}
n <span style="color: #333333;">=</span> read4bytes(root, <span style="color: #333333;">&</span>chunkSize);
<span style="color: #008800; font-weight: bold;">if</span>(n <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">4</span>){
Serial.println(<span style="background-color: #fff0f0;">"prepare data"</span>);
state <span style="color: #333333;">=</span> DATA;
}
<span style="color: #888888;">//initialize i2s with configurations above</span>
i2s_driver_install((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num, <span style="color: #333333;">&</span>i2s_config, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #007020;">NULL</span>);
i2s_set_pin((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num, <span style="color: #007020;">NULL</span>);
<span style="color: #888888;">//set sample rates of i2s to sample rate of wav file</span>
i2s_set_sample_rates((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num, wavProps.sampleRate);
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #888888;">/* after processing wav file, it is time to process music data */</span>
<span style="color: #008800; font-weight: bold;">case</span> DATA:
<span style="color: #333399; font-weight: bold;">uint8_t</span> data;
n <span style="color: #333333;">=</span> readbyte(root, <span style="color: #333333;">&</span>data);
i2s_write_sample_nb(data);
<span style="color: #008800; font-weight: bold;">break</span>;
}
}
root.close();
} <span style="color: #008800; font-weight: bold;">else</span> {
Serial.println(<span style="background-color: #fff0f0;">"error opening test.txt"</span>);
}
i2s_driver_uninstall((<span style="color: #333399; font-weight: bold;">i2s_port_t</span>)i2s_num); <span style="color: #888888;">//stop & destroy i2s driver </span>
Serial.println(<span style="background-color: #fff0f0;">"done!"</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>()
{
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>4. Result</b><br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/zIZvq5oYPBE/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/zIZvq5oYPBE?feature=player_embedded" width="480"></iframe></div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com25tag:blogger.com,1999:blog-7549705215513488945.post-67408441490380258732021-10-18T08:24:00.000-07:002021-11-06T07:47:15.729-07:00Demo 22: How to use Timer interrupt in Arduino ESP32<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
- In<b> </b><a href="http://www.iotsharing.com/2017/05/blinky-hello-world-on-arduino-esp32.html" target="_blank">blinky demo</a> we use delay() function to make the LED blink. In this demo we will replcae delay() function by using Timer (this is hardware timer). Using Timer we can schedule when a task need to be started and repeat or not. Applying to this demo, when the Timer is timeout we will change the current state of LED (ON to OFF to ON) every 1 second.<br />
<b>2. Hardware</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-Edc2Mnm_Rh8/WRjx2wVCVhI/AAAAAAAADzc/NK8uFvWzGC8dW6XMTuiXrDEsX9UCDajzQCPcBGAYYCw/s1600/led2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="692" data-original-width="624" height="400" src="https://2.bp.blogspot.com/-Edc2Mnm_Rh8/WRjx2wVCVhI/AAAAAAAADzc/NK8uFvWzGC8dW6XMTuiXrDEsX9UCDajzQCPcBGAYYCw/s400/led2.png" width="360" /> </a></div>
<div class="separator" style="clear: both; text-align: center;">
<b>Figure: ESP32 connect to LED</b> </div>
Connection:<br />
[ESP32 IO14 and ESP32 GND to LED]<br />
<b>3. Software</b><br />
In order to use Timer we will use the functions:<br />
<b>"hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp)"</b><br />
<b></b>+ num: is order of Timer. We only have 4 timers so the order can be 0,1,2,3.<br />
<b> </b><complete id="goog_2044975902">+ </complete>divider: it is a prescaler. To make 1 second scheduler, we will use divider value is 80. ESP32 main clock is 80MHZ so every tick will take T = 1/(80MHZ/80) = 1 microsecond. We need 1000000 ticks for 1 second.<br />
<complete id="goog_2044975905">+</complete> countUp: if it is true the timer will count up and vice versa.<br />
<b>"void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge)"</b><br />
<b></b>+ fn: is the callback function that will be invoked when timer timeout and timer interrupt will be invoked.<b> </b><br />
+ edge: if it is true, an alarm will generate an edge type interrupt.<br />
<b>"void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload)"</b><br />
+ alarm_value: we set it to 1000000 as calculated above<br />
+ autoreload: if it is true, timer will repeat.<br />
<b>"void timerAlarmEnable(hw_timer_t *timer)"</b>: enable the Timer.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #888888;">/* create a hardware timer */</span>
<span style="color: #333399; font-weight: bold;">hw_timer_t</span> <span style="color: #333333;">*</span> timer <span style="color: #333333;">=</span> <span style="color: #007020;">NULL</span>;
<span style="color: #888888;">/* LED pin */</span>
<span style="color: #333399; font-weight: bold;">int</span> led <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">14</span>;
<span style="color: #888888;">/* LED state */</span>
<span style="color: #008800; font-weight: bold;">volatile</span> byte state <span style="color: #333333;">=</span> LOW;
<span style="color: #333399; font-weight: bold;">void</span> IRAM_ATTR <span style="color: #0066bb; font-weight: bold;">onTimer</span>(){
state <span style="color: #333333;">=</span> <span style="color: #333333;">!</span>state;
digitalWrite(led, state);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
pinMode(led, OUTPUT);
<span style="color: #888888;">/* Use 1st timer of 4 */</span>
<span style="color: #888888;">/* 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */</span>
timer <span style="color: #333333;">=</span> timerBegin(<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">80</span>, <span style="color: #007020;">true</span>);
<span style="color: #888888;">/* Attach onTimer function to our timer */</span>
timerAttachInterrupt(timer, <span style="color: #333333;">&</span>onTimer, <span style="color: #007020;">true</span>);
<span style="color: #888888;">/* Set alarm to call onTimer function every second 1 tick is 1us</span>
<span style="color: #888888;"> => 1 second is 1000000us */</span>
<span style="color: #888888;">/* Repeat the alarm (third parameter) */</span>
timerAlarmWrite(timer, <span style="color: #0000dd; font-weight: bold;">1000000</span>, <span style="color: #007020;">true</span>);
<span style="color: #888888;">/* Start an alarm */</span>
timerAlarmEnable(timer);
Serial.println(<span style="background-color: #fff0f0;">"start timer"</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>4. Result</b><br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/bePxW1Y_riQ/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/bePxW1Y_riQ?feature=player_embedded" width="480"></iframe></div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com9tag:blogger.com,1999:blog-7549705215513488945.post-16602988230836187892021-08-22T01:18:00.007-07:002021-11-06T07:03:57.939-07:00Demo 52: Computer vision with ESP32 Camera<p><b>1. Introduction</b></p><p>I have made many demos for ESP32-Camera</p><div dir="ltr" trbidi="on"><a href="http://www.iotsharing.com/2019/07/deep-learning-computer-vision-with-esp-tensorflowjs.html">Demo 47: Deep learning - Computer vision with ESP32 and tensorflow.js</a><br /><br /><a href="http://www.iotsharing.com/2020/03/demo-48-using-websocket-for-camera-live.html">Demo 48: Using WebSocket for camera live stream</a><br /><br /><a href="http://www.iotsharing.com/2020/03/using-http-for-camera-live-stream.html">Demo 49: Using HTTP for camera live stream and bring it to the world</a><br /><br /><a href="http://www.iotsharing.com/2020/03/bring-tensorflow-lite-to-esp32-person-detection-deep-learning.html">Demo 50: Bring Tensorflow Lite to ESP32 Arduino - person detection application using deep learning with ESP32 CAM</a></div><div dir="ltr" trbidi="on"><br /></div><div dir="ltr" trbidi="on"><a href="http://www.iotsharing.com/2021/01/building-smart-home-system-with-home.html" target="_blank">Demo 51: Building a Smart Home system with Home Assistant using Raspberry Pi and ESP32/ESP8266 (A to Y)</a></div><div dir="ltr" trbidi="on"><br /></div><div dir="ltr" trbidi="on">Today I will show you how to make Computer vision applications using ESP32 CAM. As you knew ESP32 is a strong MCU but it is not strong enough to run a computer vision algorithm directly although Google has published a Tensorflow (Tensorflow CAPI or tensorflow.js) version for ESP32 (refer Demo 47 and Demo 50 above)</div><div dir="ltr" trbidi="on">There is another way to overcome this. That is using ESP32 as a Camera and streaming video (Demo 48 and Demo 49) to a server for processing and returning the result back to clients. The server can be Cloud or local server. This is a DIY project so I will use local server for demo.</div><div dir="ltr" trbidi="on">The libraries are needed for this demo:</div><div dir="ltr" trbidi="on">- Python3 (aiohttp) : HTTP server for Python</div><div dir="ltr" trbidi="on">- Python3 Opencv : famous computer vision library</div><div dir="ltr" trbidi="on">Install the necessary libraries for Python3 (you need to install python3 and pip3 - standard packages manager for Python3):</div><div dir="ltr" trbidi="on"><div dir="ltr" trbidi="on"><b><i>pip3 install --user aiohttp</i></b></div><div dir="ltr" trbidi="on"><b><i>pip3 install --user numpy</i></b></div><div dir="ltr" trbidi="on"><b><i>pip3 install --user cv2</i></b></div><div dir="ltr" trbidi="on"><b><i>pip3 install --user jinja2</i></b></div><div dir="ltr" trbidi="on"><b><i>pip3 install --user aiohttp_jinja2</i></b></div><div dir="ltr" trbidi="on"><b><i>pip3 install --user os</i></b></div><div dir="ltr" trbidi="on"><b><i>pip3 install --user asyncio</i></b></div><div dir="ltr" trbidi="on"><b><i>pip3 install --user base64</i></b></div><div dir="ltr" trbidi="on">The Diagram of the Demo:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-yqeOCQJY1xg/YSIDk16tIrI/AAAAAAAAP5g/F_n5ISHEzeoUdZd3Tiv6PYTH1MGBojAuQCLcBGAsYHQ/s618/cam1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="380" data-original-width="618" height="246" src="https://1.bp.blogspot.com/-yqeOCQJY1xg/YSIDk16tIrI/AAAAAAAAP5g/F_n5ISHEzeoUdZd3Tiv6PYTH1MGBojAuQCLcBGAsYHQ/w400-h246/cam1.png" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-O01w7FwGm2Q/YSIEGinWdKI/AAAAAAAAP5o/vix2s98MotYKIoKNHrajHIZnKwzOx2lkwCLcBGAsYHQ/s434/cam2.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="324" data-original-width="434" height="239" src="https://1.bp.blogspot.com/-O01w7FwGm2Q/YSIEGinWdKI/AAAAAAAAP5o/vix2s98MotYKIoKNHrajHIZnKwzOx2lkwCLcBGAsYHQ/s320/cam2.PNG" width="320" /></a></div><br /><div dir="ltr" trbidi="on">In the figure, the ESP32 Camera continues streaming data to local server via Websocket.</div><div dir="ltr" trbidi="on">The local server applies computer vision to streaming data and returns the result to Web browser via Websocket.</div><div dir="ltr" trbidi="on"><b>2 Hardware</b></div><div dir="ltr" trbidi="on">A ESP32-Camera module</div><div dir="ltr" trbidi="on">A USB to Serial for flashing firmware for ESP32-Cam</div><div dir="ltr" trbidi="on"><b>3. Software</b></div><div dir="ltr" trbidi="on">The ESP32 Arduino needs the Websocket Client library to communicate with local server.</div><div dir="ltr" trbidi="on">This library needs the newest ESP32-Arduino to operate.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-C-E86fh4h60/YSIE3ys0k_I/AAAAAAAAP5w/CNQd3a4mYIcHmrjfhZSvRdXfusI8D2CHACLcBGAsYHQ/s1197/soc1.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="685" data-original-width="1197" height="229" src="https://1.bp.blogspot.com/-C-E86fh4h60/YSIE3ys0k_I/AAAAAAAAP5w/CNQd3a4mYIcHmrjfhZSvRdXfusI8D2CHACLcBGAsYHQ/w400-h229/soc1.PNG" width="400" /></a></div><div dir="ltr" trbidi="on">The ESP32-Camera code:</div></div>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #557799;">#include <Arduino.h></span>
<span style="color: #557799;">#include <WiFi.h></span>
<span style="color: #557799;">#include <WebSocketsClient.h></span>
<span style="color: #557799;">#include "esp_camera.h"</span>
<span style="color: #557799;">#define PWDN_GPIO_NUM 32</span>
<span style="color: #557799;">#define RESET_GPIO_NUM -1</span>
<span style="color: #557799;">#define XCLK_GPIO_NUM 0</span>
<span style="color: #557799;">#define SIOD_GPIO_NUM 26</span>
<span style="color: #557799;">#define SIOC_GPIO_NUM 27</span>
<span style="color: #557799;">#define Y9_GPIO_NUM 35</span>
<span style="color: #557799;">#define Y8_GPIO_NUM 34</span>
<span style="color: #557799;">#define Y7_GPIO_NUM 39</span>
<span style="color: #557799;">#define Y6_GPIO_NUM 36</span>
<span style="color: #557799;">#define Y5_GPIO_NUM 21</span>
<span style="color: #557799;">#define Y4_GPIO_NUM 19</span>
<span style="color: #557799;">#define Y3_GPIO_NUM 18</span>
<span style="color: #557799;">#define Y2_GPIO_NUM 5</span>
<span style="color: #557799;">#define VSYNC_GPIO_NUM 25</span>
<span style="color: #557799;">#define HREF_GPIO_NUM 23</span>
<span style="color: #557799;">#define PCLK_GPIO_NUM 22</span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">configCamera</span>(){
<span style="color: #333399; font-weight: bold;">camera_config_t</span> config;
config.ledc_channel <span style="color: #333333;">=</span> LEDC_CHANNEL_0;
config.ledc_timer <span style="color: #333333;">=</span> LEDC_TIMER_0;
config.pin_d0 <span style="color: #333333;">=</span> Y2_GPIO_NUM;
config.pin_d1 <span style="color: #333333;">=</span> Y3_GPIO_NUM;
config.pin_d2 <span style="color: #333333;">=</span> Y4_GPIO_NUM;
config.pin_d3 <span style="color: #333333;">=</span> Y5_GPIO_NUM;
config.pin_d4 <span style="color: #333333;">=</span> Y6_GPIO_NUM;
config.pin_d5 <span style="color: #333333;">=</span> Y7_GPIO_NUM;
config.pin_d6 <span style="color: #333333;">=</span> Y8_GPIO_NUM;
config.pin_d7 <span style="color: #333333;">=</span> Y9_GPIO_NUM;
config.pin_xclk <span style="color: #333333;">=</span> XCLK_GPIO_NUM;
config.pin_pclk <span style="color: #333333;">=</span> PCLK_GPIO_NUM;
config.pin_vsync <span style="color: #333333;">=</span> VSYNC_GPIO_NUM;
config.pin_href <span style="color: #333333;">=</span> HREF_GPIO_NUM;
config.pin_sscb_sda <span style="color: #333333;">=</span> SIOD_GPIO_NUM;
config.pin_sscb_scl <span style="color: #333333;">=</span> SIOC_GPIO_NUM;
config.pin_pwdn <span style="color: #333333;">=</span> PWDN_GPIO_NUM;
config.pin_reset <span style="color: #333333;">=</span> RESET_GPIO_NUM;
config.xclk_freq_hz <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">20000000</span>;
config.pixel_format <span style="color: #333333;">=</span> PIXFORMAT_JPEG;
config.frame_size <span style="color: #333333;">=</span> FRAMESIZE_QVGA;
config.jpeg_quality <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">9</span>;
config.fb_count <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #333399; font-weight: bold;">esp_err_t</span> err <span style="color: #333333;">=</span> esp_camera_init(<span style="color: #333333;">&</span>config);
<span style="color: #008800; font-weight: bold;">if</span> (err <span style="color: #333333;">!=</span> ESP_OK) {
Serial.printf(<span style="background-color: #fff0f0;">"Camera init failed with error 0x%x"</span>, err);
<span style="color: #008800; font-weight: bold;">return</span>;
}
}
WebSocketsClient webSocket;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>ssid <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"xyz"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>password <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"xyz"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>serverIp <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"192.168.1.8"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>camId <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"living room"</span>;
<span style="color: #333399; font-weight: bold;">bool</span> connected <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">webSocketEvent</span>(WStype_t type, <span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span> payload, <span style="color: #333399; font-weight: bold;">size_t</span> length) {
<span style="color: #008800; font-weight: bold;">switch</span>(type) {
<span style="color: #008800; font-weight: bold;">case</span> WStype_DISCONNECTED:
Serial.printf(<span style="background-color: #fff0f0;">"Disconnected!</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
connected <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">case</span> WStype_CONNECTED: {
Serial.printf(<span style="background-color: #fff0f0;">"[WSc] Connected to url: %s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, payload);
connected <span style="color: #333333;">=</span> <span style="color: #007020;">true</span>;
}
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">case</span> WStype_TEXT:
Serial.printf(<span style="background-color: #fff0f0;">"RESPONSE: %s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, payload);
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">case</span> WStype_BIN:
<span style="color: #008800; font-weight: bold;">case</span> WStype_PING:
<span style="color: #008800; font-weight: bold;">case</span> WStype_PONG:
<span style="color: #008800; font-weight: bold;">case</span> WStype_ERROR:
<span style="color: #008800; font-weight: bold;">case</span> WStype_FRAGMENT_TEXT_START:
<span style="color: #008800; font-weight: bold;">case</span> WStype_FRAGMENT_BIN_START:
<span style="color: #008800; font-weight: bold;">case</span> WStype_FRAGMENT:
<span style="color: #008800; font-weight: bold;">case</span> WStype_FRAGMENT_FIN:
<span style="color: #008800; font-weight: bold;">break</span>;
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">liveCam</span>(){
<span style="color: #888888;">//capture a frame</span>
<span style="color: #333399; font-weight: bold;">camera_fb_t</span> <span style="color: #333333;">*</span> fb <span style="color: #333333;">=</span> esp_camera_fb_get();
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>fb) {
Serial.println(<span style="background-color: #fff0f0;">"Frame buffer could not be acquired"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #888888;">//send to server</span>
String start <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"start:"</span> <span style="color: #333333;">+</span> String(camId);
webSocket.sendTXT(start);
webSocket.sendBIN(fb<span style="color: #333333;">-></span>buf, fb<span style="color: #333333;">-></span>len);
webSocket.sendTXT(<span style="background-color: #fff0f0;">"end"</span>);
<span style="color: #888888;">//return the frame buffer back to be reused</span>
esp_camera_fb_return(fb);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
WiFi.begin(ssid, password);
<span style="color: #008800; font-weight: bold;">while</span> ( WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED ) {
delay ( <span style="color: #0000dd; font-weight: bold;">500</span> );
Serial.print ( <span style="background-color: #fff0f0;">"."</span> );
}
Serial.print(<span style="background-color: #fff0f0;">"Local IP: "</span>); Serial.println(WiFi.localIP());
<span style="color: #888888;">// server address, port and URL</span>
webSocket.begin(serverIp, <span style="color: #0000dd; font-weight: bold;">8080</span>, <span style="background-color: #fff0f0;">"/ws"</span>);
<span style="color: #888888;">// event handler</span>
webSocket.onEvent(webSocketEvent);
<span style="color: #888888;">//config Camera</span>
configCamera();
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
webSocket.loop();
<span style="color: #008800; font-weight: bold;">if</span> (connected){
liveCam();
delay(<span style="color: #0000dd; font-weight: bold;">100</span>);
}
}
</pre></div>
The server is to start a http server that listening 2 websockets and a HTTP sources. The first websocket will listen the ESP32-Camera Websocket client for streaming Camera data. The HTTP will serve the GUI. The second websocket will listen the GUI websocket to return the processed result.<div>The "cv2_processing" function uses opencv haarcascade to detect faces and eyes. And draws the circles on detected faces and eyes.</div><div>The ".xml" files can be downloaded here:</div><div><a href="https://github.com/opencv/opencv/tree/master/data/haarcascades">https://github.com/opencv/opencv/tree/master/data/haarcascades</a></div><div><br /><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">from</span> <span style="color: #0e84b5; font-weight: bold;">aiohttp</span> <span style="color: #008800; font-weight: bold;">import</span> web
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">aiohttp</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">threading</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">queue</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">numpy</span> <span style="color: #008800; font-weight: bold;">as</span> <span style="color: #0e84b5; font-weight: bold;">np</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">cv2</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">jinja2</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">aiohttp_jinja2</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">os</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">asyncio</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">base64</span>
cams_queue <span style="color: #333333;">=</span> queue<span style="color: #333333;">.</span>Queue(maxsize<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">10</span>)
monitor_queue <span style="color: #333333;">=</span> []
face_cascade <span style="color: #333333;">=</span> cv2<span style="color: #333333;">.</span>CascadeClassifier(<span style="background-color: #fff0f0;">'haarcascade_frontalface_default.xml'</span>)
eyes_cascade <span style="color: #333333;">=</span> cv2<span style="color: #333333;">.</span>CascadeClassifier(<span style="background-color: #fff0f0;">'haarcascade_eye_tree_eyeglasses.xml'</span>)
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">cv2_processing</span>(frame):
<span style="color: #008800; font-weight: bold;">try</span>:
frame_gray <span style="color: #333333;">=</span> cv2<span style="color: #333333;">.</span>cvtColor(frame, cv2<span style="color: #333333;">.</span>COLOR_BGR2GRAY)
frame_gray <span style="color: #333333;">=</span> cv2<span style="color: #333333;">.</span>equalizeHist(frame_gray)
<span style="color: #888888;">#-- Detect faces</span>
faces <span style="color: #333333;">=</span> face_cascade<span style="color: #333333;">.</span>detectMultiScale(frame_gray)
<span style="color: #008800; font-weight: bold;">for</span> (x,y,w,h) <span style="color: black; font-weight: bold;">in</span> faces:
center <span style="color: #333333;">=</span> (x <span style="color: #333333;">+</span> w<span style="color: #333333;">//</span><span style="color: #0000dd; font-weight: bold;">2</span>, y <span style="color: #333333;">+</span> h<span style="color: #333333;">//</span><span style="color: #0000dd; font-weight: bold;">2</span>)
frame <span style="color: #333333;">=</span> cv2<span style="color: #333333;">.</span>ellipse(frame, center, (w<span style="color: #333333;">//</span><span style="color: #0000dd; font-weight: bold;">2</span>, h<span style="color: #333333;">//</span><span style="color: #0000dd; font-weight: bold;">2</span>), <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">360</span>, (<span style="color: #0000dd; font-weight: bold;">255</span>, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">255</span>), <span style="color: #0000dd; font-weight: bold;">4</span>)
faceROI <span style="color: #333333;">=</span> frame_gray[y:y<span style="color: #333333;">+</span>h,x:x<span style="color: #333333;">+</span>w]
<span style="color: #888888;">#-- In each face, detect eyes</span>
eyes <span style="color: #333333;">=</span> eyes_cascade<span style="color: #333333;">.</span>detectMultiScale(faceROI)
<span style="color: #008800; font-weight: bold;">for</span> (x2,y2,w2,h2) <span style="color: black; font-weight: bold;">in</span> eyes:
eye_center <span style="color: #333333;">=</span> (x <span style="color: #333333;">+</span> x2 <span style="color: #333333;">+</span> w2<span style="color: #333333;">//</span><span style="color: #0000dd; font-weight: bold;">2</span>, y <span style="color: #333333;">+</span> y2 <span style="color: #333333;">+</span> h2<span style="color: #333333;">//</span><span style="color: #0000dd; font-weight: bold;">2</span>)
radius <span style="color: #333333;">=</span> <span style="color: #007020;">int</span>(<span style="color: #007020;">round</span>((w2 <span style="color: #333333;">+</span> h2)<span style="color: #333333;">*</span><span style="color: #6600ee; font-weight: bold;">0.25</span>))
frame <span style="color: #333333;">=</span> cv2<span style="color: #333333;">.</span>circle(frame, eye_center, radius, (<span style="color: #0000dd; font-weight: bold;">255</span>, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">0</span> ), <span style="color: #0000dd; font-weight: bold;">4</span>)
<span style="color: #008800; font-weight: bold;">except</span>:
<span style="color: #008800; font-weight: bold;">pass</span>
<span style="color: #008800; font-weight: bold;">return</span> frame
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">handle_cams</span>(cams_queue, monitor_queue):
loop <span style="color: #333333;">=</span> asyncio<span style="color: #333333;">.</span>new_event_loop()
mons <span style="color: #333333;">=</span> []
<span style="color: #008800; font-weight: bold;">while</span> <span style="color: #007020;">True</span>:
<span style="color: #008800; font-weight: bold;">if</span> <span style="color: black; font-weight: bold;">not</span> cams_queue<span style="color: #333333;">.</span>empty():
cam <span style="color: #333333;">=</span> cams_queue<span style="color: #333333;">.</span>get()
cam_id <span style="color: #333333;">=</span> cam[<span style="color: #0000dd; font-weight: bold;">0</span>]
image_bytes <span style="color: #333333;">=</span> np<span style="color: #333333;">.</span>array(cam[<span style="color: #0000dd; font-weight: bold;">1</span>])<span style="color: #333333;">.</span>tobytes()
image_bytes <span style="color: #333333;">=</span> np<span style="color: #333333;">.</span>frombuffer(image_bytes, dtype<span style="color: #333333;">=</span>np<span style="color: #333333;">.</span>uint8)
img <span style="color: #333333;">=</span> cv2<span style="color: #333333;">.</span>imdecode(image_bytes, flags<span style="color: #333333;">=</span>cv2<span style="color: #333333;">.</span>IMREAD_COLOR)
img <span style="color: #333333;">=</span> cv2_processing(img)
retval, <span style="color: #007020;">buffer</span> <span style="color: #333333;">=</span> cv2<span style="color: #333333;">.</span>imencode(<span style="background-color: #fff0f0;">'.jpg'</span>, img)
jpg_as_text <span style="color: #333333;">=</span> base64<span style="color: #333333;">.</span>b64encode(<span style="color: #007020;">buffer</span>)<span style="color: #333333;">.</span>decode(<span style="background-color: #fff0f0;">"utf-8"</span>)
<span style="color: #008800; font-weight: bold;">for</span> ws <span style="color: black; font-weight: bold;">in</span> monitor_queue:
<span style="color: #008800; font-weight: bold;">try</span>:
loop<span style="color: #333333;">.</span>run_until_complete(ws<span style="color: #333333;">.</span>send_str(jpg_as_text))
<span style="color: #008800; font-weight: bold;">except</span>:
<span style="color: #008800; font-weight: bold;">print</span>(<span style="background-color: #fff0f0;">'websocket closed'</span>)
async <span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">websocket_cam_handler</span>(request):
ws <span style="color: #333333;">=</span> web<span style="color: #333333;">.</span>WebSocketResponse()
await ws<span style="color: #333333;">.</span>prepare(request)
data <span style="color: #333333;">=</span> []
cam_id <span style="color: #333333;">=</span> <span style="color: #007020;">None</span>
async <span style="color: #008800; font-weight: bold;">for</span> msg <span style="color: black; font-weight: bold;">in</span> ws:
<span style="color: #008800; font-weight: bold;">if</span> msg<span style="color: #333333;">.</span>type <span style="color: #333333;">==</span> aiohttp<span style="color: #333333;">.</span>WSMsgType<span style="color: #333333;">.</span>TEXT:
<span style="color: #008800; font-weight: bold;">if</span> msg<span style="color: #333333;">.</span>data<span style="color: #333333;">.</span>startswith(<span style="background-color: #fff0f0;">'start'</span>):
cam_id <span style="color: #333333;">=</span> msg<span style="color: #333333;">.</span>data<span style="color: #333333;">.</span>replace(<span style="background-color: #fff0f0;">'start:'</span>, <span style="background-color: #fff0f0;">''</span>)
data <span style="color: #333333;">=</span> []
<span style="color: #008800; font-weight: bold;">elif</span> msg<span style="color: #333333;">.</span>data <span style="color: #333333;">==</span> <span style="background-color: #fff0f0;">'end'</span>:
cams_queue<span style="color: #333333;">.</span>put([cam_id, data])
<span style="color: #008800; font-weight: bold;">elif</span> msg<span style="color: #333333;">.</span>type <span style="color: #333333;">==</span> aiohttp<span style="color: #333333;">.</span>WSMsgType<span style="color: #333333;">.</span>BINARY:
data<span style="color: #333333;">.</span>append(msg<span style="color: #333333;">.</span>data)
<span style="color: #008800; font-weight: bold;">elif</span> msg<span style="color: #333333;">.</span>type <span style="color: #333333;">==</span> aiohttp<span style="color: #333333;">.</span>WSMsgType<span style="color: #333333;">.</span>ERROR:
await ws<span style="color: #333333;">.</span>close()
<span style="color: #008800; font-weight: bold;">print</span>(ws<span style="color: #333333;">.</span>exception())
<span style="color: #008800; font-weight: bold;">return</span> ws
async <span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">monitor_cam_handler</span>(request):
ws <span style="color: #333333;">=</span> web<span style="color: #333333;">.</span>WebSocketResponse()
await ws<span style="color: #333333;">.</span>prepare(request)
monitor_queue<span style="color: #333333;">.</span>append(ws)
async <span style="color: #008800; font-weight: bold;">for</span> msg <span style="color: black; font-weight: bold;">in</span> ws:
<span style="color: #008800; font-weight: bold;">if</span> msg<span style="color: #333333;">.</span>type <span style="color: #333333;">==</span> aiohttp<span style="color: #333333;">.</span>WSMsgType<span style="color: #333333;">.</span>TEXT:
<span style="color: #008800; font-weight: bold;">if</span> msg<span style="color: #333333;">.</span>data <span style="color: #333333;">==</span> <span style="background-color: #fff0f0;">'close'</span>:
await ws<span style="color: #333333;">.</span>close()
<span style="color: #008800; font-weight: bold;">elif</span> msg<span style="color: #333333;">.</span>type <span style="color: #333333;">==</span> aiohttp<span style="color: #333333;">.</span>WSMsgType<span style="color: #333333;">.</span>ERROR:
await ws<span style="color: #333333;">.</span>close()
<span style="color: #008800; font-weight: bold;">print</span>(ws<span style="color: #333333;">.</span>exception())
<span style="color: #008800; font-weight: bold;">return</span> ws
<span style="color: #555555; font-weight: bold;">@aiohttp_jinja2.template</span>(<span style="background-color: #fff0f0;">"index.html"</span>)
async <span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">index</span>(request):
<span style="color: #008800; font-weight: bold;">return</span> {}
<span style="color: #008800; font-weight: bold;">if</span> __name__ <span style="color: #333333;">==</span> <span style="background-color: #fff0f0;">'__main__'</span>:
p <span style="color: #333333;">=</span> threading<span style="color: #333333;">.</span>Thread(target<span style="color: #333333;">=</span>handle_cams, args<span style="color: #333333;">=</span>((cams_queue, monitor_queue)))
p<span style="color: #333333;">.</span>start()
app <span style="color: #333333;">=</span> web<span style="color: #333333;">.</span>Application()
aiohttp_jinja2<span style="color: #333333;">.</span>setup(
app, loader<span style="color: #333333;">=</span>jinja2<span style="color: #333333;">.</span>FileSystemLoader(os<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>join(os<span style="color: #333333;">.</span>getcwd(), <span style="background-color: #fff0f0;">"templates"</span>))
)
app<span style="color: #333333;">.</span>router<span style="color: #333333;">.</span>add_get(<span style="background-color: #fff0f0;">'/'</span>, index, name<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">"index"</span>)
app<span style="color: #333333;">.</span>router<span style="color: #333333;">.</span>add_get(<span style="background-color: #fff0f0;">'/ws'</span>, websocket_cam_handler)
app<span style="color: #333333;">.</span>router<span style="color: #333333;">.</span>add_get(<span style="background-color: #fff0f0;">'/monitor'</span>, monitor_cam_handler)
web<span style="color: #333333;">.</span>run_app(app)
</pre></div>
</div><div>The GUI for Web browser is in HTML</div>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #007700;"><html></span>
<span style="color: #007700;"><head></span>
<span style="color: #007700;"><title></span> ESP32 Camera Computer Vision <span style="color: #007700;"></title></span>
<span style="color: #007700;"><script </span><span style="color: #0000cc;">src=</span><span style="background-color: #fff0f0;">'http://code.jquery.com/jquery-1.9.1.min.js'</span><span style="color: #007700;">></script></span>
<span style="color: #007700;"></head></span>
<span style="color: #007700;"><body></span>
<span style="color: #007700;"><img</span> <span style="color: #0000cc;">id=</span><span style="background-color: #fff0f0;">'live'</span> <span style="color: #0000cc;">src=</span><span style="background-color: #fff0f0;">''</span><span style="color: #007700;">></span>
<span style="color: #007700;"></body></span>
<span style="color: #007700;"></html></span>
<span style="color: #007700;"><script></span>
jQuery(<span style="color: #008800; font-weight: bold;">function</span>($){
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>(<span style="background-color: #fff0f0;">'WebSocket'</span> <span style="color: #008800; font-weight: bold;">in</span> <span style="color: #007020;">window</span>)) {
alert(<span style="background-color: #fff0f0;">'Your browser does not support web sockets'</span>);
}<span style="color: #008800; font-weight: bold;">else</span>{
setup()
}
<span style="color: #008800; font-weight: bold;">function</span> setup(){
<span style="color: #008800; font-weight: bold;">var</span> host <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'ws://192.168.1.8:8080/monitor'</span>;
<span style="color: #008800; font-weight: bold;">var</span> socket <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> WebSocket(host);
socket.binaryType <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'arraybuffer'</span>;
<span style="color: #008800; font-weight: bold;">if</span>(socket){
socket.onopen <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>() {
}
socket.onmessage <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(msg){
<span style="color: #008800; font-weight: bold;">var</span> bytes <span style="color: #333333;">=</span> msg.data;
<span style="color: #008800; font-weight: bold;">var</span> img <span style="color: #333333;">=</span> <span style="color: #007020;">document</span>.getElementById(<span style="background-color: #fff0f0;">'live'</span>);
img.src <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'data:image/jpg;base64,'</span><span style="color: #333333;">+</span>bytes;
}
socket.onclose <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(){
showServerResponse(<span style="background-color: #fff0f0;">'The connection has been closed.'</span>);
}
}
}
});
<span style="color: #007700;"></script></span>
</pre></div>
<b>4. Result</b><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/LUJ1a7ENuf8" width="320" youtube-src-id="LUJ1a7ENuf8"></iframe></div><br /><div><br /></div>Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com1tag:blogger.com,1999:blog-7549705215513488945.post-42846833776629080652021-01-12T06:56:00.498-08:002021-11-05T22:34:11.081-07:00Demo 51: Building a Smart Home system with Home Assistant using Raspberry Pi and ESP32/ESP8266 (A to Y)<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
Today I will show you how to build a Smart Home with Home Assistant (HA) using Raspberry Pi and ESP32/ESP8266.<br />
Home Assistant will act as a server with GUI and ESP32/ESP8266 as clients. User will access Home Assistant by web browser with url: <a href="http://homeassistant.local:8123">http://homeassistant.local:8123</a> or <a href="http://ip_address:8123/">http://IP_address:8123</a></div><div dir="ltr" style="text-align: left;" trbidi="on">This tutorial has the steps:</div><div dir="ltr" style="text-align: left;" trbidi="on">- Install Home Assistant on Raspberry Pi</div><div dir="ltr" style="text-align: left;" trbidi="on">- Setup Ethernet, Wifi </div><div dir="ltr" style="text-align: left;" trbidi="on">- Install necessary software Mosquitto MQTT broker, InfluxDB, File Editor, ...</div><div dir="ltr" style="text-align: left;" trbidi="on">- Read data from sensor on ESP (temperature, humidity, ...)</div><div dir="ltr" style="text-align: left;" trbidi="on">- Send data to actuator on ESP (control bulb, ...)</div><div dir="ltr" style="text-align: left;" trbidi="on">- Use InfluxDB to store data</div><div dir="ltr" style="text-align: left;" trbidi="on">- Auto-detection ESP device from Home Assistant</div><div dir="ltr" style="text-align: left;" trbidi="on">- Automation script (control the ESP by context/scenario) from Home Assistant </div><div dir="ltr" style="text-align: left;" trbidi="on">- Grafana platform for beautiful analytics and monitoring</div><div dir="ltr" style="text-align: left;" trbidi="on">- Monitor ESP camera</div><div dir="ltr" style="text-align: left;" trbidi="on"><b>2. Actions</b></div><div dir="ltr" style="text-align: left;" trbidi="on"><b>2.1 Install Home Assistant on Raspberry Pi</b></div><div dir="ltr" style="text-align: left;" trbidi="on">- Go to: https://www.home-assistant.io/getting-started/ and download the image according to your Raspberry Pi</div><div dir="ltr" style="text-align: left;" trbidi="on">- Write the downloaded image to SD card by <a href="https://www.balena.io/etcher" rel="external nofollow">balenaEtcher</a> or Startup Disk Creator on Ubuntu.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-egHBngMWioI/X_R8Nyb1QJI/AAAAAAAAOuE/TXLIzkLCwfUlRJQ1Ra15wSJj0DP8-iU_gCLcBGAsYHQ/s601/ha1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="424" data-original-width="601" height="283" src="https://1.bp.blogspot.com/-egHBngMWioI/X_R8Nyb1QJI/AAAAAAAAOuE/TXLIzkLCwfUlRJQ1Ra15wSJj0DP8-iU_gCLcBGAsYHQ/w400-h283/ha1.png" width="400" /></a></div><p style="text-align: center;"><b>Figure: Startup Disk Creator </b></p><p>- Waiting until the image is written to SD card.</p><p>- Plug the SD card to Raspberry Pi.</p><p>- Power up the Raspberry Pi and connect it to your LAN network by network cable.<br /></p><p><b>2.2 Setup Ethernet, Wifi</b></p><p>If you only have Wifi and have no Wired connection hole, you can configure your laptop as a bridge (like hotspot) like below:</p><p style="text-align: center;"><b>Pi -> network cable -> laptop -> Wifi</b></p><p style="text-align: justify;"><b></b></p><div class="separator" style="clear: both; text-align: center;"><b><a href="https://1.bp.blogspot.com/-crr7kj9rPuo/X_SAWbn8pTI/AAAAAAAAOuQ/cFwElTb1dUcyNgpSX356SqcuoIYyv7-BwCLcBGAsYHQ/s855/ha2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="496" data-original-width="855" height="233" src="https://1.bp.blogspot.com/-crr7kj9rPuo/X_SAWbn8pTI/AAAAAAAAOuQ/cFwElTb1dUcyNgpSX356SqcuoIYyv7-BwCLcBGAsYHQ/w400-h233/ha2.png" width="400" /></a></b></div><p></p><div style="text-align: center;" trbidi="on"><b>Figure: laptop as a bridge</b></div><div style="text-align: center;" trbidi="on"><b><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-1Z3p7FkhkqM/X_SBJqZVZKI/AAAAAAAAOuY/XqFEOAzH4rYlBDwhB-S4nURJ6b_HoCCKgCLcBGAsYHQ/s623/ha3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="157" data-original-width="623" height="101" src="https://1.bp.blogspot.com/-1Z3p7FkhkqM/X_SBJqZVZKI/AAAAAAAAOuY/XqFEOAzH4rYlBDwhB-S4nURJ6b_HoCCKgCLcBGAsYHQ/w400-h101/ha3.png" width="400" /></a></div>Figure: ifconfig to see the IP of wired connection is up</b></div><div style="text-align: justify;" trbidi="on">- Open Terminal and type command below to scan the IP address of Raspberry Pi Home Assistant:</div><div style="text-align: center;" trbidi="on"><i>nmap -sn 10.42.0.1/24</i><br /></div><div style="text-align: justify;" trbidi="on"><b> <div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBwTaFSZUXsBuZGX8aSTT-pr6ZgacJh3N3eo-hDPgWDiAwduCfT4djSaqtbKwUpPOgW4Dg3URmh5bQu_L2QLvNzWAo-E5nwi8XbXWXoPBtiHiFadnhT8I95tCbkAWqGUkR-Kc66emw7s8/s586/ha4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="103" data-original-width="586" height="70" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBwTaFSZUXsBuZGX8aSTT-pr6ZgacJh3N3eo-hDPgWDiAwduCfT4djSaqtbKwUpPOgW4Dg3URmh5bQu_L2QLvNzWAo-E5nwi8XbXWXoPBtiHiFadnhT8I95tCbkAWqGUkR-Kc66emw7s8/w400-h70/ha4.png" width="400" /></a></div></b>- Open the Web Browser and type command: http://10.42.0.137:8123/</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-gDE88v-pRC4/X_W9dHCrA9I/AAAAAAAAOuw/VumMB0-G2bMRwi9whDxzfddg7iAnszPrgCLcBGAsYHQ/s520/ha5.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="517" data-original-width="520" height="398" src="https://1.bp.blogspot.com/-gDE88v-pRC4/X_W9dHCrA9I/AAAAAAAAOuw/VumMB0-G2bMRwi9whDxzfddg7iAnszPrgCLcBGAsYHQ/w400-h398/ha5.png" width="400" /></a></div><p>- For the first time, Home Assistant takes quite long time to startup (about ~15-20 minutes). </p><p>- Create account</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmH1G03-N3diYq4uIN91fP4DTrsgY47K4U3BOEMI5NybFpW11ExylX-hA8C7H83AWVOPhqolmtFDdfDeamuLYj83OO2WJSOGahtHXwCRT0GNXzRI4nT3mmpe2dqtIgidfy-Boc1BHv-ZQ/s555/ha6.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="555" data-original-width="466" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmH1G03-N3diYq4uIN91fP4DTrsgY47K4U3BOEMI5NybFpW11ExylX-hA8C7H83AWVOPhqolmtFDdfDeamuLYj83OO2WJSOGahtHXwCRT0GNXzRI4nT3mmpe2dqtIgidfy-Boc1BHv-ZQ/w336-h400/ha6.png" width="336" /></a></div>- Choose Next and Finish<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-uhHpknFINu4/X_XeUpWDFCI/AAAAAAAAOvY/dNcNW3PQOvU598SUnq9oMljJuqH515KxQCLcBGAsYHQ/s1202/ha7.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="686" data-original-width="1202" height="366" src="https://1.bp.blogspot.com/-uhHpknFINu4/X_XeUpWDFCI/AAAAAAAAOvY/dNcNW3PQOvU598SUnq9oMljJuqH515KxQCLcBGAsYHQ/w640-h366/ha7.png" width="640" /></a></div><p><b>Setup Wifi</b></p><p>From left Menu choose <b>Supervisor > IP Address Change > WLAN0 > IPv4 > DHCP > Wi-Fi > SCAN FOR ACCESSPOINTS > wpa-psk > Password > Save > REBOOT<br /></b></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRJIs9rs2vi_sDd-xEtQcrjRfRNQVx-E_4Hx5c4DywBQaWu9tdovXIJG8peBZ_7KP_lLL-HUuxQr45TL8NsWCGhmZp_H0qeNFSi_RXOBH4iOm8thR9MyQJIQ2C5KkWnqphPlQkw-RaIBM/s1192/ha12.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="690" data-original-width="1192" height="370" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRJIs9rs2vi_sDd-xEtQcrjRfRNQVx-E_4Hx5c4DywBQaWu9tdovXIJG8peBZ_7KP_lLL-HUuxQr45TL8NsWCGhmZp_H0qeNFSi_RXOBH4iOm8thR9MyQJIQ2C5KkWnqphPlQkw-RaIBM/w640-h370/ha12.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-TSJd4NbWwC8/X_nQxykaQNI/AAAAAAAAOwk/CnB8vw9FlpwJoNRa1NHRZljN-J1tGb0bgCLcBGAsYHQ/s1203/ha15.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="699" data-original-width="1203" height="372" src="https://1.bp.blogspot.com/-TSJd4NbWwC8/X_nQxykaQNI/AAAAAAAAOwk/CnB8vw9FlpwJoNRa1NHRZljN-J1tGb0bgCLcBGAsYHQ/w640-h372/ha15.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHJG2ud3auDplTljjbSUAbWZQvxypkj2DPmrE4Lh5iZcHiDEg35mX5i8UnbmtT8j9szJI1AHn6feqIOBdZnfpO3xkYUFXryh4l0SctSHz7yEoFOeuYb-4PQp5he5mFvSEyuVQaOojKMCU/s1208/ha16.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="689" data-original-width="1208" height="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHJG2ud3auDplTljjbSUAbWZQvxypkj2DPmrE4Lh5iZcHiDEg35mX5i8UnbmtT8j9szJI1AHn6feqIOBdZnfpO3xkYUFXryh4l0SctSHz7yEoFOeuYb-4PQp5he5mFvSEyuVQaOojKMCU/w640-h366/ha16.png" width="640" /></a></div><p><b>2.3 Install necessary software</b></p><p>From left Menu choose <b>Supervisor > Add-on Store</b></p><p>then press <b>Install</b> and press <b>Start</b> button:</p><p><b>Mosquitto broker</b></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEill0rLo9LUZrRsia85XmKbf2jll3Cuc0zZAUSYPp6_sWP7W01j-xBwsG-Y9roGuL5QivavNo1CjXhctN2Umq0_Jn1W3GOPd4j9gDa7nSjVY6xKlTAZ08dQo8nqpHhcTctDQynmdqRQSkY/s944/ha9.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="461" data-original-width="944" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEill0rLo9LUZrRsia85XmKbf2jll3Cuc0zZAUSYPp6_sWP7W01j-xBwsG-Y9roGuL5QivavNo1CjXhctN2Umq0_Jn1W3GOPd4j9gDa7nSjVY6xKlTAZ08dQo8nqpHhcTctDQynmdqRQSkY/w640-h312/ha9.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-sLIOt9_UReQ/X_cOwBm0IGI/AAAAAAAAOvo/e9wjK9Miq98j3CRxQyot9S8GoHxSpLzrACLcBGAsYHQ/s910/ha8.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="620" data-original-width="910" height="436" src="https://1.bp.blogspot.com/-sLIOt9_UReQ/X_cOwBm0IGI/AAAAAAAAOvo/e9wjK9Miq98j3CRxQyot9S8GoHxSpLzrACLcBGAsYHQ/w640-h436/ha8.png" width="640" /></a></div><div><b>Important: Enable HA to connect to this add-on</b></div><div><a href="https://1.bp.blogspot.com/-cCfY0hNkrHQ/X_xsnTCAvxI/AAAAAAAAOx8/amlA-ehTdXgSKBVHoXucQhwXLtQbEybCQCLcBGAsYHQ/s1920/ha21.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-cCfY0hNkrHQ/X_xsnTCAvxI/AAAAAAAAOx8/amlA-ehTdXgSKBVHoXucQhwXLtQbEybCQCLcBGAsYHQ/w640-h340/ha21.png" width="640" /></a></div><b>InfluxDB</b><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOAKVlFROBbTUekSNUa5Ql94ThJnl8dP-a77K6RaV2CZdO1_13rqgFYdbbCzzDDpiQe12HdDpJ1BisfX8vKm6J-mYTbt2goY61gfeW69f0pBsFFHYmj0f0Z_M_ZC6LY8PW1gx50gAFbcM/s936/ha10.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="351" data-original-width="936" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOAKVlFROBbTUekSNUa5Ql94ThJnl8dP-a77K6RaV2CZdO1_13rqgFYdbbCzzDDpiQe12HdDpJ1BisfX8vKm6J-mYTbt2goY61gfeW69f0pBsFFHYmj0f0Z_M_ZC6LY8PW1gx50gAFbcM/w640-h240/ha10.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-_gU7nVPlmT8/X_cRZ-DB9JI/AAAAAAAAOwA/abclbFI74AcuuX3h9NpheULs_guPXGzQACLcBGAsYHQ/s942/ha11.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="518" data-original-width="942" height="352" src="https://1.bp.blogspot.com/-_gU7nVPlmT8/X_cRZ-DB9JI/AAAAAAAAOwA/abclbFI74AcuuX3h9NpheULs_guPXGzQACLcBGAsYHQ/w640-h352/ha11.png" width="640" /></a></div><p><b>File editor</b></p><p>This application supports to modify <b>*.yaml </b>(choose <b>Show in sidebar</b> to add the add-on to the upper left Menu)</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1mQya6i_WIBAgMVVIORN-Is756y8Y9O6-MnOLk_BAC60y2SyMIxcS9ZKK9shvr70J4rMXX9U2gbgM8ehnVBHARtmvXhtj0i7JbXP6yUcu0dpwCC0zF6QNWyT2Gw2Tavhrd8ddMuO2n7w/s943/ha18.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="943" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1mQya6i_WIBAgMVVIORN-Is756y8Y9O6-MnOLk_BAC60y2SyMIxcS9ZKK9shvr70J4rMXX9U2gbgM8ehnVBHARtmvXhtj0i7JbXP6yUcu0dpwCC0zF6QNWyT2Gw2Tavhrd8ddMuO2n7w/w640-h348/ha18.png" width="640" /></a></div><p><b> </b></p><b>Install Grafana
</b><div class="addon-version light-color"><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-2w3V9KPj6gw/X_nTe_hDh4I/AAAAAAAAOw4/5sfz4p5hKWQ6XubnXltDaU7CEnUlnUvIgCLcBGAsYHQ/s942/ha17.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="517" data-original-width="942" height="352" src="https://1.bp.blogspot.com/-2w3V9KPj6gw/X_nTe_hDh4I/AAAAAAAAOw4/5sfz4p5hKWQ6XubnXltDaU7CEnUlnUvIgCLcBGAsYHQ/w640-h352/ha17.png" width="640" /></a></div><b>2.4 Read data from sensor on ESP (temperature, humidity, ...)</b></div><div class="addon-version light-color">We use MQTT to transfer data from ESP to HA. We will configure the HA to listen on the MQTT topic. We will use File Editor add-on above to modify "<b>confiuration.yaml"</b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ZWgsF5Sx4sE/X_nWmmLZQjI/AAAAAAAAOxQ/5MNnC3_QZx4J0KqvhRwdPxS1hlCbElfzACLcBGAsYHQ/s1221/ha19.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="700" data-original-width="1221" height="366" src="https://1.bp.blogspot.com/-ZWgsF5Sx4sE/X_nWmmLZQjI/AAAAAAAAOxQ/5MNnC3_QZx4J0KqvhRwdPxS1hlCbElfzACLcBGAsYHQ/w640-h366/ha19.png" width="640" /></a></div><p>choose <b>File Browser</b> (red circle)<br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-6MxgHuweK3w/X_nWmx7u_dI/AAAAAAAAOxU/cYb0IyUWcU0lBcJNTxkF_1CxDclcXHdwwCPcBGAYYCw/s1222/ha20.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="703" data-original-width="1222" height="368" src="https://1.bp.blogspot.com/-6MxgHuweK3w/X_nWmx7u_dI/AAAAAAAAOxU/cYb0IyUWcU0lBcJNTxkF_1CxDclcXHdwwCPcBGAYYCw/w640-h368/ha20.png" width="640" /></a></div>choose <b>"confiuration.yaml"</b> and add the below entry:<!--HTML generated using hilite.me--><div style="background: rgb(248, 248, 248); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">sensor:
- platform: mqtt
state_topic: 'home/room/temperature'
name: 'Room Temperature'
unit_of_measurement: '°C'
</pre></div>
The HA will subscribe the topic: <b><i>home/room/temperature</i></b><div>From File Editor choose Save button:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-UInJu6xQrMc/X_sllf8aGRI/AAAAAAAAOxk/Uvdqe2nbbCQVu_jf8P6eY7ZlaZPI2juYACLcBGAsYHQ/s1920/ha19.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-UInJu6xQrMc/X_sllf8aGRI/AAAAAAAAOxk/Uvdqe2nbbCQVu_jf8P6eY7ZlaZPI2juYACLcBGAsYHQ/w640-h340/ha19.png" width="640" /></a></div><div><br /></div><div>Restart HA service</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-mWPYWrTVsQw/X_slrFuBPcI/AAAAAAAAOxo/U0RSmiZtUL8j603IYYLsyAZxVPtO_nPywCLcBGAsYHQ/s1920/ha20.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-mWPYWrTVsQw/X_slrFuBPcI/AAAAAAAAOxo/U0RSmiZtUL8j603IYYLsyAZxVPtO_nPywCLcBGAsYHQ/w640-h340/ha20.png" width="640" /></a></div><div>Flash the Arduino code (refer <a href="http://www.iotsharing.com/2017/05/how-to-use-mqtt-to-build-smart-home-arduino-esp32.html" target="_blank">Demo 14</a>)</div><div>This code also refers <a href="http://www.iotsharing.com/2017/06/how-to-get-ip-address-from-mdns-host-name-in-arduino-esp32.html" target="_blank">this demo</a> to get the IP address of HA via hostname. You can set the the hostname of HA via <b>Supervisor > System > Host > Change </b>(default hostname is: homeassistant)</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-VJ7pXDXOaqw/YAPecHZf3HI/AAAAAAAAO18/FKLMjADSX80xgNi2ssRJiEsuatcaoFdzQCLcBGAsYHQ/s1920/ha37.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-VJ7pXDXOaqw/YAPecHZf3HI/AAAAAAAAO18/FKLMjADSX80xgNi2ssRJiEsuatcaoFdzQCLcBGAsYHQ/w640-h340/ha37.png" width="640" /></a></div><div><br /></div><div><!--HTML generated using hilite.me--><div style="background: rgb(248, 248, 248); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800;">#include <WiFi.h></span>
<span style="color: #008800;">#include <PubSubClient.h></span>
<span style="color: #008800;">#include <ESPmDNS.h></span>
<span style="color: #008800; font-style: italic;">/* change it with your ssid-password */</span>
<span style="color: #aa22ff; font-weight: bold;">const</span> <span style="color: #00bb00; font-weight: bold;">char</span><span style="color: #666666;">*</span> ssid <span style="color: #666666;">=</span> <span style="color: #bb4444;">"I3.41"</span>;
<span style="color: #aa22ff; font-weight: bold;">const</span> <span style="color: #00bb00; font-weight: bold;">char</span><span style="color: #666666;">*</span> password <span style="color: #666666;">=</span> <span style="color: #bb4444;">"xxx"</span>;
<span style="color: #008800; font-style: italic;">/* this is the IP of PC/raspberry where you installed MQTT Server */</span>
<span style="color: #aa22ff; font-weight: bold;">const</span> <span style="color: #00bb00; font-weight: bold;">char</span><span style="color: #666666;">*</span> mqtt_server <span style="color: #666666;">=</span> <span style="color: #bb4444;">"homeassistant"</span>;
<span style="color: #008800;">#define mqtt_user "iotsharing"</span>
<span style="color: #008800;">#define mqtt_password "xyz"</span>
<span style="color: #008800;">#define mqtt_clientId "iotsharing-sensor"</span>
<span style="color: #00bb00; font-weight: bold;">float</span> temperature <span style="color: #666666;">=</span> <span style="color: #666666;">0</span>;
<span style="color: #008800; font-style: italic;">/* create an instance of PubSubClient client */</span>
WiFiClient espClient;
PubSubClient <span style="color: #00a000;">client</span>(espClient);
<span style="color: #008800; font-style: italic;">/* topics */</span>
<span style="color: #008800;">#define TEMP_TOPIC "home/room/temperature"</span>
<span style="color: #00bb00; font-weight: bold;">long</span> lastMsg <span style="color: #666666;">=</span> <span style="color: #666666;">0</span>;
<span style="color: #00bb00; font-weight: bold;">char</span> msg[<span style="color: #666666;">20</span>];
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">reconnect</span>() {
<span style="color: #008800; font-style: italic;">//Loop until we're reconnected</span>
<span style="color: #aa22ff; font-weight: bold;">while</span> (<span style="color: #666666;">!</span>client.connected()) {
<span style="color: #aa22ff; font-weight: bold;">if</span> (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
Serial.println(<span style="color: #bb4444;">"connected"</span>);
delay(<span style="color: #666666;">1000</span>);
Serial.print(<span style="color: #bb4444;">"MQTT connected!"</span>);
} <span style="color: #aa22ff; font-weight: bold;">else</span> {
Serial.print(<span style="color: #bb4444;">"failed, rc="</span>);
Serial.print(client.state());
}
}
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">setup</span>() {
Serial.begin(<span style="color: #666666;">115200</span>);
<span style="color: #008800; font-style: italic;">// We start by connecting to a WiFi network</span>
Serial.println();
Serial.print(<span style="color: #bb4444;">"Connecting to "</span>);
Serial.println(ssid);
WiFi.begin(ssid, password);
<span style="color: #aa22ff; font-weight: bold;">while</span> (WiFi.status() <span style="color: #666666;">!=</span> WL_CONNECTED) {
delay(<span style="color: #666666;">500</span>);
Serial.print(<span style="color: #bb4444;">"."</span>);
}
Serial.println(<span style="color: #bb4444;">""</span>);
Serial.println(<span style="color: #bb4444;">"WiFi connected"</span>);
Serial.println(<span style="color: #bb4444;">"IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #aa22ff; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>MDNS.begin(<span style="color: #bb4444;">"esp32"</span>)) {
Serial.println(<span style="color: #bb4444;">"Error setting up MDNS responder!"</span>);
<span style="color: #aa22ff; font-weight: bold;">while</span>(<span style="color: #666666;">1</span>) {
delay(<span style="color: #666666;">1000</span>);
}
}
IPAddress serverIp <span style="color: #666666;">=</span> MDNS.queryHost(mqtt_server);
Serial.print(<span style="color: #bb4444;">"IP address of server: "</span>);
Serial.println(serverIp.toString());
<span style="color: #008800; font-style: italic;">/* configure the MQTT server with IPaddress and port */</span>
client.setServer(serverIp, <span style="color: #666666;">1883</span>);
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">loop</span>() {
<span style="color: #008800; font-style: italic;">/* if client was disconnected then try to reconnect again */</span>
<span style="color: #aa22ff; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>client.connected()) {
reconnect();
}
<span style="color: #008800; font-style: italic;">/* this function will listen for incomming </span>
<span style="color: #008800; font-style: italic;"> subscribed topic-process-invoke receivedCallback */</span>
client.loop();
<span style="color: #008800; font-style: italic;">/* we measure temperature every 3 secs</span>
<span style="color: #008800; font-style: italic;"> we count until 3 secs reached to avoid blocking program if using delay()*/</span>
<span style="color: #00bb00; font-weight: bold;">long</span> now <span style="color: #666666;">=</span> millis();
<span style="color: #aa22ff; font-weight: bold;">if</span> (now <span style="color: #666666;">-</span> lastMsg <span style="color: #666666;">></span> <span style="color: #666666;">3000</span>) {
lastMsg <span style="color: #666666;">=</span> now;
<span style="color: #008800; font-style: italic;">/* read DHT11/DHT22 sensor and convert to string */</span>
temperature <span style="color: #666666;">=</span> random(<span style="color: #666666;">20</span>,<span style="color: #666666;">40</span>)<span style="color: #666666;">/1.0</span>;
<span style="color: #aa22ff; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>isnan(temperature)) {
snprintf (msg, <span style="color: #666666;">20</span>, <span style="color: #bb4444;">"%lf"</span>, temperature);
Serial.println(msg);
<span style="color: #008800; font-style: italic;">/* publish the message */</span>
client.publish(TEMP_TOPIC, msg);
}
}
}
</pre></div>
</div><div>From the HA choose Edit Dashboard</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-jJuaUcJp98k/X_xt-gA_xhI/AAAAAAAAOyI/JZurQ6iMk4sBZsrqeyDTKWTBZVWotGqTACLcBGAsYHQ/s1920/ha22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-jJuaUcJp98k/X_xt-gA_xhI/AAAAAAAAOyI/JZurQ6iMk4sBZsrqeyDTKWTBZVWotGqTACLcBGAsYHQ/w640-h340/ha22.png" width="640" /></a></div><br /><div>Choose ADD CARD > By Entity > tick "sensor.room_temperator" > press Continue > Add to LOVELACE UI</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8Ym13_TFWyQiaSHW5r9E6NYR8UoispAza7pr6uPLXYkZp06-iNpfiNpAAR9hs2TL2ov5a808EKkYaC0uyZ3B8pkIHO32Fh2VQxQCW-h3DkrzF_3zWCwwgqwlw7FumJ5-Ilc3io6yYPI4/s1920/ha23.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8Ym13_TFWyQiaSHW5r9E6NYR8UoispAza7pr6uPLXYkZp06-iNpfiNpAAR9hs2TL2ov5a808EKkYaC0uyZ3B8pkIHO32Fh2VQxQCW-h3DkrzF_3zWCwwgqwlw7FumJ5-Ilc3io6yYPI4/w640-h340/ha23.png" width="640" /></a></div><br /><div>Or add a Gauge by choosing ADD CARD > GAUGE > choose Entity "sensor.room_temperator" > press Save</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTY5odVRFg6_89AhDd1m1BIZJbwJGkY_yhGzsq8g3zfK8rPzjCaWd0Qb3uNMRYK8nRGNwQlpdGdTOba3VJIEpA1vMZNkVnTZvmQdeYOIyLaajy_GyeOcVIeHOCn_kE4FtSQkTQo3fkKo0/s1920/ha25.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTY5odVRFg6_89AhDd1m1BIZJbwJGkY_yhGzsq8g3zfK8rPzjCaWd0Qb3uNMRYK8nRGNwQlpdGdTOba3VJIEpA1vMZNkVnTZvmQdeYOIyLaajy_GyeOcVIeHOCn_kE4FtSQkTQo3fkKo0/w640-h340/ha25.png" width="640" /></a></div><div><b>2.5 Send data to actuator on ESP (control bulb, ...)</b></div><div>Use File editor add-on to open <b>"confiuration.yaml"</b> and add the below entry:</div>
<!--HTML generated using hilite.me--><div style="background: rgb(248, 248, 248); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">switch:
- platform: mqtt
name: "Light"
state_topic: "home/room/switch/set"
command_topic: "home/room/switch/set"
payload_on: "on"
payload_off: "off"
qos: 0
</pre></div>
The HA will send the command topic: <b>"home/room/switch/set"</b> to ESP. After ESP received the command it must send the state topic back to the HA as ACK (acknowledgement) so that the HA can update its state. If you set the state topic same as command topic, you need not to resend ACK. The payload_on and payload_off are valid values of the topics. <div><div>Restart HA service</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-mWPYWrTVsQw/X_slrFuBPcI/AAAAAAAAOxo/U0RSmiZtUL8j603IYYLsyAZxVPtO_nPywCLcBGAsYHQ/s1920/ha20.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-mWPYWrTVsQw/X_slrFuBPcI/AAAAAAAAOxo/U0RSmiZtUL8j603IYYLsyAZxVPtO_nPywCLcBGAsYHQ/w640-h340/ha20.png" width="640" /></a></div><div>Flash the Arduino code (refer <a href="http://www.iotsharing.com/2017/05/how-to-use-mqtt-to-build-smart-home-arduino-esp32.html" target="_blank">Demo 14</a>)</div></div><div><!--HTML generated using hilite.me--><div style="background: rgb(248, 248, 248); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800;">#include <WiFi.h></span>
<span style="color: #008800;">#include <PubSubClient.h></span>
<span style="color: #008800;">#include <ESPmDNS.h></span>
<span style="color: #008800; font-style: italic;">/* change it with your ssid-password */</span>
<span style="color: #aa22ff; font-weight: bold;">const</span> <span style="color: #00bb00; font-weight: bold;">char</span><span style="color: #666666;">*</span> ssid <span style="color: #666666;">=</span> <span style="color: #bb4444;">"I3.41"</span>;
<span style="color: #aa22ff; font-weight: bold;">const</span> <span style="color: #00bb00; font-weight: bold;">char</span><span style="color: #666666;">*</span> password <span style="color: #666666;">=</span> <span style="color: #bb4444;">"xxx"</span>;
<span style="color: #008800; font-style: italic;">/* this is the IP of PC/raspberry where you installed MQTT Server */</span>
<span style="color: #aa22ff; font-weight: bold;">const</span> <span style="color: #00bb00; font-weight: bold;">char</span><span style="color: #666666;">*</span> mqtt_server <span style="color: #666666;">=</span> <span style="color: #bb4444;">"homeassistant"</span>;
<span style="color: #008800;">#define mqtt_user "iotsharing"</span>
<span style="color: #008800;">#define mqtt_password "xyz"</span>
<span style="color: #008800;">#define mqtt_clientId "iotsharing-sensor"</span>
<span style="color: #00bb00; font-weight: bold;">float</span> temperature <span style="color: #666666;">=</span> <span style="color: #666666;">0</span>;
<span style="color: #008800; font-style: italic;">/* create an instance of PubSubClient client */</span>
WiFiClient espClient;
PubSubClient <span style="color: #00a000;">client</span>(espClient);
<span style="color: #008800; font-style: italic;">/* topics */</span>
<span style="color: #008800;">#define CTRL_BULB_TOPIC "home/room/switch/set"</span>
<span style="color: #00bb00; font-weight: bold;">long</span> lastMsg <span style="color: #666666;">=</span> <span style="color: #666666;">0</span>;
<span style="color: #00bb00; font-weight: bold;">char</span> msg[<span style="color: #666666;">20</span>];
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">reconnect</span>() {
<span style="color: #008800; font-style: italic;">//Loop until we're reconnected</span>
<span style="color: #aa22ff; font-weight: bold;">while</span> (<span style="color: #666666;">!</span>client.connected()) {
<span style="color: #aa22ff; font-weight: bold;">if</span> (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
Serial.println(<span style="color: #bb4444;">"connected"</span>);
delay(<span style="color: #666666;">1000</span>);
Serial.print(<span style="color: #bb4444;">"MQTT connected!"</span>);
client.subscribe(CTRL_BULB_TOPIC);
} <span style="color: #aa22ff; font-weight: bold;">else</span> {
Serial.print(<span style="color: #bb4444;">"failed, rc="</span>);
Serial.print(client.state());
}
}
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">receivedCallback</span>(<span style="color: #00bb00; font-weight: bold;">char</span><span style="color: #666666;">*</span> topic, byte<span style="color: #666666;">*</span> payload, <span style="color: #00bb00; font-weight: bold;">unsigned</span> <span style="color: #00bb00; font-weight: bold;">int</span> length) {
Serial.print(<span style="color: #bb4444;">"Message received: "</span>);
Serial.print(<span style="color: #bb4444;">"payload: "</span>);
String cmd <span style="color: #666666;">=</span> <span style="color: #bb4444;">""</span>;
<span style="color: #aa22ff; font-weight: bold;">for</span> (<span style="color: #00bb00; font-weight: bold;">int</span> i <span style="color: #666666;">=</span> <span style="color: #666666;">0</span>; i <span style="color: #666666;"><</span> length; i<span style="color: #666666;">++</span>) {
cmd <span style="color: #666666;">+=</span> (<span style="color: #00bb00; font-weight: bold;">char</span>)payload[i];
}
Serial.print(<span style="color: #bb4444;">"HA control bulb: "</span>);
Serial.println(cmd);
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">setup</span>() {
Serial.begin(<span style="color: #666666;">115200</span>);
<span style="color: #008800; font-style: italic;">// We start by connecting to a WiFi network</span>
Serial.println();
Serial.print(<span style="color: #bb4444;">"Connecting to "</span>);
Serial.println(ssid);
WiFi.begin(ssid, password);
<span style="color: #aa22ff; font-weight: bold;">while</span> (WiFi.status() <span style="color: #666666;">!=</span> WL_CONNECTED) {
delay(<span style="color: #666666;">500</span>);
Serial.print(<span style="color: #bb4444;">"."</span>);
}
Serial.println(<span style="color: #bb4444;">""</span>);
Serial.println(<span style="color: #bb4444;">"WiFi connected"</span>);
Serial.println(<span style="color: #bb4444;">"IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #aa22ff; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>MDNS.begin(<span style="color: #bb4444;">"esp32"</span>)) {
Serial.println(<span style="color: #bb4444;">"Error setting up MDNS responder!"</span>);
<span style="color: #aa22ff; font-weight: bold;">while</span>(<span style="color: #666666;">1</span>) {
delay(<span style="color: #666666;">1000</span>);
}
}
IPAddress serverIp <span style="color: #666666;">=</span> MDNS.queryHost(mqtt_server);
Serial.print(<span style="color: #bb4444;">"IP address of server: "</span>);
Serial.println(serverIp.toString());
<span style="color: #008800; font-style: italic;">/* configure the MQTT server with IPaddress and port */</span>
client.setServer(serverIp, <span style="color: #666666;">1883</span>);
client.setCallback(receivedCallback);
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">loop</span>() {
<span style="color: #008800; font-style: italic;">/* if client was disconnected then try to reconnect again */</span>
<span style="color: #aa22ff; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>client.connected()) {
reconnect();
}
<span style="color: #008800; font-style: italic;">/* this function will listen for incomming </span>
<span style="color: #008800; font-style: italic;"> subscribed topic-process-invoke receivedCallback */</span>
client.loop();
}
</pre></div>
</div><div>From Dashboard choose Edit Dashboard > Add Card > Button > Light > Save</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-lZtX0ZAHyUM/X_23TrASvlI/AAAAAAAAOzE/kKJfivaWKFkRPV-btwKaJWPW7OctgEbXQCLcBGAsYHQ/s1920/ha26.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-lZtX0ZAHyUM/X_23TrASvlI/AAAAAAAAOzE/kKJfivaWKFkRPV-btwKaJWPW7OctgEbXQCLcBGAsYHQ/w640-h340/ha26.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-WnmQakmn_VE/X_23YH7vG-I/AAAAAAAAOzI/feyeGQkaCoUXIvcD7O4LL_O6SwiWY4ZKgCLcBGAsYHQ/s1920/ha27.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="341" src="https://1.bp.blogspot.com/-WnmQakmn_VE/X_23YH7vG-I/AAAAAAAAOzI/feyeGQkaCoUXIvcD7O4LL_O6SwiWY4ZKgCLcBGAsYHQ/w640-h341/ha27.png" width="640" /></a></div><div>From Arduino open the Terminal, then try to click the Light button, and you will see from Terminal:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-PTVsQnXxVBY/X_24FvF38rI/AAAAAAAAOzU/szBANL5egyAhPcU9CdDxNNjYX4_nfMXVwCLcBGAsYHQ/s1920/COM3%2B1_12_2021%2B9_53_57%2BPM.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="986" data-original-width="1920" height="328" src="https://1.bp.blogspot.com/-PTVsQnXxVBY/X_24FvF38rI/AAAAAAAAOzU/szBANL5egyAhPcU9CdDxNNjYX4_nfMXVwCLcBGAsYHQ/w640-h328/COM3%2B1_12_2021%2B9_53_57%2BPM.png" width="640" /></a></div><div><b>2.6 Use InfluxDB to store data</b><br /><div>Open InfluxDB add-on</div><div>Create user: open InfluxDB Admin > press Create User > Enable ALL in Permissions > press green button</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-fAAMkC8F0Lg/X_8We85pQoI/AAAAAAAAO0Y/_-AgLEvm4f4Z1D8nPZSAZlh4RCr2XLFZgCLcBGAsYHQ/s1920/ha30.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-fAAMkC8F0Lg/X_8We85pQoI/AAAAAAAAO0Y/_-AgLEvm4f4Z1D8nPZSAZlh4RCr2XLFZgCLcBGAsYHQ/w640-h340/ha30.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div>Open Explore Tab in InfluxDB</div><div>Create a database called "myhome" by using query: </div><div style="text-align: center;"><b style="font-style: italic;">CREATE DATABASE myhome </b></div><div>Press Submit Query</div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-9B7HkHyaG5Q/X_8L7mGdWGI/AAAAAAAAOzs/DTYi0Zmf8CQQNQOEx81DvGES2Ylz1r7QACLcBGAsYHQ/s1920/ha29.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-9B7HkHyaG5Q/X_8L7mGdWGI/AAAAAAAAOzs/DTYi0Zmf8CQQNQOEx81DvGES2Ylz1r7QACLcBGAsYHQ/w640-h340/ha29.png" width="640" /></a></div><div>Add entry below in <b>"configuration.yaml"</b></div>
<!--HTML generated using hilite.me--><div style="background: rgb(248, 248, 248); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">influxdb:
host: localhost
port: 8086
database: myhome
username: iotsharing
password: xyz
default_measurement: state
include:
entities:
- sensor.room_temperator
</pre></div>
Here: <div>username and password: account that created in previous step</div><div>entities: entity of ESP sensor in <b>2.4 Read data from sensor on ESP</b></div><div>In order to view the eties of myhome database, use the query:</div><div style="text-align: center;"><b><i>SELECT * FROM "myhome"."autogen"."°C" WHERE "entity_id"='room_temperator'</i></b></div><div style="text-align: left;">You will see something like this.</div><div><div class="separator" style="clear: both; font-weight: bold; text-align: center;"><a href="https://1.bp.blogspot.com/-pgQGlp6bfFw/X_8bsW6mFbI/AAAAAAAAO0k/NKTFmkvM9UgGVEvFahJxFyjRqvu9eNs6QCLcBGAsYHQ/s1920/ha31.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-pgQGlp6bfFw/X_8bsW6mFbI/AAAAAAAAO0k/NKTFmkvM9UgGVEvFahJxFyjRqvu9eNs6QCLcBGAsYHQ/w640-h340/ha31.png" width="640" /></a></div>You can use<i> <b>Dashboards in InfluxDB </b></i>to visualize easily</div><div>From InfluxDB Menu choose <b>Dashboards > Line</b> style chart > <b>Add Data</b></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFsWBxiePymIxJhDpOY2RFcQVgt5KlvH5Q3QpV1wbmWfeEAH1u2dsKMo2L466XUKEuocHGtJgNWJzt07qhaqDmfMIeA4355j7Atxmcrg95OL_rEdRQF-N5xxS6Vu_jMWT0PmWafX5T59Y/s1920/ha34.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFsWBxiePymIxJhDpOY2RFcQVgt5KlvH5Q3QpV1wbmWfeEAH1u2dsKMo2L466XUKEuocHGtJgNWJzt07qhaqDmfMIeA4355j7Atxmcrg95OL_rEdRQF-N5xxS6Vu_jMWT0PmWafX5T59Y/w640-h340/ha34.png" width="640" /></a></div><b><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-AeGybH1vZWU/YAPNqjAlfEI/AAAAAAAAO1Y/B4R4Cj7nKLoXkI0Se7KzseEOtC2pruJRgCLcBGAsYHQ/s1920/ha32.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-AeGybH1vZWU/YAPNqjAlfEI/AAAAAAAAO1Y/B4R4Cj7nKLoXkI0Se7KzseEOtC2pruJRgCLcBGAsYHQ/w640-h340/ha32.png" width="640" /></a></div><div>choose <b>myhome.autogen > entity_id > room_temperator > value > tick green button</b></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0RrButOaTpHA0xeEoreINXQ_qd7s_HA2oQ4UZ6wYAIWTUUaxR7gbVHPxzyPC61OVcX4N7ENvMC13T_Kn-aZ-JHkwOCdR9uJ5wSaiMjVqDbgDZ77z0yk2hQ89FZzRtu-EgK-k8geQAgiY/s1920/ha35.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0RrButOaTpHA0xeEoreINXQ_qd7s_HA2oQ4UZ6wYAIWTUUaxR7gbVHPxzyPC61OVcX4N7ENvMC13T_Kn-aZ-JHkwOCdR9uJ5wSaiMjVqDbgDZ77z0yk2hQ89FZzRtu-EgK-k8geQAgiY/w640-h340/ha35.png" width="640" /></a></div><br /></div><div><a href="https://1.bp.blogspot.com/-0Zws32Gk1nI/YAPQi4B_spI/AAAAAAAAO1o/MqyIMX-m_-Irlw9eipgcgEpRd0hLqF6HgCLcBGAsYHQ/s1920/ha36.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-0Zws32Gk1nI/YAPQi4B_spI/AAAAAAAAO1o/MqyIMX-m_-Irlw9eipgcgEpRd0hLqF6HgCLcBGAsYHQ/w640-h340/ha36.png" width="640" /></a></div><b>
2.7 Auto-detection ESP device from Home Assistant</b><div>With this mode, you need not to configure HA via <b>"configuration.yaml"</b>.</div><div>Auto-detection via MQTT, the ESP need to send its configuration to HA to advertise itself.</div><div>The advertising topic need to follow format: </div><div style="text-align: center;"><b><i><discovery_prefix>/<component>/[<node_id>/]<object_id>/config</i></b></div><div>We will make a demo with a send/receive data to/from HA and ESP. Here are the config topics:</div><div><b>"homeassistant/sensor/iotsharing/iotsharing_temp/config"</b> (temperature)</div><div><b>"homeassistant/switch/iotsharing/iotsharing_light/config"</b> (bulb)</div><div>The ESP will publish the temperature to HA via topic:</div><div><b>"homeassistant/sensor/iotsharing/temp_state"</b></div><div>and under json format:</div><div><b>"{{value_json.temperature}}"</b></div><div>The HA will publish command to ESP via topic:</div><div><b>"homeassistant/switch/iotsharing/light_state"</b></div><div>And ESP will send response back to HA after received the command via topic:</div><div><b>"homeassistant/switch/iotsharing/light_state/set"</b></div><div>Here is the Arduino ESP code:</div>
<!--HTML generated using hilite.me--><div style="background: rgb(248, 248, 248); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800;">#include <WiFi.h></span>
<span style="color: #008800;">#include <PubSubClient.h></span>
<span style="color: #008800;">#include "ArduinoJson.h"</span>
<span style="color: #008800;">#include <ESPmDNS.h></span>
<span style="color: #008800;">#define wifi_ssid "I3.41"</span>
<span style="color: #008800;">#define wifi_password "xxx"</span>
<span style="color: #008800;">#define mqtt_server "homeassistant"</span>
<span style="color: #008800;">#define mqtt_user "iotsharing"</span>
<span style="color: #008800;">#define mqtt_password "yyy"</span>
<span style="color: #008800;">#define mqtt_clientId "iotsharing-sensor"</span>
<span style="color: #008800; font-style: italic;">//The discovery topic need to follow a specific format:</span>
<span style="color: #008800; font-style: italic;">// <discovery_prefix>/<component>/[<node_id>/]<object_id>/config</span>
<span style="color: #008800;">#define TOPIC_TEMP_CONF "homeassistant/sensor/iotsharing/iotsharing_temp/config"</span>
<span style="color: #008800;">#define TOPIC_PRESS_CONF "homeassistant/switch/iotsharing/iotsharing_light/config"</span>
<span style="color: #008800;">#define TEMP_STATE "homeassistant/sensor/iotsharing/temp_state"</span>
<span style="color: #008800;">#define LIGHT_STATE "homeassistant/switch/iotsharing/light_state"</span>
<span style="color: #008800;">#define CMD_LIGHT_STATE "homeassistant/switch/iotsharing/light_state/set"</span>
<span style="color: #008800;">#define TEMP_NAME "IOTSHARING TEMP"</span>
<span style="color: #008800;">#define TEMP_CLASS "temperature"</span>
<span style="color: #008800;">#define LIGHT_NAME "IOTSHARING LIGHT"</span>
<span style="color: #008800; font-style: italic;">//variables</span>
WiFiClient espClient;
PubSubClient <span style="color: #00a000;">client</span>(espClient);
<span style="color: #00bb00; font-weight: bold;">long</span> lastMsg <span style="color: #666666;">=</span> <span style="color: #666666;">0</span>;
<span style="color: #00bb00; font-weight: bold;">float</span> temp <span style="color: #666666;">=</span> <span style="color: #666666;">0.00</span>;
<span style="color: #00bb00; font-weight: bold;">float</span> pressure <span style="color: #666666;">=</span> <span style="color: #666666;">0.00</span>;
<span style="color: #008800; font-style: italic;">//functions</span>
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">publishTempConfig</span>() {
<span style="color: #aa22ff; font-weight: bold;">const</span> <span style="color: #00bb00; font-weight: bold;">size_t</span> bufferSize <span style="color: #666666;">=</span> JSON_OBJECT_SIZE(<span style="color: #666666;">8</span>);
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject<span style="color: #666666;">&</span> root <span style="color: #666666;">=</span> jsonBuffer.createObject();
root[<span style="color: #bb4444;">"name"</span>] <span style="color: #666666;">=</span> TEMP_NAME;
root[<span style="color: #bb4444;">"dev_cla"</span>] <span style="color: #666666;">=</span> TEMP_CLASS;
root[<span style="color: #bb4444;">"stat_t"</span>] <span style="color: #666666;">=</span> TEMP_STATE;
root[<span style="color: #bb4444;">"unit_of_meas"</span>] <span style="color: #666666;">=</span> <span style="color: #bb4444;">"°C"</span>;
root[<span style="color: #bb4444;">"val_tpl"</span>] <span style="color: #666666;">=</span> <span style="color: #bb4444;">"{{value_json.temperature}}"</span>;
root.prettyPrintTo(Serial);
Serial.println(<span style="color: #bb4444;">""</span>);
<span style="color: #00bb00; font-weight: bold;">char</span> message[<span style="color: #666666;">256</span>];
root.printTo(message, <span style="color: #aa22ff; font-weight: bold;">sizeof</span>(message));
client.publish(TOPIC_TEMP_CONF, message, <span style="color: #aa22ff;">true</span>);
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">publishLightConfig</span>() {
<span style="color: #aa22ff; font-weight: bold;">const</span> <span style="color: #00bb00; font-weight: bold;">size_t</span> bufferSize <span style="color: #666666;">=</span> JSON_OBJECT_SIZE(<span style="color: #666666;">8</span>);
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject<span style="color: #666666;">&</span> root <span style="color: #666666;">=</span> jsonBuffer.createObject();
root[<span style="color: #bb4444;">"name"</span>] <span style="color: #666666;">=</span> LIGHT_NAME;
root[<span style="color: #bb4444;">"stat_t"</span>] <span style="color: #666666;">=</span> LIGHT_STATE;
root[<span style="color: #bb4444;">"cmd_t"</span>] <span style="color: #666666;">=</span> CMD_LIGHT_STATE;
root[<span style="color: #bb4444;">"pl_on"</span>] <span style="color: #666666;">=</span> <span style="color: #bb4444;">"on"</span>;
root[<span style="color: #bb4444;">"pl_off"</span>] <span style="color: #666666;">=</span> <span style="color: #bb4444;">"off"</span>;
root.prettyPrintTo(Serial);
Serial.println(<span style="color: #bb4444;">""</span>);
<span style="color: #00bb00; font-weight: bold;">char</span> message[<span style="color: #666666;">256</span>];
root.printTo(message, <span style="color: #aa22ff; font-weight: bold;">sizeof</span>(message));
client.publish(TOPIC_PRESS_CONF, message, <span style="color: #aa22ff;">true</span>);
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">setup_wifi</span>() {
delay(<span style="color: #666666;">10</span>);
Serial.println();
Serial.print(<span style="color: #bb4444;">"Connecting to "</span>);
Serial.println(wifi_ssid);
WiFi.begin(wifi_ssid, wifi_password);
<span style="color: #aa22ff; font-weight: bold;">while</span> (WiFi.status() <span style="color: #666666;">!=</span> WL_CONNECTED) {
delay(<span style="color: #666666;">500</span>);
Serial.print(<span style="color: #bb4444;">"."</span>);
}
Serial.println(<span style="color: #bb4444;">""</span>);
Serial.println(<span style="color: #bb4444;">"WiFi connected"</span>);
Serial.println(<span style="color: #bb4444;">"IP address: "</span>);
Serial.println(WiFi.localIP());
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">reconnect</span>() {
<span style="color: #008800; font-style: italic;">//Loop until we're reconnected</span>
<span style="color: #aa22ff; font-weight: bold;">while</span> (<span style="color: #666666;">!</span>client.connected()) {
<span style="color: #aa22ff; font-weight: bold;">if</span> (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
Serial.println(<span style="color: #bb4444;">"connected"</span>);
delay(<span style="color: #666666;">1000</span>);
publishTempConfig();
delay(<span style="color: #666666;">1000</span>);
publishLightConfig();
delay(<span style="color: #666666;">500</span>);
client.subscribe(CMD_LIGHT_STATE);
Serial.print(<span style="color: #bb4444;">"MQTT connected!"</span>);
} <span style="color: #aa22ff; font-weight: bold;">else</span> {
Serial.print(<span style="color: #bb4444;">"failed, rc="</span>);
Serial.print(client.state());
}
}
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">receivedCallback</span>(<span style="color: #00bb00; font-weight: bold;">char</span><span style="color: #666666;">*</span> topic, byte<span style="color: #666666;">*</span> payload, <span style="color: #00bb00; font-weight: bold;">unsigned</span> <span style="color: #00bb00; font-weight: bold;">int</span> length) {
Serial.print(<span style="color: #bb4444;">"Message received: "</span>);
Serial.print(<span style="color: #bb4444;">"payload: "</span>);
String cmd <span style="color: #666666;">=</span> <span style="color: #bb4444;">""</span>;
<span style="color: #aa22ff; font-weight: bold;">for</span> (<span style="color: #00bb00; font-weight: bold;">int</span> i <span style="color: #666666;">=</span> <span style="color: #666666;">0</span>; i <span style="color: #666666;"><</span> length; i<span style="color: #666666;">++</span>) {
cmd <span style="color: #666666;">+=</span> (<span style="color: #00bb00; font-weight: bold;">char</span>)payload[i];
}
Serial.println(cmd);
<span style="color: #aa22ff; font-weight: bold;">if</span>(cmd <span style="color: #666666;">==</span> <span style="color: #bb4444;">"on"</span>){
client.publish(LIGHT_STATE, <span style="color: #bb4444;">"on"</span>);
} <span style="color: #aa22ff; font-weight: bold;">else</span> {
client.publish(LIGHT_STATE, <span style="color: #bb4444;">"off"</span>);
}
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">publishData</span>(<span style="color: #00bb00; font-weight: bold;">float</span> p_temperature) {
<span style="color: #aa22ff; font-weight: bold;">const</span> <span style="color: #00bb00; font-weight: bold;">size_t</span> bufferSize <span style="color: #666666;">=</span> JSON_OBJECT_SIZE(<span style="color: #666666;">2</span>);
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject<span style="color: #666666;">&</span> root <span style="color: #666666;">=</span> jsonBuffer.createObject();
root[<span style="color: #bb4444;">"temperature"</span>] <span style="color: #666666;">=</span> (String)p_temperature;
<span style="color: #008800; font-style: italic;">//root.prettyPrintTo(Serial);</span>
<span style="color: #00bb00; font-weight: bold;">char</span> data[<span style="color: #666666;">74</span>];
root.printTo(data, <span style="color: #aa22ff; font-weight: bold;">sizeof</span>(data));
client.publish(TEMP_STATE, data, <span style="color: #aa22ff;">true</span>);
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">setup</span>() {
Serial.begin(<span style="color: #666666;">115200</span>);
delay(<span style="color: #666666;">10</span>);
setup_wifi();
<span style="color: #aa22ff; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>MDNS.begin(<span style="color: #bb4444;">"esp32"</span>)) {
Serial.println(<span style="color: #bb4444;">"Error setting up MDNS responder!"</span>);
<span style="color: #aa22ff; font-weight: bold;">while</span>(<span style="color: #666666;">1</span>) {
delay(<span style="color: #666666;">1000</span>);
}
}
IPAddress serverIp <span style="color: #666666;">=</span> MDNS.queryHost(mqtt_server);
Serial.print(<span style="color: #bb4444;">"IP address of server: "</span>);
Serial.println(serverIp.toString());
client.setServer(serverIp, <span style="color: #666666;">1883</span>);
client.setCallback(receivedCallback);
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">loop</span>() {
<span style="color: #aa22ff; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>client.connected()) {
reconnect();
}
client.loop();
<span style="color: #00bb00; font-weight: bold;">long</span> now <span style="color: #666666;">=</span> millis();
<span style="color: #aa22ff; font-weight: bold;">if</span>(now <span style="color: #666666;">-</span> lastMsg <span style="color: #666666;">></span> <span style="color: #666666;">5000</span>) {
lastMsg <span style="color: #666666;">=</span> now;
<span style="color: #aa22ff; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>client.connected()) {
reconnect();
}
temp <span style="color: #666666;">=</span> (<span style="color: #00bb00; font-weight: bold;">float</span>)random(<span style="color: #666666;">10</span>, <span style="color: #666666;">50</span>);
publishData(temp);
}
}
</pre></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Cwfiv0RpRK4/YAPgMYl5yaI/AAAAAAAAO2I/vgkoo0mGu74zl-O0AK0oPlU1vDySvjLCQCLcBGAsYHQ/s1920/ha38.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="986" data-original-width="1920" height="328" src="https://1.bp.blogspot.com/-Cwfiv0RpRK4/YAPgMYl5yaI/AAAAAAAAO2I/vgkoo0mGu74zl-O0AK0oPlU1vDySvjLCQCLcBGAsYHQ/w640-h328/ha38.png" width="640" /></a></div>From HA, choose Edit Dashboards > Add Card > Entities<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-NN00Yqvgk0U/YAPiC0Q2kcI/AAAAAAAAO2U/lxmim5-bnaciPQeQstPUW5-k0HZWaWaHwCLcBGAsYHQ/s1920/ha39.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-NN00Yqvgk0U/YAPiC0Q2kcI/AAAAAAAAO2U/lxmim5-bnaciPQeQstPUW5-k0HZWaWaHwCLcBGAsYHQ/w640-h340/ha39.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/--72FpjD4Yq8/YAPjHR7N-eI/AAAAAAAAO2g/0-KJGb7IU5s80RhFCgFjelLnw6OrofGsACLcBGAsYHQ/s1920/ha40.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/--72FpjD4Yq8/YAPjHR7N-eI/AAAAAAAAO2g/0-KJGb7IU5s80RhFCgFjelLnw6OrofGsACLcBGAsYHQ/w640-h340/ha40.png" width="640" /></a></div><div>You can try to press the IOTSHARING LIGHT switch andopen the Terminal of Arduino IDE:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-c7gLM7Q1cfI/YAPjkoczubI/AAAAAAAAO2o/51EYnyRh2f0kJn4nq-Jxl1uHxwr08-hgQCLcBGAsYHQ/s1920/ha41.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="986" data-original-width="1920" height="328" src="https://1.bp.blogspot.com/-c7gLM7Q1cfI/YAPjkoczubI/AAAAAAAAO2o/51EYnyRh2f0kJn4nq-Jxl1uHxwr08-hgQCLcBGAsYHQ/w640-h328/ha41.png" width="640" /></a></div><div><div>and monitor IOTSHARING TEMP</div><div><b>2.8 Automation script</b></div>
This feature allows users to specify a sequence of actions to be executed by Home Assistant. We will make a script to turn off the bulb at 9PM and turn on at 6PM. We will re-use the IOTSHARING LIGHT entity in previous step.</div><div>You must configure your time zone properly in:</div><div>Configuration > General > Time Zone (choose according to your location) > Save</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-oL1krSTkW7c/YAQWmizi_WI/AAAAAAAAO24/LLmsJtTlpzk7M01UElbEK_XZgBIUwIodQCLcBGAsYHQ/s1920/Configuration%2B-%2BHome%2BAssistant%2B-%2BGoogle%2BChrome%2B1_17_2021%2B4_25_06%2BPM.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://1.bp.blogspot.com/-oL1krSTkW7c/YAQWmizi_WI/AAAAAAAAO24/LLmsJtTlpzk7M01UElbEK_XZgBIUwIodQCLcBGAsYHQ/w640-h340/Configuration%2B-%2BHome%2BAssistant%2B-%2BGoogle%2BChrome%2B1_17_2021%2B4_25_06%2BPM.png" width="640" /></a></div><div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI3nZa94BbnC47b7tF88wwVA5UkpuzpVnNoVk1jB38B8m3mK5CRIn3DRdaD5eqxHQj4BURbZKnrdZxBocewEwV_XjOlzPCufb0EXnHyry0BDU7cIKH7FQ8FHmJirSYGP8e11WEXfgMHwk/s1920/Configuration+-+Home+Assistant+-+Google+Chrome+1_17_2021+5_50_13+PM.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI3nZa94BbnC47b7tF88wwVA5UkpuzpVnNoVk1jB38B8m3mK5CRIn3DRdaD5eqxHQj4BURbZKnrdZxBocewEwV_XjOlzPCufb0EXnHyry0BDU7cIKH7FQ8FHmJirSYGP8e11WEXfgMHwk/w640-h340/Configuration+-+Home+Assistant+-+Google+Chrome+1_17_2021+5_50_13+PM.png" width="640" /></a></div><div>from HA left Menu choose Configuration > Automations > ADD AUTOMATION > START WITH AN EMPTY AUTOMATION > give the name for script.</div><div>We will make 2 automations auto light off and auto light on following:</div><div>The first automation is to turn off light if time is 9PM</div><div>Name: auto light off</div><div>Mode: Single</div><div><span face="Roboto, Noto, sans-serif" style="background-color: white; color: #212121; font-size: 14px;">switch Enable/Disable automation</span></div><div>Trigger-type: Time Pattern</div><div>Hours: 21, Minutes: 00, Seconds: 00</div><div>Action type: Call service</div><div>Service: switch.turn_off</div><div>Name(s) of entities to turn off: switch.iotsharing_light</div><div><br /></div><div><div><div>The secondautomation is to turn onlight if time is 6PM</div><div>Name: auto light on</div><div>Mode: Single</div><div><span face="Roboto, Noto, sans-serif" style="background-color: white; color: #212121; font-size: 14px;">switch Enable/Disable automation</span></div><div>Trigger-type: Time Pattern</div><div>Hours: 18, Minutes: 00, Seconds: 00</div><div>Action type: Call service</div><div>Service: switch.turn_on</div><div>Name(s) of entities to turn on: switch.iotsharing_light</div></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-IKrWV0luD1HeTBBaOp1n3tzUHfNQYkzGV3KQXXKcAljA2dwrKdYshTvqHTPh0deK76goYkw3kSOPAOvqAUjBaE3tmO4cLVmXxx_bmIRKM_R8GUieG7_ahjT_pseKU52Z25oWsFr_kQE/s1920/ha42.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-IKrWV0luD1HeTBBaOp1n3tzUHfNQYkzGV3KQXXKcAljA2dwrKdYshTvqHTPh0deK76goYkw3kSOPAOvqAUjBaE3tmO4cLVmXxx_bmIRKM_R8GUieG7_ahjT_pseKU52Z25oWsFr_kQE/w640-h340/ha42.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghECNsNIHO5c3vs-d_2dbEfThla-a_kOEnsykarh81z54Q_jRknyAT3YFTpTQO2aIi57kkzI0IIAZejMYYXNwV1eYswxr7OSR8SKXWB96Odk_d5O-27wsx7adKi9qgW-JhH-WBHAbBzvA/s1920/ha43.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1020" data-original-width="1920" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghECNsNIHO5c3vs-d_2dbEfThla-a_kOEnsykarh81z54Q_jRknyAT3YFTpTQO2aIi57kkzI0IIAZejMYYXNwV1eYswxr7OSR8SKXWB96Odk_d5O-27wsx7adKi9qgW-JhH-WBHAbBzvA/w640-h340/ha43.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-MUarp5fqTCg/YARZW-2vy-I/AAAAAAAAO3g/ghce_fSi3F0PezPt4GaRXKegdSVOCK15wCLcBGAsYHQ/s1920/ha44.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="986" data-original-width="1920" height="328" src="https://1.bp.blogspot.com/-MUarp5fqTCg/YARZW-2vy-I/AAAAAAAAO3g/ghce_fSi3F0PezPt4GaRXKegdSVOCK15wCLcBGAsYHQ/w640-h328/ha44.png" width="640" /></a></div><b>2.9 Grafana platform for beautiful analytics and monitoring</b><div>This step will resue <b>2.6 Use InfluxDB to store data</b><b><br /></b><div>choose <b>Grafana from left Menu > choose Configure > Data Sources</b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-zhSLpZFinCI/YAhJoe9fQWI/AAAAAAAAO4E/6Vrhj8hcLoIRUGzE9iiRp9AsRkqfdOIywCLcBGAsYHQ/s1920/ha44.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://1.bp.blogspot.com/-zhSLpZFinCI/YAhJoe9fQWI/AAAAAAAAO4E/6Vrhj8hcLoIRUGzE9iiRp9AsRkqfdOIywCLcBGAsYHQ/w640-h360/ha44.png" width="640" /></a></div>choose InfluxDB<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-KRwRCDUxDTA/YAhJ6rS0EiI/AAAAAAAAO4Q/EQIa1CXIHnQZu_cowzWY7ZCqLfUwgEAfQCLcBGAsYHQ/s1920/ha45.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://1.bp.blogspot.com/-KRwRCDUxDTA/YAhJ6rS0EiI/AAAAAAAAO4Q/EQIa1CXIHnQZu_cowzWY7ZCqLfUwgEAfQCLcBGAsYHQ/w640-h360/ha45.png" width="640" /></a></div><div>Fill the HTTP part with:</div><div> URL: http://192.168.1.8:8086 (ip address of HA)</div><div>Fill the InfluxDB Details with (resuse previous InfluxDB step):<br /><div> Database: myhome</div><div> User and Password as in previous InfluxDB step</div><div> HTTP Method: GET</div><div>choose <b>Save & Test</b></div><div>choose Create > Dashboard</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEZnYi9G871-vpWVuG8MNf5vM8uPKbvRf_80YXCjQ2qcyMKA_oEL4v0hKiYBenHHa4lBcWjCXGwR6BWteUbTqAV6MEgQAOPB3fk7BNaAKMzpXSONvc0BU4LF6o3-5Tm8h8foISxymUM0A/s1920/ha46.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEZnYi9G871-vpWVuG8MNf5vM8uPKbvRf_80YXCjQ2qcyMKA_oEL4v0hKiYBenHHa4lBcWjCXGwR6BWteUbTqAV6MEgQAOPB3fk7BNaAKMzpXSONvc0BU4LF6o3-5Tm8h8foISxymUM0A/w640-h360/ha46.png" width="640" /></a></div>choose <b>Add new panel</b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-pMvChvjgdVI/YAhLllzZyFI/AAAAAAAAO4o/cD5Y4bw-_FYMAfg7N9CfpSvmiUdVv4WQgCLcBGAsYHQ/s1920/ha47.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://1.bp.blogspot.com/-pMvChvjgdVI/YAhLllzZyFI/AAAAAAAAO4o/cD5Y4bw-_FYMAfg7N9CfpSvmiUdVv4WQgCLcBGAsYHQ/w640-h360/ha47.png" width="640" /></a></div>choose <b>toogle text edit mode</b> (pen button) to modify the Query using text mode (you can use GUI mode by clicking on every Query rows.<div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-qvuzdipf9s4/YAhMe-xF8PI/AAAAAAAAO40/VWR2F0eMzKwmi5a-GSofjaAbPdejXXrmQCLcBGAsYHQ/s1920/ha48.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://1.bp.blogspot.com/-qvuzdipf9s4/YAhMe-xF8PI/AAAAAAAAO40/VWR2F0eMzKwmi5a-GSofjaAbPdejXXrmQCLcBGAsYHQ/w640-h360/ha48.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidQ3QFhSN2NZ-z-RSyEX50YK5HsEH15e-ozNtsJ0CzlrmUsLsqV1I84VMXJxPO018RKVs4t7nBpme4OClyk7ItVc8RnI6oGc4LNI5CFP9bk5HJ5Pgj9rLfZIQsBMMsgKmVaVEVDOtkJhA/s1920/ha49.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidQ3QFhSN2NZ-z-RSyEX50YK5HsEH15e-ozNtsJ0CzlrmUsLsqV1I84VMXJxPO018RKVs4t7nBpme4OClyk7ItVc8RnI6oGc4LNI5CFP9bk5HJ5Pgj9rLfZIQsBMMsgKmVaVEVDOtkJhA/w640-h360/ha49.png" width="640" /></a></div>Copy and Paste the Query below into Query text editor</div><div><div style="text-align: center;"><i><b>SELECT "value" FROM "autogen"."°C" WHERE ("entity_id" = 'room_temperator')</b></i></div><div>choose <b>Query Inspector > Refresh</b></div><div>choose <b>Apply </b>button<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3xVCYZWWZiJnF9ovFxLZkyCw9CqC9DJFAEAqtJlUqPIaYQZhE-6R8_VrePK_ycl8uelNmxJ1pES6IQzVzEpGZ1YhJBFDJgGsjkGZokSjJK2GoDMF_N7QKbKPIqipkImtpreRDjiuL3oA/s1920/ha50.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3xVCYZWWZiJnF9ovFxLZkyCw9CqC9DJFAEAqtJlUqPIaYQZhE-6R8_VrePK_ycl8uelNmxJ1pES6IQzVzEpGZ1YhJBFDJgGsjkGZokSjJK2GoDMF_N7QKbKPIqipkImtpreRDjiuL3oA/w640-h360/ha50.png" width="640" /></a></div>Finally,</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-alzz_NgIm7w/YAhOax1J-AI/AAAAAAAAO5Q/-zq-5gV5sr8fyqokLR8lgosULOl-0IsHACLcBGAsYHQ/s1920/ha51.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://1.bp.blogspot.com/-alzz_NgIm7w/YAhOax1J-AI/AAAAAAAAO5Q/-zq-5gV5sr8fyqokLR8lgosULOl-0IsHACLcBGAsYHQ/w640-h360/ha51.png" width="640" /></a></div>You can choose range time at the top of the chart to make it easy to read.<div><div><b>2.10 Monitor ESP camera</b></div><div>We will turn ESP CAM module to a CCTV - IP camera which are capable to stream its video with MJPEG into Home Assistant.</div><div>This follows <a href="http://www.iotsharing.com/2020/03/using-http-for-camera-live-stream.html" target="_blank">Demo 49: ESP32 HTTP Web server for camera live stream and bring it to the world</a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-imNT42L03i8/YAhRwj2ftJI/AAAAAAAAO5c/XlSVZKNMHA0pg3MJK_tvDkTUBxsQZGeugCLcBGAsYHQ/s459/ha52.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="459" data-original-width="459" height="200" src="https://1.bp.blogspot.com/-imNT42L03i8/YAhRwj2ftJI/AAAAAAAAO5c/XlSVZKNMHA0pg3MJK_tvDkTUBxsQZGeugCLcBGAsYHQ/w200-h200/ha52.png" width="200" /></a></div><div>Open <b>"configuration.yaml"</b> and add the entry below and reset HA services.</div>
<!--HTML generated using hilite.me--><div style="background: rgb(248, 248, 248); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">camera:
- platform: mjpeg
name: Livingroom Camera
mjpeg_url: http://ip_of_esp_cam/video
</pre></div>
change <b>ip_of_esp_cam </b>according to yours.<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-2MyZdQbrUvM/YAhYsExsFnI/AAAAAAAAO5o/3KVtDCbfQHc85T6-QnsXJweIuiL4DDhJwCLcBGAsYHQ/s1920/ha53.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://1.bp.blogspot.com/-2MyZdQbrUvM/YAhYsExsFnI/AAAAAAAAO5o/3KVtDCbfQHc85T6-QnsXJweIuiL4DDhJwCLcBGAsYHQ/w640-h360/ha53.png" width="640" /></a></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjydMAOimMyeTnZe_zdaCzgKwAhXkELm5Y0UWmroPTMj6xkyBS535_v6_1Al4hxz3pNxp5gBwMy5xMYd47d__oJ5bTXz_FMfODrQhyHVGeF2VSlKK19WoNYUXy2yp-Y0PpqfBOmnBDa5i0/s1920/ha54.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjydMAOimMyeTnZe_zdaCzgKwAhXkELm5Y0UWmroPTMj6xkyBS535_v6_1Al4hxz3pNxp5gBwMy5xMYd47d__oJ5bTXz_FMfODrQhyHVGeF2VSlKK19WoNYUXy2yp-Y0PpqfBOmnBDa5i0/w640-h360/ha54.png" width="640" /></a></div>Flash the ESP32-Cam code:</div></div>
<!--HTML generated using hilite.me--><div style="background: rgb(248, 248, 248); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800;">#include "esp_camera.h"</span>
<span style="color: #008800;">#include <WiFi.h></span>
<span style="color: #008800;">#define PWDN_GPIO_NUM 32</span>
<span style="color: #008800;">#define RESET_GPIO_NUM -1</span>
<span style="color: #008800;">#define XCLK_GPIO_NUM 0</span>
<span style="color: #008800;">#define SIOD_GPIO_NUM 26</span>
<span style="color: #008800;">#define SIOC_GPIO_NUM 27</span>
<span style="color: #008800;">#define Y9_GPIO_NUM 35</span>
<span style="color: #008800;">#define Y8_GPIO_NUM 34</span>
<span style="color: #008800;">#define Y7_GPIO_NUM 39</span>
<span style="color: #008800;">#define Y6_GPIO_NUM 36</span>
<span style="color: #008800;">#define Y5_GPIO_NUM 21</span>
<span style="color: #008800;">#define Y4_GPIO_NUM 19</span>
<span style="color: #008800;">#define Y3_GPIO_NUM 18</span>
<span style="color: #008800;">#define Y2_GPIO_NUM 5</span>
<span style="color: #008800;">#define VSYNC_GPIO_NUM 25</span>
<span style="color: #008800;">#define HREF_GPIO_NUM 23</span>
<span style="color: #008800;">#define PCLK_GPIO_NUM 22</span>
WiFiServer <span style="color: #00a000;">server</span>(<span style="color: #666666;">80</span>);
<span style="color: #00bb00; font-weight: bold;">bool</span> connected <span style="color: #666666;">=</span> <span style="color: #aa22ff;">false</span>;
WiFiClient live_client;
String index_html <span style="color: #666666;">=</span> <span style="color: #bb4444;">"<meta charset=</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">utf-8</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">/></span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"<style></span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"#content {</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"display: flex;</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"flex-direction: column;</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"justify-content: center;</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"align-items: center;</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"text-align: center;</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"min-height: 100vh;}</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"</style></span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span> \
<span style="color: #bb4444;">"<body bgcolor=</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">#000000</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">><div id=</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">content</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">><h2 style=</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">color:#ffffff</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">>HTTP ESP32 Cam live stream </h2><img src=</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">video</span><span style="color: #bb6622; font-weight: bold;">\"</span><span style="color: #bb4444;">></div></body>"</span>;
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">configCamera</span>(){
<span style="color: #00bb00; font-weight: bold;">camera_config_t</span> config;
config.ledc_channel <span style="color: #666666;">=</span> LEDC_CHANNEL_0;
config.ledc_timer <span style="color: #666666;">=</span> LEDC_TIMER_0;
config.pin_d0 <span style="color: #666666;">=</span> Y2_GPIO_NUM;
config.pin_d1 <span style="color: #666666;">=</span> Y3_GPIO_NUM;
config.pin_d2 <span style="color: #666666;">=</span> Y4_GPIO_NUM;
config.pin_d3 <span style="color: #666666;">=</span> Y5_GPIO_NUM;
config.pin_d4 <span style="color: #666666;">=</span> Y6_GPIO_NUM;
config.pin_d5 <span style="color: #666666;">=</span> Y7_GPIO_NUM;
config.pin_d6 <span style="color: #666666;">=</span> Y8_GPIO_NUM;
config.pin_d7 <span style="color: #666666;">=</span> Y9_GPIO_NUM;
config.pin_xclk <span style="color: #666666;">=</span> XCLK_GPIO_NUM;
config.pin_pclk <span style="color: #666666;">=</span> PCLK_GPIO_NUM;
config.pin_vsync <span style="color: #666666;">=</span> VSYNC_GPIO_NUM;
config.pin_href <span style="color: #666666;">=</span> HREF_GPIO_NUM;
config.pin_sscb_sda <span style="color: #666666;">=</span> SIOD_GPIO_NUM;
config.pin_sscb_scl <span style="color: #666666;">=</span> SIOC_GPIO_NUM;
config.pin_pwdn <span style="color: #666666;">=</span> PWDN_GPIO_NUM;
config.pin_reset <span style="color: #666666;">=</span> RESET_GPIO_NUM;
config.xclk_freq_hz <span style="color: #666666;">=</span> <span style="color: #666666;">20000000</span>;
config.pixel_format <span style="color: #666666;">=</span> PIXFORMAT_JPEG;
config.frame_size <span style="color: #666666;">=</span> FRAMESIZE_QVGA;
config.jpeg_quality <span style="color: #666666;">=</span> <span style="color: #666666;">9</span>;
config.fb_count <span style="color: #666666;">=</span> <span style="color: #666666;">1</span>;
<span style="color: #00bb00; font-weight: bold;">esp_err_t</span> err <span style="color: #666666;">=</span> esp_camera_init(<span style="color: #666666;">&</span>config);
<span style="color: #aa22ff; font-weight: bold;">if</span> (err <span style="color: #666666;">!=</span> ESP_OK) {
Serial.printf(<span style="color: #bb4444;">"Camera init failed with error 0x%x"</span>, err);
<span style="color: #aa22ff; font-weight: bold;">return</span>;
}
}
<span style="color: #008800; font-style: italic;">//continue sending camera frame</span>
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">liveCam</span>(WiFiClient <span style="color: #666666;">&</span>client){
<span style="color: #008800; font-style: italic;">//capture a frame</span>
<span style="color: #00bb00; font-weight: bold;">camera_fb_t</span> <span style="color: #666666;">*</span> fb <span style="color: #666666;">=</span> esp_camera_fb_get();
<span style="color: #aa22ff; font-weight: bold;">if</span> (<span style="color: #666666;">!</span>fb) {
Serial.println(<span style="color: #bb4444;">"Frame buffer could not be acquired"</span>);
<span style="color: #aa22ff; font-weight: bold;">return</span>;
}
client.print(<span style="color: #bb4444;">"--frame</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span>);
client.print(<span style="color: #bb4444;">"Content-Type: image/jpeg</span><span style="color: #bb6622; font-weight: bold;">\n\n</span><span style="color: #bb4444;">"</span>);
client.flush();
client.write(fb<span style="color: #666666;">-></span>buf, fb<span style="color: #666666;">-></span>len);
client.flush();
client.print(<span style="color: #bb4444;">"</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span>);
<span style="color: #008800; font-style: italic;">//return the frame buffer back to be reused</span>
esp_camera_fb_return(fb);
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">setup</span>() {
Serial.begin(<span style="color: #666666;">115200</span>);
WiFi.begin(<span style="color: #bb4444;">"I3.41"</span>, <span style="color: #bb4444;">"xxx"</span>);
Serial.println(<span style="color: #bb4444;">""</span>);
<span style="color: #aa22ff; font-weight: bold;">while</span> (WiFi.status() <span style="color: #666666;">!=</span> WL_CONNECTED) {
delay(<span style="color: #666666;">500</span>);
Serial.print(<span style="color: #bb4444;">"."</span>);
}
Serial.println(<span style="color: #bb4444;">""</span>);
String IP <span style="color: #666666;">=</span> WiFi.localIP().toString();
Serial.println(<span style="color: #bb4444;">"IP address: "</span> <span style="color: #666666;">+</span> IP);
index_html.replace(<span style="color: #bb4444;">"server_ip"</span>, IP);
server.begin();
configCamera();
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">http_resp</span>(){
WiFiClient client <span style="color: #666666;">=</span> server.available();
<span style="color: #008800; font-style: italic;">/* check client is connected */</span>
<span style="color: #aa22ff; font-weight: bold;">if</span> (client.connected()) {
<span style="color: #008800; font-style: italic;">/* client send request? */</span>
<span style="color: #008800; font-style: italic;">/* request end with '\r' -> this is HTTP protocol format */</span>
String req <span style="color: #666666;">=</span> <span style="color: #bb4444;">""</span>;
<span style="color: #aa22ff; font-weight: bold;">while</span>(client.available()){
req <span style="color: #666666;">+=</span> (<span style="color: #00bb00; font-weight: bold;">char</span>)client.read();
}
Serial.println(<span style="color: #bb4444;">"request "</span> <span style="color: #666666;">+</span> req);
<span style="color: #008800; font-style: italic;">/* First line of HTTP request is "GET / HTTP/1.1" </span>
<span style="color: #008800; font-style: italic;"> here "GET /" is a request to get the first page at root "/"</span>
<span style="color: #008800; font-style: italic;"> "HTTP/1.1" is HTTP version 1.1</span>
<span style="color: #008800; font-style: italic;"> */</span>
<span style="color: #008800; font-style: italic;">/* now we parse the request to see which page the client want */</span>
<span style="color: #00bb00; font-weight: bold;">int</span> addr_start <span style="color: #666666;">=</span> req.indexOf(<span style="color: #bb4444;">"GET"</span>) <span style="color: #666666;">+</span> strlen(<span style="color: #bb4444;">"GET"</span>);
<span style="color: #00bb00; font-weight: bold;">int</span> addr_end <span style="color: #666666;">=</span> req.indexOf(<span style="color: #bb4444;">"HTTP"</span>, addr_start);
<span style="color: #aa22ff; font-weight: bold;">if</span> (addr_start <span style="color: #666666;">==</span> <span style="color: #666666;">-1</span> <span style="color: #666666;">||</span> addr_end <span style="color: #666666;">==</span> <span style="color: #666666;">-1</span>) {
Serial.println(<span style="color: #bb4444;">"Invalid request "</span> <span style="color: #666666;">+</span> req);
<span style="color: #aa22ff; font-weight: bold;">return</span>;
}
req <span style="color: #666666;">=</span> req.substring(addr_start, addr_end);
req.trim();
Serial.println(<span style="color: #bb4444;">"Request: "</span> <span style="color: #666666;">+</span> req);
client.flush();
String s;
<span style="color: #008800; font-style: italic;">/* if request is "/" then client request the first page at root "/" -> we process this by return "Hello world"*/</span>
<span style="color: #aa22ff; font-weight: bold;">if</span> (req <span style="color: #666666;">==</span> <span style="color: #bb4444;">"/"</span>)
{
s <span style="color: #666666;">=</span> <span style="color: #bb4444;">"HTTP/1.1 200 OK</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span>;
s <span style="color: #666666;">+=</span> <span style="color: #bb4444;">"Content-Type: text/html</span><span style="color: #bb6622; font-weight: bold;">\n\n</span><span style="color: #bb4444;">"</span>;
s <span style="color: #666666;">+=</span> index_html;
s <span style="color: #666666;">+=</span> <span style="color: #bb4444;">"</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span>;
client.print(s);
client.stop();
}
<span style="color: #aa22ff; font-weight: bold;">else</span> <span style="color: #aa22ff; font-weight: bold;">if</span> (req <span style="color: #666666;">==</span> <span style="color: #bb4444;">"/video"</span>)
{
live_client <span style="color: #666666;">=</span> client;
live_client.print(<span style="color: #bb4444;">"HTTP/1.1 200 OK</span><span style="color: #bb6622; font-weight: bold;">\n</span><span style="color: #bb4444;">"</span>);
live_client.print(<span style="color: #bb4444;">"Content-Type: multipart/x-mixed-replace; boundary=frame</span><span style="color: #bb6622; font-weight: bold;">\n\n</span><span style="color: #bb4444;">"</span>);
live_client.flush();
connected <span style="color: #666666;">=</span> <span style="color: #aa22ff;">true</span>;
}
<span style="color: #aa22ff; font-weight: bold;">else</span>
{
<span style="color: #008800; font-style: italic;">/* if we can not find the page that client request then we return 404 File not found */</span>
s <span style="color: #666666;">=</span> <span style="color: #bb4444;">"HTTP/1.1 404 Not Found</span><span style="color: #bb6622; font-weight: bold;">\n\n</span><span style="color: #bb4444;">"</span>;
client.print(s);
client.stop();
}
}
}
<span style="color: #00bb00; font-weight: bold;">void</span> <span style="color: #00a000;">loop</span>() {
http_resp();
<span style="color: #aa22ff; font-weight: bold;">if</span>(connected <span style="color: #666666;">==</span> <span style="color: #aa22ff;">true</span>){
liveCam(live_client);
}
}
</pre></div>
choose <b>Edit Dashboard > Add Card > By Entity > choose Lingroom Cam > Continue > Add to LoveLace UI</b><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxmrz7gIdENDvVj-xGgy5sC1617U6xXWXMFq0SHeA9U9dnEGil46BAo7OdktGJQ9hER8gmf6oUvSsDpjL-j1NOuUGKrgBKbikVM5xdcHjDpISck0YdN1EucgTKzN0rARW6r4dxqf8WZUI/s1920/ha55.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxmrz7gIdENDvVj-xGgy5sC1617U6xXWXMFq0SHeA9U9dnEGil46BAo7OdktGJQ9hER8gmf6oUvSsDpjL-j1NOuUGKrgBKbikVM5xdcHjDpISck0YdN1EucgTKzN0rARW6r4dxqf8WZUI/w640-h360/ha55.png" width="640" /></a></div><br /><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-LJSvDxMS194/YAhasdVN0II/AAAAAAAAO6A/N8n0F-4d-akZh5pGDAyAMQT2jeP3nxz6wCLcBGAsYHQ/s1920/ha56.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://1.bp.blogspot.com/-LJSvDxMS194/YAhasdVN0II/AAAAAAAAO6A/N8n0F-4d-akZh5pGDAyAMQT2jeP3nxz6wCLcBGAsYHQ/w640-h360/ha56.png" width="640" /></a></div><b><div style="text-align: center;"><b>Thanks all.</b></div></b>Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com2tag:blogger.com,1999:blog-7549705215513488945.post-8131887545983575062020-03-31T05:12:00.004-07:002021-11-05T22:34:34.425-07:00Demo 50: Bring Tensorflow Lite to ESP32 Arduino - person detection application using deep learning with ESP32 CAM<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
Deep learning is hot. It is hotter when you can run it on ESP32 a hot MCU for IoT. I made a demo <a href="http://www.iotsharing.com/2019/07/deep-learning-computer-vision-with-esp-tensorflowjs.html">Demo 47: Deep learning - Computer vision with ESP32 and tensorflow.js </a>It is an interesting demo but it not really run on ESP32. Today I will make another demo that is bring Tensorflow Lite to ESP32 Arduino through person detection application using deep learning with ESP32 CAM.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-pAEwVUSRVUE/XoMzKBpGZhI/AAAAAAAAMaE/q4DUzfDzx0YLqVkcbgrICzx0zJDDkZ8qACLcBGAsYHQ/s1600/Screenshot_20200331-190650%257E2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1038" data-original-width="1010" height="320" src="https://1.bp.blogspot.com/-pAEwVUSRVUE/XoMzKBpGZhI/AAAAAAAAMaE/q4DUzfDzx0YLqVkcbgrICzx0zJDDkZ8qACLcBGAsYHQ/s320/Screenshot_20200331-190650%257E2.png" width="311" /></a></div>
<div style="text-align: center;">
<b>Figure: Bring Tensorflow Lite to ESP32 Arduino</b></div>
<b>2. Hardware</b><br />
I use the ESP32 CAM module<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvwkJ-3rlfJne1cM3zrjuUCp8GMn8TXeVmw8jQADaZkD3wA2ZQFOVFWx8u-RJr5lBipEygoFExOPL584hdTbe3mH16X3yU5LKjdBLBzNfiBi1bW69g1DlncOLe2Uo9Gb3OMlfPp3ZRT6E/s1600/ws3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="307" data-original-width="360" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvwkJ-3rlfJne1cM3zrjuUCp8GMn8TXeVmw8jQADaZkD3wA2ZQFOVFWx8u-RJr5lBipEygoFExOPL584hdTbe3mH16X3yU5LKjdBLBzNfiBi1bW69g1DlncOLe2Uo9Gb3OMlfPp3ZRT6E/s320/ws3.png" width="320" /></a></div>
<div style="text-align: center;">
<b>Figure: ESP32 CAM with OV2640 cam</b></div>
<b>3. Software</b><br />
I prepared the resources and the code for you.<b> </b><br />
Steps to install:<br />
- Install libraries Jpeg decoder and Tensorflow lite. <br />
Jpeg decoder: <a href="https://github.com/nhatuan84/tensorflow-lite-esp32-person-detection/blob/master/resources/JPEGDecoder-master.zip">https://github.com/nhatuan84/tensorflow-lite-esp32-person-detection/blob/master/resources/JPEGDecoder-master.zip</a><br />
Tensorflow lite: <a href="https://github.com/nhatuan84/tensorflow-lite-esp32-person-detection/blob/master/resources/tensorflow_lite.zip">https://github.com/nhatuan84/tensorflow-lite-esp32-person-detection/blob/master/resources/tensorflow_lite.zip</a><br />
- Install zip libraries, choose <b>Sketch > Include Library > Add .Zip Library</b><br />
- Download Arduino code and open it with Arduino IDE:<br />
Arduino code: <a href="https://github.com/nhatuan84/tensorflow-lite-esp32-person-detection/tree/master/Arduino_code/person_detect">https://github.com/nhatuan84/tensorflow-lite-esp32-person-detection/tree/master/Arduino_code/person_detect</a> <br />
- After flashed the code, open the Terminal to see the IP address of the board.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7HQXTAowfpGEmu_M5sqZX-POYrZXWctadlscmfs5Ci_LhMKDfjiRJQX13tm8w3MizU0PG0_Qd2uqJrCp_n_WpzXLGSkVeCN_ESrp5iBQU0Y-g1vVJXsFWnnGaRydxTAN04OnujW4zXUo/s1600/ws9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="118" data-original-width="267" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7HQXTAowfpGEmu_M5sqZX-POYrZXWctadlscmfs5Ci_LhMKDfjiRJQX13tm8w3MizU0PG0_Qd2uqJrCp_n_WpzXLGSkVeCN_ESrp5iBQU0Y-g1vVJXsFWnnGaRydxTAN04OnujW4zXUo/s1600/ws9.png" /></a></div>
- Open Web browser and type the IP address above and enjoy the result<br />
<b>4. Result</b><br />
It is not really smooth and slow.<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/zwDAXxXgUtE/0.jpg" frameborder="0" height="320" src="https://www.youtube.com/embed/zwDAXxXgUtE?feature=player_embedded" width="480"></iframe></div>
<br />
<br /></div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com3tag:blogger.com,1999:blog-7549705215513488945.post-80810117657908379702020-03-29T04:47:00.002-07:002021-11-05T22:38:47.036-07:00Demo 49: ESP32 HTTP Web server for camera live stream and bring it to the world<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
In this demo, I will show you how to make a HTTP camera live stream application with ESP32 Cam and OV2640 camera. And publish it to the world so we can view it anywhere.<br />
<b>2. Hardware</b><br />
I used the camera module:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL8EBlS2RxqkFuwLWcoMzk-8OQMfeG6TwS2oclVcuK6f_FjQrx5rvsFSb8jBMy3BFXjr5ay7IyuYkIBwdKV_UIkwgwgDLO1-NUEQlS20D6llwaPizYSu7z52bdUkwzE3xN1RGAzacuShk/s1600/ws3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="307" data-original-width="360" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL8EBlS2RxqkFuwLWcoMzk-8OQMfeG6TwS2oclVcuK6f_FjQrx5rvsFSb8jBMy3BFXjr5ay7IyuYkIBwdKV_UIkwgwgDLO1-NUEQlS20D6llwaPizYSu7z52bdUkwzE3xN1RGAzacuShk/s320/ws3.png" width="320" /></a></div>
<div style="text-align: center;">
<b>Figure: ESP32 CAM with OV2640 cam</b></div>
<div dir="ltr" style="text-align: left;" trbidi="on"><div class="separator" style="clear: both; font-weight: bold; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYozf1rwY1CCOsL9qlW46i1GGEylg76CMeVUnrv0ztJ855WzPYlr0gLEInYYsMhfq9iOwcsPMXsLD9jowE6dmbHtIx3LXnCV1Gs9j3H7OZjMxbhvR6M6ycAh6bwTrIxih1KHpbSXUhuTw/s506/ESP32-CAM-to-USB-Wiring-e1546883333528.webp" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="256" data-original-width="506" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYozf1rwY1CCOsL9qlW46i1GGEylg76CMeVUnrv0ztJ855WzPYlr0gLEInYYsMhfq9iOwcsPMXsLD9jowE6dmbHtIx3LXnCV1Gs9j3H7OZjMxbhvR6M6ycAh6bwTrIxih1KHpbSXUhuTw/s320/ESP32-CAM-to-USB-Wiring-e1546883333528.webp" width="320" /></a></div>Board: ESP32 Wrover Module</div><div dir="ltr" style="text-align: left;" trbidi="on">Upload Speed: 115200<b style="font-weight: bold;"><br /></b></div><b>3. Software</b><br />
<b>3.1 Arduino code </b><br />
In order to do live stream using HTTP we will use the below HTTP format:<br />
<br />
<i>HTTP/1.1 200 OK<br />Content-Type: multipart/x-mixed-replace; boundary=frame<br /><br />--</i><i><i>frame </i> </i><br />
<i>Content-Type: image/jpeg<br /><br />[image 1 encoded jpeg data]<br /><br />--</i><i><i>frame</i></i><br />
<i>Content-Type: image/jpeg</i><br />
<br />
<i><i>[image 1 encoded jpeg data]</i> </i><br />
<br />
We have to re-use the <a href="http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html">Demo 12</a><i> </i>to send this HTTP format. We have to process HTTP header and response manually.<br />
The software flow of this demo:<br />
- When web browser connect to web server, we send the index html.<br />
- After loading the index html, web browser continue requesting /video<br />
- When facing <i>/video</i> request the server will send the camera frame continuously.<br />
The index html:<br />
<div style="background: rgb(0, 0, 0); border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0px;"><span style="color: #cccccc;"><meta</span> <span style="color: #cccccc;">charset=</span><span style="color: #cd0000;">"utf-8"</span><span style="color: #cccccc;">/></span>
<span style="color: #cccccc;"><style></span>
<span style="color: #cccccc;">#content</span> <span style="color: #cccccc;">{</span>
<span style="color: #cdcd00;">display</span><span style="color: #3399cc;">:</span> <span style="color: #cccccc;">flex;</span>
<span style="color: #cccccc;">flex</span><span style="color: #3399cc;">-</span><span style="color: #cdcd00;">direction</span><span style="color: #3399cc;">:</span> <span style="color: #cccccc;">column;</span>
<span style="color: #cdcd00;">justify</span><span style="color: #3399cc;">-</span><span style="color: #cdcd00;">content</span><span style="color: #3399cc;">:</span> <span style="color: #cdcd00;">center</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">align</span><span style="color: #3399cc;">-</span><span style="color: #cccccc;">items</span><span style="color: #3399cc;">:</span> <span style="color: #cdcd00;">center</span><span style="color: #cccccc;">;</span>
<span style="color: #cdcd00;">text-align</span><span style="color: #3399cc;">:</span> <span style="color: #cdcd00;">center</span><span style="color: #cccccc;">;</span>
<span style="color: #cdcd00;">min-height</span><span style="color: #3399cc;">:</span> <span style="color: #cd00cd;">100</span><span style="color: #cccccc;">vh;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;"></style></span>
<span style="color: #cccccc;"><body</span> <span style="color: #cccccc;">bgcolor=</span><span style="color: #cd0000;">"#000000"</span><span style="color: #cccccc;">></span>
<span style="color: #cccccc;"><div</span> <span style="color: #cccccc;">id=</span><span style="color: #cd0000;">"content"</span><span style="color: #cccccc;">></span>
<span style="color: #cccccc;"><h2</span> <span style="color: #cccccc;">style=</span><span style="color: #cd0000;">"color:#ffffff"</span><span style="color: #cccccc;">></span>HTTP ESP32 Cam live stream <span style="color: #cccccc;"></h2></span>
<span style="color: #cccccc;"><img</span> <span style="color: #cccccc;">src=</span><span style="color: #cd0000;">"video"</span><span style="color: #cccccc;">></span>
<span style="color: #cccccc;"></div></span>
<span style="color: #cccccc;"></body></span>
</pre>
</div>
The full code:<br />
<div style="background: rgb(0, 0, 0); border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0px;"><span style="color: navy;">#include "esp_camera.h"</span>
<span style="color: navy;">#include <WiFi.h></span>
<span style="color: navy;">#define PWDN_GPIO_NUM 32</span>
<span style="color: navy;">#define RESET_GPIO_NUM -1</span>
<span style="color: navy;">#define XCLK_GPIO_NUM 0</span>
<span style="color: navy;">#define SIOD_GPIO_NUM 26</span>
<span style="color: navy;">#define SIOC_GPIO_NUM 27</span>
<span style="color: navy;">#define Y9_GPIO_NUM 35</span>
<span style="color: navy;">#define Y8_GPIO_NUM 34</span>
<span style="color: navy;">#define Y7_GPIO_NUM 39</span>
<span style="color: navy;">#define Y6_GPIO_NUM 36</span>
<span style="color: navy;">#define Y5_GPIO_NUM 21</span>
<span style="color: navy;">#define Y4_GPIO_NUM 19</span>
<span style="color: navy;">#define Y3_GPIO_NUM 18</span>
<span style="color: navy;">#define Y2_GPIO_NUM 5</span>
<span style="color: navy;">#define VSYNC_GPIO_NUM 25</span>
<span style="color: navy;">#define HREF_GPIO_NUM 23</span>
<span style="color: navy;">#define PCLK_GPIO_NUM 22</span>
<span style="color: #cccccc;">WiFiServer</span> <span style="color: #cccccc;">server(</span><span style="color: #cd00cd;">80</span><span style="color: #cccccc;">);</span>
<span style="color: #00cd00;">bool</span> <span style="color: #cccccc;">connected</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">false</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">WiFiClient</span> <span style="color: #cccccc;">live_client;</span>
<span style="color: #cccccc;">String</span> <span style="color: #cccccc;">index_html</span> <span style="color: #3399cc;">=</span> <span style="color: #cd0000;">"<meta charset=\"utf-8\"/>\n"</span> \
<span style="color: #cd0000;">"<style>\n"</span> \
<span style="color: #cd0000;">"#content {\n"</span> \
<span style="color: #cd0000;">"display: flex;\n"</span> \
<span style="color: #cd0000;">"flex-direction: column;\n"</span> \
<span style="color: #cd0000;">"justify-content: center;\n"</span> \
<span style="color: #cd0000;">"align-items: center;\n"</span> \
<span style="color: #cd0000;">"text-align: center;\n"</span> \
<span style="color: #cd0000;">"min-height: 100vh;}\n"</span> \
<span style="color: #cd0000;">"</style>\n"</span> \
<span style="color: #cd0000;">"<body bgcolor=\"#000000\"><div id=\"content\"><h2 style=\"color:#ffffff\">HTTP ESP32 Cam live stream </h2><img src=\"video\"></div></body>"</span><span style="color: #cccccc;">;</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">configCamera(){</span>
<span style="color: #00cd00;">camera_config_t</span> <span style="color: #cccccc;">config;</span>
<span style="color: #cccccc;">config.ledc_channel</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">LEDC_CHANNEL_0;</span>
<span style="color: #cccccc;">config.ledc_timer</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">LEDC_TIMER_0;</span>
<span style="color: #cccccc;">config.pin_d0</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y2_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d1</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y3_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d2</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y4_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d3</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y5_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d4</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y6_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d5</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y7_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d6</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y8_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d7</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y9_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_xclk</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">XCLK_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_pclk</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">PCLK_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_vsync</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">VSYNC_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_href</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">HREF_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_sscb_sda</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">SIOD_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_sscb_scl</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">SIOC_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_pwdn</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">PWDN_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_reset</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">RESET_GPIO_NUM;</span>
<span style="color: #cccccc;">config.xclk_freq_hz</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">20000000</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">config.pixel_format</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">PIXFORMAT_JPEG;</span>
<span style="color: #cccccc;">config.frame_size</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">FRAMESIZE_QVGA;</span>
<span style="color: #cccccc;">config.jpeg_quality</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">9</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">config.fb_count</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">1</span><span style="color: #cccccc;">;</span>
<span style="color: #00cd00;">esp_err_t</span> <span style="color: #cccccc;">err</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">esp_camera_init(</span><span style="color: #3399cc;">&</span><span style="color: #cccccc;">config);</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(err</span> <span style="color: #3399cc;">!=</span> <span style="color: #cccccc;">ESP_OK)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.printf(</span><span style="color: #cd0000;">"Camera init failed with error 0x%x"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">err);</span>
<span style="color: #cdcd00;">return</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
<span style="color: navy;">//continue sending camera frame</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">liveCam(WiFiClient</span> <span style="color: #3399cc;">&</span><span style="color: #cccccc;">client){</span>
<span style="color: navy;">//capture a frame</span>
<span style="color: #00cd00;">camera_fb_t</span> <span style="color: #3399cc;">*</span> <span style="color: #cccccc;">fb</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">esp_camera_fb_get();</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(</span><span style="color: #3399cc;">!</span><span style="color: #cccccc;">fb)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">"Frame buffer could not be acquired"</span><span style="color: #cccccc;">);</span>
<span style="color: #cdcd00;">return</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">client.print(</span><span style="color: #cd0000;">"--frame\n"</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">client.print(</span><span style="color: #cd0000;">"Content-Type: image/jpeg\n\n"</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">client.flush();</span>
<span style="color: #cccccc;">client.write(fb</span><span style="color: #3399cc;">-></span><span style="color: #cccccc;">buf,</span> <span style="color: #cccccc;">fb</span><span style="color: #3399cc;">-></span><span style="color: #cccccc;">len);</span>
<span style="color: #cccccc;">client.flush();</span>
<span style="color: #cccccc;">client.print(</span><span style="color: #cd0000;">"\n"</span><span style="color: #cccccc;">);</span>
<span style="color: navy;">//return the frame buffer back to be reused</span>
<span style="color: #cccccc;">esp_camera_fb_return(fb);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">setup()</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.begin(</span><span style="color: #cd00cd;">115200</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">WiFi.begin(</span><span style="color: #cd0000;">"I3.41"</span><span style="color: #cccccc;">,</span> <span style="color: #cd0000;">"xxx"</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">""</span><span style="color: #cccccc;">);</span>
<span style="color: #cdcd00;">while</span> <span style="color: #cccccc;">(WiFi.status()</span> <span style="color: #3399cc;">!=</span> <span style="color: #cccccc;">WL_CONNECTED)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">delay(</span><span style="color: #cd00cd;">500</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">Serial.print(</span><span style="color: #cd0000;">"."</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">""</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">String</span> <span style="color: #cccccc;">IP</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">WiFi.localIP().toString();</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">"IP address: "</span> <span style="color: #3399cc;">+</span> <span style="color: #cccccc;">IP);</span>
<span style="color: #cccccc;">index_html.replace(</span><span style="color: #cd0000;">"server_ip"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">IP);</span>
<span style="color: #cccccc;">server.begin();</span>
<span style="color: #cccccc;">configCamera();</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">http_resp(){</span>
<span style="color: #cccccc;">WiFiClient</span> <span style="color: #cccccc;">client</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">server.available();</span>
<span style="color: navy;">/* check client is connected */</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(client.connected())</span> <span style="color: #cccccc;">{</span>
<span style="color: navy;">/* client send request? */</span>
<span style="color: navy;">/* request end with '\r' -> this is HTTP protocol format */</span>
<span style="color: #cccccc;">String</span> <span style="color: #cccccc;">req</span> <span style="color: #3399cc;">=</span> <span style="color: #cd0000;">""</span><span style="color: #cccccc;">;</span>
<span style="color: #cdcd00;">while</span><span style="color: #cccccc;">(client.available()){</span>
<span style="color: #cccccc;">req</span> <span style="color: #3399cc;">+=</span> <span style="color: #cccccc;">(</span><span style="color: #00cd00;">char</span><span style="color: #cccccc;">)client.read();</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">"request "</span> <span style="color: #3399cc;">+</span> <span style="color: #cccccc;">req);</span>
<span style="color: navy;">/* First line of HTTP request is "GET / HTTP/1.1" </span>
<span style="color: navy;"> here "GET /" is a request to get the first page at root "/"</span>
<span style="color: navy;"> "HTTP/1.1" is HTTP version 1.1</span>
<span style="color: navy;"> */</span>
<span style="color: navy;">/* now we parse the request to see which page the client want */</span>
<span style="color: #00cd00;">int</span> <span style="color: #cccccc;">addr_start</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">req.indexOf(</span><span style="color: #cd0000;">"GET"</span><span style="color: #cccccc;">)</span> <span style="color: #3399cc;">+</span> <span style="color: #cccccc;">strlen(</span><span style="color: #cd0000;">"GET"</span><span style="color: #cccccc;">);</span>
<span style="color: #00cd00;">int</span> <span style="color: #cccccc;">addr_end</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">req.indexOf(</span><span style="color: #cd0000;">"HTTP"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">addr_start);</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(addr_start</span> <span style="color: #3399cc;">==</span> <span style="color: #3399cc;">-</span><span style="color: #cd00cd;">1</span> <span style="color: #3399cc;">||</span> <span style="color: #cccccc;">addr_end</span> <span style="color: #3399cc;">==</span> <span style="color: #3399cc;">-</span><span style="color: #cd00cd;">1</span><span style="color: #cccccc;">)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">"Invalid request "</span> <span style="color: #3399cc;">+</span> <span style="color: #cccccc;">req);</span>
<span style="color: #cdcd00;">return</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">req</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">req.substring(addr_start,</span> <span style="color: #cccccc;">addr_end);</span>
<span style="color: #cccccc;">req.trim();</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">"Request: "</span> <span style="color: #3399cc;">+</span> <span style="color: #cccccc;">req);</span>
<span style="color: #cccccc;">client.flush();</span>
<span style="color: #cccccc;">String</span> <span style="color: #cccccc;">s;</span>
<span style="color: navy;">/* if request is "/" then client request the first page at root "/" -> we process this by return "Hello world"*/</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(req</span> <span style="color: #3399cc;">==</span> <span style="color: #cd0000;">"/"</span><span style="color: #cccccc;">)</span>
<span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">s</span> <span style="color: #3399cc;">=</span> <span style="color: #cd0000;">"HTTP/1.1 200 OK\n"</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">s</span> <span style="color: #3399cc;">+=</span> <span style="color: #cd0000;">"Content-Type: text/html\n\n"</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">s</span> <span style="color: #3399cc;">+=</span> <span style="color: #cccccc;">index_html;</span>
<span style="color: #cccccc;">s</span> <span style="color: #3399cc;">+=</span> <span style="color: #cd0000;">"\n"</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">client.print(s);</span>
<span style="color: #cccccc;">client.stop();</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cdcd00;">else</span> <span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(req</span> <span style="color: #3399cc;">==</span> <span style="color: #cd0000;">"/video"</span><span style="color: #cccccc;">)</span>
<span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">live_client</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">client;</span>
<span style="color: #cccccc;">live_client.print(</span><span style="color: #cd0000;">"HTTP/1.1 200 OK\n"</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">live_client.print(</span><span style="color: #cd0000;">"Content-Type: multipart/x-mixed-replace; boundary=frame\n\n"</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">live_client.flush();</span>
<span style="color: #cccccc;">connected</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">true</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cdcd00;">else</span>
<span style="color: #cccccc;">{</span>
<span style="color: navy;">/* if we can not find the page that client request then we return 404 File not found */</span>
<span style="color: #cccccc;">s</span> <span style="color: #3399cc;">=</span> <span style="color: #cd0000;">"HTTP/1.1 404 Not Found\n\n"</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">client.print(s);</span>
<span style="color: #cccccc;">client.stop();</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">loop()</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">http_resp();</span>
<span style="color: #cdcd00;">if</span><span style="color: #cccccc;">(connected</span> <span style="color: #3399cc;">==</span> <span style="color: #cd00cd;">true</span><span style="color: #cccccc;">){</span>
<span style="color: #cccccc;">liveCam(live_client);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
</pre>
</div>
<b>3.2 Bring it to the world</b><br />
In order to bring it to the world, we have to use <a href="https://ngrok.com/">ngrok</a><b><a href="https://ngrok.com/"> </a></b><br />
Steps to setup ngrok:<br />
- Signup an account<br />
- Copy your Authtoken <a href="https://dashboard.ngrok.com/auth">here</a><br />
- Download ngrok application <a href="https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip">here</a> (I am using ubuntu, download it according to your OS)<br />
- Unzip downloaded file, you will see ngrok application<br />
- Open Terminal in the folder that contains ngrok app and run command:<br />
<i>"./ngrok authtoken your_copied_authtoken"</i><br />
- Bring your esp32 web server to the world using command <br />
<i>"./ngrok http ip_of_esp32_webserver:80"</i><br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-EakPVwFJw1c/XoCJ2CgfcpI/AAAAAAAAMYE/1vD6n37_0lEFnN-kBhs-zPUGrsGu-f_EACLcBGAsYHQ/s1600/ws6.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="231" data-original-width="726" height="126" src="https://1.bp.blogspot.com/-EakPVwFJw1c/XoCJ2CgfcpI/AAAAAAAAMYE/1vD6n37_0lEFnN-kBhs-zPUGrsGu-f_EACLcBGAsYHQ/s400/ws6.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: ngrok output </b></div>
From the ngrok output, your public domain from ngrok will be: <b><i>http://e059707c.ngrok.io</i><i> </i></b><br />
Open web browser and type the domain <b><b><i>http://e059707c.ngrok.io</i></b></b><br />
<b>4. Result</b><br />
The display is not really smooth.<br /><b></b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-2w7zQGyQ1Rs/XoAv4-7iV1I/AAAAAAAAMWs/y-rRU_61Xu04C9R90FvZuJHHXsneJqtvwCEwYBhgLKskDAMBZVoBKTKNiKUhlOR8iVIa-lY4K8EnV2HwpytXjnqapNUnIGSVPhylWLPNAZfrWzJqVuyB9cNfpYSpaBV9cApsf3Cg0K3BSQnXrqbE5IPZlv3RUM6Ku7MrBxF3qdgeJWuJ7ME_abrYIYjvC0cpLTwV0hW3WYNc_H42PqSl8bOz8GWKixjLz2WoG76SXhKcJjUY8VewlB1T-8bwZ2BKBNZX0XpP6OU7L83kUEYOvxDtqOQy3ED2FhxipwuZ5V2sKjpJmz39qr2JhaFBEeIX--aCt4yrYD7Y9XvhM9unSOzH5UswQFmm1Ju3LDcw2xS7tXzPnm433WP-JkSCfObNTKGGBD6vd0OAyKgW0aWWOfHpg0a7xIg48NiwV01BgEndQ3WEFXtHv1DPuISCRtU3MJd_2F-cwCvmvueRlq5Pds1DvzrW4P4QSZ-8zQEIxH6WLyP80BQmgvSujT__Q0apF-gNntz33sp9v8U5IznWKZ_3ksXQVPi3WeyeRrjFfHbv-1Mpnwy0Fctb-b-6yzhOehNXtur0Ho5RUcyFAFDHcRU6doeUHdLsXQpY9-iXGIxB6UgNsykL7vr1bTRr5u8RlAhiIx7ClpPM-4TDpi4L0BQ/s1600/ws5.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="271" data-original-width="710" height="152" src="https://1.bp.blogspot.com/-2w7zQGyQ1Rs/XoAv4-7iV1I/AAAAAAAAMWs/y-rRU_61Xu04C9R90FvZuJHHXsneJqtvwCEwYBhgLKskDAMBZVoBKTKNiKUhlOR8iVIa-lY4K8EnV2HwpytXjnqapNUnIGSVPhylWLPNAZfrWzJqVuyB9cNfpYSpaBV9cApsf3Cg0K3BSQnXrqbE5IPZlv3RUM6Ku7MrBxF3qdgeJWuJ7ME_abrYIYjvC0cpLTwV0hW3WYNc_H42PqSl8bOz8GWKixjLz2WoG76SXhKcJjUY8VewlB1T-8bwZ2BKBNZX0XpP6OU7L83kUEYOvxDtqOQy3ED2FhxipwuZ5V2sKjpJmz39qr2JhaFBEeIX--aCt4yrYD7Y9XvhM9unSOzH5UswQFmm1Ju3LDcw2xS7tXzPnm433WP-JkSCfObNTKGGBD6vd0OAyKgW0aWWOfHpg0a7xIg48NiwV01BgEndQ3WEFXtHv1DPuISCRtU3MJd_2F-cwCvmvueRlq5Pds1DvzrW4P4QSZ-8zQEIxH6WLyP80BQmgvSujT__Q0apF-gNntz33sp9v8U5IznWKZ_3ksXQVPi3WeyeRrjFfHbv-1Mpnwy0Fctb-b-6yzhOehNXtur0Ho5RUcyFAFDHcRU6doeUHdLsXQpY9-iXGIxB6UgNsykL7vr1bTRr5u8RlAhiIx7ClpPM-4TDpi4L0BQ/s400/ws5.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/jwfu2qV9Ss4/0.jpg" frameborder="0" height="320" src="https://www.youtube.com/embed/jwfu2qV9Ss4?feature=player_embedded" width="480"></iframe></div>
<br /></div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com1tag:blogger.com,1999:blog-7549705215513488945.post-75183254292441457282020-03-28T22:25:00.004-07:002021-11-05T22:38:39.472-07:00Demo 48: ESP32 WebSocket for camera live stream<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
In this demo, I will show you how to make a camera live stream application with ESP32 Cam.<br />
<b>1.1 Problems of HTTP</b><br />
- Request/Response<br />
- Stateless<br />
- Half duplex protocol<br />
The web client sends request to web server, the web server send response and the connection close. If the the client want to know a continuous state change on the
server, It has to send a request to server every specific time to get the state change on the server. this is polling. It is inefficient and waste resources<br />
<b>1.2 WebSocket</b><br />
In order to solve the problems of HTTP, WebSocket was born. It is:<br />
- Based on the TCP protocol<br />
- Uses the HTTP protocol on the handshake phase<br />
- The protocol identifier is ws (ws://iotsharing.com:80/)<br />
- After the connection is established, it will be keep alive. So client and server can send messages to each other. It is full duplex protocol.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6UEH_1IQtFe76h-yljvvkeuanPSPtbP5olEMFD34vqyukBD9ypUcRvaMrE0HweNB6B7bOZXZi3K06-gGn7CT6xsVxowXqDNhsb4bPUCya5Ur4le01VS1oP19Q9kN9hvlZSO_rhl6sBzQ/s1600/ws01.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="511" data-original-width="628" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6UEH_1IQtFe76h-yljvvkeuanPSPtbP5olEMFD34vqyukBD9ypUcRvaMrE0HweNB6B7bOZXZi3K06-gGn7CT6xsVxowXqDNhsb4bPUCya5Ur4le01VS1oP19Q9kN9hvlZSO_rhl6sBzQ/s400/ws01.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: HTTP vs WebSocket (<a href="https://www.tutorialdocs.com/article/websocket-tutorial-in-10-minutes.html">source</a>)</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-PlDRGQsH8wg/XnzGPLZurBI/AAAAAAAAMVw/hL0kRPPSPrUVf3qfpBq7vUlc3XuJ7g_awCLcBGAsYHQ/s1600/ws02.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="837" data-original-width="929" height="288" src="https://1.bp.blogspot.com/-PlDRGQsH8wg/XnzGPLZurBI/AAAAAAAAMVw/hL0kRPPSPrUVf3qfpBq7vUlc3XuJ7g_awCLcBGAsYHQ/s320/ws02.png" width="320" /></a></div>
<div style="text-align: center;">
<b>Figure: WebSocket protocol</b></div>
<b>2. Hardware</b><br />
I used the camera module:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL8EBlS2RxqkFuwLWcoMzk-8OQMfeG6TwS2oclVcuK6f_FjQrx5rvsFSb8jBMy3BFXjr5ay7IyuYkIBwdKV_UIkwgwgDLO1-NUEQlS20D6llwaPizYSu7z52bdUkwzE3xN1RGAzacuShk/s1600/ws3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="307" data-original-width="360" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL8EBlS2RxqkFuwLWcoMzk-8OQMfeG6TwS2oclVcuK6f_FjQrx5rvsFSb8jBMy3BFXjr5ay7IyuYkIBwdKV_UIkwgwgDLO1-NUEQlS20D6llwaPizYSu7z52bdUkwzE3xN1RGAzacuShk/s320/ws3.png" width="320" /></a></div>
<div style="text-align: center;">
<b>Figure: ESP32 CAM with OV2640 cam</b></div>
<b>3. Software </b><br />
<b>3.1 WebSocket Server for ESP32</b><br />
We will use this WebSocket <a href="https://github.com/Links2004/arduinoWebSockets">library</a>. We will make a simple demo to get familiar with it. In this demo ESP32 will act as a WebSocket server, it will send the HTTP index page to web browser client (follow <a href="http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html">Demo 12</a>). After loaded the index page, a javascript using jquery will create a WebSocket client that connects to WebSocket server. On server a counter will continuously sending counter value to client and display this value to web browser.<br />
<b>Note</b>: we have 2 servers: simple HTTP Web server (follow <a href="http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html">Demo 12</a>) and WebSocket server. <br />
<div style="background: rgb(0, 0, 0); border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0px;"><span style="color: navy;">#include <WiFi.h></span>
<span style="color: navy;">#include <WebSocketsServer.h></span>
<span style="color: #cccccc;">WebSocketsServer</span> <span style="color: #cccccc;">webSocket</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">WebSocketsServer(</span><span style="color: #cd00cd;">81</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">WiFiServer</span> <span style="color: #cccccc;">server(</span><span style="color: #cd00cd;">80</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">String</span> <span style="color: #cccccc;">index_html</span> <span style="color: #3399cc;">=</span> <span style="color: #cd0000;">"<html>\n \</span>
<span style="color: #cd0000;"><head>\n \</span>
<span style="color: #cd0000;"><title> WebSockets Client</title>\n \</span>
<span style="color: #cd0000;"><script src='http://code.jquery.com/jquery-1.9.1.min.js'></script>\n \</span>
<span style="color: #cd0000;"></head>\n \</span>
<span style="color: #cd0000;"><body>\n \</span>
<span style="color: #cd0000;"><div id='output'></div>\n \</span>
<span style="color: #cd0000;"></body>\n \</span>
<span style="color: #cd0000;"></html>\n \</span>
<span style="color: #cd0000;"><script>\n \</span>
<span style="color: #cd0000;">jQuery(function($){\n \</span>
<span style="color: #cd0000;">if (!('WebSocket' in window)) {\n \</span>
<span style="color: #cd0000;">alert('Your browser does not support web sockets');\n \</span>
<span style="color: #cd0000;">}else{\n \</span>
<span style="color: #cd0000;">setup();\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">function setup(){\n \</span>
<span style="color: #cd0000;">var host = 'ws://server_ip:81';\n \</span>
<span style="color: #cd0000;">var socket = new WebSocket(host);\n \</span>
<span style="color: #cd0000;">if(socket){\n \</span>
<span style="color: #cd0000;">socket.onopen = function(){\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">socket.onmessage = function(msg){\n \</span>
<span style="color: #cd0000;">showServerResponse(msg.data);\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">socket.onclose = function(){\n \</span>
<span style="color: #cd0000;">showServerResponse('The connection has been closed.');\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">function showServerResponse(txt){\n \</span>
<span style="color: #cd0000;">document.getElementById('output').innerHTML = txt;\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">});\n \</span>
<span style="color: #cd0000;"></script>"</span><span style="color: #cccccc;">;</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">hexdump(</span><span style="color: #cdcd00;">const</span> <span style="color: #00cd00;">void</span> <span style="color: #3399cc;">*</span><span style="color: #cccccc;">mem,</span> <span style="color: #00cd00;">uint32_t</span> <span style="color: #cccccc;">len,</span> <span style="color: #00cd00;">uint8_t</span> <span style="color: #cccccc;">cols</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">16</span><span style="color: #cccccc;">)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cdcd00;">const</span> <span style="color: #00cd00;">uint8_t</span><span style="color: #3399cc;">*</span> <span style="color: #cccccc;">src</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">(</span><span style="color: #cdcd00;">const</span> <span style="color: #00cd00;">uint8_t</span><span style="color: #3399cc;">*</span><span style="color: #cccccc;">)</span> <span style="color: #cccccc;">mem;</span>
<span style="color: #cccccc;">Serial.printf(</span><span style="color: #cd0000;">"\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">(</span><span style="color: #00cd00;">ptrdiff_t</span><span style="color: #cccccc;">)src,</span> <span style="color: #cccccc;">len,</span> <span style="color: #cccccc;">len);</span>
<span style="color: #cdcd00;">for</span><span style="color: #cccccc;">(</span><span style="color: #00cd00;">uint32_t</span> <span style="color: #cccccc;">i</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">0</span><span style="color: #cccccc;">;</span> <span style="color: #cccccc;">i</span> <span style="color: #3399cc;"><</span> <span style="color: #cccccc;">len;</span> <span style="color: #cccccc;">i</span><span style="color: #3399cc;">++</span><span style="color: #cccccc;">)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cdcd00;">if</span><span style="color: #cccccc;">(i</span> <span style="color: #3399cc;">%</span> <span style="color: #cccccc;">cols</span> <span style="color: #3399cc;">==</span> <span style="color: #cd00cd;">0</span><span style="color: #cccccc;">)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.printf(</span><span style="color: #cd0000;">"\n[0x%08X] 0x%08X: "</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">(</span><span style="color: #00cd00;">ptrdiff_t</span><span style="color: #cccccc;">)src,</span> <span style="color: #cccccc;">i);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">Serial.printf(</span><span style="color: #cd0000;">"%02X "</span><span style="color: #cccccc;">,</span> <span style="color: #3399cc;">*</span><span style="color: #cccccc;">src);</span>
<span style="color: #cccccc;">src</span><span style="color: #3399cc;">++</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">Serial.printf(</span><span style="color: #cd0000;">"\n"</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">webSocketEvent(</span><span style="color: #00cd00;">uint8_t</span> <span style="color: #cccccc;">num,</span> <span style="color: #cccccc;">WStype_t</span> <span style="color: #cccccc;">type,</span> <span style="color: #00cd00;">uint8_t</span> <span style="color: #3399cc;">*</span> <span style="color: #cccccc;">payload,</span> <span style="color: #00cd00;">size_t</span> <span style="color: #cccccc;">length)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cdcd00;">switch</span><span style="color: #cccccc;">(type)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_DISCONNECTED</span>:
<span style="color: #cccccc;">Serial.printf(</span><span style="color: #cd0000;">"[%u] Disconnected!\n"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">num);</span>
<span style="color: #cdcd00;">break</span><span style="color: #cccccc;">;</span>
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_CONNECTED</span>:
<span style="color: #cccccc;">{</span>
<span style="color: #00cd00;">int</span> <span style="color: #cccccc;">counter</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">0</span><span style="color: #cccccc;">;</span>
<span style="color: #cdcd00;">while</span><span style="color: #cccccc;">(</span><span style="color: #cd00cd;">true</span><span style="color: #cccccc;">){</span>
<span style="color: #cccccc;">counter</span><span style="color: #3399cc;">++</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">String</span> <span style="color: #cccccc;">n</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">String(counter);</span>
<span style="color: #cccccc;">webSocket.sendTXT(num,</span> <span style="color: #cccccc;">n);</span>
<span style="color: #cccccc;">delay(</span><span style="color: #cd00cd;">1000</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cdcd00;">break</span><span style="color: #cccccc;">;</span>
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_TEXT</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_BIN</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_ERROR</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_FRAGMENT_TEXT_START</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_FRAGMENT_BIN_START</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_FRAGMENT</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_FRAGMENT_FIN</span>:
<span style="color: #cdcd00;">break</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">setup()</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.begin(</span><span style="color: #cd00cd;">115200</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">WiFi.begin(</span><span style="color: #cd0000;">"I3.41"</span><span style="color: #cccccc;">,</span> <span style="color: #cd0000;">"xxx"</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">""</span><span style="color: #cccccc;">);</span>
<span style="color: #cdcd00;">while</span> <span style="color: #cccccc;">(WiFi.status()</span> <span style="color: #3399cc;">!=</span> <span style="color: #cccccc;">WL_CONNECTED)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">delay(</span><span style="color: #cd00cd;">500</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">Serial.print(</span><span style="color: #cd0000;">"."</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">""</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">String</span> <span style="color: #cccccc;">IP</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">WiFi.localIP().toString();</span>
<span style="color: #cccccc;">Serial.print(</span><span style="color: #cd0000;">"IP address: "</span> <span style="color: #3399cc;">+</span> <span style="color: #cccccc;">IP);</span>
<span style="color: #cccccc;">index_html.replace(</span><span style="color: #cd0000;">"server_ip"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">IP);</span>
<span style="color: #cccccc;">server.begin();</span>
<span style="color: #cccccc;">webSocket.begin();</span>
<span style="color: #cccccc;">webSocket.onEvent(webSocketEvent);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">http_resp(){</span>
<span style="color: #cccccc;">WiFiClient</span> <span style="color: #cccccc;">client</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">server.available();</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(client.connected()</span> <span style="color: #3399cc;">&&</span> <span style="color: #cccccc;">client.available())</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">client.flush();</span>
<span style="color: #cccccc;">client.print(index_html);</span>
<span style="color: #cccccc;">client.stop();</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">loop()</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">http_resp();</span>
<span style="color: #cccccc;">webSocket.loop();</span>
<span style="color: #cccccc;">}</span>
</pre>
</div>
This library will catch some event from WebSocket. We will use CONNECTED event to send counter value to web browser.<br />
<b>3.2 Camera driver</b><br />
The driver for OV2640 cam is available with ESP32 Arduino, you need to configure pins definitions, pixel_format, frame_size and jpeg_quality for camera then you can use it.<br />
<div style="background: rgb(0, 0, 0); border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0px;"><span style="color: navy;">#define PWDN_GPIO_NUM 32</span>
<span style="color: navy;">#define RESET_GPIO_NUM -1</span>
<span style="color: navy;">#define XCLK_GPIO_NUM 0</span>
<span style="color: navy;">#define SIOD_GPIO_NUM 26</span>
<span style="color: navy;">#define SIOC_GPIO_NUM 27</span>
<span style="color: navy;">#define Y9_GPIO_NUM 35</span>
<span style="color: navy;">#define Y8_GPIO_NUM 34</span>
<span style="color: navy;">#define Y7_GPIO_NUM 39</span>
<span style="color: navy;">#define Y6_GPIO_NUM 36</span>
<span style="color: navy;">#define Y5_GPIO_NUM 21</span>
<span style="color: navy;">#define Y4_GPIO_NUM 19</span>
<span style="color: navy;">#define Y3_GPIO_NUM 18</span>
<span style="color: navy;">#define Y2_GPIO_NUM 5</span>
<span style="color: navy;">#define VSYNC_GPIO_NUM 25</span>
<span style="color: navy;">#define HREF_GPIO_NUM 23</span>
<span style="color: navy;">#define PCLK_GPIO_NUM 22</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">configCamera(){</span>
<span style="color: #00cd00;">camera_config_t</span> <span style="color: #cccccc;">config;</span>
<span style="color: #cccccc;">config.ledc_channel</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">LEDC_CHANNEL_0;</span>
<span style="color: #cccccc;">config.ledc_timer</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">LEDC_TIMER_0;</span>
<span style="color: #cccccc;">config.pin_d0</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y2_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d1</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y3_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d2</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y4_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d3</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y5_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d4</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y6_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d5</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y7_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d6</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y8_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d7</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y9_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_xclk</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">XCLK_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_pclk</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">PCLK_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_vsync</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">VSYNC_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_href</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">HREF_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_sscb_sda</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">SIOD_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_sscb_scl</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">SIOC_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_pwdn</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">PWDN_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_reset</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">RESET_GPIO_NUM;</span>
<span style="color: #cccccc;">config.xclk_freq_hz</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">20000000</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">config.pixel_format</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">PIXFORMAT_JPEG;</span>
<span style="color: #cccccc;">config.frame_size</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">FRAMESIZE_QVGA;</span>
<span style="color: #cccccc;">config.jpeg_quality</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">9</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">config.fb_count</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">1</span><span style="color: #cccccc;">;</span>
<span style="color: #00cd00;">esp_err_t</span> <span style="color: #cccccc;">err</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">esp_camera_init(</span><span style="color: #3399cc;">&</span><span style="color: #cccccc;">config);</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(err</span> <span style="color: #3399cc;">!=</span> <span style="color: #cccccc;">ESP_OK)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.printf(</span><span style="color: #cd0000;">"Camera init failed with error 0x%x"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">err);</span>
<span style="color: #cdcd00;">return</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
</pre>
</div>
<b>3.3 Combine WebSocket vs Camera</b><br />
When WebSocket client connected to WebSocket server we start streaming the camera to client using sendBIN(). This function sends camera frame buffer to client. At client side we need to convert this buffer stream to base64 so that it can be displayed to <img /> tag of HTML.<br />
<div style="background: rgb(0, 0, 0); border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0px;">img.src = 'data:image/jpg;base64,'+window.btoa(binary);
</pre>
</div>
The full code:<br />
<div style="background: rgb(0, 0, 0); border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0px;"><span style="color: navy;">#include "esp_camera.h"</span>
<span style="color: navy;">#include <WiFi.h></span>
<span style="color: navy;">#include <WebSocketsServer.h></span>
<span style="color: navy;">#define PWDN_GPIO_NUM 32</span>
<span style="color: navy;">#define RESET_GPIO_NUM -1</span>
<span style="color: navy;">#define XCLK_GPIO_NUM 0</span>
<span style="color: navy;">#define SIOD_GPIO_NUM 26</span>
<span style="color: navy;">#define SIOC_GPIO_NUM 27</span>
<span style="color: navy;">#define Y9_GPIO_NUM 35</span>
<span style="color: navy;">#define Y8_GPIO_NUM 34</span>
<span style="color: navy;">#define Y7_GPIO_NUM 39</span>
<span style="color: navy;">#define Y6_GPIO_NUM 36</span>
<span style="color: navy;">#define Y5_GPIO_NUM 21</span>
<span style="color: navy;">#define Y4_GPIO_NUM 19</span>
<span style="color: navy;">#define Y3_GPIO_NUM 18</span>
<span style="color: navy;">#define Y2_GPIO_NUM 5</span>
<span style="color: navy;">#define VSYNC_GPIO_NUM 25</span>
<span style="color: navy;">#define HREF_GPIO_NUM 23</span>
<span style="color: navy;">#define PCLK_GPIO_NUM 22</span>
<span style="color: #cccccc;">WebSocketsServer</span> <span style="color: #cccccc;">webSocket</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">WebSocketsServer(</span><span style="color: #cd00cd;">81</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">WiFiServer</span> <span style="color: #cccccc;">server(</span><span style="color: #cd00cd;">80</span><span style="color: #cccccc;">);</span>
<span style="color: #00cd00;">uint8_t</span> <span style="color: #cccccc;">cam_num;</span>
<span style="color: #00cd00;">bool</span> <span style="color: #cccccc;">connected</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">false</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">String</span> <span style="color: #cccccc;">index_html</span> <span style="color: #3399cc;">=</span> <span style="color: #cd0000;">"<html>\n \</span>
<span style="color: #cd0000;"><head>\n \</span>
<span style="color: #cd0000;"><title> WebSockets Client</title>\n \</span>
<span style="color: #cd0000;"><script src='http://code.jquery.com/jquery-1.9.1.min.js'></script>\n \</span>
<span style="color: #cd0000;"></head>\n \</span>
<span style="color: #cd0000;"><body>\n \</span>
<span style="color: #cd0000;"><img id='live' src=''>\n \</span>
<span style="color: #cd0000;"></body>\n \</span>
<span style="color: #cd0000;"></html>\n \</span>
<span style="color: #cd0000;"><script>\n \</span>
<span style="color: #cd0000;">jQuery(function($){\n \</span>
<span style="color: #cd0000;">if (!('WebSocket' in window)) {\n \</span>
<span style="color: #cd0000;">alert('Your browser does not support web sockets');\n \</span>
<span style="color: #cd0000;">}else{\n \</span>
<span style="color: #cd0000;">setup();\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">function setup(){\n \</span>
<span style="color: #cd0000;">var host = 'ws://server_ip:81';\n \</span>
<span style="color: #cd0000;">var socket = new WebSocket(host);\n \</span>
<span style="color: #cd0000;">socket.binaryType = 'arraybuffer';\n \</span>
<span style="color: #cd0000;">if(socket){\n \</span>
<span style="color: #cd0000;">socket.onopen = function(){\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">socket.onmessage = function(msg){\n \</span>
<span style="color: #cd0000;">var bytes = new Uint8Array(msg.data);\n \</span>
<span style="color: #cd0000;">var binary= '';\n \</span>
<span style="color: #cd0000;">var len = bytes.byteLength;\n \</span>
<span style="color: #cd0000;">for (var i = 0; i < len; i++) {\n \</span>
<span style="color: #cd0000;">binary += String.fromCharCode(bytes[i])\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">var img = document.getElementById('live');\n \</span>
<span style="color: #cd0000;">img.src = 'data:image/jpg;base64,'+window.btoa(binary);\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">socket.onclose = function(){\n \</span>
<span style="color: #cd0000;">showServerResponse('The connection has been closed.');\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">}\n \</span>
<span style="color: #cd0000;">});\n \</span>
<span style="color: #cd0000;"></script>"</span><span style="color: #cccccc;">;</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">configCamera(){</span>
<span style="color: #00cd00;">camera_config_t</span> <span style="color: #cccccc;">config;</span>
<span style="color: #cccccc;">config.ledc_channel</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">LEDC_CHANNEL_0;</span>
<span style="color: #cccccc;">config.ledc_timer</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">LEDC_TIMER_0;</span>
<span style="color: #cccccc;">config.pin_d0</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y2_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d1</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y3_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d2</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y4_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d3</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y5_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d4</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y6_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d5</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y7_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d6</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y8_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_d7</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">Y9_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_xclk</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">XCLK_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_pclk</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">PCLK_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_vsync</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">VSYNC_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_href</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">HREF_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_sscb_sda</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">SIOD_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_sscb_scl</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">SIOC_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_pwdn</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">PWDN_GPIO_NUM;</span>
<span style="color: #cccccc;">config.pin_reset</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">RESET_GPIO_NUM;</span>
<span style="color: #cccccc;">config.xclk_freq_hz</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">20000000</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">config.pixel_format</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">PIXFORMAT_JPEG;</span>
<span style="color: #cccccc;">config.frame_size</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">FRAMESIZE_QVGA;</span>
<span style="color: #cccccc;">config.jpeg_quality</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">9</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">config.fb_count</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">1</span><span style="color: #cccccc;">;</span>
<span style="color: #00cd00;">esp_err_t</span> <span style="color: #cccccc;">err</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">esp_camera_init(</span><span style="color: #3399cc;">&</span><span style="color: #cccccc;">config);</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(err</span> <span style="color: #3399cc;">!=</span> <span style="color: #cccccc;">ESP_OK)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.printf(</span><span style="color: #cd0000;">"Camera init failed with error 0x%x"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">err);</span>
<span style="color: #cdcd00;">return</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">liveCam(</span><span style="color: #00cd00;">uint8_t</span> <span style="color: #cccccc;">num){</span>
<span style="color: navy;">//capture a frame</span>
<span style="color: #00cd00;">camera_fb_t</span> <span style="color: #3399cc;">*</span> <span style="color: #cccccc;">fb</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">esp_camera_fb_get();</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(</span><span style="color: #3399cc;">!</span><span style="color: #cccccc;">fb)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">"Frame buffer could not be acquired"</span><span style="color: #cccccc;">);</span>
<span style="color: #cdcd00;">return</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: navy;">//replace this with your own function</span>
<span style="color: #cccccc;">webSocket.sendBIN(num,</span> <span style="color: #cccccc;">fb</span><span style="color: #3399cc;">-></span><span style="color: #cccccc;">buf,</span> <span style="color: #cccccc;">fb</span><span style="color: #3399cc;">-></span><span style="color: #cccccc;">len);</span>
<span style="color: navy;">//return the frame buffer back to be reused</span>
<span style="color: #cccccc;">esp_camera_fb_return(fb);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">webSocketEvent(</span><span style="color: #00cd00;">uint8_t</span> <span style="color: #cccccc;">num,</span> <span style="color: #cccccc;">WStype_t</span> <span style="color: #cccccc;">type,</span> <span style="color: #00cd00;">uint8_t</span> <span style="color: #3399cc;">*</span> <span style="color: #cccccc;">payload,</span> <span style="color: #00cd00;">size_t</span> <span style="color: #cccccc;">length)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cdcd00;">switch</span><span style="color: #cccccc;">(type)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_DISCONNECTED</span>:
<span style="color: #cccccc;">Serial.printf(</span><span style="color: #cd0000;">"[%u] Disconnected!\n"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">num);</span>
<span style="color: #cdcd00;">break</span><span style="color: #cccccc;">;</span>
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_CONNECTED</span>:
<span style="color: #cccccc;">cam_num</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">num;</span>
<span style="color: #cccccc;">connected</span> <span style="color: #3399cc;">=</span> <span style="color: #cd00cd;">true</span><span style="color: #cccccc;">;</span>
<span style="color: #cdcd00;">break</span><span style="color: #cccccc;">;</span>
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_TEXT</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_BIN</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_ERROR</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_FRAGMENT_TEXT_START</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_FRAGMENT_BIN_START</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_FRAGMENT</span>:
<span style="color: #cdcd00;">case</span> <span style="color: #cccccc;">WStype_FRAGMENT_FIN</span>:
<span style="color: #cdcd00;">break</span><span style="color: #cccccc;">;</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">setup()</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">Serial.begin(</span><span style="color: #cd00cd;">115200</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">WiFi.begin(</span><span style="color: #cd0000;">"I3.41"</span><span style="color: #cccccc;">,</span> <span style="color: #cd0000;">"xxx"</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">""</span><span style="color: #cccccc;">);</span>
<span style="color: #cdcd00;">while</span> <span style="color: #cccccc;">(WiFi.status()</span> <span style="color: #3399cc;">!=</span> <span style="color: #cccccc;">WL_CONNECTED)</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">delay(</span><span style="color: #cd00cd;">500</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">Serial.print(</span><span style="color: #cd0000;">"."</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">Serial.println(</span><span style="color: #cd0000;">""</span><span style="color: #cccccc;">);</span>
<span style="color: #cccccc;">String</span> <span style="color: #cccccc;">IP</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">WiFi.localIP().toString();</span>
<span style="color: #cccccc;">Serial.print(</span><span style="color: #cd0000;">"IP address: "</span> <span style="color: #3399cc;">+</span> <span style="color: #cccccc;">IP);</span>
<span style="color: #cccccc;">index_html.replace(</span><span style="color: #cd0000;">"server_ip"</span><span style="color: #cccccc;">,</span> <span style="color: #cccccc;">IP);</span>
<span style="color: #cccccc;">server.begin();</span>
<span style="color: #cccccc;">webSocket.begin();</span>
<span style="color: #cccccc;">webSocket.onEvent(webSocketEvent);</span>
<span style="color: #cccccc;">configCamera();</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">http_resp(){</span>
<span style="color: #cccccc;">WiFiClient</span> <span style="color: #cccccc;">client</span> <span style="color: #3399cc;">=</span> <span style="color: #cccccc;">server.available();</span>
<span style="color: #cdcd00;">if</span> <span style="color: #cccccc;">(client.connected()</span> <span style="color: #3399cc;">&&</span> <span style="color: #cccccc;">client.available())</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">client.flush();</span>
<span style="color: #cccccc;">client.print(index_html);</span>
<span style="color: #cccccc;">client.stop();</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
<span style="color: #00cd00;">void</span> <span style="color: #cccccc;">loop()</span> <span style="color: #cccccc;">{</span>
<span style="color: #cccccc;">http_resp();</span>
<span style="color: #cccccc;">webSocket.loop();</span>
<span style="color: #cdcd00;">if</span><span style="color: #cccccc;">(connected</span> <span style="color: #3399cc;">==</span> <span style="color: #cd00cd;">true</span><span style="color: #cccccc;">){</span>
<span style="color: #cccccc;">liveCam(cam_num);</span>
<span style="color: #cccccc;">}</span>
<span style="color: #cccccc;">}</span>
</pre>
</div>
<b>4. Result</b><br />
The display frame is not really smooth.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-2w7zQGyQ1Rs/XoAv4-7iV1I/AAAAAAAAMWk/axYhfPp78vMSEVyy-UuN-jF3jVAumaI3QCLcBGAsYHQ/s1600/ws5.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="271" data-original-width="710" height="152" src="https://1.bp.blogspot.com/-2w7zQGyQ1Rs/XoAv4-7iV1I/AAAAAAAAMWk/axYhfPp78vMSEVyy-UuN-jF3jVAumaI3QCLcBGAsYHQ/s400/ws5.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/syk4g0fLmbE/0.jpg" frameborder="0" height="320" src="https://www.youtube.com/embed/syk4g0fLmbE?feature=player_embedded" width="480"></iframe></div>
<b> </b></div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com6tag:blogger.com,1999:blog-7549705215513488945.post-89438309871311033582019-07-03T07:03:00.002-07:002020-06-29T01:38:52.604-07:00Demo 45: Copy data from/to SPIFFS without using mkspiffs (web file server)<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
This tutorial assumed that you are familiar with SPIFFS Filesystem (a file system intended for SPI NOR flash devices on embedded targets).<br />
If you want to store small data, you can use SPIFFS instead of sdcard module.<br />
In order to use sdcard module, refer <a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html">Demo 7: How to use Arduino ESP32 to store data to sdcard</a> <br />
If you are using SPIFFS, you may face the inconvenient situation that you want to copy data from/to SPIFFS. You have to install <a href="https://github.com/me-no-dev/arduino-esp32fs-plugin/releases/">ESP32FS</a> as a plugin of Arduino-version following steps:<br />
+ Download the ESP32FS-x.x.zip at the <a href="https://github.com/me-no-dev/arduino-esp32fs-plugin/releases/">link</a>.<br />
+ Unzip and copy unziped folder to "where_to_installed_Arduino/tools/"<br />
then it will become <b>"where_to_installed_Arduino/tools/ESP32FS/tool/esp32fs.jar"</b><br />
+ Create a Sketch project named "xyz". A folder named "xyz" will be created.<br />
+ Create a folder named "<b>data</b>" and copied the files that you want to copy to SPIFFS into "<b>data</b>" folder.<br />
+ From Arduino menu, choose <b>Tools > ESP32 Sketch Data Upload</b><br />
<b>Note: </b>when copying files to SPIFFS, keep pressing the Boot button on ESP module.<br />
This tutorial will help you to copy files from/to (2 directions) SPIFFS easier.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-LNWNyvygMs4/XRwqj6KTJ_I/AAAAAAAAKd4/KP5Rh8MPEWgF-mROdHz6FBNCwvyXr-DagCLcBGAs/s1600/spiffs.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="387" data-original-width="468" height="330" src="https://1.bp.blogspot.com/-LNWNyvygMs4/XRwqj6KTJ_I/AAAAAAAAKd4/KP5Rh8MPEWgF-mROdHz6FBNCwvyXr-DagCLcBGAs/s400/spiffs.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: copy files to/from SPIFFS as Web File Server</b></div>
<b>2. Hardware</b><br />
You only need a ESP32 module.<br />
<b>3. Software</b><br />
I will use webserver to create a web file server.<br />
Please refer <a href="http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html">Demo 12: How to turn the Arduino ESP32 into a Web Server</a><br />
Here is the full source code with comments:<br />
<!--HTML generated using hilite.me--><br />
<div style="background: rgb(255, 255, 255) none repeat scroll 0% 0%; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188</pre>
</td><td><pre style="line-height: 125%; margin: 0px;"><span style="color: #557799;">#include <WiFiClient.h></span>
<span style="color: #557799;">#include <ESP32WebServer.h></span>
<span style="color: #557799;">#include <WiFi.h></span>
<span style="color: #557799;">#include <ESPmDNS.h></span>
<span style="color: #557799;">#include "FS.h"</span>
<span style="color: #557799;">#include "SPIFFS.h"</span>
String serverIndex <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"</span>
<span style="background-color: #5eeb34;">"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"</span>
<span style="background-color: #5eeb34;">"<input type='file' name='update'>"</span>
<span style="background-color: #5eeb34;">"<input type='submit' value='Upload'>"</span>
<span style="background-color: #5eeb34;">"</form>"</span>
<span style="background-color: #5eeb34;">"<div id='prg'>progress: 0%</div>"</span>
<span style="background-color: #5eeb34;">"<script>"</span>
<span style="background-color: #5eeb34;">"$('form').submit(function(e){"</span>
<span style="background-color: #5eeb34;">"e.preventDefault();"</span>
<span style="background-color: #5eeb34;">"var form = $('#upload_form')[0];"</span>
<span style="background-color: #5eeb34;">"var data = new FormData(form);"</span>
<span style="background-color: #5eeb34;">" $.ajax({"</span>
<span style="background-color: #5eeb34;">"url: '/update',"</span>
<span style="background-color: #5eeb34;">"type: 'POST',"</span>
<span style="background-color: #5eeb34;">"data: data,"</span>
<span style="background-color: #5eeb34;">"contentType: false,"</span>
<span style="background-color: #5eeb34;">"processData:false,"</span>
<span style="background-color: #5eeb34;">"xhr: function() {"</span>
<span style="background-color: #5eeb34;">"var xhr = new window.XMLHttpRequest();"</span>
<span style="background-color: #5eeb34;">"xhr.upload.addEventListener('progress', function(evt) {"</span>
<span style="background-color: #5eeb34;">"if (evt.lengthComputable) {"</span>
<span style="background-color: #5eeb34;">"var per = evt.loaded / evt.total;"</span>
<span style="background-color: #5eeb34;">"$('#prg').html('progress: ' + Math.round(per*100) + '%');"</span>
<span style="background-color: #5eeb34;">"}"</span>
<span style="background-color: #5eeb34;">"}, false);"</span>
<span style="background-color: #5eeb34;">"return xhr;"</span>
<span style="background-color: #5eeb34;">"},"</span>
<span style="background-color: #5eeb34;">"success:function(d, s) {"</span>
<span style="background-color: #5eeb34;">"console.log('success!')"</span>
<span style="background-color: #5eeb34;">"},"</span>
<span style="background-color: #5eeb34;">"error: function (a, b, c) {"</span>
<span style="background-color: #5eeb34;">"}"</span>
<span style="background-color: #5eeb34;">"});"</span>
<span style="background-color: #5eeb34;">"});"</span>
<span style="background-color: #5eeb34;">"</script>"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> ssid <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"707"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> password <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"0000000000"</span>;
<span style="color: #333399; font-weight: bold;">bool</span> opened <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
File file;
<span style="color: #557799;">#define FORMAT_SPIFFS_IF_FAILED true</span>
ESP32WebServer <span style="color: #0066bb; font-weight: bold;">server</span>(<span style="color: #0000dd; font-weight: bold;">80</span>);
String <span style="color: #0066bb; font-weight: bold;">listDir</span>(fs<span style="color: #333333;">::</span>FS <span style="color: #333333;">&</span>fs, <span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span> dirname, <span style="color: #333399; font-weight: bold;">uint8_t</span> levels){
String response <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">""</span>;
Serial.printf(<span style="background-color: #5eeb34;">"Listing directory: %s</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\r\n</span><span style="background-color: #5eeb34;">"</span>, dirname);
File root <span style="color: #333333;">=</span> fs.open(dirname);
<span style="color: #008800; font-weight: bold;">if</span>(<span style="color: #333333;">!</span>root){
Serial.println(<span style="background-color: #5eeb34;">"- failed to open directory"</span>);
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #5eeb34;">""</span>;
}
<span style="color: #008800; font-weight: bold;">if</span>(<span style="color: #333333;">!</span>root.isDirectory()){
Serial.println(<span style="background-color: #5eeb34;">" - not a directory"</span>);
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #5eeb34;">""</span>;
}
File file <span style="color: #333333;">=</span> root.openNextFile();
<span style="color: #008800; font-weight: bold;">while</span>(file){
<span style="color: #008800; font-weight: bold;">if</span>(file.isDirectory()){
Serial.print(<span style="background-color: #5eeb34;">" DIR : "</span>);
Serial.println(file.name());
<span style="color: #008800; font-weight: bold;">if</span>(levels){
listDir(fs, file.name(), levels <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>);
}
} <span style="color: #008800; font-weight: bold;">else</span> {
Serial.print(<span style="background-color: #5eeb34;">" FILE: "</span>);
Serial.print(file.name());
Serial.print(<span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\t</span><span style="background-color: #5eeb34;">SIZE: "</span>);
Serial.println(file.size());
response <span style="color: #333333;">+=</span> String(<span style="background-color: #5eeb34;">"<a href='"</span>) <span style="color: #333333;">+</span> String(file.name()) <span style="color: #333333;">+</span> String(<span style="background-color: #5eeb34;">"'>"</span>) <span style="color: #333333;">+</span> String(file.name()) <span style="color: #333333;">+</span> String(<span style="background-color: #5eeb34;">"</a>"</span>) <span style="color: #333333;">+</span> String(<span style="background-color: #5eeb34;">"</br>"</span>);
}
file <span style="color: #333333;">=</span> root.openNextFile();
}
<span style="color: #008800; font-weight: bold;">return</span> String(<span style="background-color: #5eeb34;">"List files:</br>"</span>) <span style="color: #333333;">+</span> response <span style="color: #333333;">+</span> String(<span style="background-color: #5eeb34;">"</br></br> Upload file:"</span>) <span style="color: #333333;">+</span> serverIndex;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">handleRoot</span>() {
String res <span style="color: #333333;">=</span> listDir(SPIFFS, <span style="background-color: #5eeb34;">"/"</span>, <span style="color: #0000dd; font-weight: bold;">0</span>);
server.send(<span style="color: #0000dd; font-weight: bold;">200</span>, <span style="background-color: #5eeb34;">"text/html"</span>, res);
}
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #0066bb; font-weight: bold;">loadFromSPIFFS</span>(String path){
String dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"text/plain"</span>;
<span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">"/"</span>)) path <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"index.htm"</span>;
<span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".src"</span>)) path <span style="color: #333333;">=</span> path.substring(<span style="color: #0000dd; font-weight: bold;">0</span>, path.lastIndexOf(<span style="background-color: #5eeb34;">"."</span>));
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".jpg"</span>)) dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"image/jpeg"</span>;
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".txt"</span>)) dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"text/plain"</span>;
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(path.endsWith(<span style="background-color: #5eeb34;">".zip"</span>)) dataType <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"application/zip"</span>;
File dataFile <span style="color: #333333;">=</span> SPIFFS.open(path.c_str());
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>dataFile)
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">false</span>;
<span style="color: #008800; font-weight: bold;">if</span> (server.streamFile(dataFile, dataType) <span style="color: #333333;">!=</span> dataFile.size()) {
Serial.println(<span style="background-color: #5eeb34;">"Sent less data than expected!"</span>);
}
dataFile.close();
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">true</span>;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">handleNotFound</span>(){
<span style="color: #008800; font-weight: bold;">if</span>(loadFromSPIFFS(server.uri())) <span style="color: #008800; font-weight: bold;">return</span>;
String message <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"SDCARD Not Detected</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n\n</span><span style="background-color: #5eeb34;">"</span>;
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"URI: "</span>;
message <span style="color: #333333;">+=</span> server.uri();
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">Method: "</span>;
message <span style="color: #333333;">+=</span> (server.method() <span style="color: #333333;">==</span> HTTP_GET)<span style="color: #333333;">?</span><span style="background-color: #5eeb34;">"GET"</span><span style="color: #333333;">:</span><span style="background-color: #5eeb34;">"POST"</span>;
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">Arguments: "</span>;
message <span style="color: #333333;">+=</span> server.args();
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">"</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">uint8_t</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>; i<span style="color: #333333;"><</span>server.args(); i<span style="color: #333333;">++</span>){
message <span style="color: #333333;">+=</span> <span style="background-color: #5eeb34;">" NAME:"</span><span style="color: #333333;">+</span>server.argName(i) <span style="color: #333333;">+</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;"> VALUE:"</span> <span style="color: #333333;">+</span> server.arg(i) <span style="color: #333333;">+</span> <span style="background-color: #5eeb34;">"</span><span style="background-color: #5eeb34; color: #666666; font-weight: bold;">\n</span><span style="background-color: #5eeb34;">"</span>;
}
server.send(<span style="color: #0000dd; font-weight: bold;">404</span>, <span style="background-color: #5eeb34;">"text/plain"</span>, message);
Serial.println(message);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>(<span style="color: #333399; font-weight: bold;">void</span>){
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
WiFi.begin(ssid, password);
Serial.println(<span style="background-color: #5eeb34;">""</span>);
<span style="color: #888888;">// Wait for connection</span>
<span style="color: #008800; font-weight: bold;">while</span> (WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED) {
delay(<span style="color: #0000dd; font-weight: bold;">500</span>);
Serial.print(<span style="background-color: #5eeb34;">"."</span>);
}
Serial.println(<span style="background-color: #5eeb34;">""</span>);
Serial.print(<span style="background-color: #5eeb34;">"Connected to "</span>);
Serial.println(ssid);
Serial.print(<span style="background-color: #5eeb34;">"IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #888888;">//use IP or iotsharing.local to access webserver</span>
<span style="color: #008800; font-weight: bold;">if</span> (MDNS.begin(<span style="background-color: #5eeb34;">"iotsharing"</span>)) {
Serial.println(<span style="background-color: #5eeb34;">"MDNS responder started"</span>);
}
<span style="color: #888888;">//init spiffs</span>
<span style="color: #008800; font-weight: bold;">if</span>(<span style="color: #333333;">!</span>SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){
Serial.println(<span style="background-color: #5eeb34;">"SPIFFS Mount Failed"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #888888;">//handle uri </span>
server.on(<span style="background-color: #5eeb34;">"/"</span>, handleRoot);
server.onNotFound(handleNotFound);
<span style="color: #888888;">/*handling uploading file */</span>
server.on(<span style="background-color: #5eeb34;">"/update"</span>, HTTP_POST, [](){
server.sendHeader(<span style="background-color: #5eeb34;">"Connection"</span>, <span style="background-color: #5eeb34;">"close"</span>);
opened <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
},[](){
HTTPUpload<span style="color: #333333;">&</span> upload <span style="color: #333333;">=</span> server.upload();
<span style="color: #008800; font-weight: bold;">if</span>(opened <span style="color: #333333;">==</span> <span style="color: #007020;">false</span>){
opened <span style="color: #333333;">=</span> <span style="color: #007020;">true</span>;
file <span style="color: #333333;">=</span> SPIFFS.open(String(<span style="background-color: #5eeb34;">"/"</span>) <span style="color: #333333;">+</span> upload.filename, FILE_WRITE);
<span style="color: #008800; font-weight: bold;">if</span>(<span style="color: #333333;">!</span>file){
Serial.println(<span style="background-color: #5eeb34;">"- failed to open file for writing"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
}
<span style="color: #008800; font-weight: bold;">if</span>(upload.status <span style="color: #333333;">==</span> UPLOAD_FILE_WRITE){
<span style="color: #008800; font-weight: bold;">if</span>(file.write(upload.buf, upload.currentSize) <span style="color: #333333;">!=</span> upload.currentSize){
Serial.println(<span style="background-color: #5eeb34;">"- failed to write"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(upload.status <span style="color: #333333;">==</span> UPLOAD_FILE_END){
opened <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
}
});
server.begin();
Serial.println(<span style="background-color: #5eeb34;">"HTTP server started"</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>(<span style="color: #333399; font-weight: bold;">void</span>){
server.handleClient();
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>4. Result</b></div>
<div class="separator" style="clear: both; text-align: left;">
Type "iotsharing.local" in web-browser you will see this.<b> </b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN4Gluo4ujf17b3uDR01g6eyNy5HVzg3FrTVeeJbTTPWG2FEiG0_ufr2bAo1EtmBDGj8-0o8KwQE7QTvCPjbs8R4fD0bsyCrZ-vOxjmrv6nu9XpxHs5O7QCTecuq9UpPkDf17aGPjDM3o/s1600/spiffs.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="362" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN4Gluo4ujf17b3uDR01g6eyNy5HVzg3FrTVeeJbTTPWG2FEiG0_ufr2bAo1EtmBDGj8-0o8KwQE7QTvCPjbs8R4fD0bsyCrZ-vOxjmrv6nu9XpxHs5O7QCTecuq9UpPkDf17aGPjDM3o/s400/spiffs.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: GUI of demo</b></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/KTEFiHIlzJ4/0.jpg" frameborder="0" height="320" src="https://www.youtube.com/embed/KTEFiHIlzJ4?feature=player_embedded" width="480"></iframe></div>
<br /></div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com2tag:blogger.com,1999:blog-7549705215513488945.post-75520051054535872122019-06-29T07:33:00.000-07:002020-01-16T00:17:37.986-08:00Demo 44: Play "Happy Birthday" by ESP with Sigma-delta Modulation<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
In this post, we will play "Happy Birthday" melody by ESP with Sigma-delta Modulation. Actually, you can use "digitalWrite" but Sigma-delta Modulation make the output smoother.<br />
The mechanism to play melody you can find <a href="https://www.arduino.cc/en/tutorial/melody">here</a>.<br />
<b>2. Hardware</b><br />
<div class="separator" style="clear: both; text-align: left;">
We will use cheap <span style="text-align: center;">Audio Power Amplifier </span><span style="text-align: center;">LM386 to aplify the melody.</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBgHAlCYmtL-N7jPrf3CRykBNyXBRGVLdh1WrgkFbg5-GfbAoNkjO9KqlBuH10cUQvwY_zW0HD4vq5Nwec8NHhVcLsOrDSAZT73r4B8WHKrX8Gd_naLkdUUrs3gggNvYUe26HMU5aFCDA/s1600/lm386.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="242" data-original-width="922" height="83" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBgHAlCYmtL-N7jPrf3CRykBNyXBRGVLdh1WrgkFbg5-GfbAoNkjO9KqlBuH10cUQvwY_zW0HD4vq5Nwec8NHhVcLsOrDSAZT73r4B8WHKrX8Gd_naLkdUUrs3gggNvYUe26HMU5aFCDA/s320/lm386.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: center;">
<b>Figure: LM386 Low Voltage Audio Power Amplifier</b></div>
Pins are connected as:<br />
<b>ESP32 G27 connect LM386 IN</b><br />
<b>ESP32 5V (or 3.3 V) connect LM386 Vcc</b><br />
<b>ESP32 GND connect LM386 GND</b><br />
<b>3. Software</b><br />
In order to use Sigma-delta Modulation in ESP please refer <a href="https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/AnalogOut/SigmaDelta">this</a>.<br />
Here is the full source code:
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #333399; font-weight: bold;">int</span> speakerPin <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">27</span>;
//"happy birthday melody notes"
<span style="color: #333399; font-weight: bold;">char</span> notes[] <span style="color: #333333;">=</span> <span style="background-color: #5eeb34;">"GGAGcB GGAGdc GGxecBA yyecdc"</span>;
<span style="color: #333399; font-weight: bold;">int</span> beats[] <span style="color: #333333;">=</span> { <span style="color: #0000dd; font-weight: bold;">2</span>, <span style="color: #0000dd; font-weight: bold;">2</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">16</span>, <span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">2</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">16</span>, <span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">2</span>, <span style="color: #0000dd; font-weight: bold;">2</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">16</span>, <span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">2</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0000dd; font-weight: bold;">16</span> };
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">playTone</span>(<span style="color: #333399; font-weight: bold;">int</span> tone) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">long</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">100</span>; i<span style="color: #333333;">++</span>) {
sigmaDeltaWrite(<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">0</span>);
delayMicroseconds(tone);
sigmaDeltaWrite(<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">100</span>);
delayMicroseconds(tone);
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">playNote</span>(<span style="color: #333399; font-weight: bold;">char</span> note) {
<span style="color: #888888;">//notes</span>
<span style="color: #333399; font-weight: bold;">char</span> note_name[] <span style="color: #333333;">=</span> {<span style="color: #0044dd;">'C'</span>, <span style="color: #0044dd;">'D'</span>, <span style="color: #0044dd;">'E'</span>, <span style="color: #0044dd;">'F'</span>, <span style="color: #0044dd;">'G'</span>, <span style="color: #0044dd;">'A'</span>, <span style="color: #0044dd;">'B'</span>, <span style="color: #0044dd;">'c'</span>, <span style="color: #0044dd;">'d'</span>, <span style="color: #0044dd;">'e'</span>, <span style="color: #0044dd;">'f'</span>, <span style="color: #0044dd;">'g'</span>, <span style="color: #0044dd;">'a'</span>, <span style="color: #0044dd;">'b'</span>, <span style="color: #0044dd;">'x'</span>, <span style="color: #0044dd;">'y'</span> };
<span style="color: #333399; font-weight: bold;">int</span> timeHigh[] <span style="color: #333333;">=</span> { <span style="color: #0000dd; font-weight: bold;">1915</span>, <span style="color: #0000dd; font-weight: bold;">1700</span>, <span style="color: #0000dd; font-weight: bold;">1519</span>, <span style="color: #0000dd; font-weight: bold;">1432</span>, <span style="color: #0000dd; font-weight: bold;">1275</span>, <span style="color: #0000dd; font-weight: bold;">1136</span>, <span style="color: #0000dd; font-weight: bold;">1014</span>, <span style="color: #0000dd; font-weight: bold;">956</span>, <span style="color: #0000dd; font-weight: bold;">834</span>, <span style="color: #0000dd; font-weight: bold;">765</span>, <span style="color: #0000dd; font-weight: bold;">593</span>, <span style="color: #0000dd; font-weight: bold;">468</span>, <span style="color: #0000dd; font-weight: bold;">346</span>, <span style="color: #0000dd; font-weight: bold;">224</span>, <span style="color: #0000dd; font-weight: bold;">655</span> , <span style="color: #0000dd; font-weight: bold;">715</span> };
<span style="color: #888888;">// play the tone corresponding to the note name</span>
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> <span style="color: #008800; font-weight: bold;">sizeof</span>(note_name); i<span style="color: #333333;">++</span>) {
<span style="color: #008800; font-weight: bold;">if</span> (note_name[i] <span style="color: #333333;">==</span> note) {
playTone(timeHigh[i]);
}
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
sigmaDeltaSetup(<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">12000</span>);
<span style="color: #888888;">//attach pin speakerPin to channel 0</span>
sigmaDeltaAttachPin(speakerPin, <span style="color: #0000dd; font-weight: bold;">0</span>);
<span style="color: #888888;">//initialize channel 0 to off</span>
sigmaDeltaWrite(<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">0</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> strlen(notes); i<span style="color: #333333;">++</span>) {
<span style="color: #888888;">// space is rest note</span>
<span style="color: #008800; font-weight: bold;">if</span> (notes[i] <span style="color: #333333;">==</span> <span style="color: #0044dd;">' '</span>) {
delay(beats[i] <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100</span>);
} <span style="color: #008800; font-weight: bold;">else</span> {
playNote(notes[i]);
}
<span style="color: #888888;">// pause between notes</span>
delay(<span style="color: #0000dd; font-weight: bold;">100</span>);
}
}
</pre>
</td></tr>
</tbody></table>
</div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com7tag:blogger.com,1999:blog-7549705215513488945.post-86531206275530996422018-05-26T04:54:00.002-07:002018-05-26T05:00:50.192-07:00Demo 42: How to build an IoT Dashboard using Node-Red dashboard and ESP<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
In this post, we will learn how to build an IoT Dashboard using Node-Redand node-red-dashboard.<br />
These set-up can be deployed on Raspberry Pi, Orange Pi, ... easily.<br />
We will make a demo for this post, a simple smart home demo: a floor has 1 bulb and 1 temperature sensor. They will be control by a ESP32. This ESP32 send and receive data using MQTT protocol. A server with MQTT broker, Node-Red, NodeJS and a dashboard with a chart to monitor temperature and a switch to control the bulb.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcnor0jJVDW5Niqpk-w1utA4IYLktPZ7h4QMomu4kv9YIwur559WKmYMpef3LbNobEszGmL17ZDVB-vyEQ7Tfbb25BZjQGoV8ZuD2-PtPKWUHnrnhiEYDgUuckyWR9MAo0jnXAvPPZRm4/s1600/dashboard4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="319" data-original-width="656" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcnor0jJVDW5Niqpk-w1utA4IYLktPZ7h4QMomu4kv9YIwur559WKmYMpef3LbNobEszGmL17ZDVB-vyEQ7Tfbb25BZjQGoV8ZuD2-PtPKWUHnrnhiEYDgUuckyWR9MAo0jnXAvPPZRm4/s640/dashboard4.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: Demo model</b></div>
<b>Note:</b> This post will re-use the posts:<br />
<a href="http://www.iotsharing.com/2017/06/how-to-turn-the-Orange-Pi-into-an-IoT-node.html">How to turn the Orange Pi/Raspberry Pi into an IoT node</a> : To install Mosquito and use host name instead of remembering the IP address<br />
<a href="http://www.iotsharing.com/2017/05/tcp-udp-ip-with-esp32.html">Demo 8: How to use TCP/IP with Arduino ESP32</a> : part 1.2 - Introduction to Node-Red (installation and usage)<br />
<a href="http://www.iotsharing.com/2017/05/how-to-use-mqtt-to-build-smart-home-arduino-esp32.html">Demo 14: How to use MQTT and Arduino ESP32 to build a simple Smart home system </a>: build a smart home using Mosquito MQTT, ESP32 MQTT.<br />
<b>2. node-red-dashboard</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-TWHJnttO2c0/Wwjd8CIUC4I/AAAAAAAAIKk/2YQzyaXy2fYuZx2hXd_oQVsKEO__GZ-awCLcBGAs/s1600/dashboard1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="460" data-original-width="600" height="306" src="https://2.bp.blogspot.com/-TWHJnttO2c0/Wwjd8CIUC4I/AAAAAAAAIKk/2YQzyaXy2fYuZx2hXd_oQVsKEO__GZ-awCLcBGAs/s400/dashboard1.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: node-red-dashboard</b></div>
<b>2.1 Concepts </b><br />
With this dashboard: <br />
+ Layout will be considered as a grid. It is in Dashboard Tab.<br />
+ A group element has a width - by default 6 'units'.<br />
+ A unit is 48px wide by default with a 6px gap.<br />
+ A widget in the group also has a default 'auto'. It means it will fill the width of the group contained it, or you can set it to a fixed number of units.<br />
<b>2.2 Features</b><br />
+ Layout: Tab, Link to other web pages. <br />
+ Theme: Light, Dark or Custom Theme.<br />
+ Widgets include Button, Chart, Form, Gauge, Notification, Switch ...<br />
<b>Note</b>: the node-red-dashboard will be deployed at: <a href="http://localhost:1880/ui" rel="nofollow">http://localhost:1880/ui</a> (change localhost accordingly)<br />
<b>2.3 Installation</b><br />
<b>Note</b>: I instaled all things on my <b>localhost </b><br />
I assume that you did install <a href="https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions">NodeJS</a><br />
Then install Mosquito broker following <a href="http://www.iotsharing.com/2017/06/how-to-turn-the-Orange-Pi-into-an-IoT-node.html">How to turn the Orange Pi/Raspberry Pi into an IoT node</a><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-N7b60mqao-o/WwlELAM6_uI/AAAAAAAAIOU/sD5wuWNEUdsCbv7EkS9ZIFxA8QXW9JkzQCLcBGAs/s1600/dash25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="658" data-original-width="528" height="400" src="https://4.bp.blogspot.com/-N7b60mqao-o/WwlELAM6_uI/AAAAAAAAIOU/sD5wuWNEUdsCbv7EkS9ZIFxA8QXW9JkzQCLcBGAs/s400/dash25.png" width="320" /></a></div>
<div style="text-align: center;">
<b>Figure: ensuare MQTT broker is running </b></div>
Then you need to install Node-Red following <a href="http://www.iotsharing.com/2017/05/tcp-udp-ip-with-esp32.html">Demo 8: How to use TCP/IP with Arduino ESP32</a> - part 1.<br />
Then install node-red-dashboard. It requires Node-RED version 0.14 or more recent. Open Terminal and typing commands:<br />
<i><b>cd ~/.node-red</b></i><br />
<i><b>npm i node-red-dashboard</b></i><br />
Then run Node-Red from Terminal using command:<br />
<i><b>node-red</b></i><br />
You will see:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV_7ghbosITdKHqN_-AkQEXG4_lwExiLdizBQbtXJSusIFS3kPsQbNI5ZtZja9IuBHQdYjP5jRrC9AzRaxyd04kEUUA29W7gZNkd25ouo1QrXEcTqGA5hCCKuBVNb9qBHeiudc8JQkTBw/s1600/dashboard2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="832" height="368" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV_7ghbosITdKHqN_-AkQEXG4_lwExiLdizBQbtXJSusIFS3kPsQbNI5ZtZja9IuBHQdYjP5jRrC9AzRaxyd04kEUUA29W7gZNkd25ouo1QrXEcTqGA5hCCKuBVNb9qBHeiudc8JQkTBw/s640/dashboard2.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: Node-Red started</b></div>
Now open your web browser and go to the link http://127.0.0.1:1880/<br />
If you use MDNS as in <a href="http://www.iotsharing.com/2017/06/how-to-turn-the-Orange-Pi-into-an-IoT-node.html">How to turn the Oavahi-daemonrange Pi/Raspberry Pi into an IoT node</a>.<br />
You will see:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-BDvzjbo4b0o/Wwjm-_Q4evI/AAAAAAAAIK8/-etMxJl0zKQSRSCNBoF3aJo3C0Sgw9evwCLcBGAs/s1600/dashboard3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="695" data-original-width="1350" height="328" src="https://1.bp.blogspot.com/-BDvzjbo4b0o/Wwjm-_Q4evI/AAAAAAAAIK8/-etMxJl0zKQSRSCNBoF3aJo3C0Sgw9evwCLcBGAs/s640/dashboard3.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: left side is widgets area, right side is layout area, middile is working space of node-red-dashboard</b></div>
<b>3. </b><b>Hardware</b><br />
2 modules ESP32, an Raspberry Pi or Orange Pi or PC. I will use a Led for testing and generate temperature randomly.<br />
<b>4. Software</b>:<br />
We define MQTT topics and values:<br />
+ For Led: "floor1/led" with value false-off, true-on<br />
+ For temerature: "floor1/temp" with value is an integer or string <br />
<b>4.1 Node-Red side</b><br />
The steps to create our model on Node-Red<b>:</b><br />
Step 1: Create 2 tabs (when deploying real website, it becomes 1 menu - 2 categories) standing for 2 floors.<br />
Step 2: Create Tab 1 - Floor 1 has 2 groups: Group 1 contains 1 switch, Group 2 contains 1 chart.<br />
Step 3: Create Tab 2 - Floor 2 has 2 groups: Group 1 contains 1 switch, Group 2 contains 1 Gauge.<br />
Just follow red boxes and steps in order number.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-BDvzjbo4b0o/Wwjm-_Q4evI/AAAAAAAAILA/XYnnzFZMElQN-5kOQGDTN0IzI8WfHbNrwCEwYBhgL/s1600/dashboard3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="695" data-original-width="1350" height="328" src="https://1.bp.blogspot.com/-BDvzjbo4b0o/Wwjm-_Q4evI/AAAAAAAAILA/XYnnzFZMElQN-5kOQGDTN0IzI8WfHbNrwCEwYBhgL/s640/dashboard3.png" width="640" /></a></div>
<div style="text-align: center;">
<b> Figure: Node-Red GUI</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZEv6_p_vg6QISmmOUEu7vCbgFRp5MP0Efu4IknulCZElEn5t9fuNKrow4pmxCYdLJMR9dvU3kLS7cN7-WMN4HhL6s3grQXqaEUQHSL66ScKdWoIPZOhjxL3ymWAwlto96GaJFQbhfVso/s1600/dash6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="390" data-original-width="359" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZEv6_p_vg6QISmmOUEu7vCbgFRp5MP0Efu4IknulCZElEn5t9fuNKrow4pmxCYdLJMR9dvU3kLS7cN7-WMN4HhL6s3grQXqaEUQHSL66ScKdWoIPZOhjxL3ymWAwlto96GaJFQbhfVso/s400/dash6.png" width="367" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-_Qc0wsIomVo/Wwk1yqbRMdI/AAAAAAAAILo/5I2tbFgU0LciNyM-Gm0Llw7w6izzc5XLACLcBGAs/s1600/dash7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="838" height="169" src="https://2.bp.blogspot.com/-_Qc0wsIomVo/Wwk1yqbRMdI/AAAAAAAAILo/5I2tbFgU0LciNyM-Gm0Llw7w6izzc5XLACLcBGAs/s640/dash7.png" width="640" /></a></div>
<br />
<div style="text-align: center;">
<b>Figure: Create Tab 1 - Floor 1</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVTMFE0nCP-xH7a7mgwFv7y2Gqm0y8SRso3sUxhDGhOL7n6O4UWF_z95mPjZM2gGdK9vHLhazUzZxJwfNmoSAmaFxNYteLL-nXeJKXL7qLU9Qb-SBqeMb0UQVV_kHDV1RCEKZZWluqbyg/s1600/dash8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="539" data-original-width="1351" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVTMFE0nCP-xH7a7mgwFv7y2Gqm0y8SRso3sUxhDGhOL7n6O4UWF_z95mPjZM2gGdK9vHLhazUzZxJwfNmoSAmaFxNYteLL-nXeJKXL7qLU9Qb-SBqeMb0UQVV_kHDV1RCEKZZWluqbyg/s640/dash8.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-K87A6SxGYjs/Wwk3l9tILSI/AAAAAAAAIL4/sHJovtIUc9U-3ZStmJx_6J53OtYqGoKfwCLcBGAs/s1600/dash9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="332" data-original-width="523" height="253" src="https://4.bp.blogspot.com/-K87A6SxGYjs/Wwk3l9tILSI/AAAAAAAAIL4/sHJovtIUc9U-3ZStmJx_6J53OtYqGoKfwCLcBGAs/s400/dash9.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-EFPdkgP9Nps/Wwk3rFlJs9I/AAAAAAAAIL8/VqDjgz4P-s4xWHEFfGfJ2p7drmbreLHRwCLcBGAs/s1600/dash10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="560" data-original-width="500" height="400" src="https://1.bp.blogspot.com/-EFPdkgP9Nps/Wwk3rFlJs9I/AAAAAAAAIL8/VqDjgz4P-s4xWHEFfGfJ2p7drmbreLHRwCLcBGAs/s400/dash10.png" width="356" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<b>Figure: create Floor 1-Group 1-Switch</b><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmySqLGCr7MApaHC9XE6aS1HS6M7XiHLzdihPk-wl3ZYkw5_e8LALFFeABENnEN3Et9sKqwmNUPe7Dyrt7q0ylTGc0ux_Hc7w8MuDqvJppi5rWvttYY0iaH8TrsnES_Uta6oAGxtdNRdU/s1600/dash11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="397" data-original-width="1048" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmySqLGCr7MApaHC9XE6aS1HS6M7XiHLzdihPk-wl3ZYkw5_e8LALFFeABENnEN3Et9sKqwmNUPe7Dyrt7q0ylTGc0ux_Hc7w8MuDqvJppi5rWvttYY0iaH8TrsnES_Uta6oAGxtdNRdU/s640/dash11.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-552VJVqJNWo/Wwk5Ys7Z4gI/AAAAAAAAIMY/iFJHJdWM8FE8hNhe09GbZCt3qn7oZSBUwCLcBGAs/s1600/dash12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="366" data-original-width="681" height="213" src="https://3.bp.blogspot.com/-552VJVqJNWo/Wwk5Ys7Z4gI/AAAAAAAAIMY/iFJHJdWM8FE8hNhe09GbZCt3qn7oZSBUwCLcBGAs/s400/dash12.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-7TtNOt05pws/Wwk5cVmrtWI/AAAAAAAAIMc/yJ7zdcA_Uh4r6eVzHojfXMlvMw0oui-IACLcBGAs/s1600/dash13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="364" data-original-width="857" height="270" src="https://3.bp.blogspot.com/-7TtNOt05pws/Wwk5cVmrtWI/AAAAAAAAIMc/yJ7zdcA_Uh4r6eVzHojfXMlvMw0oui-IACLcBGAs/s640/dash13.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: create MQTT publish when switch is pressed</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-hO0ctTwxnlM/Wwk6KlS8gGI/AAAAAAAAIMs/UC92P-dcrO8xbR17u-2NUETxqRejFxk7wCLcBGAs/s1600/dash14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="402" data-original-width="1043" height="246" src="https://1.bp.blogspot.com/-hO0ctTwxnlM/Wwk6KlS8gGI/AAAAAAAAIMs/UC92P-dcrO8xbR17u-2NUETxqRejFxk7wCLcBGAs/s640/dash14.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: create MQTT subscribe temperature sensor floor1/temp"</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-13_XLLHuVTY/Wwk8WdrHsjI/AAAAAAAAIM4/wNWT89cgLbown2pXi4SXowtmld-OvjimgCLcBGAs/s1600/dash15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="725" data-original-width="1044" height="444" src="https://4.bp.blogspot.com/-13_XLLHuVTY/Wwk8WdrHsjI/AAAAAAAAIM4/wNWT89cgLbown2pXi4SXowtmld-OvjimgCLcBGAs/s640/dash15.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-Jmx5Vozx960/Wwk8drjNp8I/AAAAAAAAIM8/oHF-oFtPqaYd4iu6F6T9fpPhQjnVQA0sQCLcBGAs/s1600/dash16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="345" data-original-width="504" height="273" src="https://3.bp.blogspot.com/-Jmx5Vozx960/Wwk8drjNp8I/AAAAAAAAIM8/oHF-oFtPqaYd4iu6F6T9fpPhQjnVQA0sQCLcBGAs/s400/dash16.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-4VYqdOfnsok/Wwk8iyr1tBI/AAAAAAAAINA/CjQBmXPhmcMxzeMdeJ8csE227XzHRunugCLcBGAs/s1600/dash18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="723" data-original-width="1040" height="444" src="https://4.bp.blogspot.com/-4VYqdOfnsok/Wwk8iyr1tBI/AAAAAAAAINA/CjQBmXPhmcMxzeMdeJ8csE227XzHRunugCLcBGAs/s640/dash18.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: create a chart</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-hZKorkWed1A/Wwk_g3p35nI/AAAAAAAAINg/KWDqhMV4mRMy9SfNeZ3jJjCDpFt8nWhXACLcBGAs/s1600/dash19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="417" data-original-width="1355" height="196" src="https://2.bp.blogspot.com/-hZKorkWed1A/Wwk_g3p35nI/AAAAAAAAINg/KWDqhMV4mRMy9SfNeZ3jJjCDpFt8nWhXACLcBGAs/s640/dash19.png" width="640" /></a></div>
<br />
<div style="text-align: center;">
<b>Figure: deploy our model</b></div>
Open Web Browser and go to the url: <a href="http://localhost:1880/ui" rel="nofollow">http://localhost:1880/ui</a><br />
Our first draft:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-feY3pbbBWyU/WwlBR73bI0I/AAAAAAAAINs/ffq4zGw6DNAjhyb6_8Uydgm0hr6oaD1VwCLcBGAs/s1600/dash21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="428" data-original-width="1096" height="248" src="https://1.bp.blogspot.com/-feY3pbbBWyU/WwlBR73bI0I/AAAAAAAAINs/ffq4zGw6DNAjhyb6_8Uydgm0hr6oaD1VwCLcBGAs/s640/dash21.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: first draft</b></div>
Do similar things for Floor 2.<br />
Change the theme to dark:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-UJTuqs51Mw0/WwlDU699lFI/AAAAAAAAIOA/lRls2Z8wbrwGPmU-B46ybTmGxvQAqd5uACLcBGAs/s1600/dash23.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="289" data-original-width="356" height="323" src="https://4.bp.blogspot.com/-UJTuqs51Mw0/WwlDU699lFI/AAAAAAAAIOA/lRls2Z8wbrwGPmU-B46ybTmGxvQAqd5uACLcBGAs/s400/dash23.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: Dark theme</b></div>
Our final model:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-pOlhprvY_pQ/WwlC8YA41KI/AAAAAAAAIN4/i7zNav2DFFcbnYJt6QLuASS-Gx2dd7hyQCLcBGAs/s1600/dash22.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="759" data-original-width="1371" height="354" src="https://2.bp.blogspot.com/-pOlhprvY_pQ/WwlC8YA41KI/AAAAAAAAIN4/i7zNav2DFFcbnYJt6QLuASS-Gx2dd7hyQCLcBGAs/s640/dash22.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-gNF2In2gAgY/WwlDj4jzyQI/AAAAAAAAIOE/1wsYTodL-S4WCcFZM9jsAdJ9qsmd1-skQCLcBGAs/s1600/dash24.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="624" data-original-width="1372" height="290" src="https://1.bp.blogspot.com/-gNF2In2gAgY/WwlDj4jzyQI/AAAAAAAAIOE/1wsYTodL-S4WCcFZM9jsAdJ9qsmd1-skQCLcBGAs/s640/dash24.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: final model</b></div>
Or you can import Node-Red model from script below:<br />
[{"id":"bc6c4c2e.077c5","type":"mqtt in","z":"d4b07266.f397","name":"","topic":"floor2/temp","qos":"2","broker":"fc2a1412.370a68","x":284.5,"y":478,"wires":[["b9eef4aa.a11648"]]},{"id":"fc2a1412.370a68","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}] <b><br /></b><br />
<b>4.2 ESP32 side</b><br />
ESP32 Arduino code:<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <WiFi.h></span>
<span style="color: #557799;">#include <PubSubClient.h></span>
<span style="color: #888888;">/* change it with your ssid-password */</span>
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> ssid <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"dd-wrt"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> password <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"0000000000"</span>;
<span style="color: #888888;">/* this is the IP of PC/raspberry where you installed MQTT Server </span>
<span style="color: #888888;">on Wins use "ipconfig" </span>
<span style="color: #888888;">on Linux use "ifconfig" to get its IP address */</span>
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> mqtt_server <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"192.168.1.107"</span>;
<span style="color: #333399; font-weight: bold;">float</span> temperature <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #888888;">/* create an instance of PubSubClient client */</span>
WiFiClient espClient;
PubSubClient <span style="color: #0066bb; font-weight: bold;">client</span>(espClient);
<span style="color: #888888;">/*LED GPIO pin*/</span>
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span> led <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">4</span>;
<span style="color: #888888;">/* topics */</span>
<span style="color: #557799;">#define TEMP_TOPIC "floor1/temp"</span>
<span style="color: #557799;">#define LED_TOPIC "floor1/led" </span><span style="color: #888888;">/* true=on, false=off */</span><span style="color: #557799;"></span>
<span style="color: #333399; font-weight: bold;">long</span> lastMsg <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">char</span> msg[<span style="color: #0000dd; font-weight: bold;">20</span>];
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">receivedCallback</span>(<span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> topic, byte<span style="color: #333333;">*</span> payload, <span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">int</span> length) {
Serial.print(<span style="background-color: #fff0f0;">"Message received: "</span>);
Serial.println(topic);
Serial.print(<span style="background-color: #fff0f0;">"payload: "</span>);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> length; i<span style="color: #333333;">++</span>) {
Serial.print((<span style="color: #333399; font-weight: bold;">char</span>)payload[i]);
}
Serial.println();
<span style="color: #888888;">/* we got '1' -> on */</span>
<span style="color: #008800; font-weight: bold;">if</span> ((<span style="color: #333399; font-weight: bold;">char</span>)payload[<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">==</span> <span style="color: #0044dd;">'t'</span>) {
digitalWrite(led, HIGH);
} <span style="color: #008800; font-weight: bold;">else</span> {
<span style="color: #888888;">/* we got '0' -> on */</span>
digitalWrite(led, LOW);
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">mqttconnect</span>() {
<span style="color: #888888;">/* Loop until reconnected */</span>
<span style="color: #008800; font-weight: bold;">while</span> (<span style="color: #333333;">!</span>client.connected()) {
Serial.print(<span style="background-color: #fff0f0;">"MQTT connecting ..."</span>);
<span style="color: #888888;">/* client ID */</span>
String clientId <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"ESP32Client"</span>;
<span style="color: #888888;">/* connect now */</span>
<span style="color: #008800; font-weight: bold;">if</span> (client.connect(clientId.c_str())) {
Serial.println(<span style="background-color: #fff0f0;">"connected"</span>);
<span style="color: #888888;">/* subscribe topic with default QoS 0*/</span>
client.subscribe(LED_TOPIC);
} <span style="color: #008800; font-weight: bold;">else</span> {
Serial.print(<span style="background-color: #fff0f0;">"failed, status code ="</span>);
Serial.print(client.state());
Serial.println(<span style="background-color: #fff0f0;">"try again in 5 seconds"</span>);
<span style="color: #888888;">/* Wait 5 seconds before retrying */</span>
delay(<span style="color: #0000dd; font-weight: bold;">5000</span>);
}
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
<span style="color: #888888;">// We start by connecting to a WiFi network</span>
Serial.println();
Serial.print(<span style="background-color: #fff0f0;">"Connecting to "</span>);
Serial.println(ssid);
WiFi.begin(ssid, password);
<span style="color: #008800; font-weight: bold;">while</span> (WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED) {
delay(<span style="color: #0000dd; font-weight: bold;">500</span>);
Serial.print(<span style="background-color: #fff0f0;">"."</span>);
}
<span style="color: #888888;">/* set led as output to control led on-off */</span>
pinMode(led, OUTPUT);
Serial.println(<span style="background-color: #fff0f0;">""</span>);
Serial.println(<span style="background-color: #fff0f0;">"WiFi connected"</span>);
Serial.println(<span style="background-color: #fff0f0;">"IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #888888;">/* configure the MQTT server with IPaddress and port */</span>
client.setServer(mqtt_server, <span style="color: #0000dd; font-weight: bold;">1883</span>);
<span style="color: #888888;">/* this receivedCallback function will be invoked </span>
<span style="color: #888888;"> when client received subscribed topic */</span>
client.setCallback(receivedCallback);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
<span style="color: #888888;">/* if client was disconnected then try to reconnect again */</span>
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>client.connected()) {
mqttconnect();
}
<span style="color: #888888;">/* this function will listen for incomming </span>
<span style="color: #888888;"> subscribed topic-process-invoke receivedCallback */</span>
client.loop();
<span style="color: #888888;">/* we measure temperature every 3 secs</span>
<span style="color: #888888;"> we count until 3 secs reached to avoid blocking program if using delay()*/</span>
<span style="color: #333399; font-weight: bold;">long</span> now <span style="color: #333333;">=</span> millis();
<span style="color: #008800; font-weight: bold;">if</span> (now <span style="color: #333333;">-</span> lastMsg <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">3000</span>) {
lastMsg <span style="color: #333333;">=</span> now;
temperature <span style="color: #333333;">=</span> random(<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">40</span>);
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>isnan(temperature)) {
snprintf (msg, <span style="color: #0000dd; font-weight: bold;">20</span>, <span style="background-color: #fff0f0;">"%lf"</span>, temperature);
<span style="color: #888888;">/* publish the message */</span>
client.publish(TEMP_TOPIC, msg);
}
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>5. Result</b><br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/6fi8pSn_UjM/0.jpg" frameborder="0" height="480" src="https://www.youtube.com/embed/6fi8pSn_UjM?feature=player_embedded" width="320"></iframe></div>
<br /></div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com3tag:blogger.com,1999:blog-7549705215513488945.post-28989752815411512572018-03-21T20:43:00.002-07:002019-10-02T00:59:45.577-07:00Demo 41: ESP32 connects with nRF24L01 2.4 GHz wireless chip<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-rOcrNRGMP1Q/WrMonaobbeI/AAAAAAAAHII/0l3yrHA705AbCkLLT2jMn4WmJr-Ov3PIwCLcBGAs/s1600/nrf24l01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="177" data-original-width="188" src="https://4.bp.blogspot.com/-rOcrNRGMP1Q/WrMonaobbeI/AAAAAAAAHII/0l3yrHA705AbCkLLT2jMn4WmJr-Ov3PIwCLcBGAs/s1600/nrf24l01.png" /></a></div>
<div style="text-align: center;">
<b>Figure: Module nRF24L01</b></div>
The nRF24L01 2.4 GHz wireless chip from Nordic Semiconductor. It has:<br />
- SPI interface, hardware link layer, multiple pipelines, ...<br />
- The chip is very cheap.<br />
Comparing to Wifi modules such as ESP8266, ESP32: <br />
- It has less power consumption.<br />
- It is cheaper (but need a MCU to control). <br />
- It has lower data rate.<br />
If your Wifi infrastructure is good, you can consider using Wifi modules for your application.<br />
If power consumption is not your issue, you can consider using Wifi modules for your application. <br />
If we use nrf24l01 and need to send data to cloud via Internet, consider using ESP or Raspberry as a Gateway. <br />
Some main characteristics: <br />
<b>1.1 NRF24L01 Hardware Interface</b><br />
- 8 pins Vcc, GND, IRQ, CE, SPI pins (CSN (chip select not), SCK, MISO, and MOSI).<br />
- IO pins are 5V-tolerant and operating range of 1.9 to 3.6V for Vcc.<br />
- CSN, SCK, MISO, and MOSI for data transmission and reception.<br />
- The CSN pin is active-low, and is normally kept high. When this pin goes low, the 24L01 begins listening on its SPI port for data and processes it accordingly.<br />
- CE is used to control data transmission and reception when in TX and RX modes.<br />
- IRQ is the interrupt pin, and is active-low. There are three internal interrupts that can cause this pin to go low when they are active. Each of these bits can be masked out such that when the bit’s respective interrupt becomes active, the status of the IRQ pin is not changed.<br />
<b>1.2 Interfacing the nRF24L01 via SPI</b><br />
- The SPI interface allows you to read/write registers, transmit data, receive data from and to the 24L01. For start step we use SPI at 2 Mbps. The high SPI data rates are used if you needed huge on-air data rates.<br />
<b>1.3 SPI Instruction Set Summary</b><br />
- In order to send data to or receive data from the SPI port on the nRF24L01:<br />
+ The CSN pin on the 24L01 must be high then bring the CSN pin low to receive SPI data.<b> Note</b>: this pin will stay low throughout the entire transaction. <br />
+ You will transmit the command byte of the instruction you wish to send. If you are receiving data bytes for this instruction, you must then send one byte to the 24L01 for every one byte that you wish to get out of the 24L01. If you are just sending the 24L01 data, you simply send your data bytes and generally don’t worry about what it sends back to you.<br />
+ Once you have transmitted and/or read all of the bytes that you need, you bring CSN back high.<br />
+ When you send any command byte, the 24L01 always returns to you the STATUS register.<br />
<b>1.4 FIFO Info</b><br />
- There are FIFOs for both TX and RX modes.<br />
- Both of the FIFOs will hold the three newest packets that have been put into them. If you receive three packets in RX mode and you don’t read the payloads, the first (oldest) packet received is pushed out by the newest packet received. The same goes for the TX payload – if you load three packets and don’t transmit them (by executing the aforementioned CE toggle), then the fourth packet will push out the first packet you loaded.<br />
<b>1.5 Data Packet Format</b><br />
- The transceiver protocol has 2 modes:<b> </b>Shockburst and Enhanced Shockburst<br />
- The message format for both Shockburst and Enhanced Shockburst modes are different.<br />
- In both modes, the preamble is sent first (1 byte), is used to allow the receiver to know that what it is hearing is the beginning of a packet and not just on-air noise. <br />
- The next bytes sent are the address bytes. This is set by the user, and is between three and five bytes long.<br />
- The next bytes sent is different between the two modes. In Enhanced Shockburst only, a flag word of nine bits is sent to indicate the message status concerning re-transmissions. Only two bits are currently used (a count of resent packets), and the other seven are reserved for future use.<br />
- The last half of the packet that is sent is the same in both modes. The first of the fields to be sent in both modes is the payload data. The length of the payload is also set by the user (1 to 32 bytes long). The final part of the packet to be sent is the CRC, which is user-settable (0, 1, or 2 byte(s)).<br />
Let 's make 2 demos:<br />
<b>- Demo 1: ESP32 Nano will send "hello" message to Arduino. </b><br />
<b>- Demo 2: Arduino Nano will send "hello" message to ESP32.</b><br />
If you have 2 ESP32 you can replace Arduino Nano with ESP32. <br />
<b>2. Hardware</b><br />
You need 2 Arduino/ESP8266/ESP32/Raspberry boards for testing: 1 board will send/receive message and 1 board will receive/send message which was sent by first board.<br />
I used Arduino for testing, just do wiring like below:<br />
<b>Arduino_D8 x NRF24_CSN<br />Arduino_D7 x NRF24_CE<br />Arduino_D13 x NRF24_SCK<br />Arduino_D11 x NRF24_MOSI<br />Arduino_D12 x NRF24_MISO</b><br />
<b><b>Arduino_3.3 x NRF24_Vcc</b></b><br />
<b><b><b>Arduino_GND x NRF24_GND</b></b></b><i><b> </b></i><br />
For ESP32, I modified the library RF24 so that the software can use SPI software instead of using SPI hardware. Do wiring like below:<br />
<b>NRF24_CE x ESP32_IO12</b><br />
<b>NRF24_</b><b><b>CSN</b> x ESP32_IO14</b><br />
<b>NRF24_SCK x ESP32_IO26</b><br />
<b>NRF24_MISO x ESP32_IO25</b><br />
<b>NRF24_MOSI x ESP32_IO27</b><br />
<b><b>NRF24_Vcc x ESP32_3.3V</b></b><br />
<b><b><b><b>NRF24_GND x ESP32_GND</b></b> </b> </b> <br />
<b>3. Software</b><br />
For ESP32, I modified <a href="https://github.com/nhatuan84/RF24">the library RF24</a> (https://github.com/nhatuan84/RF24) so that the software can use SPI software insted of using SPI hardware. The new API has new form:<br />
<i><b>RF24(uint16_t _cepin, uint16_t _cspin, uint16_t sck, uint16_t miso, uint16_t mosi)</b></i><br />
and to create an instance: RF24 radio(<span style="color: #0000dd; font-weight: bold;">12</span>, <span style="color: #0000dd; font-weight: bold;">14</span>, <span style="color: #0000dd; font-weight: bold;">26</span>, <span style="color: #0000dd; font-weight: bold;">25</span>, <span style="color: #0000dd; font-weight: bold;">27</span>);<br />
For Arduino, we use SPI hardware so just use form: <i><b> </b></i><br />
<i><b>RF24(uint16_t _cepin, uint16_t _cspin)</b></i><br />
and the instance is RF24 radio(<span style="color: #0000dd; font-weight: bold;">7</span>,<span style="color: #0000dd; font-weight: bold;">8</span>);<br />
<b>- Demo 1: ESP32 Nano will send "hello" message to Arduino.</b><br />
<b>ESP32 </b><b><b>transmitter </b>code</b><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #888888;">#include <SPI.h></span>
<span style="color: #888888;">#include "nRF24L01.h"</span>
<span style="color: #888888;">#include "RF24.h"</span>
char msg[<span style="color: #0000dd; font-weight: bold;">6</span>] <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"hello"</span>;
RF24 radio(<span style="color: #0000dd; font-weight: bold;">12</span>, <span style="color: #0000dd; font-weight: bold;">14</span>, <span style="color: #0000dd; font-weight: bold;">26</span>, <span style="color: #0000dd; font-weight: bold;">25</span>, <span style="color: #0000dd; font-weight: bold;">27</span>);
const uint64_t pipe <span style="color: #333333;">=</span> <span style="color: #005588; font-weight: bold;">0xE8E8F0F0E1</span>LL;
void setup(void) {
Serial<span style="color: #333333;">.</span>begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
radio<span style="color: #333333;">.</span>begin();
radio<span style="color: #333333;">.</span>setChannel(<span style="color: #0000dd; font-weight: bold;">2</span>);
radio<span style="color: #333333;">.</span>setPayloadSize(<span style="color: #0000dd; font-weight: bold;">7</span>);
radio<span style="color: #333333;">.</span>setDataRate(RF24_250KBPS);
radio<span style="color: #333333;">.</span>openWritingPipe(pipe);
}
void loop(void) {
Serial<span style="color: #333333;">.</span>println(<span style="background-color: #fff0f0;">"send ..."</span>);
radio<span style="color: #333333;">.</span>write(msg, <span style="color: #0000dd; font-weight: bold;">6</span>);
delay(<span style="color: #0000dd; font-weight: bold;">3000</span>);
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>Arduino receiver code</b><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #888888;">#include <SPI.h></span>
<span style="color: #888888;">#include "nRF24L01.h"</span>
<span style="color: #888888;">#include "RF24.h"</span>
char msg[<span style="color: #0000dd; font-weight: bold;">6</span>];
RF24 radio(<span style="color: #0000dd; font-weight: bold;">7</span>,<span style="color: #0000dd; font-weight: bold;">8</span>);
const uint64_t pipe <span style="color: #333333;">=</span> <span style="color: #005588; font-weight: bold;">0xE8E8F0F0E1</span>LL;
void setup(void){
Serial<span style="color: #333333;">.</span>begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
radio<span style="color: #333333;">.</span>begin();
radio<span style="color: #333333;">.</span>setChannel(<span style="color: #0000dd; font-weight: bold;">2</span>);
radio<span style="color: #333333;">.</span>setPayloadSize(<span style="color: #0000dd; font-weight: bold;">7</span>);
radio<span style="color: #333333;">.</span>setDataRate(RF24_250KBPS);
radio<span style="color: #333333;">.</span>openReadingPipe(<span style="color: #0000dd; font-weight: bold;">1</span>,pipe);
radio<span style="color: #333333;">.</span>startListening();
}
void loop(void){
<span style="color: #008800; font-weight: bold;">if</span> (radio<span style="color: #333333;">.</span>available()){
radio<span style="color: #333333;">.</span>read(msg, <span style="color: #0000dd; font-weight: bold;">6</span>);
Serial<span style="color: #333333;">.</span>println(msg);
delay(<span style="color: #0000dd; font-weight: bold;">10</span>);
}
<span style="color: #008800; font-weight: bold;">else</span>{
<span style="color: #333333;">//</span>Serial<span style="color: #333333;">.</span>println(<span style="background-color: #fff0f0;">"No radio available"</span>);
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<b><b>- Demo 2: Arduino Nano will send "hello" message to ESP32.</b> </b><br />
<b>ESP32 receiver code</b><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #888888;">#include <SPI.h></span>
<span style="color: #888888;">#include "nRF24L01.h"</span>
<span style="color: #888888;">#include "RF24.h"</span>
char msg[<span style="color: #0000dd; font-weight: bold;">6</span>];
RF24 radio(<span style="color: #0000dd; font-weight: bold;">12</span>, <span style="color: #0000dd; font-weight: bold;">14</span>, <span style="color: #0000dd; font-weight: bold;">26</span>, <span style="color: #0000dd; font-weight: bold;">25</span>, <span style="color: #0000dd; font-weight: bold;">27</span>);
const uint64_t pipe <span style="color: #333333;">=</span> <span style="color: #005588; font-weight: bold;">0xE8E8F0F0E1</span>LL;
void setup(void){
Serial<span style="color: #333333;">.</span>begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
radio<span style="color: #333333;">.</span>begin();
radio<span style="color: #333333;">.</span>setChannel(<span style="color: #0000dd; font-weight: bold;">2</span>);
radio<span style="color: #333333;">.</span>setPayloadSize(<span style="color: #0000dd; font-weight: bold;">7</span>);
radio<span style="color: #333333;">.</span>setDataRate(RF24_250KBPS);
radio<span style="color: #333333;">.</span>openReadingPipe(<span style="color: #0000dd; font-weight: bold;">1</span>,pipe);
radio<span style="color: #333333;">.</span>startListening();
}
void loop(void){
<span style="color: #008800; font-weight: bold;">if</span> (radio<span style="color: #333333;">.</span>available()){
radio<span style="color: #333333;">.</span>read(msg, <span style="color: #0000dd; font-weight: bold;">6</span>);
Serial<span style="color: #333333;">.</span>println(msg);
delay(<span style="color: #0000dd; font-weight: bold;">10</span>);
}
<span style="color: #008800; font-weight: bold;">else</span>{
<span style="color: #333333;">//</span>Serial<span style="color: #333333;">.</span>println(<span style="background-color: #fff0f0;">"No radio available"</span>);
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>Arduino transmitter code</b><br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #888888;">#include <SPI.h></span>
<span style="color: #888888;">#include "nRF24L01.h"</span>
<span style="color: #888888;">#include "RF24.h"</span>
char msg[<span style="color: #0000dd; font-weight: bold;">6</span>] <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"hello"</span>;
RF24 radio(<span style="color: #0000dd; font-weight: bold;">7</span>,<span style="color: #0000dd; font-weight: bold;">8</span>);
const uint64_t pipe <span style="color: #333333;">=</span> <span style="color: #005588; font-weight: bold;">0xE8E8F0F0E1</span>LL;
void setup(void) {
Serial<span style="color: #333333;">.</span>begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
radio<span style="color: #333333;">.</span>begin();
radio<span style="color: #333333;">.</span>setChannel(<span style="color: #0000dd; font-weight: bold;">2</span>);
radio<span style="color: #333333;">.</span>setPayloadSize(<span style="color: #0000dd; font-weight: bold;">7</span>);
radio<span style="color: #333333;">.</span>setDataRate(RF24_250KBPS);
radio<span style="color: #333333;">.</span>openWritingPipe(pipe);
}
void loop(void) {
Serial<span style="color: #333333;">.</span>println(<span style="background-color: #fff0f0;">"send ..."</span>);
radio<span style="color: #333333;">.</span>write(msg, <span style="color: #0000dd; font-weight: bold;">6</span>);
delay(<span style="color: #0000dd; font-weight: bold;">3000</span>);
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>4. Result</b><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJHJ4i_tt9pBIQPDMHXgh_xHDj2LlgiOr2gpC3-hPznxwRehb5gf_YSc_1gXeGQGOAkRE7es4p_mpqZoA7NunP-BWZhmtzrYVNmk6BsoVEMf5kVBp4nJtC1oqBxD58MHlGQjhMtFVyLaI/s1600/esp32-nrf24_rec.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="542" data-original-width="483" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJHJ4i_tt9pBIQPDMHXgh_xHDj2LlgiOr2gpC3-hPznxwRehb5gf_YSc_1gXeGQGOAkRE7es4p_mpqZoA7NunP-BWZhmtzrYVNmk6BsoVEMf5kVBp4nJtC1oqBxD58MHlGQjhMtFVyLaI/s320/esp32-nrf24_rec.png" width="285" /> </a></div>
<div style="text-align: center;">
Figure: ESP32 received "hello" message from Arduino </div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com23tag:blogger.com,1999:blog-7549705215513488945.post-5992344027188667302018-01-22T00:05:00.001-08:002018-01-22T00:06:58.738-08:00Demo 40: Create a Facebook Messenger chat bot for monitoring and controlling home devices using Raspberry/Orange Pi and ESP32/8266<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
In this demo, I will show you how to create a Facebook Messenger chat bot for monitoring and controlling home devices using Raspberry/Orange Pi and ESP32/8266. This is not a full solution so you need to improve it by yourself.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-8IXr7dWjxNg/WmVTua4RtQI/AAAAAAAAGOw/1ZGgc4XMVTw4d4XMqAbgoTz5r-9blPHagCLcBGAs/s1600/27048000_1810483808962464_137593235_o.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://4.bp.blogspot.com/-8IXr7dWjxNg/WmVTua4RtQI/AAAAAAAAGOw/1ZGgc4XMVTw4d4XMqAbgoTz5r-9blPHagCLcBGAs/s400/27048000_1810483808962464_137593235_o.jpg" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: Facebook Messenger chat bot for monitoring and controlling home devices</b></div>
<div style="text-align: left;">
There are 2 steps to make this demo:</div>
<div style="text-align: left;">
- How to setup a Facebook chat bot<b></b></div>
<div style="text-align: left;">
- How to setup local system (Raspberry/Orange Pi, ESP32/8266)</div>
<div style="text-align: left;">
This is the model of the demo<b>:</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-yoRvgVaW4G0/WmVYEtWBp3I/AAAAAAAAGO8/aaLWSMBigPQT7x_JnT5dYBUyGxL1RWiCACLcBGAs/s1600/ESP32_chatbot1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="235" data-original-width="721" height="208" src="https://3.bp.blogspot.com/-yoRvgVaW4G0/WmVYEtWBp3I/AAAAAAAAGO8/aaLWSMBigPQT7x_JnT5dYBUyGxL1RWiCACLcBGAs/s640/ESP32_chatbot1.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: The model of the demo </b></div>
<div style="text-align: left;">
<b>2. Setup</b></div>
<div style="text-align: left;">
<b>2.1 Create Facebook page</b></div>
<div style="text-align: left;">
You can refer to this <a href="https://www.facebook.com/business/help/104002523024878">guideline</a>.<b> </b>And choose type of Page is <span class="_63d-"><b>Business, Brand or Place</b>. In my demo, I created a page named <b>IoT Sharing</b>.</span></div>
<div style="text-align: left;">
<b>2.2 Setup Facebook chat bot</b></div>
<div style="text-align: left;">
In order to develop or use Facebook services for Software development you need to register a Facebook developer account <a href="https://developers.facebook.com/">here</a><b>.</b></div>
<div style="text-align: left;">
After created a FB developer account choose <b>My Apps -> Add a new App -> </b>Fill <b>Display name</b></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhMxaDwLf76PM1l5gPTkSqn1oLw4I22TJtFHCcnT7YjB7ORyPbYYsKqHALKpQKjc7-9Oi8wyxdtC-uc2iuncsTuBwWjC0mQTihDOWv9Fwd55hsRxf7Lz0NK21EajTpDAALRTMoVtzmuDo/s1600/ESP32_chatbot2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="346" data-original-width="1040" height="211" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhMxaDwLf76PM1l5gPTkSqn1oLw4I22TJtFHCcnT7YjB7ORyPbYYsKqHALKpQKjc7-9Oi8wyxdtC-uc2iuncsTuBwWjC0mQTihDOWv9Fwd55hsRxf7Lz0NK21EajTpDAALRTMoVtzmuDo/s640/ESP32_chatbot2.png" width="640" /></a> In <b>Select a Product -> </b>choose <b>messenger -> Set Up</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-mUcAb-Wh6aM/WmVce5-C8FI/AAAAAAAAGPQ/WuW_UlkhCOIgACGL9fdcfJAhpt8iybHswCLcBGAs/s1600/ESP32_chatbot3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="349" data-original-width="347" height="320" src="https://4.bp.blogspot.com/-mUcAb-Wh6aM/WmVce5-C8FI/AAAAAAAAGPQ/WuW_UlkhCOIgACGL9fdcfJAhpt8iybHswCLcBGAs/s320/ESP32_chatbot3.png" width="317" /></a></div>
<div style="text-align: left;">
Choose <b>Webhooks -> Setup Webhooks</b></div>
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTsxSvRdL9MDupCZlu6llrI7bGsbm5hq17DWmFDCNjvdCt3q2J-nTspWFBupsPgjgmgJJ6PekW-eNABxoOo0fA1aEYtRI21bUuRucw84k3jodqKT9_Q4gV6FeLxf9wa8tnGl_CfKSiKo0/s1600/ESP32_chatbot4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="148" data-original-width="921" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTsxSvRdL9MDupCZlu6llrI7bGsbm5hq17DWmFDCNjvdCt3q2J-nTspWFBupsPgjgmgJJ6PekW-eNABxoOo0fA1aEYtRI21bUuRucw84k3jodqKT9_Q4gV6FeLxf9wa8tnGl_CfKSiKo0/s640/ESP32_chatbot4.png" width="640" /></a><b>Note</b>: We do not do this step now. This step will be done after running the Raspbbery/Orange Pi software. Because after filled <b>Callback URL, </b><b>Verify Token </b>and press<b> Verify and Save</b>, FB will send a GET request with "<b>hub.challenge=</b><b>value of Verify Token"</b> (in this case <b>Verify Token </b>is "iotsharing.com" string)<b> </b>to Pi<b>. </b>Pi need to check the value of <b>hub.challenge </b>must match the value that we filled in <b>Verify Token </b>field (in this case Verify Token is "iotsharing.com"<b> </b>string). And then send this <b>hub.challenge</b> back to FB to finish the verification.<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3
4
5
6</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #555555; font-weight: bold;">@app.route</span>(<span style="background-color: #fff0f0;">'/'</span>, methods<span style="color: #333333;">=</span>[<span style="background-color: #fff0f0;">'GET'</span>])
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">handle_verification</span>():
<span style="color: #008800; font-weight: bold;">if</span>(request<span style="color: #333333;">.</span>args[<span style="background-color: #fff0f0;">'hub.challenge'</span>] <span style="color: #333333;">==</span> <span style="background-color: #fff0f0;">'iotsharing.com'</span>):
<span style="color: #008800; font-weight: bold;">return</span> request<span style="color: #333333;">.</span>args[<span style="background-color: #fff0f0;">'hub.challenge'</span>]
<span style="color: #008800; font-weight: bold;">else</span>:
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">'not match'</span>
</pre>
</td></tr>
</tbody></table>
</div>
Fill information like below and choose <b>Verify and Save.</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-_qMLp0L3gwQ/WmVfEZHwi-I/AAAAAAAAGPo/FUaESSkmG7cCcSG36SZQ4UuuE6BbpDxJACLcBGAs/s1600/ESP32_chatbot5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="510" data-original-width="813" height="400" src="https://2.bp.blogspot.com/-_qMLp0L3gwQ/WmVfEZHwi-I/AAAAAAAAGPo/FUaESSkmG7cCcSG36SZQ4UuuE6BbpDxJACLcBGAs/s640/ESP32_chatbot5.png" width="640" /></a></div>
<div style="text-align: left;">
choose the Page that you created in previous step and <b>Subscribe/</b><b>Unsubscribe</b>.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1Or_lrtOMN8LfHRUucet6w86GvKK540OHYsf5dUe5p70mqDMChuC2uxVyLEIRtcIBYX0WXDUS6v20Ix-icRnJs3LDUARlHb1vuGl994LPHmsk0ymLe_NH9mlBeMEvFlicNNcQ6rg1zYo/s1600/ESP32_chatbot6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="293" data-original-width="918" height="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1Or_lrtOMN8LfHRUucet6w86GvKK540OHYsf5dUe5p70mqDMChuC2uxVyLEIRtcIBYX0WXDUS6v20Ix-icRnJs3LDUARlHb1vuGl994LPHmsk0ymLe_NH9mlBeMEvFlicNNcQ6rg1zYo/s640/ESP32_chatbot6.png" width="640" /></a></div>
<div style="text-align: left;">
Finally, extract the ACCESS_TOKEN of the FB app so that our application can authenticate to use FB services.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj_BgiTxmvOiMKO_9ZuRZyVswCHoaBHuRTGUY2mXiDdtEzifkG2v6sEjwBv-Ki59vRwm2C-Ejmt5wvjePJshuHPMjdo-s4QWyrys_N_4whzb2rKHH13qb7z_1QdkzuCZDcpAGJr-nJAn4/s1600/ESP32_chatbot7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="286" data-original-width="916" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj_BgiTxmvOiMKO_9ZuRZyVswCHoaBHuRTGUY2mXiDdtEzifkG2v6sEjwBv-Ki59vRwm2C-Ejmt5wvjePJshuHPMjdo-s4QWyrys_N_4whzb2rKHH13qb7z_1QdkzuCZDcpAGJr-nJAn4/s640/ESP32_chatbot7.png" width="640" /></a></div>
<div style="text-align: left;">
It is done for Facebook setup step.</div>
<div style="text-align: left;">
<b>2.2 Setup local system (Raspberry/Orange Pi, ESP32/8266)</b></div>
<div style="text-align: left;">
In this demo, Pi will keep some roles:</div>
<div style="text-align: left;">
- Communicate with Facebook server to receive and respond message.</div>
<div style="text-align: left;">
- Parse Facebook message and then using MQTT protocol to publish the commands to ESP32/8266 clients and subscribe responses from ESP32/8266 clients.</div>
<div style="text-align: left;">
- Refer to this <a href="http://www.iotsharing.com/2017/06/how-to-turn-the-Orange-Pi-into-an-IoT-node.html">post </a>to setup MQTT for Pi.</div>
<div style="text-align: left;">
- We use <b>Python Paho MQTT</b> for local communication. Refer to this <a href="http://www.iotsharing.com/2017/05/how-to-build-system-to-update-price-tag.html">post</a> to install it.<b> </b></div>
<div style="text-align: left;">
- Besides we need<b> </b>to install some packages (Flask, ngrok) on <b>Raspberry/Orange Pi</b> for our demo. </div>
<div style="text-align: left;">
+ <b>Flask </b>is a Python web framework. In our demo, It is a web server to handle Facebook https request.</div>
<div style="text-align: left;">
+ <b>ngrok </b>secure introspect-able tunnels to local host web hook development tool and debugging tool. This tool helps Facebook server can see our Flask local web server.</div>
<div style="text-align: left;">
From Pi Terminal running the commands:</div>
<div style="text-align: left;">
+ Install <b>Flask </b>Python server: <b>"sudo pip install Flask"</b></div>
<div style="text-align: left;">
+ Download <b>ngrok: "wget https://bin.equinox.io/a/26q6mq7ddJR/ngrok-2.2.9-linux-arm.zip"</b></div>
<div style="text-align: left;">
<b>+ </b>Unzip zip file for executable app<b>: "unzip </b><b><b>ngrok-2.2.9-linux-arm.zip"</b></b></div>
<div style="text-align: left;">
<b>3. Hardware</b></div>
<div style="text-align: left;">
- 1 ESP32 or ESP8266</div>
<div style="text-align: left;">
- 1 Raspberry Pi or Orange Pi</div>
<div style="text-align: left;">
- 1 LED connect to ESP</div>
<div style="text-align: left;">
- 1 temperature sensor connect to ESP. </div>
<div style="text-align: left;">
In this demo I do not use temperature sensor. I used <b>random(min, max)</b> function to generate temperature.</div>
<div style="text-align: left;">
<b>4. Software</b><br />
The source code of this demo can be found on <a href="https://github.com/nhatuan84/facebook-chatbot-control-monitor-pi-esp">github</a>.<br />
Define messages: <b><br /></b></div>
<div style="text-align: left;">
- Pi send MQTT request topics to ESP:</div>
<div style="text-align: left;">
Temperature topic: <b>"floor1/room1/temp1"</b> to measure temperature<b><br /></b>Led topic:<b> "floor1/room1/led1" </b>to set "0" (off) or "1" (on)<b><br /></b></div>
<div style="text-align: left;">
- ESP send MQTT response topics to Pi:</div>
<div style="text-align: left;">
Temperature response topic:<b> <b>"floor1/room1/temp1/res" </b></b>with temperature value<b><b><br /></b></b>Led response topic:<b><b> "floor1/room1/led1/res" </b></b>to inform that the request was executed<b> </b></div>
<div style="text-align: left;">
- The template for Facebook message:</div>
<div style="text-align: left;">
<b>"set floor1/room1/led1 on" -> turn on LED and get response</b></div>
<div style="text-align: left;">
<b><b>"set floor1/room1/led1 off" -> turn off LED</b></b><b> and get response</b></div>
<div style="text-align: left;">
<b><b><b>"get floor1/room1/temp1" -> request temperature measurement</b></b></b><b> and get response</b></div>
<div style="text-align: left;">
<b>ESP code I reused the <a href="http://www.iotsharing.com/2017/05/how-to-arduino-esp32-dht11-dht22-temperature-humidity-sensor.html">post</a> (esp32chatbot.ino)</b></div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <WiFi.h></span>
<span style="color: #557799;">#include <PubSubClient.h></span>
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> ssid <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"dd-wrt"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> password <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"0000000000"</span>;
<span style="color: #888888;">//ip address of Raspberry/orange pi</span>
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> mqtt_server <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"192.168.1.106"</span>;
<span style="color: #333399; font-weight: bold;">char</span> msg[<span style="color: #0000dd; font-weight: bold;">20</span>];
<span style="color: #888888;">/* create an instance of PubSubClient client */</span>
WiFiClient espClient;
PubSubClient <span style="color: #0066bb; font-weight: bold;">client</span>(espClient);
<span style="color: #888888;">/*LED GPIO pin*/</span>
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span> led <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">4</span>;
<span style="color: #888888;">/* topics */</span>
<span style="color: #557799;">#define TEMP_TOPIC "floor1/room1/temp1"</span>
<span style="color: #557799;">#define LED_TOPIC "floor1/room1/led1" </span><span style="color: #888888;">/* on, off */</span><span style="color: #557799;"></span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">receivedCallback</span>(<span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> topic, byte<span style="color: #333333;">*</span> payload, <span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">int</span> length) {
Serial.print(<span style="background-color: #fff0f0;">"topic: "</span>);
Serial.println(topic);
<span style="color: #008800; font-weight: bold;">if</span>(strcmp(topic, LED_TOPIC) <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>){
Serial.print(<span style="background-color: #fff0f0;">"payload: "</span>);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> length; i<span style="color: #333333;">++</span>) {
Serial.print((<span style="color: #333399; font-weight: bold;">char</span>)payload[i]);
}
Serial.println();
<span style="color: #888888;">/* we got '1' -> on */</span>
<span style="color: #008800; font-weight: bold;">if</span> ((<span style="color: #333399; font-weight: bold;">char</span>)payload[<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">==</span> <span style="color: #0044dd;">'1'</span>) {
digitalWrite(led, HIGH);
snprintf (msg, <span style="color: #0000dd; font-weight: bold;">20</span>, <span style="background-color: #fff0f0;">"%s"</span>, <span style="background-color: #fff0f0;">"on"</span>);
<span style="color: #888888;">/* publish the response */</span>
client.publish(LED_TOPIC <span style="background-color: #fff0f0;">"/res"</span>, msg);
} <span style="color: #008800; font-weight: bold;">else</span> {
<span style="color: #888888;">/* we got '0' -> on */</span>
digitalWrite(led, LOW);
snprintf (msg, <span style="color: #0000dd; font-weight: bold;">20</span>, <span style="background-color: #fff0f0;">"%s"</span>, <span style="background-color: #fff0f0;">"off"</span>);
client.publish(LED_TOPIC <span style="background-color: #fff0f0;">"/res"</span>, msg);
}
}<span style="color: #008800; font-weight: bold;">else</span> {
snprintf (msg, <span style="color: #0000dd; font-weight: bold;">20</span>, <span style="background-color: #fff0f0;">"%d"</span>, random(<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">40</span>));
client.publish(TEMP_TOPIC <span style="background-color: #fff0f0;">"/res"</span>, msg);
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">mqttconnect</span>() {
<span style="color: #888888;">/* Loop until reconnected */</span>
<span style="color: #008800; font-weight: bold;">while</span> (<span style="color: #333333;">!</span>client.connected()) {
Serial.print(<span style="background-color: #fff0f0;">"MQTT connecting ..."</span>);
<span style="color: #888888;">/* client ID */</span>
String clientId <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"ESP32Client"</span>;
<span style="color: #888888;">/* connect now */</span>
<span style="color: #008800; font-weight: bold;">if</span> (client.connect(clientId.c_str())) {
Serial.println(<span style="background-color: #fff0f0;">"connected"</span>);
<span style="color: #888888;">/* subscribe topic */</span>
client.subscribe(LED_TOPIC);
client.subscribe(TEMP_TOPIC);
} <span style="color: #008800; font-weight: bold;">else</span> {
Serial.print(<span style="background-color: #fff0f0;">"failed, status code ="</span>);
Serial.print(client.state());
Serial.println(<span style="background-color: #fff0f0;">"try again in 5 seconds"</span>);
<span style="color: #888888;">/* Wait 5 seconds before retrying */</span>
delay(<span style="color: #0000dd; font-weight: bold;">5000</span>);
}
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
<span style="color: #888888;">// We start by connecting to a WiFi network</span>
Serial.println();
Serial.print(<span style="background-color: #fff0f0;">"Connecting to "</span>);
Serial.println(ssid);
WiFi.begin(ssid, password);
<span style="color: #008800; font-weight: bold;">while</span> (WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED) {
delay(<span style="color: #0000dd; font-weight: bold;">500</span>);
Serial.print(<span style="background-color: #fff0f0;">"."</span>);
}
<span style="color: #888888;">/* set led as output to control led on-off */</span>
pinMode(led, OUTPUT);
Serial.println(<span style="background-color: #fff0f0;">""</span>);
Serial.println(<span style="background-color: #fff0f0;">"WiFi connected"</span>);
Serial.println(<span style="background-color: #fff0f0;">"IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #888888;">/* configure the MQTT server with IPaddress and port */</span>
client.setServer(mqtt_server, <span style="color: #0000dd; font-weight: bold;">1883</span>);
<span style="color: #888888;">/* this receivedCallback function will be invoked </span>
<span style="color: #888888;"> when client received subscribed topic */</span>
client.setCallback(receivedCallback);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
<span style="color: #888888;">/* if client was disconnected then try to reconnect again */</span>
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>client.connected()) {
mqttconnect();
}
<span style="color: #888888;">/* this function will listen for incomming </span>
<span style="color: #888888;"> subscribed topic-process-invoke receivedCallback */</span>
client.loop();
}
</pre>
</td></tr>
</tbody></table>
</div>
<div style="text-align: left;">
<b><b>Pi code (chatbot.py):</b></b><br />
We use variable <b>history</b> to hold the id of Facebook messenger sender while waiting for the response from ESP<b><b>.</b></b> This sender id is used in reply() function to send response back to Facebook messenger sender.<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">from</span> <span style="color: #0e84b5; font-weight: bold;">flask</span> <span style="color: #008800; font-weight: bold;">import</span> Flask, request
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">requests</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">paho.mqtt.publish</span> <span style="color: #008800; font-weight: bold;">as</span> <span style="color: #0e84b5; font-weight: bold;">publish</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">paho.mqtt.client</span> <span style="color: #008800; font-weight: bold;">as</span> <span style="color: #0e84b5; font-weight: bold;">mqtt</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">thread</span>
ACCESS_TOKEN <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"your_fb_access token_here"</span>;
<span style="color: #888888;">#hold sender id</span>
history <span style="color: #333333;">=</span> <span style="color: #007020;">dict</span>()
set_cmd <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'floor1/room1/led1'</span>
get_cmd <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'floor1/room1/temp1'</span>
<span style="color: #888888;">#respond to FB messenger</span>
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">reply</span>(user_id, msg):
data <span style="color: #333333;">=</span> {
<span style="background-color: #fff0f0;">"recipient"</span>: {<span style="background-color: #fff0f0;">"id"</span>: user_id},
<span style="background-color: #fff0f0;">"message"</span>: {<span style="background-color: #fff0f0;">"text"</span>: msg}
}
resp <span style="color: #333333;">=</span> requests<span style="color: #333333;">.</span>post(<span style="background-color: #fff0f0;">"https://graph.facebook.com/v2.6/me/messages?access_token="</span> <span style="color: #333333;">+</span> ACCESS_TOKEN, json<span style="color: #333333;">=</span>data)
<span style="color: #008800; font-weight: bold;">print</span>(resp<span style="color: #333333;">.</span>content)
<span style="color: #888888;">#MQTT handler</span>
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_connect</span>(mqttc, obj, flags, rc):
<span style="color: #008800; font-weight: bold;">print</span>(<span style="background-color: #fff0f0;">"rc: "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(rc))
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_message</span>(mqttc, obj, msg):
<span style="color: #008800; font-weight: bold;">print</span>(msg<span style="color: #333333;">.</span>topic<span style="color: #333333;">+</span><span style="background-color: #fff0f0;">": "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(msg<span style="color: #333333;">.</span>payload))
<span style="color: #008800; font-weight: bold;">if</span> msg<span style="color: #333333;">.</span>topic <span style="color: black; font-weight: bold;">in</span> history:
user_id <span style="color: #333333;">=</span> history[msg<span style="color: #333333;">.</span>topic]
<span style="color: #888888;">#reply FB messenger</span>
reply(user_id, msg<span style="color: #333333;">.</span>payload)
history<span style="color: #333333;">.</span>pop(msg<span style="color: #333333;">.</span>topic, <span style="color: #007020;">None</span>)
mqttc <span style="color: #333333;">=</span> mqtt<span style="color: #333333;">.</span>Client()
mqttc<span style="color: #333333;">.</span>on_connect <span style="color: #333333;">=</span> on_connect
mqttc<span style="color: #333333;">.</span>on_message <span style="color: #333333;">=</span> on_message
mqttc<span style="color: #333333;">.</span>connect(<span style="background-color: #fff0f0;">"localhost"</span>, <span style="color: #0000dd; font-weight: bold;">1883</span>, <span style="color: #0000dd; font-weight: bold;">60</span>)
mqttc<span style="color: #333333;">.</span>subscribe(<span style="background-color: #fff0f0;">"floor1/#"</span>, <span style="color: #0000dd; font-weight: bold;">0</span>)
<span style="color: #888888;">#MQTT subscribe thread </span>
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">mqtt_thread</span>( threadName, delay):
mqttc<span style="color: #333333;">.</span>loop_forever()
<span style="color: #008800; font-weight: bold;">try</span>:
thread<span style="color: #333333;">.</span>start_new_thread( mqtt_thread, (<span style="background-color: #fff0f0;">"mqtt-thread"</span>, <span style="color: #0000dd; font-weight: bold;">0</span>, ) )
<span style="color: #008800; font-weight: bold;">except</span>:
<span style="color: #008800; font-weight: bold;">print</span> <span style="background-color: #fff0f0;">"Error: unable to start thread"</span>
<span style="color: #888888;">#Flask web server instance</span>
app <span style="color: #333333;">=</span> Flask(__name__)
<span style="color: #888888;">#handle GET request from Facebook</span>
<span style="color: #555555; font-weight: bold;">@app.route</span>(<span style="background-color: #fff0f0;">'/'</span>, methods<span style="color: #333333;">=</span>[<span style="background-color: #fff0f0;">'GET'</span>])
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">handle_verification</span>():
<span style="color: #008800; font-weight: bold;">if</span>(request<span style="color: #333333;">.</span>args[<span style="background-color: #fff0f0;">'hub.challenge'</span>] <span style="color: #333333;">==</span> <span style="background-color: #fff0f0;">'iotsharing.com'</span>):
<span style="color: #008800; font-weight: bold;">return</span> request<span style="color: #333333;">.</span>args[<span style="background-color: #fff0f0;">'hub.challenge'</span>]
<span style="color: #008800; font-weight: bold;">else</span>:
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">'not matched'</span>
<span style="color: #888888;">#handle POST request from Facebook</span>
<span style="color: #555555; font-weight: bold;">@app.route</span>(<span style="background-color: #fff0f0;">'/'</span>, methods<span style="color: #333333;">=</span>[<span style="background-color: #fff0f0;">'POST'</span>])
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">handle_incoming_messages</span>():
data <span style="color: #333333;">=</span> request<span style="color: #333333;">.</span>json
<span style="color: #008800; font-weight: bold;">print</span>(data)
sender <span style="color: #333333;">=</span> data[<span style="background-color: #fff0f0;">'entry'</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="background-color: #fff0f0;">'messaging'</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="background-color: #fff0f0;">'sender'</span>][<span style="background-color: #fff0f0;">'id'</span>]
message <span style="color: #333333;">=</span> data[<span style="background-color: #fff0f0;">'entry'</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="background-color: #fff0f0;">'messaging'</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="background-color: #fff0f0;">'message'</span>][<span style="background-color: #fff0f0;">'text'</span>]
<span style="color: #008800; font-weight: bold;">print</span>(message)
<span style="color: #008800; font-weight: bold;">if</span>(message<span style="color: #333333;">.</span>startswith(<span style="background-color: #fff0f0;">'set'</span>)):
arr <span style="color: #333333;">=</span> message<span style="color: #333333;">.</span>split()
l <span style="color: #333333;">=</span> <span style="color: #007020;">len</span>(arr)
<span style="color: #008800; font-weight: bold;">if</span>(l <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">3</span> <span style="color: black; font-weight: bold;">and</span> set_cmd <span style="color: #333333;">==</span> arr[<span style="color: #0000dd; font-weight: bold;">1</span>]):
cmd <span style="color: #333333;">=</span> arr[<span style="color: #0000dd; font-weight: bold;">1</span>]
val <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'1'</span> <span style="color: #008800; font-weight: bold;">if</span> arr[<span style="color: #0000dd; font-weight: bold;">2</span>]<span style="color: #333333;">==</span><span style="background-color: #fff0f0;">'on'</span> <span style="color: #008800; font-weight: bold;">else</span> <span style="background-color: #fff0f0;">'0'</span>
publish<span style="color: #333333;">.</span>single(cmd, val, hostname<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">"localhost"</span>)
<span style="color: #888888;">#record command with sender id</span>
history[cmd<span style="color: #333333;">+</span><span style="background-color: #fff0f0;">'/res'</span>] <span style="color: #333333;">=</span> sender
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">'ok'</span>
<span style="color: #008800; font-weight: bold;">elif</span>(message<span style="color: #333333;">.</span>startswith(<span style="background-color: #fff0f0;">'get'</span>)):
arr <span style="color: #333333;">=</span> message<span style="color: #333333;">.</span>split()
l <span style="color: #333333;">=</span> <span style="color: #007020;">len</span>(arr)
<span style="color: #008800; font-weight: bold;">if</span>(l <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">2</span> <span style="color: black; font-weight: bold;">and</span> get_cmd <span style="color: #333333;">==</span> arr[<span style="color: #0000dd; font-weight: bold;">1</span>]):
cmd <span style="color: #333333;">=</span> arr[<span style="color: #0000dd; font-weight: bold;">1</span>]
publish<span style="color: #333333;">.</span>single(cmd, <span style="background-color: #fff0f0;">''</span>, hostname<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">"localhost"</span>)
<span style="color: #888888;">#record command with sender id</span>
history[cmd<span style="color: #333333;">+</span><span style="background-color: #fff0f0;">'/res'</span>] <span style="color: #333333;">=</span> sender
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">'ok'</span>
reply(sender, <span style="background-color: #fff0f0;">'invalid query'</span>)
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">"ok"</span>
<span style="color: #008800; font-weight: bold;">if</span> __name__ <span style="color: #333333;">==</span> <span style="background-color: #fff0f0;">'__main__'</span>:
app<span style="color: #333333;">.</span>run(debug<span style="color: #333333;">=</span><span style="color: #007020;">True</span>)
</pre>
</td></tr>
</tbody></table>
</div>
<b><b>5. Steps to deploy</b></b><br />
- MQTT broker run on Pi<br />
- Open 2 Terminal on Pi:<br />
+ Run "<b>python chatbot.py</b>" with <b>Flask </b>in it.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-ZYBPm0sqB04/WmWWuDs6TAI/AAAAAAAAGQU/hU9C4HY3zyAnZqpRN-ZHe37DqzzfAR6zgCLcBGAs/s1600/ESP32_chatbot8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="68" data-original-width="326" height="66" src="https://1.bp.blogspot.com/-ZYBPm0sqB04/WmWWuDs6TAI/AAAAAAAAGQU/hU9C4HY3zyAnZqpRN-ZHe37DqzzfAR6zgCLcBGAs/s320/ESP32_chatbot8.png" width="320" /></a></div>
+ Run <b>ngrok </b>(5000 is the port Flask listen on): "<b>./ngrok http 5000</b>" <br />
<b><b></b></b><br />
<div class="separator" style="clear: both; text-align: center;">
<b><b><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVplEXwkaKW5x_3b69H6ZVSVqc5RL1q_VpuJD4l9UyBcLcdh7iPwCSwNzO3EIHLsLMgBxuX9mAaraE8gcJDjE3L1jz6hT_8eqkenMQYAJwCatJmUyplYYA-Pz_h8zoO1H6F4usyW6lF5w/s1600/ESP32_chatbot9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="95" data-original-width="576" height="104" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVplEXwkaKW5x_3b69H6ZVSVqc5RL1q_VpuJD4l9UyBcLcdh7iPwCSwNzO3EIHLsLMgBxuX9mAaraE8gcJDjE3L1jz6hT_8eqkenMQYAJwCatJmUyplYYA-Pz_h8zoO1H6F4usyW6lF5w/s640/ESP32_chatbot9.png" width="640" /></a></b></b></div>
Copy the url in red box to <b>Callback URL field </b>that mention in step <b>2.2 Setup Facebook chat bot</b><br />
<b>Note</b>: in case we shutdown ngrok and run it again the new url will be generated. We have to re-register this url to Facebook.<br />
Choose <b>Webhooks -> Edit Subscription</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-bPpnPD1K18Q/WmWZFJRLsFI/AAAAAAAAGQo/8_BgaRP3GUAZqLMVezW5W_WNQWG4OLxzACLcBGAs/s1600/ESP32_chatbot10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="410" data-original-width="808" height="202" src="https://2.bp.blogspot.com/-bPpnPD1K18Q/WmWZFJRLsFI/AAAAAAAAGQo/8_BgaRP3GUAZqLMVezW5W_WNQWG4OLxzACLcBGAs/s400/ESP32_chatbot10.png" width="400" /></a></div>
And then Unsubcribe and Subscribe the page again:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjshaAQ_9t_SDSQGpJB3u4WtSpnDdvGG2fOY91PuWpMHQ-rEr4s2p2Na_AO0PJJEudarm8Dy65wd2NefMalYh57rmXFpfZ7qLThuRwpzvNCX8Qgfbq7Jo29sK9oftaQ8-4wR_Oz20LxFXw/s1600/ESP32_chatbot6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="293" data-original-width="918" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjshaAQ_9t_SDSQGpJB3u4WtSpnDdvGG2fOY91PuWpMHQ-rEr4s2p2Na_AO0PJJEudarm8Dy65wd2NefMalYh57rmXFpfZ7qLThuRwpzvNCX8Qgfbq7Jo29sK9oftaQ8-4wR_Oz20LxFXw/s400/ESP32_chatbot6.png" width="400" /></a></div>
Now go to the Page that we created, choose About and Send Message<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSRk4TjUPfUkwQhWg507ubJdJLCoA9I0MhQjaqgaFITJEG4cIgFi50CPzAG-iF634tfsk48t-LZS7Al-vmimQtrba70UFBpMhsWCe5Axb06wK_KHmsQLKhMYRQ8vEgE0AcxF9V7aYyw-4/s1600/27048000_1810483808962464_137593235_o.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSRk4TjUPfUkwQhWg507ubJdJLCoA9I0MhQjaqgaFITJEG4cIgFi50CPzAG-iF634tfsk48t-LZS7Al-vmimQtrba70UFBpMhsWCe5Axb06wK_KHmsQLKhMYRQ8vEgE0AcxF9V7aYyw-4/s640/27048000_1810483808962464_137593235_o.jpg" width="640" /></a></div>
And type one of commands:<br />
<b>"set floor1/room1/led1 on"<br />"set floor1/room1/led1 off"<br />"get floor1/room1/temp1"</b><br />
<b>6. Result</b><br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/BMPNvKMY_gU/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/BMPNvKMY_gU?feature=player_embedded" width="480"></iframe></div>
<br />
<br />
<b><b> </b></b></div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
<br />
<b></b></div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com4tag:blogger.com,1999:blog-7549705215513488945.post-58186208616719873312017-12-07T05:10:00.004-08:002017-12-07T19:58:44.466-08:00Demo 38: How to decode error/exception "CPU halted" of ESP on Arduino<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
When developing software for ESP8266 or ESP32, you often face error(s) that caused the ESP halt. At that moment, looking the <a href="http://www.iotsharing.com/2017/05/how-to-use-serial-arduino-esp32-print-debug.html">Serial Monitor</a> window, you will see the error/exception like below:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-tKRx2nr3Juw/WijjzVsg4LI/AAAAAAAAF3k/6yiWc6yfCQ4x9A445t_NgM83buERDiDEACLcBGAs/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="464" data-original-width="1312" height="224" src="https://3.bp.blogspot.com/-tKRx2nr3Juw/WijjzVsg4LI/AAAAAAAAF3k/6yiWc6yfCQ4x9A445t_NgM83buERDiDEACLcBGAs/s640/3.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: error that caused ESP CPU halt</b></div>
It is not easy to know what was happening with our software. Actually, the string that is highlighted has meaning; it is the called stack of software when the CPU halted. There is a <a href="https://github.com/me-no-dev/EspExceptionDecoder">tool </a>that supports you to decode the ESP error/exception above. It called <a href="https://github.com/me-no-dev/EspExceptionDecoder">EspExceptionDecoder</a>. It is tool that is attached with Arduino IDE.<br />
In order to install it, please follow these steps:<br />
- Install Arduino IDE with ESP8266/ESP32 core.<br />
- Download the tool <a href="https://github.com/me-no-dev/EspExceptionDecoder/releases/download/1.0.6/EspExceptionDecoder-1.0.6.zip">here</a>.<br />
- Create <b>tools </b>directory under Arduino directory if it is not exist.<br />
- Unpack the downloaded tool into tools directory (the path will look like <home_dir>/Arduino/tools/EspExceptionDecoder/tool/EspExceptionDecoder.jar).<br /> - Restart Arduino IDE.</home_dir><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0iLA6g4sQt-9w1_-0yEvLcLSGO8CX2oRD8G_6zfO_eBbI4p6k9y6qG0tRRTvryUtr6vqPPO3r4Xuy_9CNggs_HrMdmK62m9FTouAs1Y9Z5zsWytx9o6zyl1PRT5iEM0d7eqAsJspXpOQ/s1600/5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="233" data-original-width="425" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0iLA6g4sQt-9w1_-0yEvLcLSGO8CX2oRD8G_6zfO_eBbI4p6k9y6qG0tRRTvryUtr6vqPPO3r4Xuy_9CNggs_HrMdmK62m9FTouAs1Y9Z5zsWytx9o6zyl1PRT5iEM0d7eqAsJspXpOQ/s640/5.png" width="640" /></a></div>
<br />
<div style="text-align: center;">
<b>Figure: Under Tools menu, new entry ESP Exception Decoder </b></div>
<b>2. Demo</b><br />
I will make a simple program demo for this tool.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>buf <span style="color: #333333;">=</span> <span style="color: #007020;">NULL</span>;
buf[<span style="color: #0000dd; font-weight: bold;">2</span>] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">4</span>;
Serial.printf(<span style="background-color: #fff0f0;">"val %d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, buf[<span style="color: #0000dd; font-weight: bold;">2</span>]);
}
<span style="color: #888888;">/* the forever loop() function is invoked by Arduino ESP32 loopTask */</span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
}
</pre>
</td></tr>
</tbody></table>
</div>
Here the bug is that <b>buf</b> is not initialized buf <b>buf[2]</b> is assigned to 4. <br />
Loading the software to ESP and look the Serial Monitor:<br />
<div style="text-align: center;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-mPfau37CRQw/Wik7zuGFoEI/AAAAAAAAF4c/5jaouYI4ShARXtB24FaPfQiTcRcFC8O3gCEwYBhgL/s1600/esp32stacktrace5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="438" data-original-width="639" height="438" src="https://2.bp.blogspot.com/-mPfau37CRQw/Wik7zuGFoEI/AAAAAAAAF4c/5jaouYI4ShARXtB24FaPfQiTcRcFC8O3gCEwYBhgL/s640/esp32stacktrace5.png" width="640" /></a></div>
</div>
<div style="text-align: center;">
<b>Figure: error in software </b></div>
After that choosing <b>Tools->ESP Exception Decoder</b>, a window will occur.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQA7l9WRcezOc7a0EXNksOtoygU-TNjCPbb7yTcDfjnMX5nFcGUvGh0i7YMC6CXkNRiCA1uPpR6MgdDOzC9MhykYsnqjJECIXW_gcEhf_3PtqnuxMlShjuxq_0nvJjYdKWRxMN-IT75j0/s1600/esp32stacktrace6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="501" data-original-width="787" height="406" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQA7l9WRcezOc7a0EXNksOtoygU-TNjCPbb7yTcDfjnMX5nFcGUvGh0i7YMC6CXkNRiCA1uPpR6MgdDOzC9MhykYsnqjJECIXW_gcEhf_3PtqnuxMlShjuxq_0nvJjYdKWRxMN-IT75j0/s640/esp32stacktrace6.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: Exception Decoder window</b></div>
<br />
Copy and paste the string "<b>Backtrace: 0x400d05be:0x3ffc77c0 0x400d9b1a:0x3ffc77e0</b>
" to it and you will see the output:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNa1oPS23d3ve7UBVJ6jxcegtdBzFhIuoE8qTptw0wJn-6-EZLFY0bedZR3RBJtYEv3X7ovm2Ir5mxlfDpkfvC5Dm-VOZXiFN19tUvnFbddnzfarG7oLEsoV5khxJ4ES1xgBeiypYMwPQ/s1600/esp32stacktrace6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="562" data-original-width="1194" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNa1oPS23d3ve7UBVJ6jxcegtdBzFhIuoE8qTptw0wJn-6-EZLFY0bedZR3RBJtYEv3X7ovm2Ir5mxlfDpkfvC5Dm-VOZXiFN19tUvnFbddnzfarG7oLEsoV5khxJ4ES1xgBeiypYMwPQ/s640/esp32stacktrace6.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: the result after decoding stacktrace</b></div>
So you see the CPU halted executing the code at line 4: <b>buf[2] = 4; </b>as we knew.<br />
This is just a simple application. In real world, you may face a more difficult situation than this, but at least you could know where your application is halted. <br />
<b></b></div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com4tag:blogger.com,1999:blog-7549705215513488945.post-47073062031472182232017-12-03T03:43:00.002-08:002017-12-06T15:36:50.249-08:00Demo 37: Display distance measured by ultrasonic sensor using module 7-segment-LED-N-Digits<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
Today I will show you how to use module 7-segment-LED-N-Digits to display distance which is measured by ultrasonic sensor. <br />
<b>2. Hardware and Software </b><br />
<b>2.1 Ultrasonic sensor</b><br />
I used HC - SR04.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-VF5or8dyKR8/WiO66aNjIsI/AAAAAAAAF0A/9Oiz5JmsC7A19BjRm5bnYNRI-inCG1ImgCLcBGAs/s1600/esp-ultrasonic-sensor.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="431" data-original-width="664" height="206" src="https://1.bp.blogspot.com/-VF5or8dyKR8/WiO66aNjIsI/AAAAAAAAF0A/9Oiz5JmsC7A19BjRm5bnYNRI-inCG1ImgCLcBGAs/s320/esp-ultrasonic-sensor.png" width="320" /></a></div>
<br />
<div style="text-align: center;">
<b>Figure: Ultrasonic sensor HC - SR04 (Source: <a href="http://www.micropik.com/PDF/HCSR04.pdf">Internet</a>)</b> </div>
<div style="text-align: left;">
The sensor has 2 heads: one is emit the ultrasonic and one receives it when the ultrasonic is reflect by the obstacle. The range of this sensor is 2cm - 400cm non-contact.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-qVZcOEdiH5M/WiO88pXw1JI/AAAAAAAAF0M/GeallDJ54l4cVd1GVtv68jvXwtJvgBymgCLcBGAs/s1600/esp-ultrasonic-mechanism.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="306" data-original-width="571" height="213" src="https://1.bp.blogspot.com/-qVZcOEdiH5M/WiO88pXw1JI/AAAAAAAAF0M/GeallDJ54l4cVd1GVtv68jvXwtJvgBymgCLcBGAs/s400/esp-ultrasonic-mechanism.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: the operation mechanism of ultrasonic sensor</b></div>
<div style="text-align: left;">
The picture below is timing diagram of HC - SR04.</div>
<div class="separator" style="clear: both; text-align: left;">
<img border="0" data-original-height="295" data-original-width="686" height="274" src="https://4.bp.blogspot.com/-95sLErP3Cz8/WiO9kTxlkYI/AAAAAAAAF0U/zWX2W4os4ykKD-J9g5GV0wCjMUkSoBEJACLcBGAs/s640/esp-ultrasonic-timing-diagram.png" width="640" /> </div>
<div class="separator" style="clear: both; text-align: center;">
<b>Figure: timing diagram of HC - SR04</b></div>
The basic principle of work: <br />
(1) Using IO trigger for at least 10us high level signal. <br />
(2) The Module automatically sends eight 40 kHz and detect whether there is a ultrasonic signal back. <br />
(3) IF the ultrasonic signal back, through high level, time of high output IO duration is the time from sending ultrasonic to returning. <br />
Test distance = (High level time x velocity of sound (299 cm/us) / 2<br />
<b>2.2 7-segment-LED-8-digit module</b><br />
<b>I used</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEittaR82RwUD0GeuIvkjc-EMO9A7-KBrIEqjNhZzmRexHL1dZoOjJfSJ2rkYfS2bj68yJQqUZ2T3kL-5OgojMS9PeMkXUMfbco7ERMRnU3JRJ-RANemamGTW7SQRDlbCYX1lRsCmSGrKTc/s1600/esp-led7seg8digit.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="360" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEittaR82RwUD0GeuIvkjc-EMO9A7-KBrIEqjNhZzmRexHL1dZoOjJfSJ2rkYfS2bj68yJQqUZ2T3kL-5OgojMS9PeMkXUMfbco7ERMRnU3JRJ-RANemamGTW7SQRDlbCYX1lRsCmSGrKTc/s320/esp-led7seg8digit.jpg" width="240" /></a></div>
<div style="text-align: center;">
<b><b>Figure: 7-segment-LED-8-digit module</b></b></div>
<div style="text-align: left;">
This module used IC 74HC595. It is a 8 bits shift register. With this IC we can save more IO digital instead of using a lot of IO pins to trigger each segment of LED. <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-ZJxfjhl0WHA/WiPDIqwu63I/AAAAAAAAF0s/2E-CvXU93aUGYSf2dc0yJXgWLADYFzxzQCLcBGAs/s1600/esp-7-seg-led-n-digit-module.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="484" data-original-width="831" height="372" src="https://1.bp.blogspot.com/-ZJxfjhl0WHA/WiPDIqwu63I/AAAAAAAAF0s/2E-CvXU93aUGYSf2dc0yJXgWLADYFzxzQCLcBGAs/s640/esp-7-seg-led-n-digit-module.png" width="640" /></a></div>
</div>
<div style="text-align: center;">
<b>Figure: schematic application of </b><b>IC 74HC595</b></div>
<div style="text-align: left;">
In order to bring data to this LED module, first we shift data that will be displayed on LED then we shift the value that indicate which LED in order that will display the data. i created the library <a href="https://github.com/nhatuan84/arduino-led-7-seg-N-digit.git">here</a>. The library is easy to use. You create an instance of library <b> </b></div>
<div style="text-align: left;">
<b>EspLed7SegNDigit ledm(SCLK, RCLK, DIO, 8);</b></div>
<div style="text-align: left;">
where SCLK, RCLK, DIO is pins that connect between ESP and LED module. 8 is number of LEDs in module.</div>
<div style="text-align: left;">
We can use<b> ledm.setCharAt(8, 'd'); </b>to set the value (here is character 'd') that will be displayed at specific LED (here is LED number 8)<b>.</b></div>
<div style="text-align: left;">
In order to human can see the LED clearly, the LED scan time will be default 400ms (25 frames/second). You can set it using setRefreshTime(ms). The callback function <b>updateDisplayCb()</b> will be invoked after every refreshing time to update new value for LED displaying. You should call "<b>ledm.clearDisplay()</b>" to clear LED module before updating new display. You can use <b>ledm.displayNum(num, 3); </b>to display the float number with 3 digits behind the dot character. The function "<b>ledm.loop();</b>" will run continuously to update the display on LED.<br />
<b>Pins connection:</b><br />
<b>LED module </b><br />
+SCLK with ESP32 GPIO14+RCLK with ESP32 GPIO27<br />
+DIO with ESP32 GPIO12<br />
<b>Ultrasonic sensor</b><br />
+TRIG with ESP32 GPIO25<br />
+ECHO with ESP32 GPIO33</div>
<div style="text-align: left;">
<b>2.3 Full software</b></div>
<div style="text-align: left;">
Our application has 2 <a href="http://www.iotsharing.com/2017/06/how-to-apply-freertos-in-arduino-esp32.html">FreeRTOS tasks</a>: 1 for ultrasonic measurement and 1 for LED updating.<br />
<div style="text-align: center;">
<b>This version do not use FreeRTOS </b></div>
</div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include "EspLed7SegNDigit.h"</span>
<span style="color: #888888;">//LED pins</span>
<span style="color: #333399; font-weight: bold;">int</span> SCLK <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">14</span>; <span style="color: #888888;">//pulse</span>
<span style="color: #333399; font-weight: bold;">int</span> RCLK <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">27</span>; <span style="color: #888888;">//latch</span>
<span style="color: #333399; font-weight: bold;">int</span> DIO <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">12</span>; <span style="color: #888888;">//data</span>
<span style="color: #888888;">//utrasonic pins</span>
<span style="color: #333399; font-weight: bold;">int</span> TRIG_PIN <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">25</span>;
<span style="color: #333399; font-weight: bold;">int</span> ECHO_PIN <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">33</span>;
<span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">long</span> startMeasure <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">long</span> endMeasure <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">long</span> measureTime <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">long</span> distance <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
EspLed7SegNDigit <span style="color: #0066bb; font-weight: bold;">ledm</span>(SCLK, RCLK, DIO, <span style="color: #0000dd; font-weight: bold;">8</span>);
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">updateDisplayCb</span>(<span style="color: #333399; font-weight: bold;">void</span>){
ledm.clearDisplay();
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0044dd;">'d'</span>);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">7</span>, <span style="color: #0044dd;">'s'</span>);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">6</span>, <span style="color: #0044dd;">'t'</span>);
ledm.displayNum(distance, 3);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">initUltra</span>(){
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ultraTask</span>(){
<span style="color: #888888;">//trigger sensor with pulse LOW-HIGH-LOW</span>
digitalWrite(TRIG_PIN, LOW);
<span style="color: #888888;">//wait 2 us</span>
delayMicroseconds(<span style="color: #0000dd; font-weight: bold;">2</span>);
digitalWrite(TRIG_PIN, HIGH);
<span style="color: #888888;">//wait 10 us</span>
delayMicroseconds(<span style="color: #0000dd; font-weight: bold;">10</span>);
digitalWrite(TRIG_PIN, LOW);
<span style="color: #888888;">//at the beginning ECHO pin will be pull LOW until finishing transmitting ultrasonic signal</span>
<span style="color: #008800; font-weight: bold;">while</span> (digitalRead(ECHO_PIN) <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>){
startMeasure <span style="color: #333333;">=</span> micros();
}
<span style="color: #888888;">//ECHO pin will be pulled HIGH until get response</span>
<span style="color: #008800; font-weight: bold;">while</span> (digitalRead(ECHO_PIN) <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">1</span>){
endMeasure <span style="color: #333333;">=</span> micros();
}
<span style="color: #888888;">//response time will be calculated by</span>
measureTime <span style="color: #333333;">=</span> endMeasure <span style="color: #333333;">-</span> startMeasure;
<span style="color: #888888;">//convert to cm</span>
distance <span style="color: #333333;">=</span> (measureTime)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">29</span><span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
Serial.printf(<span style="background-color: #fff0f0;">"distance = %d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, distance);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
<span style="color: #888888;">// put your setup code here, to run once:</span>
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
initUltra();
<span style="color: #888888;">//this callback will be invoked for updating new ultrasonic value</span>
ledm.setUpdateCb(updateDisplayCb);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0044dd;">'d'</span>);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">7</span>, <span style="color: #0044dd;">'s'</span>);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">6</span>, <span style="color: #0044dd;">'t'</span>);
<span style="color: #888888;">//in loop it take time to do ultraTask so we decrease refresh time</span>
ledm.setRefreshTime(<span style="color: #0000dd; font-weight: bold;">100</span>);
}
<span style="color: #333399; font-weight: bold;">long</span> tick <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
<span style="color: #888888;">// put your main code here, to run repeatedly:</span>
ledm.loop();
<span style="color: #333399; font-weight: bold;">long</span> now <span style="color: #333333;">=</span> millis();
<span style="color: #008800; font-weight: bold;">if</span> (now <span style="color: #333333;">-</span> tick <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">1000</span>) {
tick <span style="color: #333333;">=</span> now;
ultraTask();
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<div style="text-align: center;">
<b>This version uses FreeRTOS</b></div>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include "EspLed7SegNDigit.h"</span>
<span style="color: #888888;">//utrasonic pins</span>
<span style="color: #333399; font-weight: bold;">int</span> TRIG_PIN <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">25</span>;
<span style="color: #333399; font-weight: bold;">int</span> ECHO_PIN <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">33</span>;
<span style="color: #888888;">//LED pins</span>
<span style="color: #333399; font-weight: bold;">int</span> SCLK <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">14</span>; <span style="color: #888888;">//pulse</span>
<span style="color: #333399; font-weight: bold;">int</span> RCLK <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">27</span>; <span style="color: #888888;">//latch</span>
<span style="color: #333399; font-weight: bold;">int</span> DIO <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">12</span>; <span style="color: #888888;">//data</span>
<span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">long</span> measureTime <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">long</span> distance <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
EspLed7SegNDigit <span style="color: #0066bb; font-weight: bold;">ledm</span>(SCLK, RCLK, DIO, <span style="color: #0000dd; font-weight: bold;">8</span>);
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">initUltra</span>(){
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">updateDisplayCb</span>(<span style="color: #333399; font-weight: bold;">void</span>){
ledm.clearDisplay();
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0044dd;">'d'</span>);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">7</span>, <span style="color: #0044dd;">'s'</span>);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">6</span>, <span style="color: #0044dd;">'t'</span>);
ledm.displayNum(distance, <span style="color: #0000dd; font-weight: bold;">3</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
Serial.begin(<span style="color: #0000dd; font-weight: bold;">112500</span>);
initUltra();
<span style="color: #888888;">//this callback will be invoked for updating new ultrasonic value</span>
ledm.setUpdateCb(updateDisplayCb);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">8</span>, <span style="color: #0044dd;">'d'</span>);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">7</span>, <span style="color: #0044dd;">'s'</span>);
ledm.setCharAt(<span style="color: #0000dd; font-weight: bold;">6</span>, <span style="color: #0044dd;">'t'</span>);
ledm.setRefreshTime(<span style="color: #0000dd; font-weight: bold;">100</span>);
<span style="color: #888888;">/* we create a new task here */</span>
xTaskCreate(
ultraTask, <span style="color: #888888;">/* Task function. */</span>
<span style="background-color: #fff0f0;">"ultrasonic Task"</span>, <span style="color: #888888;">/* name of task. */</span>
<span style="color: #0000dd; font-weight: bold;">10000</span>, <span style="color: #888888;">/* Stack size of task */</span>
<span style="color: #007020;">NULL</span>, <span style="color: #888888;">/* parameter of the task */</span>
<span style="color: #0000dd;">3</span>, <span style="color: #888888;">/* priority of the task */</span>
<span style="color: #007020;">NULL</span>); <span style="color: #888888;">/* Task handle to keep track of created task */</span>
}
<span style="color: #888888;">/* the forever loop() function is invoked by Arduino ESP32 loopTask */</span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
ledm.loop();
delay(<span style="color: #0000dd; font-weight: bold;">1</span>);
}
<span style="color: #888888;">/* this function will be invoked when ultraTask was created */</span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ultraTask</span>( <span style="color: #333399; font-weight: bold;">void</span> <span style="color: #333333;">*</span> parameter )
{
<span style="color: #008800; font-weight: bold;">for</span>(;;){
<span style="color: #888888;">//trigger sensor with pulse LOW-HIGH-LOW</span>
digitalWrite(TRIG_PIN, LOW);
<span style="color: #888888;">//wait 2 us</span>
delayMicroseconds(<span style="color: #0000dd; font-weight: bold;">2</span>);
digitalWrite(TRIG_PIN, HIGH);
<span style="color: #888888;">//wait 10 us</span>
delayMicroseconds(<span style="color: #0000dd; font-weight: bold;">10</span>);
digitalWrite(TRIG_PIN, LOW);
measureTime <span style="color: #333333;">=</span> pulseIn(ECHO_PIN, HIGH);//read measurement time for HIGH level from Echo
<span style="color: #888888;">//convert to cm</span>
distance <span style="color: #333333;">=</span> (measureTime)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">29</span><span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
Serial.printf(<span style="background-color: #fff0f0;">"distance = %d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, distance);
delay(<span style="color: #0000dd; font-weight: bold;">1000</span>);
}
vTaskDelete( <span style="color: #007020;">NULL</span> );
}
</pre>
</td></tr>
</tbody></table>
</div>
<b>3. Result</b><br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/qz4Cmff7Vjk/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/qz4Cmff7Vjk?feature=player_embedded" width="480"></iframe></div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com1tag:blogger.com,1999:blog-7549705215513488945.post-18916691698647802332017-11-25T19:26:00.001-08:002018-02-28T00:52:31.930-08:00Demo 36: Firmware update OTA via ESP Http Web Server<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
In <a href="http://www.iotsharing.com/2017/11/firmware-update-ota-for-esp32-using-http-sdcard.html">Demo 34: firmware update OTA for ESP32 using HTTP and sdcard</a> and <a href="http://www.iotsharing.com/2017/11/firmware-update-ota-for-esp32-using-http.html">Demo 35: firmware update OTA for ESP32 directly using HTTP</a>, I showed ways to update firmware OTA. In this demo, I will show you another way. That is updating firmware OTA for ESP via ESP Http Web server. With this demo, ESP will act as a web server and user will access the web server and upload the firmware file to ESP via web browser.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-VqeyOEv438M/WhQitKb5A_I/AAAAAAAAFs8/6LhPYW9uk6MQNOab47wil49GjO9vXDvIwCLcBGAs/s1600/esp32wota.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="192" data-original-width="482" height="158" src="https://4.bp.blogspot.com/-VqeyOEv438M/WhQitKb5A_I/AAAAAAAAFs8/6LhPYW9uk6MQNOab47wil49GjO9vXDvIwCLcBGAs/s400/esp32wota.png" width="400" /></a></div>
<div style="text-align: center;">
<b>Figure: Web interface of the demo</b></div>
<div style="text-align: left;">
User choose <b>Browse</b> button, navigate to firmware file and press <b>Update</b> button. The updating progress will be shown.</div>
<div style="text-align: left;">
<b>2. Hardware</b></div>
<div style="text-align: left;">
Using <a href="http://www.iotsharing.com/2017/05/blinky-hello-world-on-arduino-esp32.html" target="_blank">Demo 1 </a>to connect ESP to LED.</div>
<div style="text-align: left;">
<b>3. Software</b><br />
- First, we will create a simple LED blink application, export the binary file
for updating. In order to export the <b>.bin</b> file from Arduino IDE Menu, we
choose <b>Sketch -> Export compiled Binary</b>. After finishing we choose <b>Sketch -> Show Sketch Folder</b>. You will see the <b>.bin</b> file there, rename it as <b>led.bin. </b>Below is the LED blinky code.
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #333399; font-weight: bold;">int</span> ledPin <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">14</span>;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>(){
pinMode(ledPin, OUTPUT);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>(){
digitalWrite(ledPin, HIGH);
delay(<span style="color: #0000dd; font-weight: bold;">1000</span>);
digitalWrite(ledPin, LOW);
delay(<span style="color: #0000dd; font-weight: bold;">1000</span>);
}
</pre>
</td></tr>
</tbody></table>
</div>
<div style="text-align: left;">
- Second, we will re-use the Web Server library in <a href="http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html" target="_blank">Demo 12: How to turn the Arduino ESP32 into a Web Server.</a> Beside that, i also used the jquery library to create uploading Http POST request. MDNS (<a href="http://www.iotsharing.com/2017/05/how-to-use-mdns-to-resolve-hostname-esp32-ipaddress.html" target="_blank">Demo 9: How to use mDNS to resolve host names to Arduino ESP32 IP addresses</a>) was used to resolve host name for our web server instead of using IP address directly. The code will be explained below.</div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <WiFi.h></span>
<span style="color: #557799;">#include <WiFiClient.h></span>
<span style="color: #557799;">#include <ESP32WebServer.h></span>
<span style="color: #557799;">#include <ESPmDNS.h></span>
<span style="color: #557799;">#include <Update.h></span>
#include "esp_wps.h"
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> host <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"esp32webupdate"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> ssid <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"dd-wrt"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> password <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"0000000000"</span>;
ESP32WebServer <span style="color: #0066bb; font-weight: bold;">server</span>(<span style="color: #0000dd; font-weight: bold;">80</span>);
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> serverIndex <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"</span>
<span style="background-color: #fff0f0;">"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"</span>
<span style="background-color: #fff0f0;">"<input type='file' name='update'>"</span>
<span style="background-color: #fff0f0;">"<input type='submit' value='Update'>"</span>
<span style="background-color: #fff0f0;">"</form>"</span>
<span style="background-color: #fff0f0;">"<div id='prg'>progress: 0%</div>"</span>
<span style="background-color: #fff0f0;">"<script>"</span>
<span style="background-color: #fff0f0;">"$('form').submit(function(e){"</span>
<span style="background-color: #fff0f0;">"e.preventDefault();"</span>
<span style="background-color: #fff0f0;">"var form = $('#upload_form')[0];"</span>
<span style="background-color: #fff0f0;">"var data = new FormData(form);"</span>
<span style="background-color: #fff0f0;">" $.ajax({"</span>
<span style="background-color: #fff0f0;">"url: '/update',"</span>
<span style="background-color: #fff0f0;">"type: 'POST',"</span>
<span style="background-color: #fff0f0;">"data: data,"</span>
<span style="background-color: #fff0f0;">"contentType: false,"</span>
<span style="background-color: #fff0f0;">"processData:false,"</span>
<span style="background-color: #fff0f0;">"xhr: function() {"</span>
<span style="background-color: #fff0f0;">"var xhr = new window.XMLHttpRequest();"</span>
<span style="background-color: #fff0f0;">"xhr.upload.addEventListener('progress', function(evt) {"</span>
<span style="background-color: #fff0f0;">"if (evt.lengthComputable) {"</span>
<span style="background-color: #fff0f0;">"var per = evt.loaded / evt.total;"</span>
<span style="background-color: #fff0f0;">"$('#prg').html('progress: ' + Math.round(per*100) + '%');"</span>
<span style="background-color: #fff0f0;">"}"</span>
<span style="background-color: #fff0f0;">"}, false);"</span>
<span style="background-color: #fff0f0;">"return xhr;"</span>
<span style="background-color: #fff0f0;">"},"</span>
<span style="background-color: #fff0f0;">"success:function(d, s) {"</span>
<span style="background-color: #fff0f0;">"console.log('success!')"</span>
<span style="background-color: #fff0f0;">"},"</span>
<span style="background-color: #fff0f0;">"error: function (a, b, c) {"</span>
<span style="background-color: #fff0f0;">"}"</span>
<span style="background-color: #fff0f0;">"});"</span>
<span style="background-color: #fff0f0;">"});"</span>
<span style="background-color: #fff0f0;">"</script>"</span>;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>(<span style="color: #333399; font-weight: bold;">void</span>){
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
<span style="color: #888888;">// Connect to WiFi network</span>
WiFi.begin(ssid, password);
Serial.println(<span style="background-color: #fff0f0;">""</span>);
<span style="color: #888888;">// Wait for connection</span>
<span style="color: #008800; font-weight: bold;">while</span> (WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED) {
delay(<span style="color: #0000dd; font-weight: bold;">500</span>);
Serial.print(<span style="background-color: #fff0f0;">"."</span>);
}
Serial.println(<span style="background-color: #fff0f0;">""</span>);
Serial.print(<span style="background-color: #fff0f0;">"Connected to "</span>);
Serial.println(ssid);
Serial.print(<span style="background-color: #fff0f0;">"IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #888888;">/*use mdns for host name resolution*/</span>
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>MDNS.begin(host)) {
Serial.println(<span style="background-color: #fff0f0;">"Error setting up MDNS responder!"</span>);
<span style="color: #008800; font-weight: bold;">while</span>(<span style="color: #0000dd; font-weight: bold;">1</span>) {
delay(<span style="color: #0000dd; font-weight: bold;">1000</span>);
}
}
Serial.println(<span style="background-color: #fff0f0;">"mDNS responder started"</span>);
<span style="color: #888888;">/*return index page which is stored in serverIndex */</span>
server.on(<span style="background-color: #fff0f0;">"/"</span>, HTTP_GET, [](){
server.sendHeader(<span style="background-color: #fff0f0;">"Connection"</span>, <span style="background-color: #fff0f0;">"close"</span>);
server.send(<span style="color: #0000dd; font-weight: bold;">200</span>, <span style="background-color: #fff0f0;">"text/html"</span>, serverIndex);
});
<span style="color: #888888;">/*handling uploading firmware file */</span>
server.on(<span style="background-color: #fff0f0;">"/update"</span>, HTTP_POST, [](){
server.sendHeader(<span style="background-color: #fff0f0;">"Connection"</span>, <span style="background-color: #fff0f0;">"close"</span>);
server.send(<span style="color: #0000dd; font-weight: bold;">200</span>, <span style="background-color: #fff0f0;">"text/plain"</span>, (Update.hasError())<span style="color: #333333;">?</span><span style="background-color: #fff0f0;">"FAIL"</span><span style="color: #333333;">:</span><span style="background-color: #fff0f0;">"OK"</span>);
esp_wifi_wps_disable(); ESP.restart();
},[](){
HTTPUpload<span style="color: #333333;">&</span> upload <span style="color: #333333;">=</span> server.upload();
<span style="color: #008800; font-weight: bold;">if</span>(upload.status <span style="color: #333333;">==</span> UPLOAD_FILE_START){
Serial.printf(<span style="background-color: #fff0f0;">"Update: %s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, upload.filename.c_str());
<span style="color: #008800; font-weight: bold;">if</span>(<span style="color: #333333;">!</span>Update.begin(UPDATE_SIZE_UNKNOWN)){<span style="color: #888888;">//start with max available size</span>
Update.printError(Serial);
}
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(upload.status <span style="color: #333333;">==</span> UPLOAD_FILE_WRITE){
<span style="color: #888888;">/* flashing firmware to ESP*/</span>
<span style="color: #008800; font-weight: bold;">if</span>(Update.write(upload.buf, upload.currentSize) <span style="color: #333333;">!=</span> upload.currentSize){
Update.printError(Serial);
}
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span>(upload.status <span style="color: #333333;">==</span> UPLOAD_FILE_END){
<span style="color: #008800; font-weight: bold;">if</span>(Update.end(<span style="color: #007020;">true</span>)){ <span style="color: #888888;">//true to set the size to the current progress</span>
Serial.printf(<span style="background-color: #fff0f0;">"Update Success: %u</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">Rebooting...</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, upload.totalSize);
} <span style="color: #008800; font-weight: bold;">else</span> {
Update.printError(Serial);
}
}
});
server.begin();
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>(<span style="color: #333399; font-weight: bold;">void</span>){
server.handleClient();
delay(<span style="color: #0000dd; font-weight: bold;">1</span>);
}
</pre>
</td></tr>
</tbody></table>
</div>
In the code, the variable <b>serverIndex </b>holds the <b>index</b> page which is return to the web browser firstly. We will use "<b>$.ajax</b>" to create asynchronous uploading request. This request will be handled by "/update" action at web server. We also use "<b>var xhr = new window.XMLHttpRequest()</b>" to handle the progress of uploading. <br />
The code "<b>MDNS.begin(host)</b>" will use MDNS to resolve "<b>http://esp32webupdate.local</b>" to our web server IP address.<br />
The code "<b>server.on("/", HTTP_GET, []()</b>" will handle the first HTTP GET request from web browser and return the http status code 200 and the web page content in <b>serverIndex</b> variable.<br />
The code "<b>server.on("/update", HTTP_POST, []()</b>" will handle the uploading firmware file process via HTTP POST. We handle the order of process via "<b>upload.status</b>" and use <b>Update </b>for flashing firmware. After finishing, we call "ESP.restart();" to restart ESP to get effect.<br />
<b>4. Result</b><br />
Open web browser and <b>Browse </b>to the file "led.bin" and press <b>Update </b>button.<b> </b><br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/wuKAGIeEk9U/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/wuKAGIeEk9U?feature=player_embedded" width="480"></iframe></div>
<br /></div>
</div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com31tag:blogger.com,1999:blog-7549705215513488945.post-55083373213645321272017-11-22T22:56:00.000-08:002018-01-15T18:17:24.872-08:00Demo 35: firmware update OTA for ESP32 directly using HTTP<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
This tutorial is similar to <a href="http://www.iotsharing.com/2017/11/firmware-update-ota-for-esp32-using-http-sdcard.html">Demo 34 </a>but without using sdcard. It means<b> </b>firmware will be flashed to ESP directly from HTTP downloading process.<b> </b>Here is the model of this demo:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv1d725tmd3SY_pTA4H-1SjTpGCIGIfqLB8yMvtaFJ1XGqXMrFzY27OGteFhFRrCOtKOskaQMWhw6_xiENUGvccMyWX6u1MnOorQFMRQCVsWFwWKtArsLIrwo37T0DF_JrgCX69hg6wD8/s1600/httpota.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="256" data-original-width="389" height="419" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv1d725tmd3SY_pTA4H-1SjTpGCIGIfqLB8yMvtaFJ1XGqXMrFzY27OGteFhFRrCOtKOskaQMWhw6_xiENUGvccMyWX6u1MnOorQFMRQCVsWFwWKtArsLIrwo37T0DF_JrgCX69hg6wD8/s640/httpota.png" width="640" /></a></div>
<div style="text-align: center;">
<b>Figure: model of demo</b></div>
<b>2. Hardware</b><br />
Refer <a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html" target="_blank">Demo 7</a> to connect ESP32 pins with sdcard module. And <a href="http://www.iotsharing.com/2017/05/blinky-hello-world-on-arduino-esp32.html" target="_blank">Demo 1 </a>to connect ESP to LED.<br />
<b>3. Software</b><br />
I made the library in <a href="https://github.com/nhatuan84/esp32-http-fota">github</a>. Just download, install it and run example <b>esp32httpota2</b>. <b>Change the Wifi ssid, password and IP of MQTT server according to yours</b>. The code will be explained below.<b><b><br /></b></b><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <WiFi.h></span>
<span style="color: #557799;">#include <HttpFOTA.h></span>
<span style="color: #557799;">#include <PubSubClient.h></span>
<span style="color: #008800; font-weight: bold;">typedef</span> <span style="color: #008800; font-weight: bold;">enum</span> {
Runnning_e <span style="color: #333333;">=</span> <span style="color: #005588; font-weight: bold;">0x01</span>,
Fota_e
}SysState;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> ssid <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"dd-wrt"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> password <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"0000000000"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> mqtt_server <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"192.168.1.107"</span>;
<span style="color: #333399; font-weight: bold;">char</span> url[<span style="color: #0000dd; font-weight: bold;">100</span>];
<span style="color: #333399; font-weight: bold;">char</span> md5[<span style="color: #0000dd; font-weight: bold;">50</span>];
WiFiClient espClient;
PubSubClient <span style="color: #0066bb; font-weight: bold;">client</span>(espClient);
SysState state <span style="color: #333333;">=</span> Runnning_e;
<span style="color: #888888;">/* topics */</span>
<span style="color: #557799;">#define OTA_TOPIC "smarthome/room1/ota"</span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">progress</span>(DlState state, <span style="color: #333399; font-weight: bold;">int</span> percent){
Serial.printf(<span style="background-color: #fff0f0;">"state = %d - percent = %d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, state, percent);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">receivedCallback</span>(<span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> topic, byte<span style="color: #333333;">*</span> payload, <span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">int</span> length) {
<span style="color: #008800; font-weight: bold;">if</span>(strncmp(OTA_TOPIC, topic, strlen(OTA_TOPIC)) <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>){
memset(url, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">100</span>);
memset(md5, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">50</span>);
<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>tmp <span style="color: #333333;">=</span> strstr((<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)payload, <span style="background-color: #fff0f0;">"url:"</span>);
<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>tmp1 <span style="color: #333333;">=</span> strstr((<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)payload, <span style="background-color: #fff0f0;">","</span>);
memcpy(url, tmp<span style="color: #333333;">+</span>strlen(<span style="background-color: #fff0f0;">"url:"</span>), tmp1<span style="color: #333333;">-</span>(tmp<span style="color: #333333;">+</span>strlen(<span style="background-color: #fff0f0;">"url:"</span>)));
<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>tmp2 <span style="color: #333333;">=</span> strstr((<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)payload, <span style="background-color: #fff0f0;">"md5:"</span>);
memcpy(md5, tmp2<span style="color: #333333;">+</span>strlen(<span style="background-color: #fff0f0;">"md5:"</span>), length<span style="color: #333333;">-</span>(tmp2<span style="color: #333333;">+</span>strlen(<span style="background-color: #fff0f0;">"md5:"</span>)<span style="color: #333333;">-</span>(<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)<span style="color: #333333;">&</span>payload[<span style="color: #0000dd; font-weight: bold;">0</span>]));
Serial.printf(<span style="background-color: #fff0f0;">"started fota url: %s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, url);
Serial.printf(<span style="background-color: #fff0f0;">"started fota md5: %s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, md5);
state <span style="color: #333333;">=</span> Fota_e;
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">mqttconnect</span>() {
<span style="color: #888888;">/* Loop until reconnected */</span>
<span style="color: #008800; font-weight: bold;">while</span> (<span style="color: #333333;">!</span>client.connected()) {
Serial.print(<span style="background-color: #fff0f0;">"MQTT connecting ..."</span>);
<span style="color: #888888;">/* client ID */</span>
String clientId <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"ESP32Client"</span>;
<span style="color: #888888;">/* connect now */</span>
<span style="color: #008800; font-weight: bold;">if</span> (client.connect(clientId.c_str())) {
Serial.println(<span style="background-color: #fff0f0;">"connected"</span>);
<span style="color: #888888;">/* subscribe topic */</span>
client.subscribe(OTA_TOPIC);
} <span style="color: #008800; font-weight: bold;">else</span> {
Serial.print(<span style="background-color: #fff0f0;">"failed, status code ="</span>);
Serial.print(client.state());
Serial.println(<span style="background-color: #fff0f0;">"try again in 5 seconds"</span>);
<span style="color: #888888;">/* Wait 5 seconds before retrying */</span>
delay(<span style="color: #0000dd; font-weight: bold;">5000</span>);
}
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">error</span>(<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>message){
printf(<span style="background-color: #fff0f0;">"%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, message);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">startDl</span>(<span style="color: #333399; font-weight: bold;">void</span>){
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">endDl</span>(<span style="color: #333399; font-weight: bold;">void</span>){
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
<span style="color: #888888;">// put your setup code here, to run once:</span>
<span style="color: #888888;">// put your setup code here, to run once:</span>
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
Serial.print(<span style="background-color: #fff0f0;">"Connecting to "</span>);
Serial.print(ssid);
WiFi.begin(ssid, password);
<span style="color: #008800; font-weight: bold;">while</span> (WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED) {
delay(<span style="color: #0000dd; font-weight: bold;">500</span>);
Serial.print(<span style="background-color: #fff0f0;">"."</span>);
}
Serial.println(<span style="background-color: #fff0f0;">""</span>);
Serial.print(<span style="background-color: #fff0f0;">"WiFi connected, IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #888888;">/* configure the MQTT server with IPaddress and port */</span>
client.setServer(mqtt_server, <span style="color: #0000dd; font-weight: bold;">1883</span>);
<span style="color: #888888;">/* this receivedCallback function will be invoked </span>
<span style="color: #888888;"> when client received subscribed topic */</span>
client.setCallback(receivedCallback);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
<span style="color: #008800; font-weight: bold;">switch</span>(state)
{
<span style="color: #008800; font-weight: bold;">case</span> Runnning_e:
<span style="color: #888888;">/* if client was disconnected then try to reconnect again */</span>
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>client.connected()) {
mqttconnect();
}
<span style="color: #888888;">/* this function will listen for incomming </span>
<span style="color: #888888;"> subscribed topic-process-invoke receivedCallback */</span>
client.loop();
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">case</span> Fota_e:
DlInfo info;
info.url <span style="color: #333333;">=</span> url;
info.md5 <span style="color: #333333;">=</span> md5;
info.startDownloadCallback <span style="color: #333333;">=</span> startDl;
info.endDownloadCallback <span style="color: #333333;">=</span> endDl;
info.progressCallback <span style="color: #333333;">=</span> progress;
info.errorCallback <span style="color: #333333;">=</span> error;
httpFOTA.start(info);
client.publish(OTA_TOPIC, <span style="background-color: #fff0f0;">"ok"</span>);
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #997700; font-weight: bold;">default:</span>
<span style="color: #008800; font-weight: bold;">break</span>;
}
}
</pre>
</td></tr>
</tbody></table>
</div>
In order to start fota updating process, using the Python code below
and type "1" to publish FOTA command to ESP. The ESP will receive the
command, parse it and starting FOTA process. <b>Change the url and md5 value according to yours.</b><br />
The
library is simple. It only has 1 interface that is start with input is <b>
DlInfo </b>structure. When calling this function, it will block the <b>loop()</b> function. We must initialize the structure before using it. The
structure includes:<br />
- <b>url</b>: is the http url of the firmware file.<br />
- <b>md5</b>: is the md5 checksum of the firmware file.<br />
- <b>startDownloadCallback</b>:
is the function that will be invoked before starting downloading. I left it empty in this demo.<br />
- <b>endDownloadCallback</b>:
is the function that will be invoked after downloading was finished. I left it empty in this demo.<br />
- <b>progressCallback</b>: is the function that will be invoked to show the progress of downloading and flashing process.<br />
- <b>errorCallback</b>: is the function that will be invoked to show the error of downloading and flashing process.<br />
The functions: s<b>aveData, readData, progress, error, startDl, endDl, startFl, endFl</b> will be invoked by the library in the update process. They are assigned to the members of <b>DlInfo</b> structure.<br />
The function <b>receiveCallback</b>
will be invoked whenever ESP received the MQTT command. It will check
if the topic is OTA_TOPIC then parsing the payload to get url and md5
value of firmware file. After that, it change the state of system to <b>Fota_e</b> to start updating process.<br />
After finishing the whole process, the code "<b>client.publish(OTA_TOPIC, "ok");</b>" will publish message "ok" back to Python application. <br />
When the system is in <b>Running_e</b>, it just listen the MQTT command. <br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">from</span> <span style="color: #0e84b5; font-weight: bold;">random</span> <span style="color: #008800; font-weight: bold;">import</span> randint
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">thread</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">sys</span>
<span style="color: #008800; font-weight: bold;">try</span>:
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">paho.mqtt.client</span> <span style="color: #008800; font-weight: bold;">as</span> <span style="color: #0e84b5; font-weight: bold;">mqtt</span>
<span style="color: #008800; font-weight: bold;">except</span> <span style="color: red; font-weight: bold;">ImportError</span>:
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">os</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">inspect</span>
cmd_subfolder <span style="color: #333333;">=</span> os<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>realpath(os<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>abspath(os<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>join(os<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>split(inspect<span style="color: #333333;">.</span>getfile( inspect<span style="color: #333333;">.</span>currentframe() ))[<span style="color: #0000dd; font-weight: bold;">0</span>],<span style="background-color: #fff0f0;">"../src"</span>)))
<span style="color: #008800; font-weight: bold;">if</span> cmd_subfolder <span style="color: black; font-weight: bold;">not</span> <span style="color: black; font-weight: bold;">in</span> sys<span style="color: #333333;">.</span>path:
sys<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>insert(<span style="color: #0000dd; font-weight: bold;">0</span>, cmd_subfolder)
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">paho.mqtt.client</span> <span style="color: #008800; font-weight: bold;">as</span> <span style="color: #0e84b5; font-weight: bold;">mqtt</span>
server <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"192.168.1.107"</span>;
topic <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"smarthome/room1/ota"</span>
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_connect</span>(mqttc, obj, flags, rc):
<span style="color: #008800; font-weight: bold;">print</span>(<span style="background-color: #fff0f0;">"rc: "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(rc))
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_message</span>(mqttc, obj, msg):
<span style="color: #008800; font-weight: bold;">print</span>(msg<span style="color: #333333;">.</span>topic<span style="color: #333333;">+</span><span style="background-color: #fff0f0;">" "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(msg<span style="color: #333333;">.</span>qos)<span style="color: #333333;">+</span><span style="background-color: #fff0f0;">" "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(msg<span style="color: #333333;">.</span>payload))
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_publish</span>(mqttc, obj, mid):
<span style="color: #008800; font-weight: bold;">print</span>(<span style="background-color: #fff0f0;">"mid: "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(mid))
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_subscribe</span>(mqttc, obj, mid, granted_qos):
<span style="color: #008800; font-weight: bold;">print</span>(<span style="background-color: #fff0f0;">"Subscribed: "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(mid)<span style="color: #333333;">+</span><span style="background-color: #fff0f0;">" "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(granted_qos))
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_log</span>(mqttc, obj, level, string):
<span style="color: #008800; font-weight: bold;">print</span>(string)
mqttc <span style="color: #333333;">=</span> mqtt<span style="color: #333333;">.</span>Client()
mqttc<span style="color: #333333;">.</span>on_message <span style="color: #333333;">=</span> on_message
mqttc<span style="color: #333333;">.</span>on_connect <span style="color: #333333;">=</span> on_connect
mqttc<span style="color: #333333;">.</span>on_publish <span style="color: #333333;">=</span> on_publish
mqttc<span style="color: #333333;">.</span>on_subscribe <span style="color: #333333;">=</span> on_subscribe
mqttc<span style="color: #333333;">.</span>connect(server, <span style="color: #0000dd; font-weight: bold;">1883</span>, <span style="color: #0000dd; font-weight: bold;">60</span>)
mqttc<span style="color: #333333;">.</span>subscribe(topic, <span style="color: #0000dd; font-weight: bold;">0</span>)
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">fotaControl</span>( threadName, delay):
<span style="color: #008800; font-weight: bold;">while</span> <span style="color: #007020;">True</span>:
val <span style="color: #333333;">=</span> <span style="color: #007020;">raw_input</span>(<span style="background-color: #fff0f0;">'Enter 1 to update firmware OTA '</span>)
<span style="color: #008800; font-weight: bold;">if</span>(val <span style="color: #333333;">==</span> <span style="background-color: #fff0f0;">"1"</span>):
mqttc<span style="color: #333333;">.</span>publish(topic, <span style="background-color: #fff0f0;">"url:http://192.168.1.107/</span><span style="background-color: #fff0f0;"><span style="background-color: #fff0f0;"><b>phphello</b></span>/led.bin,md5:6bd07139c21f572370242905c4465056"</span>)
<span style="color: #008800; font-weight: bold;">try</span>:
thread<span style="color: #333333;">.</span>start_new_thread( fotaControl, (<span style="background-color: #fff0f0;">"Fota Control"</span>, <span style="color: #0000dd; font-weight: bold;">0</span>, ) )
<span style="color: #008800; font-weight: bold;">except</span>:
<span style="color: #008800; font-weight: bold;">print</span> <span style="background-color: #fff0f0;">"Error: unable to start thread"</span>
mqttc<span style="color: #333333;">.</span>loop_forever()
</pre>
</td></tr>
</tbody></table>
</div>
<b>4. Result</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-c5qLb2sXr4c/WhGmV7aoUUI/AAAAAAAAFrQ/3R9PJQlvakI1RzS9SwDDFV6PspvoteFUwCLcBGAs/s1600/espota1.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1000" data-original-width="1334" height="239" src="https://4.bp.blogspot.com/-c5qLb2sXr4c/WhGmV7aoUUI/AAAAAAAAFrQ/3R9PJQlvakI1RzS9SwDDFV6PspvoteFUwCLcBGAs/s320/espota1.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-VT04WFPi1P8/WhGmVcovXQI/AAAAAAAAFrM/RrZN4kBLK1M2DoYv4V2mCdkVd5aDl4QIgCLcBGAs/s1600/httpota.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="835" data-original-width="457" height="320" src="https://1.bp.blogspot.com/-VT04WFPi1P8/WhGmVcovXQI/AAAAAAAAFrM/RrZN4kBLK1M2DoYv4V2mCdkVd5aDl4QIgCLcBGAs/s320/httpota.png" width="175" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/U9Eu3Ga-i-4/0.jpg" frameborder="0" height="266" src="?feature=player_embedded" width="320"></iframe></div>
<br /></div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com6tag:blogger.com,1999:blog-7549705215513488945.post-38342138742751103242017-11-19T18:30:00.003-08:002018-01-16T18:51:59.083-08:00Demo 34: firmware update OTA for ESP32 using HTTP and sdcard<div dir="ltr" style="text-align: left;" trbidi="on">
<b>1. Introduction</b><br />
In <span id="goog_2018845372"></span><a href="http://www.iotsharing.com/2017/05/how-to-update-firmware-ota-for-batch-esp32.html">Demo 16</a>, we knew how to update firmware OTA for a batch of Arduino ESP32. Actually, the method behind that tutorial is UDP protocol. In this tutorial I will show you another way to update firmware for ESP OTA. That is using HTTP and sdcard. It means we will use Http to download the firmware from Http Apache server to sdcard and then flashing downloaded firmware from sdcard to ESP.<br />
<b>Note</b>: In case you do not want to store firmware file in sdcard, I will make another demo without using sdcard <a href="http://www.iotsharing.com/2017/11/firmware-update-ota-for-esp32-using-http.html">Demo 35</a>.<br />
We will re-use these demos for this tutorial:<br />
+ <a href="http://www.iotsharing.com/2017/05/how-to-use-mqtt-to-build-smart-home-arduino-esp32.html" target="_blank">Demo 14: How to use MQTT and Arduino ESP32 to build a simple Smart home system</a><br />
+ <a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html" target="_blank">Demo 7: How to use Arduino ESP32 to store data to sdcard</a><br />
<complete id="goog_860235222">+ </complete><a href="http://www.iotsharing.com/2017/05/blinky-hello-world-on-arduino-esp32.html" target="_blank">Demo 1: Blinky - a Hello World on Arduino ESP32</a> <br />
+ <a href="http://www.iotsharing.com/2017/06/how-to-turn-the-Orange-Pi-into-an-IoT-node.html">How to turn the Orange Pi/Raspberry Pi into an IoT node</a> (this tutorial will show you how to install Apache2 HTTP server to hold firmware .bin file. Following the steps in <b>2.4</b> of the tutorial and copy the .bin file to "<b>/var/www/html/phphello</b>". So the url to download the firmware file (<b>led.bin</b>) is: <b>http://192.168.1.107/phphello/led.bin</b>)<br />
<br />
<b>Note</b>: the firmware file "led.bin" is exported from Arduino IDE. It is a simple LED blink application that blink the LED on pin GPIO4. In order to export the .bin file from Arduino IDE Menu, we choose <b>Sketch -> Export compiled Binary</b>.<b> </b>After finishing we choose <b>Sketch -> Show Sketch Folder</b>. You will se the .bin file there, rename it as <b>led.bin</b><br />
<b><br /></b>
The model of this demo is below: <br />
<div class="separator" style="clear: both; text-align: center;">
<b><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWWyflYYSDNMTP7yTc5AqatoprkyMmKSOqhw-iYNnVLyoW_sTyDY623wJPc7Bilz99ujoDjCiXuoL1vbiz489E7LvwTlnowi8pOVYuvgpgPna7XNwo4vxlKCJ_d08sZAuKC4j1db6HJ8U/s1600/httpota.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="390" data-original-width="389" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWWyflYYSDNMTP7yTc5AqatoprkyMmKSOqhw-iYNnVLyoW_sTyDY623wJPc7Bilz99ujoDjCiXuoL1vbiz489E7LvwTlnowi8pOVYuvgpgPna7XNwo4vxlKCJ_d08sZAuKC4j1db6HJ8U/s320/httpota.png" width="319" /></a></b></div>
<b> </b><br />
<div style="text-align: center;">
<b>Figure: Model of demo </b></div>
ESP will receive MQTT command (including <b>url</b> to download .bin firmware file and <b>md5</b> value of that file to verify whether downloading and flashing firmware is correct or not) from Python application "fotacontrol.py". After downloading and flashing process was finished the ESP send "ok" to Python application to notify the updating process was finished.<br />
<b></b><br />
<b>2. Hardware</b><br />
Refer <a href="http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html" target="_blank">Demo 7</a> to connect ESP32 pins with sdcard module. And <a href="http://www.iotsharing.com/2017/05/blinky-hello-world-on-arduino-esp32.html" target="_blank">Demo 1 </a>to connect ESP to LED.<br />
<b>3. Software</b><br />
I made the library in <a href="https://github.com/nhatuan84/esp32-http-ota">github</a>. Just download, install it and run example <b>esp32httpota2</b>. <b>Change the Wifi ssid, password and IP of MQTT server according to yours</b>. The code will be explained below.<b><br /></b><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <WiFi.h></span>
<span style="color: #557799;">#include <HttpOTA.h></span>
<span style="color: #557799;">#include <mySD.h></span>
<span style="color: #557799;">#include <PubSubClient.h></span>
<span style="color: #008800; font-weight: bold;">typedef</span> <span style="color: #008800; font-weight: bold;">enum</span> {
Runnning_e <span style="color: #333333;">=</span> <span style="color: #005588; font-weight: bold;">0x01</span>,
Fota_e
}SysState;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> ssid <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"dd-wrt"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> password <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"0000000000"</span>;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> mqtt_server <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"192.168.1.107"</span>;
<span style="color: #333399; font-weight: bold;">char</span> url[<span style="color: #0000dd; font-weight: bold;">100</span>];
<span style="color: #333399; font-weight: bold;">char</span> md5[<span style="color: #0000dd; font-weight: bold;">50</span>];
File file;
WiFiClient espClient;
PubSubClient <span style="color: #0066bb; font-weight: bold;">client</span>(espClient);
SysState state <span style="color: #333333;">=</span> Runnning_e;
<span style="color: #888888;">/* topics */</span>
<span style="color: #557799;">#define OTA_TOPIC "smarthome/room1/ota"</span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">saveData</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>buffer, <span style="color: #333399; font-weight: bold;">int</span> bytes){
file.write(buffer, bytes);
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">readData</span>(<span style="color: #333399; font-weight: bold;">uint8_t</span> <span style="color: #333333;">*</span>buffer, <span style="color: #333399; font-weight: bold;">int</span> bytes){
<span style="color: #008800; font-weight: bold;">return</span> file.read(buffer, bytes);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">progress</span>(DlState state, <span style="color: #333399; font-weight: bold;">int</span> percent){
Serial.printf(<span style="background-color: #fff0f0;">"state = %d - percent = %d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, state, percent);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">receivedCallback</span>(<span style="color: #333399; font-weight: bold;">char</span><span style="color: #333333;">*</span> topic, byte<span style="color: #333333;">*</span> payload, <span style="color: #333399; font-weight: bold;">unsigned</span> <span style="color: #333399; font-weight: bold;">int</span> length) {
<span style="color: #008800; font-weight: bold;">if</span>(strncmp(OTA_TOPIC, topic, strlen(OTA_TOPIC)) <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>){
memset(url, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">100</span>);
memset(md5, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">50</span>);
<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>tmp <span style="color: #333333;">=</span> strstr((<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)payload, <span style="background-color: #fff0f0;">"url:"</span>);
<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>tmp1 <span style="color: #333333;">=</span> strstr((<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)payload, <span style="background-color: #fff0f0;">","</span>);
memcpy(url, tmp<span style="color: #333333;">+</span>strlen(<span style="background-color: #fff0f0;">"url:"</span>), tmp1<span style="color: #333333;">-</span>(tmp<span style="color: #333333;">+</span>strlen(<span style="background-color: #fff0f0;">"url:"</span>)));
<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>tmp2 <span style="color: #333333;">=</span> strstr((<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)payload, <span style="background-color: #fff0f0;">"md5:"</span>);
memcpy(md5, tmp2<span style="color: #333333;">+</span>strlen(<span style="background-color: #fff0f0;">"md5:"</span>), length<span style="color: #333333;">-</span>(tmp2<span style="color: #333333;">+</span>strlen(<span style="background-color: #fff0f0;">"md5:"</span>)<span style="color: #333333;">-</span>(<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>)<span style="color: #333333;">&</span>payload[<span style="color: #0000dd; font-weight: bold;">0</span>]));
Serial.printf(<span style="background-color: #fff0f0;">"started fota url: %s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, url);
Serial.printf(<span style="background-color: #fff0f0;">"started fota md5: %s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, md5);
state <span style="color: #333333;">=</span> Fota_e;
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">mqttconnect</span>() {
<span style="color: #888888;">/* Loop until reconnected */</span>
<span style="color: #008800; font-weight: bold;">while</span> (<span style="color: #333333;">!</span>client.connected()) {
Serial.print(<span style="background-color: #fff0f0;">"MQTT connecting ..."</span>);
<span style="color: #888888;">/* client ID */</span>
String clientId <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"ESP32Client"</span>;
<span style="color: #888888;">/* connect now */</span>
<span style="color: #008800; font-weight: bold;">if</span> (client.connect(clientId.c_str())) {
Serial.println(<span style="background-color: #fff0f0;">"connected"</span>);
<span style="color: #888888;">/* subscribe topic */</span>
client.subscribe(OTA_TOPIC);
} <span style="color: #008800; font-weight: bold;">else</span> {
Serial.print(<span style="background-color: #fff0f0;">"failed, status code ="</span>);
Serial.print(client.state());
Serial.println(<span style="background-color: #fff0f0;">"try again in 5 seconds"</span>);
<span style="color: #888888;">/* Wait 5 seconds before retrying */</span>
delay(<span style="color: #0000dd; font-weight: bold;">5000</span>);
}
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">error</span>(<span style="color: #333399; font-weight: bold;">char</span> <span style="color: #333333;">*</span>message){
printf(<span style="background-color: #fff0f0;">"%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, message);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">startDl</span>(<span style="color: #333399; font-weight: bold;">void</span>){
<span style="color: #888888;">//write bin file to sdcard</span>
SD.remove(<span style="background-color: #fff0f0;">"fw.bin"</span>);
file <span style="color: #333333;">=</span> SD.open(<span style="background-color: #fff0f0;">"fw.bin"</span>, FILE_WRITE);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">endDl</span>(<span style="color: #333399; font-weight: bold;">void</span>){
file.close();
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">startFl</span>(<span style="color: #333399; font-weight: bold;">void</span>){
<span style="color: #888888;">//write bin file to sdcard</span>
file <span style="color: #333333;">=</span> SD.open(<span style="background-color: #fff0f0;">"fw.bin"</span>, FILE_READ);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">endFl</span>(<span style="color: #333399; font-weight: bold;">void</span>){
file.close();
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setup</span>() {
<span style="color: #888888;">// put your setup code here, to run once:</span>
<span style="color: #888888;">// put your setup code here, to run once:</span>
Serial.begin(<span style="color: #0000dd; font-weight: bold;">115200</span>);
Serial.print(<span style="background-color: #fff0f0;">"Connecting to "</span>);
Serial.print(ssid);
WiFi.begin(ssid, password);
<span style="color: #008800; font-weight: bold;">while</span> (WiFi.status() <span style="color: #333333;">!=</span> WL_CONNECTED) {
delay(<span style="color: #0000dd; font-weight: bold;">500</span>);
Serial.print(<span style="background-color: #fff0f0;">"."</span>);
}
Serial.println(<span style="background-color: #fff0f0;">""</span>);
Serial.print(<span style="background-color: #fff0f0;">"WiFi connected, IP address: "</span>);
Serial.println(WiFi.localIP());
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>SD.begin(<span style="color: #0000dd; font-weight: bold;">32</span>, <span style="color: #0000dd; font-weight: bold;">14</span>, <span style="color: #0000dd; font-weight: bold;">12</span>, <span style="color: #0000dd; font-weight: bold;">27</span>)) {
Serial.println(<span style="background-color: #fff0f0;">"initialization failed!"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
Serial.println(<span style="background-color: #fff0f0;">"initialization done."</span>);
<span style="color: #888888;">/* configure the MQTT server with IPaddress and port */</span>
client.setServer(mqtt_server, <span style="color: #0000dd; font-weight: bold;">1883</span>);
<span style="color: #888888;">/* this receivedCallback function will be invoked </span>
<span style="color: #888888;"> when client received subscribed topic */</span>
client.setCallback(receivedCallback);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">loop</span>() {
<span style="color: #008800; font-weight: bold;">switch</span>(state)
{
<span style="color: #008800; font-weight: bold;">case</span> Runnning_e:
<span style="color: #888888;">/* if client was disconnected then try to reconnect again */</span>
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>client.connected()) {
mqttconnect();
}
<span style="color: #888888;">/* this function will listen for incomming </span>
<span style="color: #888888;"> subscribed topic-process-invoke receivedCallback */</span>
client.loop();
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">case</span> Fota_e:
DlInfo info;
info.url <span style="color: #333333;">=</span> url;
info.md5 <span style="color: #333333;">=</span> md5;
info.startDownloadCallback <span style="color: #333333;">=</span> startDl;
info.endDownloadCallback <span style="color: #333333;">=</span> endDl;
info.startFlashingCallback <span style="color: #333333;">=</span> startFl;
info.endFlashingCallback <span style="color: #333333;">=</span> endFl;
info.saveDataCallback <span style="color: #333333;">=</span> saveData;
info.readDataCallback <span style="color: #333333;">=</span> readData;
info.progressCallback <span style="color: #333333;">=</span> progress;
info.errorCallback <span style="color: #333333;">=</span> error;
httpOTA.start(info);
client.publish(OTA_TOPIC, <span style="background-color: #fff0f0;">"ok"</span>);
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #997700; font-weight: bold;">default:</span>
<span style="color: #008800; font-weight: bold;">break</span>;
}
}
</pre>
</td></tr>
</tbody></table>
</div>
In order to start fota updating process, using the Python code below and type "1" to publish FOTA command to ESP. The ESP will receive the command, parse it and starting FOTA process. <b>Change the url and md5 value according to yours.</b><br />
The
library is simple. It only has 1 interface that is start with input is <b>
DlInfo </b>structure. When calling this function, it will block the <b>loop()</b> function. We must initialize the structure before using it. The
structure includes:<br />
- <b>url</b>: is the http url of the firmware file.<br />
- <b>md5</b>: is the md5 checksum of the firmware file.<br />
- <b>startDownloadCallback</b>: is the function that will be invoked before starting downloading. I used it to open firmware file in sdcard for writing downloaded data.<br />
- <b>endDownloadCallback</b>: is the function that will be invoked after downloading was finished. I used it to close firmware file in sdcard after finishing writing downloaded data.<br />
- <b>startFlashingCallback</b>: is the function that will be invoked before starting flashing downloaded firmware. I used it to open firmware file for flashing.<br />
- <b>endFlashingcallback</b>: is the function that will be invoked after flashing was finished. I used it to close firmware file after finishing flashing.<br />
- <b>saveDataCallback</b>: is the function that will be invoked to save downloading data to sdcard. I made it in generic way so that the library can be applied for SPIFFS.<br />
- <b>readDataCallback</b>: is the function that will be invoked to read data from sdcard for flashing. I made it in generic way so that the library
can be applied for SPIFFS.<br />
- <b>progressCallback</b>: is the function that will be invoked to show the progress of downloading and flashing process.<br />
- <b>errorCallback</b>: is the function that will be invoked to show the error of downloading and flashing process.<br />
<!-- HTML generated using hilite.me -->The functions: s<b>aveData, readData, progress, error, startDl, endDl, startFl, endFl</b> will be invoked by the library in the update process. They are assigned to the members of <b>DlInfo</b> structure.<br />
The function <b>receiveCallback</b> will be invoked whenever ESP received the MQTT command. It will check if the topic is OTA_TOPIC then parsing the payload to get url and md5 value of firmware file. After that, it change the state of system to <b>Fota_e</b> to start updating process.<br />
After finishing the whole process, the code "<b>client.publish(OTA_TOPIC, "ok");</b>" will publish message "ok" back to Python application. <br />
When the system is in <b>Running_e</b>, it just listen the MQTT command.<br />
The code "<b>SD.begin(32, 14, 12, 27)</b>" is ti initialize SD card before operating on it.<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">from</span> <span style="color: #0e84b5; font-weight: bold;">random</span> <span style="color: #008800; font-weight: bold;">import</span> randint
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">thread</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">sys</span>
<span style="color: #008800; font-weight: bold;">try</span>:
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">paho.mqtt.client</span> <span style="color: #008800; font-weight: bold;">as</span> <span style="color: #0e84b5; font-weight: bold;">mqtt</span>
<span style="color: #008800; font-weight: bold;">except</span> <span style="color: red; font-weight: bold;">ImportError</span>:
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">os</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">inspect</span>
cmd_subfolder <span style="color: #333333;">=</span> os<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>realpath(os<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>abspath(os<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>join(os<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>split(inspect<span style="color: #333333;">.</span>getfile( inspect<span style="color: #333333;">.</span>currentframe() ))[<span style="color: #0000dd; font-weight: bold;">0</span>],<span style="background-color: #fff0f0;">"../src"</span>)))
<span style="color: #008800; font-weight: bold;">if</span> cmd_subfolder <span style="color: black; font-weight: bold;">not</span> <span style="color: black; font-weight: bold;">in</span> sys<span style="color: #333333;">.</span>path:
sys<span style="color: #333333;">.</span>path<span style="color: #333333;">.</span>insert(<span style="color: #0000dd; font-weight: bold;">0</span>, cmd_subfolder)
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">paho.mqtt.client</span> <span style="color: #008800; font-weight: bold;">as</span> <span style="color: #0e84b5; font-weight: bold;">mqtt</span>
server <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"192.168.1.107"</span>;
topic <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"smarthome/room1/ota"</span>
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_connect</span>(mqttc, obj, flags, rc):
<span style="color: #008800; font-weight: bold;">print</span>(<span style="background-color: #fff0f0;">"rc: "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(rc))
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_message</span>(mqttc, obj, msg):
<span style="color: #008800; font-weight: bold;">print</span>(msg<span style="color: #333333;">.</span>topic<span style="color: #333333;">+</span><span style="background-color: #fff0f0;">" "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(msg<span style="color: #333333;">.</span>qos)<span style="color: #333333;">+</span><span style="background-color: #fff0f0;">" "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(msg<span style="color: #333333;">.</span>payload))
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_publish</span>(mqttc, obj, mid):
<span style="color: #008800; font-weight: bold;">print</span>(<span style="background-color: #fff0f0;">"mid: "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(mid))
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_subscribe</span>(mqttc, obj, mid, granted_qos):
<span style="color: #008800; font-weight: bold;">print</span>(<span style="background-color: #fff0f0;">"Subscribed: "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(mid)<span style="color: #333333;">+</span><span style="background-color: #fff0f0;">" "</span><span style="color: #333333;">+</span><span style="color: #007020;">str</span>(granted_qos))
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">on_log</span>(mqttc, obj, level, string):
<span style="color: #008800; font-weight: bold;">print</span>(string)
mqttc <span style="color: #333333;">=</span> mqtt<span style="color: #333333;">.</span>Client()
mqttc<span style="color: #333333;">.</span>on_message <span style="color: #333333;">=</span> on_message
mqttc<span style="color: #333333;">.</span>on_connect <span style="color: #333333;">=</span> on_connect
mqttc<span style="color: #333333;">.</span>on_publish <span style="color: #333333;">=</span> on_publish
mqttc<span style="color: #333333;">.</span>on_subscribe <span style="color: #333333;">=</span> on_subscribe
mqttc<span style="color: #333333;">.</span>connect(server, <span style="color: #0000dd; font-weight: bold;">1883</span>, <span style="color: #0000dd; font-weight: bold;">60</span>)
mqttc<span style="color: #333333;">.</span>subscribe(topic, <span style="color: #0000dd; font-weight: bold;">0</span>)
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">fotaControl</span>( threadName, delay):
<span style="color: #008800; font-weight: bold;">while</span> <span style="color: #007020;">True</span>:
val <span style="color: #333333;">=</span> <span style="color: #007020;">raw_input</span>(<span style="background-color: #fff0f0;">'Enter 1 to update firmware OTA '</span>)
<span style="color: #008800; font-weight: bold;">if</span>(val <span style="color: #333333;">==</span> <span style="background-color: #fff0f0;">"1"</span>):
mqttc<span style="color: #333333;">.</span>publish(topic, <span style="background-color: #fff0f0;">"url:http://192.168.1.107/</span><span style="background-color: #fff0f0;"><b>phphello</b>/led.bin,md5:6bd07139c21f572370242905c4465056"</span>)
<span style="color: #008800; font-weight: bold;">try</span>:
thread<span style="color: #333333;">.</span>start_new_thread( fotaControl, (<span style="background-color: #fff0f0;">"Fota Control"</span>, <span style="color: #0000dd; font-weight: bold;">0</span>, ) )
<span style="color: #008800; font-weight: bold;">except</span>:
<span style="color: #008800; font-weight: bold;">print</span> <span style="background-color: #fff0f0;">"Error: unable to start thread"</span>
mqttc<span style="color: #333333;">.</span>loop_forever()
</pre>
</td></tr>
</tbody></table>
</div>
The Python application is quite simple, It has 2 thread: listening MQTT thread and fota control thread to send FOTA command to ESP (pressing "1" to start FOTA).<br />
Before using paho MQTT we need to initialize some callback functions: <b>on_message, on_connect, on_publish, on_subscribe</b>.<br />
<b>4. Result</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-c5qLb2sXr4c/WhGmV7aoUUI/AAAAAAAAFrQ/3R9PJQlvakI1RzS9SwDDFV6PspvoteFUwCLcBGAs/s1600/espota1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1000" data-original-width="1334" height="239" src="https://4.bp.blogspot.com/-c5qLb2sXr4c/WhGmV7aoUUI/AAAAAAAAFrQ/3R9PJQlvakI1RzS9SwDDFV6PspvoteFUwCLcBGAs/s320/espota1.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-VT04WFPi1P8/WhGmVcovXQI/AAAAAAAAFrM/RrZN4kBLK1M2DoYv4V2mCdkVd5aDl4QIgCLcBGAs/s1600/httpota.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="835" data-original-width="457" height="320" src="https://1.bp.blogspot.com/-VT04WFPi1P8/WhGmVcovXQI/AAAAAAAAFrM/RrZN4kBLK1M2DoYv4V2mCdkVd5aDl4QIgCLcBGAs/s320/httpota.png" width="175" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/U9Eu3Ga-i-4/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/U9Eu3Ga-i-4?feature=player_embedded" width="480"></iframe></div>
<br />
<br /></div>
Tech It Yourselfhttp://www.blogger.com/profile/00459942306964625402noreply@blogger.com5