<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Blinky on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/blinky/</link><description>Recent content in Blinky on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Fri, 23 Jun 2023 12:00:00 +0200</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/blinky/index.xml" rel="self" type="application/rss+xml"/><item><title>Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 3</title><link>https://blog.zwindler.fr/2023/06/23/reverse-blinky-enix-part3/</link><pubDate>Fri, 23 Jun 2023 12:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2023/06/23/reverse-blinky-enix-part3/</guid><description>&lt;img src="https://blog.zwindler.fr/2023/06/blinky2.webp" alt="Featured image of post Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 3" /&gt;&lt;p&gt;Cet article fait partie d&amp;rsquo;une suite d&amp;rsquo;articles sur le reverse engineering d&amp;rsquo;un prototype de Gyrophare connecté appelé Blinky :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/16/reverse-blinky-enix-part1/" &gt;Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/21/reverse-blinky-enix-part2/" &gt;Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/23/reverse-blinky-enix-part3/" &gt;Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="rappel-des-épisodes-précédents"&gt;Rappel des épisodes précédents
&lt;/h2&gt;&lt;p&gt;Dans les articles précédents, j&amp;rsquo;avais reçu un gyrophare connecté conçu par les copain⋅es de chez Enix et plutôt que de tester leur produit en SaaS (la vraie proposition de valeur), j&amp;rsquo;ai décidé de faire un peu de reverse engineering dessus.&lt;/p&gt;
&lt;p&gt;A l&amp;rsquo;issue du tout dernier article, j&amp;rsquo;ai réussi à piloter les LEDs et faire des patterns rigolos avec.&lt;/p&gt;
&lt;h2 id="bouton-"&gt;Bouton ?
&lt;/h2&gt;&lt;p&gt;Je n&amp;rsquo;ai toujours pas le code source à ma disposition donc je teste un peu tout ce que je trouve, au fur et à mesure.&lt;/p&gt;
&lt;p&gt;Un des composants que j&amp;rsquo;avais repérés lors de mon exploration était un bouton poussoir. Je ne savais jusqu&amp;rsquo;à présent pas comment l&amp;rsquo;utiliser, mais j&amp;rsquo;avais repéré 2 choses visiblement en rapport :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;firmware_blinky_esp32&amp;#39;&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;firmware_blinky_esp32.py&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle_button_release&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle_button_release&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x3ffe7ad0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;BUTTON&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;Pin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;J&amp;rsquo;avais déjà essayé de jouer avec, mais j&amp;rsquo;avais reçu l&amp;rsquo;erreur suivante :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle_button_release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;takes&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;positional&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;were&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ne sachant pas trop quel type d&amp;rsquo;argument était attendu&amp;hellip; J&amp;rsquo;ai testé une string au hasard&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle_button_release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;toto&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ets&lt;/span&gt; &lt;span class="n"&gt;Jul&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt; &lt;span class="mi"&gt;2019&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0xc&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SW_CPU_RESET&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x13&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SPI_FAST_FLASH_BOOT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;configsip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SPIWP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0xee&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;clk_drv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;q_drv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;d_drv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;cs0_drv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hd_drv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;wp_drv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;DIO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clock&lt;/span&gt; &lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x3fff0018&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x3fff001c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4252&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x40078000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11920&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x40080400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3344&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="mh"&gt;0x4008060c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div id=video&gt;&lt;video controls="controls" height="500" src="https://blog.zwindler.fr/2023/06/blink.mp4"&gt;&lt;/video&gt;&lt;/div&gt;
&lt;p&gt;AH !&lt;/p&gt;
&lt;p&gt;Au moment où on pousse déclenche la fonction, le blinky fait 3 flashs très brefs (bleu, vert, rouge, je ne sais pas dans quel ordre) et redémarre.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;en déduis que c&amp;rsquo;est comme cela que l&amp;rsquo;acquittement des &amp;ldquo;alertes&amp;rdquo;, reçues depuis le SaaS, est réalisé.&lt;/p&gt;
&lt;p&gt;A noter, on s&amp;rsquo;en servira peut-être plus tard, mais &lt;strong&gt;SPI_FAST_FLASH_BOOT&lt;/strong&gt; m&amp;rsquo;a permis de trouver des &lt;a class="link" href="https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/boot-mode-selection.html" target="_blank" rel="noopener"
&gt;informations complémentaires sur la façon dont boot l&amp;rsquo;ESP32 ici&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Visiblement il y a plusieurs modes de boot et je pourrais peut-être trouver des choses intéressantes là dessus.&lt;/p&gt;
&lt;h2 id="bouton-encore"&gt;Bouton encore
&lt;/h2&gt;&lt;p&gt;Tout ça c&amp;rsquo;est intéressant, mais j&amp;rsquo;aimerais pouvoir réaliser autre chose que juste flasher très vite et reboot l&amp;rsquo;ESP32&amp;hellip;&lt;/p&gt;
&lt;p&gt;Le code précédent que j&amp;rsquo;ai trouvé laisse penser que le bouton c&amp;rsquo;est le Pin(13). Je cherche des tutos sur le net pour savoir comment jouer avec un bouton et je tombe &lt;a class="link" href="https://microcontrollerslab.com/push-button-esp32-esp8266-micropython-digital-input/" target="_blank" rel="noopener"
&gt;sur ce tutoriel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;En théorie, j&amp;rsquo;ai juste à vérifier la valeur du &lt;strong&gt;Pin(13)&lt;/strong&gt; en position IN pour détecter un appui.&lt;/p&gt;
&lt;p&gt;Sauf que j&amp;rsquo;ai beau appuyer sur le bouton, la valeur reste toujours à 0. Je commence à me demander si c&amp;rsquo;est le bon Pin&amp;hellip;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; app.Pin(2, app.Pin.IN).value()
0
&amp;gt;&amp;gt;&amp;gt; app.Pin(2, app.Pin.IN).value()
0
&amp;gt;&amp;gt;&amp;gt; app.Pin(2, app.Pin.IN).value()
0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Après quelques tests bourrins (j&amp;rsquo;ai testé plusieurs valeurs), bingo !&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; app.Pin(16, app.Pin.IN).value()
0
&amp;gt;&amp;gt;&amp;gt; app.Pin(16, app.Pin.IN).value()
1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;La valeur passe à 1 quand je maintiens le bouton appuyé ! Pour le fun j&amp;rsquo;ai écrit un petit bout de code qui change la couleur du NeoPixel quand on clique :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CTRL&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;random&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;randint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;led_color_random_when_clicked&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;button_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;button_state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;led&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NEO_PIXEL&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;led&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NEO_PIXEL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;button_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sleep_ms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CTRL&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div id=video&gt;&lt;video controls="controls" height="500" src="https://blog.zwindler.fr/2023/06/click.mp4"&gt;&lt;/video&gt;&lt;/div&gt;
&lt;p&gt;Note : la valeur du click est pas super stable au moment où on lâche le bouton. D&amp;rsquo;où l&amp;rsquo;ajout d&amp;rsquo;un sleep de 50ms pour stabiliser la valeur du bouton.&lt;/p&gt;
&lt;h2 id="du-son-"&gt;Du son ?
&lt;/h2&gt;&lt;p&gt;Lors de mon démontage, j&amp;rsquo;avais pensé repérer un buzzer (cf &lt;a class="link" href="https://blog.zwindler.fr/2023/06/16/reverse-blinky-enix-part1/" &gt;le premier article&lt;/a&gt;). Une rapide recherche sur Internet sur la marque &lt;strong&gt;FUET&lt;/strong&gt; me laisse penser que c&amp;rsquo;est plutôt un speaker et qu&amp;rsquo;on peut donc jouer plus que des sons mais aussi des WAV.&lt;/p&gt;
&lt;p&gt;Assez rapidement, je suis tombé sur la doc de &lt;a class="link" href="https://docs.micropython.org/en/latest/library/machine.I2S.html" target="_blank" rel="noopener"
&gt;micropython à ce sujet&lt;/a&gt; et j&amp;rsquo;ai pu déterminer qu&amp;rsquo;il fallait chercher des exemples de codes avec &amp;ldquo;I2S&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai donc trouvé un bout de code assez bien documenté et complet pour expliquer comment enregistrer et jouer des sons avec plusieurs types de boards, avec micropython.&lt;/p&gt;
&lt;p&gt;Malheureusement, même en changeant certaines combinaisons de paramètres (notamment les pins SCK_PIN, WS_PIN et SD_PIN), j&amp;rsquo;ai été incapable de faire fonctionner le speaker, même sur un exemple simple avec une bête tonalité.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/miketeachman/micropython-i2s-examples/blob/master/examples/play_tone.py" target="_blank" rel="noopener"
&gt;github.com/miketeachman/micropython-i2s-examples/blob/master/examples/play_tone.py&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si j&amp;rsquo;avais réussi, j&amp;rsquo;aurai profité de ce que j&amp;rsquo;ai appris lors du deuxième article pour copier un WAV et vous faire marrer avec une idée à la c**.&lt;/p&gt;
&lt;h2 id="du-stockage-"&gt;Du stockage ?
&lt;/h2&gt;&lt;p&gt;Tant qu&amp;rsquo;on parle de tests non concluants, j&amp;rsquo;ai aussi remarqué la présence d&amp;rsquo;un composant appelé &lt;strong&gt;W25Q128JVSIQ&lt;/strong&gt;, de marque &lt;strong&gt;winbond&lt;/strong&gt;. On peut &lt;a class="link" href="https://www.mouser.fr/ProductDetail/Winbond/W25Q128JVSIQ?qs=qSfuJ%252Bfl%2Fd6tLXvPR4fl9w%3D%3D" target="_blank" rel="noopener"
&gt;trouver les specs ici&lt;/a&gt;. Il s&amp;rsquo;agit d&amp;rsquo;une mémoire flash de 128 Mbit et qui coûte entre 1 et 2 euros.&lt;/p&gt;
&lt;p&gt;En re-parcourant tous les objets en mémoire, j&amp;rsquo;ai (re)découvert la présence d&amp;rsquo;un objet &amp;ldquo;bdev&amp;rdquo; qui semble être une partition (probablement le stockage monté dans /flash, qui contient le fichier &lt;code&gt;hw_version&lt;/code&gt; ainsi qu&amp;rsquo;un couple clé privée/clé publique ? cf &lt;a class="link" href="https://blog.zwindler.fr/2023/06/16/reverse-blinky-enix-part1/" &gt;le premier article&lt;/a&gt;).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; help(bdev)
object &amp;lt;Partition type=1, subtype=129, address=2097152, size=2097152, label=vfs, encrypted=0&amp;gt; is of type Partition
find -- &amp;lt;staticmethod&amp;gt;
info -- &amp;lt;function&amp;gt;
readblocks -- &amp;lt;function&amp;gt;
writeblocks -- &amp;lt;function&amp;gt;
ioctl -- &amp;lt;function&amp;gt;
set_boot -- &amp;lt;function&amp;gt;
mark_app_valid_cancel_rollback -- &amp;lt;classmethod&amp;gt;
get_next_update -- &amp;lt;function&amp;gt;
BOOT -- 0
RUNNING -- 1
TYPE_APP -- 0
TYPE_DATA -- 1
&amp;gt;&amp;gt;&amp;gt; bdev.info()
(1, 129, 2097152, 2097152, &amp;#39;vfs&amp;#39;, False)
&amp;gt;&amp;gt;&amp;gt; uos.statvfs(&amp;#39;/&amp;#39;)
(4096, 4096, 512, 509, 509, 0, 0, 0, 0, 255)
&amp;gt;&amp;gt;&amp;gt; uos.statvfs(&amp;#39;/flash&amp;#39;)
(512, 512, 32768, 32758, 32758, 0, 0, 0, 0, 255)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Quelques docs en vrac :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.micropython.org/en/latest/library/machine.SDCard.html" target="_blank" rel="noopener"
&gt;docs.micropython.org/en/latest/library/machine.SDCard.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://micropython.fr/modules_center/seriel_spi/module_sd_card_spi/" target="_blank" rel="noopener"
&gt;micropython.fr/modules_center/seriel_spi/module_sd_card_spi/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion-"&gt;Conclusion ?
&lt;/h2&gt;&lt;p&gt;On ne va pas se mentir&amp;hellip; Je suis un poil déçu de ne pas avoir réussi à trouver le code source&amp;hellip;&lt;/p&gt;
&lt;p&gt;Je me demande vraiment comment c&amp;rsquo;est possible de lancer du code python sans qu&amp;rsquo;il soit visible sur le filesystem. Je me dis que j&amp;rsquo;ai forcément loupé un truc et ça me laisse un sentiment d&amp;rsquo;inachevé.&lt;/p&gt;
&lt;p&gt;Mais j&amp;rsquo;y ai passé beaucoup de temps (tout n&amp;rsquo;est pas détaillé ici mais j&amp;rsquo;ai été cherché par mal d&amp;rsquo;infos, notamment sur la façon dont on boot la board et sur le stockage flash/SD, sans succès).&lt;/p&gt;
&lt;p&gt;Un peu déçu aussi de ne pas avoir trouvé les bons paramètres pour piloter le speaker, j&amp;rsquo;aurais bien fait un petit bout de code avec du son en plus de la lumière. A voir ce que l&amp;rsquo;équipe ajoutera de ce côté.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai laissé tomber la partie MQTT. Je suis certain que j&amp;rsquo;aurais réussi à faire marcher la communication avec l&amp;rsquo;ESP32 et un serveur Mosquitto ou RabbitMQ et j&amp;rsquo;avais déjà configuré le réseau (&lt;a class="link" href="https://blog.zwindler.fr/2023/06/21/reverse-blinky-enix-part2/" &gt;dans le 2ème article&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Pour autant, ce n&amp;rsquo;est pas la fin !&lt;/p&gt;
&lt;p&gt;Maintenant que je met sde côté (au moins provisoirement) le reverse du blinky, je peux me concentrer sur la partie SaaS et enfin &amp;ldquo;enroll&amp;rdquo; mon device dans le site mis à disposition par Enix, pour commencer à jouer avec &amp;ldquo;pour de vrai&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;On verra si ça m&amp;rsquo;amène d&amp;rsquo;autres idées. En attendant, have fun :-)&lt;/p&gt;</description></item><item><title>Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 2</title><link>https://blog.zwindler.fr/2023/06/21/reverse-blinky-enix-part2/</link><pubDate>Wed, 21 Jun 2023 12:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2023/06/21/reverse-blinky-enix-part2/</guid><description>&lt;img src="https://blog.zwindler.fr/2023/06/noepixel2.webp" alt="Featured image of post Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 2" /&gt;&lt;p&gt;Cet article fait partie d&amp;rsquo;une suite d&amp;rsquo;articles sur le reverse engineering d&amp;rsquo;un prototype de Gyrophare connecté appelé Blinky :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/16/reverse-blinky-enix-part1/" &gt;Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/21/reverse-blinky-enix-part2/" &gt;Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/23/reverse-blinky-enix-part3/" &gt;Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="rappel-des-épisodes-précédents"&gt;Rappel des épisodes précédents
&lt;/h2&gt;&lt;p&gt;Dans l&amp;rsquo;article précédent, j&amp;rsquo;avais reçu un gyrophare connecté conçu par les copain⋅es de chez Enix. Comme je n&amp;rsquo;avais pas reçu les instructions comme les autres destinataires de ce prototype, j&amp;rsquo;avais décidé de faire un peu de reverse engineering dessus, même si à vrai dire je n&amp;rsquo;y connais pas grand-chose.&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/16/reverse-blinky-enix-part1/" &gt;L&amp;rsquo;article précédent est disponible ici&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Je m&amp;rsquo;étais arrêté en changeant la couleur des LEDs, car j&amp;rsquo;avais réussi à deviner que la fonction &lt;code&gt;app.set_status_pixel()&lt;/code&gt; prenait comme argument un tuple RGB.&lt;/p&gt;
&lt;p&gt;Mais c&amp;rsquo;est encore un peu pénible de deviner comme utiliser le blinky sans avoir le code source. J&amp;rsquo;ai donc tenté de le trouver&amp;hellip;&lt;/p&gt;
&lt;h2 id="inspect-"&gt;inspect ?
&lt;/h2&gt;&lt;p&gt;Ma première idée a été de chercher sur les Internets comment aller récupérer le code source d&amp;rsquo;une fonction en mémoire en python.&lt;/p&gt;
&lt;p&gt;En iPython, il existe un moyen d&amp;rsquo;afficher directement le code d&amp;rsquo;une fonction en ajoutant en suffixe d&amp;rsquo;une fonction &amp;ldquo;??&amp;rdquo;. Pas de bol, Micropython n&amp;rsquo;implémente pas ça :(&lt;/p&gt;
&lt;p&gt;En CPython, il existe un module &amp;ldquo;inspect&amp;rdquo; en CPython qui permet (entre autres) de faire ce que je veux faire. Je suis assez vite tombé sur un module pip &lt;strong&gt;micropython-inspect&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://pypi.org/project/micropython-inspect/" target="_blank" rel="noopener"
&gt;pypi.org/project/micropython-inspect&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a module reimplemented specifically for MicroPython standard library, with efficient and lean design in mind.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Reste à trouver comment installer un module pip sur notre ESP32. Evidemment, comme je n&amp;rsquo;ai pas de shell, impossible de faire &lt;code&gt;pip install&lt;/code&gt; directement.&lt;/p&gt;
&lt;p&gt;ChatGPT (oui, j&amp;rsquo;ai demandé de l&amp;rsquo;aide 🤖) me propose 2 solutions :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;utiliser le module &amp;ldquo;upip&amp;rdquo; qui permet de télécharger les modules portés pour MicroPython&lt;/li&gt;
&lt;li&gt;télécharger un &amp;ldquo;remote shell&amp;rdquo; pour MicroPython&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Essayons la première solution&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;upip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;upip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inspect&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Installing&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Unable&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;resolve&lt;/span&gt; &lt;span class="n"&gt;micropython&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;Internet&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Evidemment ça ne peut pas marcher, vu que je n&amp;rsquo;ai encore pas configuré Internet 🤦. Mais on avait vu que c&amp;rsquo;était possible dans l&amp;rsquo;article précédent, puisque l&amp;rsquo;ESP32 Espressif du Blinky dispose de WIFI.&lt;/p&gt;
&lt;p&gt;On trouve assez vite comment faire sur la doc de micropython :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;wifi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WLAN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STA_IF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;wifi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;xxxxxx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;xxxxxx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;wifi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isconnected&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Connected! IP address:&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wifi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ifconfig&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Connected&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt; &lt;span class="n"&gt;IP&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;192.168&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La preuve donc que cette board a bien un module wifi fonctionnel !! Bon à savoir, ça sera utile :)/&lt;/p&gt;
&lt;p&gt;Une fois qu&amp;rsquo;on a le réseau, on peut télécharger des packages pour notre board&amp;hellip; mais là, c&amp;rsquo;est le drame&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/inspect.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;source redacted to save you memory&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What the actuel frak???&lt;/p&gt;
&lt;p&gt;En copiant collant la ligne de sortie, je tombe sur ce fichier source&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/micropython/micropython-lib/blob/master/python-stdlib/inspect/inspect.py#L67" target="_blank" rel="noopener"
&gt;github.com/micropython/micropython-lib/blob/master/python-stdlib/inspect/inspect.py&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En gros, ce module ne fait de définir les fonctions, mais l&amp;rsquo;implémentation n&amp;rsquo;a pas été faite&amp;hellip;&lt;/p&gt;
&lt;h2 id="rshell"&gt;rshell
&lt;/h2&gt;&lt;p&gt;Passons à la 2ème idée de ChatGPT, utiliser un shell depuis notre PC.&lt;/p&gt;
&lt;p&gt;Sur mon PC :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; pip3 install rshell
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;rshell --port /dev/ttyUSB0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A partir de là, on peut lister les boards avec la commande &lt;code&gt;boards&lt;/code&gt; (si on en a plusieurs connectées), faire des &lt;code&gt;cat&lt;/code&gt;, des &lt;code&gt;cp&lt;/code&gt; entre le PC et la board&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/rshell-repl.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est assez utile pour du debug, mais comme je n&amp;rsquo;avais pas trouvé le code sur le filesystem dans mes tentatives précédentes (à part en mémoire), ça ne m&amp;rsquo;aide pas plus&amp;hellip;&lt;/p&gt;
&lt;p&gt;Quelques liens utiles&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://wiki.mchobby.be/index.php?title=MicroPython-Hack-RShell" target="_blank" rel="noopener"
&gt;wiki.mchobby.be/index.php?title=MicroPython-Hack-RShell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/dhylands/rshell" target="_blank" rel="noopener"
&gt;github.com/dhylands/rshell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="webrepl"&gt;webrepl
&lt;/h2&gt;&lt;p&gt;Pendant mes premières explorations, j&amp;rsquo;avais remarqué qu&amp;rsquo;il y avait un fichier &lt;code&gt;boot.py&lt;/code&gt; qui ne contenait que tu codes commenté. Je l&amp;rsquo;avais donc ignoré.&lt;/p&gt;
&lt;p&gt;En allant relire le contenu du fichier je suis tombé sur ça :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# This file is executed on every boot (including wake-boot from deepsleep)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#import esp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#esp.osdebug(None)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#import webrepl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#webrepl.start()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;J&amp;rsquo;ai donc tenté de lancer les commandes dans mon shell Python sur la board :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;esp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;osdebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;webrepl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;webrepl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;WebREPL&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;configured&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;import webrepl_setup&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Qu&amp;rsquo;est ce que c&amp;rsquo;est que WebREPL ?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;webrepl_setup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;WebREPL&lt;/span&gt; &lt;span class="n"&gt;daemon&lt;/span&gt; &lt;span class="n"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;disabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Would&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;like&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;nable&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;isable&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;To&lt;/span&gt; &lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="n"&gt;WebREPL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;must&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;New&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;xxxxxx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Confirm&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;xxxxxx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Changes&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;activated&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="n"&gt;reboot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Would&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;like&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;reboot&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Après reboot, je remarque la ligne suivante :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;WebREPL daemon started on ws://192.168.x.y:8266
Started webrepl in normal mode
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ahah ! On va pouvoir accéder à un autre shell à distance !&lt;/p&gt;
&lt;p&gt;En cherchant rapidement, je tombe sur &lt;a class="link" href="https://github.com/micropython/webrepl" target="_blank" rel="noopener"
&gt;ce dépôt git&lt;/a&gt;. Il explique comment ça marche et indique qu&amp;rsquo;il faut un client pour parler avec le websocket. Il y a une version web du client que je n&amp;rsquo;ai pas réussi à faire marcher.&lt;/p&gt;
&lt;p&gt;En revanche, en clonant le dépôt et en utilisant le client local, ça fonctionne.&lt;/p&gt;
&lt;p&gt;Sur mon PC :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/micropython/webrepl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Je lance ensuite le fichier html, je peux me connecter avec l&amp;rsquo;IP de mon Blinky (connecté en WIFI) et un mot de passe.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/webrepl.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai donc un 3ème shell sur le Blinky (c&amp;rsquo;est cool), mais je ne suis toujours pas plus avancé :-p. Je referme donc ce chapitre (je ne dirais pas que c&amp;rsquo;est un échec, je dirais que ça n&amp;rsquo;a pas marché).&lt;/p&gt;
&lt;h2 id="tu-es-lélu-néo-pixel"&gt;Tu es l&amp;rsquo;élu, Néo (Pixel)
&lt;/h2&gt;&lt;p&gt;Retour sur notre shell, avec les infos que j&amp;rsquo;ai. Dans ce que &lt;code&gt;help(app)&lt;/code&gt; m&amp;rsquo;a remonté, il y a cet objet qui m&amp;rsquo;intrigue :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;NEO_PIXEL&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NeoPixel&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;ffe8300&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Une rapide recherche avec le terme NEOPIXEL me sort ce site &lt;a class="link" href="https://gcworks.fr/tutoriel/esp/LEDNeoPixel.html" target="_blank" rel="noopener"
&gt;gcworks.fr/tutoriel/esp/LEDNeoPixel&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Les NeoPixel sont des LEDS RVB intelligentes ultra lumineuses.
Exemple : ce petit module sous la forme d&amp;rsquo;un stick, est équipé de 8 NeoPixels.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ca sent très très bon cette histoire ! Mon blinky c&amp;rsquo;est quand même un peu un ruban de LED rond ! Le site donne même du code d&amp;rsquo;exemple pour tester :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;machine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;neopixel&lt;/span&gt; &lt;span class="c1"&gt;# import de la bibliothèque NeoPixel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;np&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;neopixel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeoPixel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;machine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 8 LEDS connectées broche 26 (D2 shiel base 1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Petit retour en arrière, quand j&amp;rsquo;avais démonté le blinky, voilà à quoi ça ressemblait :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/leds.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Si on regarde plus en détail, on remarque qu&amp;rsquo;il y a 13 LEDs sur notre Blinky. Une au milieu (&lt;strong&gt;led_status&lt;/strong&gt;) et 12 autres en cercle.&lt;/p&gt;
&lt;p&gt;Il est donc probable que mon tableau neopixel fasse une taille de 13 cases. Cependant, difficile de deviner sur quel PIN le ruban est connecté avec cette photo&amp;hellip;&lt;/p&gt;
&lt;p&gt;Je suis donc parti du principe que c&amp;rsquo;était bien le pin 26 et j&amp;rsquo;ai testé le code d&amp;rsquo;exemple&amp;hellip; sans succès&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;neopixel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeoPixel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Et puis, j&amp;rsquo;ai réfléchis et je ne suis dis&amp;hellip; &amp;ldquo;pourquoi je m&amp;rsquo;embête à déclarer un objet NeoPixel, puisque j&amp;rsquo;en ai déjà un en mémoire 🤔 ???&amp;rdquo;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; app.NEO_PIXEL
&amp;lt;NeoPixel object at 3ffe8300&amp;gt;
&amp;gt;&amp;gt;&amp;gt; app.NEO_PIXEL[0]
(0, 0, 255)
&amp;gt;&amp;gt;&amp;gt; app.NEO_PIXEL[1]
(0, 0, 0)
&amp;gt;&amp;gt;&amp;gt; app.NEO_PIXEL[2]
(0, 0, 0)
&amp;gt;&amp;gt;&amp;gt; app.NEO_PIXEL[12]
(0, 0, 0)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A l&amp;rsquo;état initial du Blinky, toutes les leds sont bien positionnées sur &amp;ldquo;(0, 0, 0)&amp;rdquo; (éteint), et la &lt;strong&gt;led_status&lt;/strong&gt; à &amp;ldquo;(0, 0, 255)&amp;rdquo; (bleu). On est pas mals là !&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; app.NEO_PIXEL[13]
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
File &amp;#34;neopixel.py&amp;#34;, line 1, in __getitem__
File &amp;#34;neopixel.py&amp;#34;, line 1, in &amp;lt;genexpr&amp;gt;
IndexError: bytearray index out of range
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Il n&amp;rsquo;y a pas de case 13, comme j&amp;rsquo;avais deviné (de 0 à 12).&lt;/p&gt;
&lt;p&gt;Et si je change une couleur sur une LED&amp;hellip;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; app.NEO_PIXEL[1]=(255, 0, 0)
&amp;gt;&amp;gt;&amp;gt; app.NEO_PIXEL.write()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/noepixel.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;BINGO !&lt;/p&gt;
&lt;h2 id="et-maintenant-que-vais-je-fai-re-"&gt;Et maintenant&amp;hellip; que vais-je fai-re ?
&lt;/h2&gt;&lt;p&gt;Bon, on a toujours pas trouvé ce fichu code source et je commence à manquer d&amp;rsquo;idées&amp;hellip; Mais on a du réseau et on a pas encore été graté du côté du MQTT (il y a des choses qui sont configurées)&amp;hellip; On va probablement regarder de ce côté là dans le prochain épisode !&lt;/p&gt;
&lt;h2 id="bonus-faire-des-trucs-rigolos-avec-mes-leds"&gt;Bonus, faire des trucs rigolos avec mes LEDs
&lt;/h2&gt;&lt;p&gt;En bonus, je vous met quelques bouts de codes que je me suis amusés à écrire et qui font des trucs jolis / mignons avec le blinky :&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai découvert sur le tard qu&amp;rsquo;on pouvait copier coller de large morceaux de codes indentés avec [CTRL-E], puis [CTRL-D] pour valider.&lt;/p&gt;
&lt;div id=video&gt;&lt;video controls="controls" height="300" src="https://blog.zwindler.fr/2023/06/blinky1.mp4"&gt;&lt;/video&gt;&lt;/div&gt;
&lt;div id=video&gt;&lt;video controls="controls" height="300" src="https://blog.zwindler.fr/2023/06/blinky2.mp4"&gt;&lt;/video&gt;&lt;/div&gt;
&lt;div id=video&gt;&lt;video controls="controls" height="300" src="https://blog.zwindler.fr/2023/06/blinky3.mp4"&gt;&lt;/video&gt;&lt;/div&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[CTRL-E]
from time import *
from random import randint
def full_random():
while True:
r = randint(0, 100)
g = randint(0, 100)
b = randint(0, 100)
for led in range(1, 12):
app.NEO_PIXEL[led] = (r, g, b)
app.NEO_PIXEL.write()
sleep_ms(100)
def full_random_rotation():
while True:
for led in range(1, 12):
r = randint(0, 100)
g = randint(0, 100)
b = randint(0, 100)
app.NEO_PIXEL[led] = (r, g, b)
app.NEO_PIXEL.write()
sleep_ms(50)
def blue_rotation():
while True:
for led in range(1, 12):
for i in range(1,12):
app.NEO_PIXEL[i] = (0, 0, 0)
app.NEO_PIXEL[led] = (0, 0, 255)
app.NEO_PIXEL.write()
sleep_ms(100)
def kitt():
# Set all leds to black
for i in range(0, 12):
app.NEO_PIXEL[i] = (0, 0, 0)
while True:
# Forward loop from 2 to 6 (7 excluded)
for led in range(2, 7):
app.NEO_PIXEL[led] = (150, 0, 0)
app.NEO_PIXEL.write()
sleep_ms(100)
app.NEO_PIXEL[led] = (0, 0, 0)
# Backward loop from 5 to 3 (2 excluded)
for led in range(5, 2, -1):
app.NEO_PIXEL[led] = (150, 0, 0)
app.NEO_PIXEL.write()
sleep_ms(100)
app.NEO_PIXEL[led] = (0, 0, 0)
[CTRL-D]
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 1</title><link>https://blog.zwindler.fr/2023/06/16/reverse-blinky-enix-part1/</link><pubDate>Fri, 16 Jun 2023 12:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2023/06/16/reverse-blinky-enix-part1/</guid><description>&lt;img src="https://blog.zwindler.fr/2023/06/blinky.webp" alt="Featured image of post Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 1" /&gt;&lt;p&gt;Cet article fait partie d&amp;rsquo;une suite d&amp;rsquo;articles sur le reverse engineering d&amp;rsquo;un prototype de Gyrophare connecté appelé Blinky :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/16/reverse-blinky-enix-part1/" &gt;Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/21/reverse-blinky-enix-part2/" &gt;Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2023/06/23/reverse-blinky-enix-part3/" &gt;Reverse du Blinky, le gyrophare connecté des copains de chez Enix - part 3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Il y a quelques mois, j&amp;rsquo;ai rejoint une beta pour un projet de &amp;ldquo;gyrophare connecté&amp;rdquo;, &lt;strong&gt;Blinky&lt;/strong&gt;, lancé par &lt;a class="link" href="https://enix.io/fr/" target="_blank" rel="noopener"
&gt;les copain⋅es de chez Enix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Yaaaar 🦍🏴‍☠️&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;La semaine dernière, j&amp;rsquo;ai donc reçu une version de test/PoC du fameux gyrophare, par la Poste (il y avait une soirée de lancement sur Paris, mais je n&amp;rsquo;étais pas disponible).&lt;/p&gt;
&lt;p&gt;Sauf qu&amp;rsquo;un petit malin à la soirée parisienne a (a priori) récupéré le petit papier expliquant ce qu&amp;rsquo;il fallait en faire.&lt;/p&gt;
&lt;p&gt;En temps normal, un adulte responsable aurait juste demandé aux membres de l&amp;rsquo;équipe de l&amp;rsquo;aide. Mais c&amp;rsquo;est sans compter mon côté gamin espiègle, qui a pris le dessus.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/hackerman.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Pourquoi prendre 5 minutes pour demander de l&amp;rsquo;aide alors qu&amp;rsquo;on peut passer plusieurs heures à faire du ✨ &lt;em&gt;reverse engineering&lt;/em&gt; ✨ ?&lt;/p&gt;
&lt;p&gt;Note : je précise que je ne suis pas un spécialiste du reverse engineering, que je n&amp;rsquo;ai jamais bidouillé d&amp;rsquo;IoT et que je n&amp;rsquo;y connais rien en impression 3D. Je débute dans tous ces domaines. Vous pardonnerez donc mon côté noob ;-).&lt;/p&gt;
&lt;h2 id="par-où-commencer-"&gt;Par où commencer ?
&lt;/h2&gt;&lt;p&gt;Au moment où je décide de commencer ma session de retro ingénierie, je me dis juste qu&amp;rsquo;il y a sûrement une image Docker qui traîne quelque part pour communiquer avec le Blinky.&lt;/p&gt;
&lt;p&gt;Note : A ce moment-là, je ne sais pas encore que c&amp;rsquo;est un produit SaaS et je pense qu&amp;rsquo;on peut le faire tourner en local.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;en trouve une que je télécharge, je fais quelques tests et voilà ce que ça donne quand j&amp;rsquo;arrive à la faire fonctionner :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/blinky_docker_image.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;En lisant tout ça, j&amp;rsquo;en retire plusieurs infos. Je repère les termes &lt;code&gt;esp32&lt;/code&gt;, &lt;code&gt;pyboard&lt;/code&gt; et je remarque surtout que l&amp;rsquo;image Docker disponible sur Internet est en version &lt;strong&gt;1.0.3&lt;/strong&gt; alors que l&amp;rsquo;image sur mon Blinky est elle en version &lt;strong&gt;2.1.0&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;On va essayer d&amp;rsquo;éviter de l&amp;rsquo;écraser, du coup !&lt;/p&gt;
&lt;p&gt;Comme je ne sais plus trop où chercher, je cherche des informations supplémentaires sur le site &lt;a class="link" href="https://getblinky.io" target="_blank" rel="noopener"
&gt;getblinky.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Je vois tout de suite une animation qui montre les entrailles du Blinky.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/capture_blinky.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est pas très net, mais j&amp;rsquo;ai l&amp;rsquo;impression d&amp;rsquo;apercevoir les LEDs, un bouton poussoir, un buzzer et la mention Espressif sur le plus gros composant.&lt;/p&gt;
&lt;h2 id="on-ouvre-le-blinky-pour-voir"&gt;On ouvre le Blinky pour voir
&lt;/h2&gt;&lt;p&gt;La capture d&amp;rsquo;écran faites à l&amp;rsquo;arrache est pas super nette. Comme j&amp;rsquo;ai l&amp;rsquo;objet dans les mains, le plus simple c&amp;rsquo;est de l&amp;rsquo;ouvrir pour aller voir par moi-même !&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/impression.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;y connais rien en impression 3d mais sans trop de doute, ici ça en est 😉. Je découvre par la même qu&amp;rsquo;il existe des filaments translucides, pratique pour les LEDs ;-)&lt;/p&gt;
&lt;p&gt;Pour ouvrir la bestiole, je vois 3 vis 6 pans. Heureusement que j&amp;rsquo;avais des tournevis étoile (t8) sous la main, ça marche quand même&amp;hellip;&lt;/p&gt;
&lt;p&gt;La partie supérieure est composée de plusieurs morceaux imprimés en 3d :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/morceaux.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;La partie translucide, la partie supérieure sont relativement simples. La partie blanche est plus travaillée en revanche, et permet de faire &amp;ldquo;ressort&amp;rdquo; pour le bouton poussoir.&lt;/p&gt;
&lt;p&gt;Dans la partie inférieure, on trouve les pas de vis, fusionnées.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/vis.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Je ne savais pas comment c&amp;rsquo;était possible de faire ça, heureusement le &lt;em&gt;Twitter makers&lt;/em&gt; m&amp;rsquo;a expliqué que ça se faisait super simplement, à l&amp;rsquo;aide d&amp;rsquo;un fer à souder (&lt;a class="link" href="https://www.youtube.com/watch?v=hwq15qH-4x4" target="_blank" rel="noopener"
&gt;cf cette vidéo&lt;/a&gt;)!&lt;/p&gt;
&lt;p&gt;Et voilà le morceau que vous attendiez tous/toutes : le circuit imprimé qui pilote tout ça :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/back.avif"
loading="lazy"
&gt;
&lt;img src="https://blog.zwindler.fr/2023/06/front.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;On retrouve tout ce que j&amp;rsquo;avais pu observer sur la capture d&amp;rsquo;écran faite sur le site &lt;a class="link" href="http://getblinky.io" target="_blank" rel="noopener"
&gt;http://getblinky.io&lt;/a&gt; mais sur quelque chose de bien plus clean. Il y a des LEDs, un buzzer, le bouton poussoir et&amp;hellip; le fameux esp32 espressif !&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/espressif.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;A priori, je l&amp;rsquo;ai remonté sans rien casser 🤣&lt;/p&gt;
&lt;h2 id="a-la-découverte-de-lesp32"&gt;A la découverte de l&amp;rsquo;ESP32
&lt;/h2&gt;&lt;p&gt;Maintenant que j&amp;rsquo;ai une photo plus nette de l&amp;rsquo;ESP32, je peux commencer à me documenter dessus.&lt;/p&gt;
&lt;p&gt;Il s&amp;rsquo;agit d&amp;rsquo;un &lt;strong&gt;ESP32-WROOM-32E&lt;/strong&gt; de chez ESPRESSIF, dont &lt;a class="link" href="https://espressif.com/sites/default/files/documentation/esp32-wroom-32e_esp32-wroom-32ue_datasheet_en.pdf" target="_blank" rel="noopener"
&gt;les specs sont disponibles ici&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Je remarque qu&amp;rsquo;il dispose du WI-FI, j&amp;rsquo;en ai déduit que c&amp;rsquo;était probablement une machine autonome, une fois connectée au réseau.&lt;/p&gt;
&lt;p&gt;Niveau puissance, on est sur un &lt;em&gt;dual-core 32-bit LX6&lt;/em&gt; 🤷, qui monte jusqu&amp;rsquo;à (tenez-vous bien) 240 MHz !&lt;/p&gt;
&lt;p&gt;Je blague, mais en vrai c&amp;rsquo;est même trop pour ce qu&amp;rsquo;on va en faire ;-).&lt;/p&gt;
&lt;p&gt;Par curiosité, je suis allé voir mon copain Ali, et ça coûte 3,34€ pièce pour ce modèle exact (&lt;a class="link" href="https://fr.aliexpress.com/item/33007945338.html%29" target="_blank" rel="noopener"
&gt;https://fr.aliexpress.com/item/33007945338.html)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;En revanche, je n&amp;rsquo;ai aucune idée de combien ça coûte de faire produire le circuit sur lequel il est branché (c&amp;rsquo;est visiblement fait en usine).&lt;/p&gt;
&lt;h2 id="on-se-connecte-"&gt;On se connecte ?
&lt;/h2&gt;&lt;p&gt;Une fois que je connecte en USB mon Blinky, je vois apparaître une ligne &lt;code&gt; Silicon Labs CP210x UART Bridge&lt;/code&gt; quand je lance la commande &lt;code&gt;lsusb&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Une rapide recherche permet de comprendre que c&amp;rsquo;est bien notre port série virtuel (via USB)&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://silabs.com/developers/usb-to-uart-bridge-vcp-drivers" target="_blank" rel="noopener"
&gt;https://silabs.com/developers/usb-to-uart-bridge-vcp-drivers&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The CP210x USB to UART Bridge Virtual COM Port (VCP)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Donc ça, ça fonctionne correctement.&lt;/p&gt;
&lt;p&gt;La &lt;a class="link" href="https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/establish-serial-connection.html#example-output" target="_blank" rel="noopener"
&gt;doc officielle sur le site &lt;strong&gt;espressif&lt;/strong&gt;&lt;/a&gt; dit d&amp;rsquo;ajouter son utilisateur au groupe &lt;em&gt;dialout&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo usermod -a -G dialout &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Puis d&amp;rsquo;utiliser &lt;code&gt;putty&lt;/code&gt; pour se connecter en série sur le &lt;strong&gt;ttyUSB0&lt;/strong&gt; :-/. Personnellement (sous Linux), je n&amp;rsquo;ai pas réussi. En revanche, je remarque qu&amp;rsquo;on peut utiliser &lt;code&gt;screen&lt;/code&gt;, sous Mac. Pas de raison que ça ne marche pas sous Linux.&lt;/p&gt;
&lt;p&gt;Et effectivement, ça fonctionne.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/screen.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Le &lt;code&gt;screen&lt;/code&gt; a l&amp;rsquo;air bloqué mais&amp;hellip; un simple [Ctrl-C] et me voilà dans le terminal python&amp;hellip;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Traceback (most recent call last):
File &amp;#34;main.py&amp;#34;, line 7, in &amp;lt;module&amp;gt;
File &amp;#34;firmware_blinky_esp32.py&amp;#34;, line 92, in main
File &amp;#34;uasyncio/core.py&amp;#34;, line 1, in run_forever
File &amp;#34;uasyncio/core.py&amp;#34;, line 1, in run_until_complete
File &amp;#34;firmware_blinky_esp32.py&amp;#34;, line 69, in start
File &amp;#34;serial_cli.py&amp;#34;, line 101, in poll_cli
KeyboardInterrupt:
MicroPython v1.18 on 2023-04-26; ESP32 module with ESP32
Type &amp;#34;help()&amp;#34; for more information.
&amp;gt;&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;C&amp;rsquo;est le moment dans les films d&amp;rsquo;espions où le hacker dit &amp;ldquo;I&amp;rsquo;m in&amp;rdquo; 😎.&lt;/p&gt;
&lt;h2 id="on-va-essayer-de-trouver-du-code"&gt;On va essayer de trouver du code
&lt;/h2&gt;&lt;p&gt;Maintenant qu&amp;rsquo;on a la main sur l&amp;rsquo;interpréteur Python, on va pouvoir farfouiller un peu :).&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;avais déjà vu mention de &lt;code&gt;pyboard&lt;/code&gt; dans l&amp;rsquo;image Docker, ce qui m&amp;rsquo;avait emmené sur &lt;a class="link" href="https://docs.micropython.org/en/latest/" target="_blank" rel="noopener"
&gt;la doc de MicroPython&lt;/a&gt;. Ici, on a bien la confirmation que c&amp;rsquo;est MicroPython qui tourne sur le Blinky.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;MicroPython v1.18 on 2023-04-26; ESP32 module with ESP32&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;La première idée qui vient à l&amp;rsquo;esprit est de parcourir le filesystem, pour voir si je peux pas trouver les sources.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;TAB&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="n"&gt;VfsFat&lt;/span&gt; &lt;span class="n"&gt;VfsLfs2&lt;/span&gt; &lt;span class="n"&gt;chdir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dupterm&lt;/span&gt; &lt;span class="n"&gt;dupterm_notify&lt;/span&gt; &lt;span class="n"&gt;getcwd&lt;/span&gt; &lt;span class="n"&gt;ilistdir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;listdir&lt;/span&gt; &lt;span class="n"&gt;mkdir&lt;/span&gt; &lt;span class="n"&gt;mount&lt;/span&gt; &lt;span class="n"&gt;rename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rmdir&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt; &lt;span class="n"&gt;statvfs&lt;/span&gt; &lt;span class="n"&gt;umount&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;uname&lt;/span&gt; &lt;span class="n"&gt;urandom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;flash&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;boot.py&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/flash&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;client.crt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;client.key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;hw_version&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;flash/hw_version&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;v1mk3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La capture précédente montre tout ce que je peux voir sur le FS et je ne vois pas le code source. Le fichier &lt;code&gt;boot.py&lt;/code&gt; ne contient rien (tout est commenté), &lt;code&gt;hw_version&lt;/code&gt; affiche juste &lt;strong&gt;v1mk3&lt;/strong&gt;, la version de mon Blinky (comme on a pu le voir au dos du circuit imprimé).&lt;/p&gt;
&lt;h2 id="je-découvre-des-trucs-en-python"&gt;Je découvre des trucs en Python
&lt;/h2&gt;&lt;p&gt;Un peu par hasard, j&amp;rsquo;ai testé la commande &lt;code&gt;dir()&lt;/code&gt;, qui m&amp;rsquo;affiche ce qui est chargé en mémoire, et qu&amp;rsquo;on peut afficher des infos dessus avec &lt;code&gt;help()&lt;/code&gt; :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; dir()
[&amp;#39;uos&amp;#39;, &amp;#39;__name__&amp;#39;, &amp;#39;app&amp;#39;, &amp;#39;gc&amp;#39;, &amp;#39;bdev&amp;#39;, &amp;#39;mount_flash&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Il y a tout un tas de type d&amp;rsquo;objets, des strings (&lt;code&gt;__name__&lt;/code&gt;), des fonctions, des modules&amp;hellip;&lt;/p&gt;
&lt;p&gt;Il y en a une entrée qui me fait de l’œil : &amp;ldquo;app&amp;rdquo;. Il se trouve que c&amp;rsquo;est un module.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; dir(app)
[&amp;#39;__class__&amp;#39;, &amp;#39;__name__&amp;#39;, &amp;#39;main&amp;#39;, &amp;#39;start&amp;#39;, &amp;#39;__file__&amp;#39;, &amp;#39;Pin&amp;#39;, &amp;#39;log&amp;#39;, &amp;#39;machine&amp;#39;, &amp;#39;network&amp;#39;, &amp;#39;uasyncio&amp;#39;, &amp;#39;NEO_PIXEL&amp;#39;, &amp;#39;handle_pbpv2_message&amp;#39;, &amp;#39;BEACON_ID&amp;#39;, &amp;#39;PATTERNS&amp;#39;, &amp;#39;STATUS&amp;#39;, &amp;#39;BUTTON&amp;#39;, &amp;#39;VERSION&amp;#39;, &amp;#39;load_config&amp;#39;, &amp;#39;check_config&amp;#39;, &amp;#39;poll_cli&amp;#39;, &amp;#39;MQTT&amp;#39;, &amp;#39;set_status_pixel&amp;#39;, &amp;#39;init_logger&amp;#39;, &amp;#39;resetting&amp;#39;, &amp;#39;handle_button_release&amp;#39;, &amp;#39;greetings&amp;#39;, &amp;#39;exception_handler&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et avec plus de détails :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; help(app)
object &amp;lt;module &amp;#39;firmware_blinky_esp32&amp;#39; from &amp;#39;firmware_blinky_esp32.py&amp;#39;&amp;gt; is of type module
[...]
set_status_pixel -- &amp;lt;function set_status_pixel at 0x3ffe73a0&amp;gt;
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note : j&amp;rsquo;omets volontairement une grande partie des infos qu&amp;rsquo;on peut dénicher, on y reviendra plus tard.&lt;/p&gt;
&lt;p&gt;La première chose qui me saute aux yeux est qu&amp;rsquo;il existe une fonction &lt;code&gt;set_status_pixel()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Si je la lance telle quelle, j&amp;rsquo;apprends qu&amp;rsquo;elle attend un argument :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; app.set_status_pixel()
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
TypeError: function takes 1 positional arguments but 0 were given
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et comme par hasard, j&amp;rsquo;ai une structure &lt;strong&gt;STATUS&lt;/strong&gt; qui contient des tuples qui ressemblent très fortement à des codes RGB.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[...]
STATUS -- {&amp;#39;configuring&amp;#39;: (0, 0, 255), &amp;#39;connecting_to_wifi&amp;#39;: (255, 0, 0), &amp;#39;connecting_to_mqtt&amp;#39;: (255, 100, 0), &amp;#39;ready&amp;#39;: (0, 255, 0)}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Qu&amp;rsquo;est ce qu&amp;rsquo;il se passe si je lance la fonction suivante ??? 🕵️‍♂️&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_status_pixel&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/06/red.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;BINGO !&lt;/p&gt;
&lt;h2 id="la-suite-"&gt;La suite ?
&lt;/h2&gt;&lt;p&gt;Je m&amp;rsquo;arrête ici pour que l&amp;rsquo;article reste digeste, mais j&amp;rsquo;ai plein d&amp;rsquo;idée pour aller plus loin (j&amp;rsquo;ai d&amp;rsquo;ailleurs bien commencé).&lt;/p&gt;
&lt;p&gt;Le but du jeu va être de trouver comment piloter les LEDs (voire plus ?), comment communiquer avec le Blinky (MQTT ?) et continuer à chercher pour trouver où est ce coquin de code source ;-)&lt;/p&gt;</description></item></channel></rss>