<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Electronics on BlocNotes</title>
    <link>https://notes.iopush.net/tags/electronics/</link>
    <description>Recent content in Electronics on BlocNotes</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 13 Sep 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://notes.iopush.net/tags/electronics/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Reverse engineer Cubii elliptic bike BLE protocol</title>
      <link>https://notes.iopush.net/blog/2023/09-cubii-ble-protocol/</link>
      <pubDate>Wed, 13 Sep 2023 00:00:00 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2023/09-cubii-ble-protocol/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I recently bought a &lt;a href=&#34;https://cubii.eu/&#34;&gt;Cubii&lt;/a&gt; under desk elliptical bike, I have two use cases for it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Physiotherapy after a foot surgery&lt;/li&gt;
&lt;li&gt;Help me to warm-up in my cold home office in the winter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Added bonus, doing light exercise. I definitely not find it as enjoyable as using a full size machine, or doing &amp;ldquo;real&amp;rdquo; sports, but this is just my preference and I am stuck at home with crutches anyway 😅&lt;/p&gt;
&lt;p&gt;So my second hand model is a Cubii pro: no screen to display statistics, but with Bluetooth connectivity, which means that I had to install &lt;em&gt;yet another proprietary app&lt;/em&gt;. I doubt usefulness of collecting those data but as it is BLE communications I wondered if it would be easy to reverse engineer the protocol by spying on the frames&amp;hellip;&lt;br&gt;
It appeared to be even easier to look into the Android application to find everything I need to dump the data into InfluxDB, and a fun weekend project.&lt;/p&gt;
&lt;h2 id=&#34;decompiling-the-android-application&#34;&gt;Decompiling the Android application&lt;/h2&gt;
&lt;p&gt;I never decompiled any Android application but I knew that it was not hard, especially as Java is interpreted and not a compiled language. A quick search pointed me to &lt;a href=&#34;https://github.com/skylot/jadx&#34;&gt;Jadx&lt;/a&gt;, which did all the magic to extract the code from the Android APK to human readable Java files. Then it took only few minutes to get to the interesting code:&lt;/p&gt;
&lt;h2 id=&#34;calories-conversion&#34;&gt;Calories conversion&lt;/h2&gt;
&lt;p&gt;From the class &lt;code&gt;CubiiBleManager&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Java&#34; data-lang=&#34;Java&#34;&gt;calories &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;this$0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getCalories&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;$revolutions&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;latestCubiiNoLive &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;cubiiResistance &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; latestCubiiNoLive&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getCubiiResistance&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;())&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; 1 &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; cubiiResistance&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;intValue&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;());&lt;/span&gt;
distance &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;this$0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getDistance&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;$revolutions&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;

&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCalories&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#75715e&#34;&gt;// Oliv&amp;#39;: i=revolutions, i2=resistance selector
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;717d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
    &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;i2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; 2&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
            d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;733d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; 3&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
            d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;767d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; 4&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
            d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;833d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; 5&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
            d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;9d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; 6&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
            d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;033d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; 7&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
            d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;267d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; 8&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
            d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;483d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;03d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; d&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getDistance&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#75715e&#34;&gt;// Oliv&amp;#39;: i=revolutions
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;93E&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;4d&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;ble-uuid&#34;&gt;BLE UUID&lt;/h2&gt;
&lt;p&gt;From &lt;code&gt;BLEConstants&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;UUID&lt;/th&gt;
&lt;th&gt;BLE defined&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RPM&lt;/td&gt;
&lt;td&gt;00001731-2927-efef-cdab-eba0fe583711&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Battery&lt;/td&gt;
&lt;td&gt;00001732-2927-efef-cdab-eba0fe583711&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Break position&lt;/td&gt;
&lt;td&gt;00001733-2927-efef-cdab-eba0fe583711&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Revolutions&lt;/td&gt;
&lt;td&gt;00001734-2927-efef-cdab-eba0fe583711&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Device info&lt;/td&gt;
&lt;td&gt;0000180a-0000-1000-8000-00805f9b34fb&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Software version&lt;/td&gt;
&lt;td&gt;00002a28-0000-1000-8000-00805f9b34fb&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware version&lt;/td&gt;
&lt;td&gt;00002a27-0000-1000-8000-00805f9b34fb&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cubii BLE service&lt;/td&gt;
&lt;td&gt;00001730-2927-efef-cdab-eba0fe583711&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cubii motorized BLE service&lt;/td&gt;
&lt;td&gt;6e400001-b5a3-f393-e0a9-e50e9ecadc24&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cubii + BLE service&lt;/td&gt;
&lt;td&gt;6e400001-b5a3-f393-e0a9-e50e24dcca9e&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cubii+ OTA BLe service&lt;/td&gt;
&lt;td&gt;0000fe59-0000-1000-8000-00805f9b34fb&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;read-ble-value-from-broadcast&#34;&gt;Read BLE value from broadcast&lt;/h2&gt;
&lt;p&gt;From &lt;code&gt;broadcastUpdate()&lt;/code&gt; in file &lt;code&gt;BLEService&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GetIntValue()&lt;/code&gt; &lt;a href=&#34;https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic#getIntValue(int,%20int)&#34;&gt;documentation&lt;/a&gt;, constant list &lt;a href=&#34;https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic#constants_1&#34;&gt;here&lt;/a&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Float&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sfloat&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sint16&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sint32&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sint8&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uint16&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uint32&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uint8&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Java&#34; data-lang=&#34;Java&#34;&gt;Integer revolutions &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bluetoothGattCharacteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getIntValue&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;18&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
Integer rpm &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bluetoothGattCharacteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getIntValue&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;((&lt;/span&gt;bluetoothGattCharacteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getProperties&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; 17 &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; 18&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
Integer battery &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bluetoothGattCharacteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getIntValue&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;((&lt;/span&gt;bluetoothGattCharacteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getProperties&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; 17 &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; 18&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;color:#75715e&#34;&gt;// Hardware revision
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bluetoothGattCharacteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getValue&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;color:#75715e&#34;&gt;// Software revision
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; value2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bluetoothGattCharacteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getValue&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;read-value-from-ble-service&#34;&gt;Read value from BLE service&lt;/h2&gt;
&lt;p&gt;From file &lt;code&gt;BLEService&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Java&#34; data-lang=&#34;Java&#34;&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;readRPM&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
        BluetoothGatt bluetoothGatt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mBluetoothGatt&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
        BluetoothGattService service &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bluetoothGatt &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; bluetoothGatt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getService&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;UUID&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fromString&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;BLEConstants&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CUBII_BLE_SERVICE&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;));&lt;/span&gt;
        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;service &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
            Logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;INSTANCE&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;TAG&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Cubii service not found!&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
        BluetoothGattCharacteristic characteristic &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; service&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getCharacteristic&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;BLEConstants&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Companion&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getRPM&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;());&lt;/span&gt;
        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;characteristic &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
            Logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;INSTANCE&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;TAG&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Battery level not found!&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
            readCharacteristic&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;characteristic&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;easter-egg&#34;&gt;Easter egg&lt;/h2&gt;
&lt;p&gt;There is a small copy/paste typo in &lt;code&gt;BLEService&lt;/code&gt;.  If the RPM BLE service cannot be found the warning is about the battery :-)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Java&#34; data-lang=&#34;Java&#34;&gt;    BluetoothGattCharacteristic characteristic &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; service&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getCharacteristic&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;BLEConstants&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Companion&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getRPM&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;());&lt;/span&gt;
    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;characteristic &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
        Logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;INSTANCE&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;TAG&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Battery level not found!&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
        readCharacteristic&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;characteristic&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;ble-connection-mode&#34;&gt;BLE connection mode&lt;/h2&gt;
&lt;p&gt;Cubii is using connected BLE mode, then either notify you with new data or accumulate them between two consecutive read operations.&lt;/p&gt;
&lt;h2 id=&#34;reading-data-and-sending-them-to-influxdb&#34;&gt;Reading data and sending them to InfluxDB&lt;/h2&gt;
&lt;p&gt;Thanks to Python, the libraries &lt;a href=&#34;https://github.com/hbldh/bleak&#34;&gt;Bleak&lt;/a&gt; (BLE) and &lt;a href=&#34;https://influxdb-client.readthedocs.io/en/latest/&#34;&gt;InfluxDB&lt;/a&gt; it was fairly easy:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connect to the device&lt;/li&gt;
&lt;li&gt;Subscribe to notifications&lt;/li&gt;
&lt;li&gt;Accumulate/average data for 15 seconds&lt;/li&gt;
&lt;li&gt;Write them to InfluxDB&lt;/li&gt;
&lt;li&gt;In case of disconnection, restart in 1.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cubii is sending the data every 3 seconds but I am sending them only every 15 seconds to avoid extra disk space. It could easily be down sampled inside InfluxDB thanks to &lt;a href=&#34;https://docs.influxdata.com/influxdb/cloud/process-data/common-tasks/downsample-data/&#34;&gt;tasks&lt;/a&gt; but yeah, it was not really required in the beginning for the small amount of data, and all the actions are done in the Python code, easier to manager for such small project&lt;/p&gt;
&lt;h2 id=&#34;dashboard&#34;&gt;Dashboard&lt;/h2&gt;
&lt;p&gt;As expected I have no real use of the data but it was fun, so I draw the data in Grafana:&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2023/09-cubii-ble-protocol/grafana_dashboard.webp&#34; alt=&#34;Grafana dashboard with the collected data&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Grafana dashboard with the collected data
        &lt;/div&gt;&lt;/p&gt;
    


&lt;h2 id=&#34;code&#34;&gt;Code&lt;/h2&gt;
&lt;p&gt;The Python script is hosted on &lt;a href=&#34;https://gitlab.com/oliv4945/cubii-to-influxdb&#34;&gt;Gitlab&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;tools&#34;&gt;Tools&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/skylot/jadx/releases&#34;&gt;jadx&lt;/a&gt;: Decompile and transform Dex to Java&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ibotpeaches.github.io/Apktool/&#34;&gt;Apktool&lt;/a&gt;: Decompile/recompile APK&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://btprodspecificationrefs.blob.core.windows.net/assigned-numbers/Assigned%20Number%20Types/Assigned_Numbers.pdf&#34;&gt;BLE assigned numbers&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    
    <item>
      <title>Reverse engineer a wireless temperature sensor - Rika pellet stove</title>
      <link>https://notes.iopush.net/blog/2022/12-rika-wireless-temperature-1/</link>
      <pubDate>Sun, 04 Dec 2022 00:00:00 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2022/12-rika-wireless-temperature-1/</guid>
      <description>&lt;p&gt;I own a &lt;a href=&#34;https://www.rika.eu/filo&#34;&gt;Rika Filo&lt;/a&gt; pellet stove, which I like, but it is on the expensive side of the market and the Wi-Fi module to remote control it was a no-go. This article describes the way I reverse-engineered the radio protocol.&lt;br&gt;
As it is my sole heating system and winter is coming, I wanted a non invasive approach to avoid breaking anything, so I hooked up a logic analyzer to record the commands sent by the micro-controller to the radio chip, which helped me to learn the RF parameters + actual payload.&lt;/p&gt;
&lt;h1 id=&#34;1-hardware&#34;&gt;1. Hardware&lt;/h1&gt;
&lt;p&gt;The wireless temperature sensor is really simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Battery holder - with polarity inversion protection :-)&lt;/li&gt;
&lt;li&gt;ATmega48 micro-controller&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ti.com/product/CC1101&#34;&gt;TI CC1101&lt;/a&gt; radio transceiver&lt;/li&gt;
&lt;li&gt;Temperature sensor in a SOT-23 package?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fortunately, the ATmega is using a programming port called &amp;ldquo;ISP&amp;rdquo;, which shares the SPI port, and there is a nice 0.1&amp;quot; 2x3 header footprint on the PCB. I soldered the pin headers and easily used them to connect a logic analyzer, in order to spy the commands sent by the ATmega. The only missing signal was the chip select, which I found on a pull-up resistor between the batteries.&lt;/p&gt;
&lt;h1 id=&#34;2-understanding-the-spi-commands&#34;&gt;2. Understanding the SPI commands&lt;/h1&gt;
&lt;p&gt;I initially used &lt;a href=&#34;https://github.com/gusmanb/logicanalyzer&#34;&gt;LogicAnalyzer by El Dr. Gusman&lt;/a&gt;: a nice project based on Raspberry Pi Pico RP2040, which I recommend. Then I lent it to a friend so I finished with my work&amp;rsquo;s Saleae device.&lt;br&gt;
As Dr. Gusman&amp;rsquo;s logic analyzer can export to Sigrok I wanted to use the integrated CC1101 decoder to figure out the commands sent by the device. It did not work, I tried to debug it, figured out that the bug was already fixed, compiled the latest Sigrok then&amp;hellip; the decoder was not able to decode my frames for a reason I did not understood. I gave up and wrote a quick and dirty parser which, in the end, would have been a faster solution :).&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2022/12-rika-wireless-temperature-1/logic_analyzer.png&#34; alt=&#34;Fill TX buffer and send data&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Fill TX buffer and send data
        &lt;/div&gt;&lt;/p&gt;
    


&lt;h1 id=&#34;3-radio-parameters&#34;&gt;3. Radio parameters&lt;/h1&gt;
&lt;p&gt;Decoding the SPI commands gave the following parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modulation: FSK&lt;/li&gt;
&lt;li&gt;Manchester encoding: No&lt;/li&gt;
&lt;li&gt;Forward Error Correction (FEC): No&lt;/li&gt;
&lt;li&gt;Carrier frequency: 868.317 MHz&lt;/li&gt;
&lt;li&gt;Frequency deviation: 19042 Hz&lt;/li&gt;
&lt;li&gt;IF frequency: 304.687 kHz&lt;/li&gt;
&lt;li&gt;Bandwidth: 203.125 kHz&lt;/li&gt;
&lt;li&gt;Datarate: 115051 bauds&lt;/li&gt;
&lt;li&gt;Sync mode: 30/32 bits&lt;/li&gt;
&lt;li&gt;Preamble length: 32 bits&lt;/li&gt;
&lt;li&gt;Sync word: 0x4904&lt;/li&gt;
&lt;li&gt;Whitening: Yes (Seed: 0x01FF)&lt;/li&gt;
&lt;li&gt;FSK header: implicit/fixed length, ie address and size are not added by the chip&lt;/li&gt;
&lt;li&gt;CRC: Yes (16 bits. polynomial: XX, init: XXX)&lt;/li&gt;
&lt;li&gt;Transmitted packet length: 5 bytes&lt;/li&gt;
&lt;li&gt;Bit shift between preamble and sync word (not in SPI recording, I discovered it later&amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Despite the Sigrok CC1101 protocol analyzer issue, it was not that hard. I had everything I needed to simulate the Rika temperature sensor, so I took a &lt;a href=&#34;https://www.semtech.fr/products/wireless-rf/lora-connect/sx1261&#34;&gt;Semtech LR1110&lt;/a&gt; eval board I had laying on my desk, set the right parameters and the payload, flashed the eval board and&amp;hellip; it did not work :(&lt;/p&gt;
&lt;h1 id=&#34;4-radio-analysis&#34;&gt;4. Radio analysis&lt;/h1&gt;
&lt;p&gt;I doubled check each parameter, they where correct. What could be the issue then? Time to look at the FSK signal itself: I used an SDR stick with the wonderful &lt;a href=&#34;https://github.com/jopohl/urh&#34;&gt;Universal Radio Hacker&lt;/a&gt; software to record the transmitted payload and try to understand the issue.&lt;/p&gt;
&lt;h2 id=&#34;41-preamble&#34;&gt;4.1 Preamble&lt;/h2&gt;
&lt;p&gt;Small detail, the preamble was shifted by one because the TI chip is transmitting 0xAA, but the Semtech chip is transmitting 0x55. Fortunately, the LR1110 allows to select the number of bits of sync word to transmit, so I can added the missing &amp;lsquo;0&amp;rsquo; bit before my sync word and set its length to 33 instead of 32.&lt;/p&gt;
&lt;h2 id=&#34;42-what-thewhitening&#34;&gt;4.2 What the&amp;hellip;Whitening?&lt;/h2&gt;
&lt;p&gt;Now the difficult part: the preamble and the sync word are the same between both records, but not the payload and the CRC. It has to be a whitening issue! Both chips are using a PN9 algorithm, and I set in the Semtech chip the same init than TI is using: &lt;code&gt;0x01FF&lt;/code&gt;. What next? It took me a while to understand that the CC1101 starts the whitening on the most significant bit of each byte, while LR1110 starts the whitening on the least significant bit!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Whitening:&lt;/em&gt; Also called &lt;a href=&#34;https://en.wikipedia.org/wiki/Scrambler&#34;&gt;scrambling&lt;/a&gt;, is to avoid long series of the same bit. Alternate bits helps the receiver to avoid desynchronization as TX and RX clock do not perfectly match.&lt;/p&gt;
&lt;h2 id=&#34;43-wrapping-up&#34;&gt;4.3 Wrapping-up&lt;/h2&gt;
&lt;p&gt;Knowing this I was able to implement the whitening in software, and this time, it worked! The pellet stove was receiving my packets :-)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; I also had to implement the CRC16 as the whitening is applied to it:&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2022/12-rika-wireless-temperature-1/FSK_payload_data_schema.png&#34; alt=&#34;FSK payload, from Semtech SX126x datasheet&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            FSK payload, from Semtech SX126x datasheet
        &lt;/div&gt;&lt;/p&gt;
    


&lt;h1 id=&#34;5-payload-analysis&#34;&gt;5 Payload analysis&lt;/h1&gt;
&lt;h2 id=&#34;51-header&#34;&gt;5.1 Header&lt;/h2&gt;
&lt;p&gt;The payload is surprising, in FSK we explicit header can often see &lt;code&gt;preamble | syncword | payload length | address | payload |&lt;/code&gt;. In our case, the DIP switch on the board allows to change the second byte, which corresponds to the address but the first byte is always &lt;code&gt;0x11&lt;/code&gt;, so it might actually be a custom Rika header&amp;hellip;&lt;/p&gt;
&lt;p&gt;=&amp;gt; header is one byte, &lt;code&gt;0x11&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;52-address&#34;&gt;5.2 Address&lt;/h2&gt;
&lt;p&gt;The second byte is an address directly correlated to the first three DIP switches, 1 is the LSB, and 3 is the MSB:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;| Switch #3 | Switch #2 | Switch #1 | Address value |
+ --------- + --------- + --------- + ------------- +
|    Off    |    Off    |    Off    |      0x00     |
|    ...    |    ...    |    ...    |       ...     |
|    On     |    On     |    Off    |      0x06     |
|    On     |    On     |    On     |      0x07     |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Note on switch #4&lt;/em&gt;: as written in the documentation it is selecting power output of 1 dBm (Off) or 10 dBm (On).&lt;/p&gt;
&lt;h2 id=&#34;53-battery&#34;&gt;5.3 Battery&lt;/h2&gt;
&lt;p&gt;The last byte was more difficult to figure out and I must admit that I decided to not bother with it until I found &lt;a href=&#34;https://github.com/hublol/Rika_E14558&#34;&gt;Hublol&amp;rsquo;s github&lt;/a&gt; project when writing this article, who already did some reverse engineering. Even if the radio parameters are not fully described on Github he found that this byte was the battery. I do not plan to use it, but for the completeness of the reverse engineering I hooked my lab power supply and recorded the value transmitted when I swiped the voltage from 1.8 V to 3 V:&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2022/12-rika-wireless-temperature-1/graph_power_supply.png&#34; alt=&#34;Graph - Sent value = f(supply voltage)&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Graph - Sent value = f(supply voltage)
        &lt;/div&gt;&lt;/p&gt;
    


&lt;pre&gt;&lt;code&gt;| Supply voltage (V) | Value sent | Trendline |
+ ------------------ + ---------- + --------- +
|         3.0        |     215    |    213    |
|         2.8        |     193    |    193    |
|         2.6        |     172    |    172    |
|         2.5        |     159    |    162    |
|         2.3        |     143    |    142    |
|         2.1        |     118    |    122    |
|         1.8        |      97    |     62    |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;=&amp;gt; The function &lt;code&gt;encoded_value = voltage_V * 100.02 - 87.556&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;54-temperature&#34;&gt;5.4 Temperature&lt;/h2&gt;
&lt;p&gt;I eventually figured out that the temperature is encoded in the first two bytes, it is weird as I was not able to find a &amp;ldquo;usual&amp;rdquo; way to encode the temperature&amp;hellip; I then swiped the values with steps of 256 and read the temperature displayed by the stove: the conversion is not linear!&lt;br&gt;
As we usually heat around 19°C, I did a linear trendline between 15 and 22°C where I want the highest precision: the room never reached more than 22°C thanks to the stove, and the temperature accuracy below 15°C is not important as the stove need to heat at full power&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2022/12-rika-wireless-temperature-1/graph_temperature.png&#34; alt=&#34;Graph - temperature = f(sent value)&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Graph - temperature = f(sent value)
        &lt;/div&gt;&lt;/p&gt;
    


&lt;pre&gt;&lt;code&gt;| Value | Displayed        |           Hublol         |         Trendline        |
|  Hex  | temperature (°C) | temperature (°C) | delta | temperature (°C) | delta |
+ ----- + ---------------- + ---------------- + ----- + ---------------- + ----- +
| 4080  |       2.0        |        -0.80     |  2.8  |         2.4      | -0.4  |
| 4500  |      10.2        |         8.20     |  2.0  |        10.2      |    0  |
| 4600  |      11.9        |        10.20     |  1.7  |        11.9      |    0  |
| 4700  |      13.7        |        12.20     |  1.5  |        13.7      |    0  |
| 4800  |      15.4        |        14.20     |  1.2  |        15.4      | -0.1  |
| 4900  |      17.2        |        16.20     |  1.0  |        17.2      |    0  |
| 4A00  |      18.8        |        18.20     |  0.6  |        18.9      | -0.1  |
| 4B00  |      20.5        |        20.20     |  0.3  |        20.7      | -0.1  |
| 4C00  |      22.4        |        22.20     |  0.2  |        22.4      |    0  |
| 4D00  |      24.0        |        24.20     | -0.2  |        24.1      | -0.1  |
| 4E00  |      25.6        |        26.20     | -0.6  |        25.9      | -0.3  |
| 4EAD  |      26.8        |        27.55     | -0.8  |        27.0      | -0.2  |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;=&amp;gt; The function is &lt;code&gt;encoded_value = temperature_celsius * 0.0068 - 109.91&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&#34;6-code&#34;&gt;6. Code&lt;/h1&gt;
&lt;p&gt;The library to create the payload, as well as the whitening and CRC, is on available on &lt;a href=&#34;https://gitlab.com/oliv4945/rika-temperature-sensor-encoding&#34;&gt;Gitlab&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;7-conclusion&#34;&gt;7. Conclusion&lt;/h1&gt;
&lt;p&gt;I am now able to replace Rika&amp;rsquo;s temperature sensor, so I will be able to create a &amp;ldquo;smart thermostat&amp;rdquo; and remotely control my stove to rise the temperature when I am returning from vacation, or prevent its start when the sun will heat the house in the next hour or so. Next step is to create a dedicated board to be able to control the remote from LoRaWAN.&lt;/p&gt;
&lt;p&gt;I tested it against Rika pellet stove Filo and Sumo, but I am surprised that the temperature encoding differs so much from Hublol&amp;rsquo;s findings; he might have a more recent stove where they changed the electronics, I will ask him&amp;hellip;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>LoRaWAN on RAK3172 thanks to ST CubeMX, with VS Code</title>
      <link>https://notes.iopush.net/blog/2022/01-rak3172/</link>
      <pubDate>Thu, 06 Jan 2022 00:00:00 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2022/01-rak3172/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://twitter.com/Kongduino&#34;&gt;Kongduino&lt;/a&gt; kindly sent me a WisDuo &lt;a href=&#34;https://store.rakwireless.com/products/wisduo-breakout-board-rak3272s&#34;&gt;RAK3272s&lt;/a&gt; few weeks ago,
it is a a breakout board for RAK nice module (&lt;a href=&#34;https://www.rakwireless.com/en-us/products/lpwan-modules/rak3172-wisduo-lpwan-module&#34;&gt;RAK3172&lt;/a&gt;) around the
STM32WL5 system on chip from ST. Let&amp;rsquo;s see how to use STM32 CubeMX
to generate the initialization files and the LoRaWAN stack, then setup Visual
Studio code debugger.&lt;/p&gt;
&lt;h1 id=&#34;1-stm32-cubemx&#34;&gt;1. STM32 CubeMX&lt;/h1&gt;
&lt;p&gt;Download &lt;a href=&#34;https://www.st.com/en/development-tools/stm32cubemx.html&#34;&gt;STM32 CubeMX&lt;/a&gt; from ST website,
install it as instructed.&lt;br&gt;
Open it then create a new project thanks to &lt;code&gt;ACCESS TO MCU SELECTOR&lt;/code&gt;. In the &lt;code&gt;Part Number&lt;/code&gt; searchbox look for &lt;code&gt;STM32WLE5CC&lt;/code&gt; then select &lt;code&gt;STM32WLE5CCUx&lt;/code&gt; and &lt;code&gt;Start Project&lt;/code&gt;. CubeMX will now create empty project with only the RF and oscillator pins initialized plus some core peripherals, we have to select the features we want:&lt;/p&gt;
&lt;h2 id=&#34;11-pinout--configuration-tab&#34;&gt;1.1 Pinout &amp;amp; configuration tab&lt;/h2&gt;
&lt;h3 id=&#34;analog---adc&#34;&gt;Analog -&amp;gt; ADC&lt;/h3&gt;
&lt;p&gt;Check &lt;code&gt;Vrefint Channel&lt;/code&gt;, it will be used by the demo application.&lt;/p&gt;
&lt;h3 id=&#34;timers---rtc&#34;&gt;Timers -&amp;gt; RTC&lt;/h3&gt;
&lt;p&gt;Check &lt;code&gt;Activate Clock Source&lt;/code&gt; and &lt;code&gt;Activate calendar&lt;/code&gt;. Add the following values in configuration section, tab &lt;code&gt;User constants&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RTC_PREDIV_A&lt;/code&gt;: &lt;code&gt;((1&amp;lt;&amp;lt;(15-RTC_N_PREDIV_S))-1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RTC_N_PREDIV_S&lt;/code&gt;: &lt;code&gt;10&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RTC_PREDIV_S&lt;/code&gt;: &lt;code&gt;((1&amp;lt;&amp;lt;RTC_N_PREDIV_S)-1)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In &lt;code&gt;Parameters Settings&lt;/code&gt; tab:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Bin mode&lt;/code&gt;: &lt;code&gt;Free running binary mode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Asynchronous predivider value&lt;/code&gt;: &lt;code&gt;RTC_PREDIV_A&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;connectivity---subghz&#34;&gt;Connectivity -&amp;gt; SUBGHZ&lt;/h3&gt;
&lt;p&gt;Check &lt;code&gt;Activated&lt;/code&gt; to use the LoRa IP.&lt;/p&gt;
&lt;h3 id=&#34;connectivity---usart2&#34;&gt;Connectivity -&amp;gt; USART2&lt;/h3&gt;
&lt;p&gt;To send traces (printf) from the STM32 to the computer.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select &lt;code&gt;Mode&lt;/code&gt; to &lt;code&gt;Asynchronous&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;Configuration&lt;/code&gt; section, tab &lt;code&gt;DMA Settings&lt;/code&gt;:
&lt;ol&gt;
&lt;li&gt;Click on &lt;code&gt;Add&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;DMA request&lt;/code&gt; select &lt;code&gt;USART2 TX&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;Channel&lt;/code&gt; select &lt;code&gt;DMA 1 channel 5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;Direction&lt;/code&gt; select &lt;code&gt;Memory to peripheral&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;Priority&lt;/code&gt; select &lt;code&gt;Low&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Tab &lt;code&gt;GPIO Settings&lt;/code&gt; should already have:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PA2&lt;/code&gt; as &lt;code&gt;USART2_TX&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PA3&lt;/code&gt; as &lt;code&gt;USART2_RX&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;middleware---lorawan&#34;&gt;Middleware -&amp;gt; LoRaWAN&lt;/h3&gt;
&lt;p&gt;Check &lt;code&gt;enabled&lt;/code&gt; to add the LoRaWAN stack to the project then in the configuration section, tab &lt;code&gt;LoRaWAN Middleware&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;lorawan_conf&lt;/code&gt;: select your region&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Tx Rfo Config&lt;/code&gt;: &lt;code&gt;CONF RFO HP&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In tab &lt;code&gt;LoraWAN Application&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Application&lt;/code&gt;: &lt;code&gt;End Node skeleton&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LoRa App&lt;/code&gt;-&amp;gt;&lt;code&gt;Active region&lt;/code&gt;: Select your region&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In tab &lt;code&gt;Platform Settings&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;IPs or Components&lt;/th&gt;
&lt;th&gt;Found Solutions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ADC&lt;/td&gt;
&lt;td&gt;ADC: Vrefint channel&lt;/td&gt;
&lt;td&gt;ADC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USART&lt;/td&gt;
&lt;td&gt;USART: Asynchronous&lt;/td&gt;
&lt;td&gt;USART2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTC&lt;/td&gt;
&lt;td&gt;RTC: RTC Enabled&lt;/td&gt;
&lt;td&gt;RTC&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; If you do not know which EUI/Key to use follow the chapter &lt;code&gt;TTN OTAA Device Registration&lt;/code&gt; in &lt;a href=&#34;https://docs.rakwireless.com/Product-Categories/WisDuo/RAK3172-Module/Quickstart/#ttn-otaa-device-registration&#34;&gt;RAK&amp;rsquo;s quickstart&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In tab &lt;code&gt;LoRaWAN commissioning&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check &lt;code&gt;Static Device Eui&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Fill &lt;code&gt;LoRaWAN device eui&lt;/code&gt;, &lt;code&gt;App/JoinEUI&lt;/code&gt; and &lt;code&gt;Application key&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;system-core---nvic&#34;&gt;System core -&amp;gt; NVIC&lt;/h3&gt;
&lt;p&gt;Check &lt;code&gt;SUBGHZ&lt;/code&gt; Radio Interrupt.&lt;/p&gt;
&lt;h3 id=&#34;pin-configuration&#34;&gt;Pin configuration&lt;/h3&gt;
&lt;p&gt;On the STM32 picture click on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pin &lt;code&gt;PB0&lt;/code&gt;: select &lt;code&gt;VDDTCXO&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Pin &lt;code&gt;PC14&lt;/code&gt;: select &lt;code&gt;RCC_OSC32_IN&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Pin &lt;code&gt;PC15&lt;/code&gt;: select &lt;code&gt;RCC_OSC32_OUT&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;12-clock-configuration-tab&#34;&gt;1.2 Clock Configuration tab&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;In &lt;code&gt;RTC Clock Mux&lt;/code&gt; select &lt;code&gt;LSE&lt;/code&gt; input&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MSI RC&lt;/code&gt; can be pushed to &lt;code&gt;48000&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;13-project-manager-tab&#34;&gt;1.3 Project Manager tab&lt;/h2&gt;
&lt;p&gt;Set &lt;code&gt;Project name&lt;/code&gt;, then in &lt;code&gt;Toolchain/IDE&lt;/code&gt; select &lt;code&gt;Makefile&lt;/code&gt;.&lt;br&gt;
The project is ready, click on &lt;code&gt;GENERATE CODE&lt;/code&gt; in top right corner.&lt;/p&gt;
&lt;p&gt;When generated you can open the folder in your favorite editor, I will use VS Code.&lt;/p&gt;
&lt;h1 id=&#34;2-configure-the-c-code&#34;&gt;2. Configure the C code&lt;/h1&gt;
&lt;p&gt;Now the program skeleton is generated but it can not be compiled yet, otherwise
the compiler with output warnings like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#warning user to provide its board definitions pins
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We have to provide some specifics about the radio pins. Download &lt;a href=&#34;https://notes.iopush.net/blog/2022/01-rak3172/radio_board_if_c.patch&#34;&gt;radio_board_if_c.patch&lt;/a&gt; and &lt;a href=&#34;https://notes.iopush.net/blog/2022/01-rak3172/radio_board_if_h.patch&#34;&gt;radio_board_if_h.patch&lt;/a&gt;, place them in the root directory of your project then:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;patch -u LoRaWAN/Target/radio_board_if.c -i radio_board_if_c.patch
patch -u LoRaWAN/Target/radio_board_if.h -i radio_board_if_h.patch
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;3-compile-the-binary&#34;&gt;3. Compile the binary&lt;/h1&gt;
&lt;p&gt;Download &lt;a href=&#34;https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads&#34;&gt;arm-none-eabi&lt;/a&gt; toolchain, add it to your path then it is as simple as &lt;code&gt;make -j&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&#34;4-flash-the-microcontroller&#34;&gt;4. Flash the microcontroller&lt;/h1&gt;
&lt;p&gt;RAK &lt;a href=&#34;https://docs.rakwireless.com/Product-Categories/WisDuo/RAK3172-Module/Low-Level-Development/#uploading-the-fw-generated-using-stm32cubeprogrammer&#34;&gt;official documentation&lt;/a&gt; is using a serial&amp;lt;&amp;gt;USB converter and the integrated STM32 serial bootloader to flash the firmware, but I prefer an ST-Link as I will also be able to debug the code.&lt;/p&gt;
&lt;h2 id=&#34;41-st-link-pinout-and-wiring&#34;&gt;4.1 ST-Link pinout and wiring&lt;/h2&gt;
&lt;p&gt;You can use an ST-Link or any Nucleo header as long as it is broke from the target board or the jumpers &lt;code&gt;ST-LINK&lt;/code&gt; are removed. Then the connector &lt;code&gt;SWD/CN4&lt;/code&gt; must be wired to the RAK module, Nucleo&amp;rsquo;s serial&amp;lt;&amp;gt;USB converter can be used thanks to &lt;code&gt;CN3&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal name&lt;/th&gt;
&lt;th&gt;Nucleo header&lt;/th&gt;
&lt;th&gt;RAK3272s&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VDD_ref (optional)&lt;/td&gt;
&lt;td&gt;CN4-&amp;gt;1&lt;/td&gt;
&lt;td&gt;3V3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SWCLK&lt;/td&gt;
&lt;td&gt;CN4-&amp;gt;2&lt;/td&gt;
&lt;td&gt;SWCLK-PA14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GND&lt;/td&gt;
&lt;td&gt;CN4-&amp;gt;3&lt;/td&gt;
&lt;td&gt;GND&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SWDIO&lt;/td&gt;
&lt;td&gt;CN4-&amp;gt;4&lt;/td&gt;
&lt;td&gt;SWDIO-PA13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nRST&lt;/td&gt;
&lt;td&gt;CN4-&amp;gt;5&lt;/td&gt;
&lt;td&gt;RST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UART_TX&lt;/td&gt;
&lt;td&gt;CN3-&amp;gt;1&lt;/td&gt;
&lt;td&gt;UART2_TX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UART_RX&lt;/td&gt;
&lt;td&gt;CN3-&amp;gt;2&lt;/td&gt;
&lt;td&gt;UART2_RX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Power Supply (3.3V)&lt;/td&gt;
&lt;td&gt;CN1-&amp;gt;1&lt;/td&gt;
&lt;td&gt;3V3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;42-use-st-link-usb-mass-storage&#34;&gt;4.2 Use ST-Link USB mass storage&lt;/h2&gt;
&lt;p&gt;You can flash the microcontroler by copy/pasting the &lt;code&gt;.bin&lt;/code&gt; file in the ST Link folder.&lt;/p&gt;
&lt;h2 id=&#34;43-openocd&#34;&gt;4.3 OpenOCD&lt;/h2&gt;
&lt;p&gt;Required only if you want to use the debugger. As of december 2021 most OpenOCD releases does not yet include STM32WL support, it has to be compiled from the sources. The steps are easy for Linux:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git clone https://git.code.sf.net/p/openocd/code openocd-code&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apt install make libtool pkg-config autoconf automake texinfo libusb-1.0-0 libusb-1.0-0-dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;./bootstrap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;./configure --enable-stlink&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;make&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;make install&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;45-vs-code&#34;&gt;4.5 VS Code&lt;/h2&gt;
&lt;p&gt;Install the extension &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug&#34;&gt;Cortex-Debug&lt;/a&gt; if you want to use the debugger, then edit the &lt;code&gt;launch.json&lt;/code&gt; file, or create it if required, to have&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &amp;quot;version&amp;quot;: &amp;quot;0.2.0&amp;quot;,
    &amp;quot;configurations&amp;quot;: [
        {
            &amp;quot;name&amp;quot;: &amp;quot;Cortex Debug&amp;quot;,
            &amp;quot;cwd&amp;quot;: &amp;quot;${workspaceRoot}&amp;quot;,
            &amp;quot;executable&amp;quot;: &amp;quot;./build/${workspaceFolderBasename}.elf&amp;quot;,
            &amp;quot;request&amp;quot;: &amp;quot;launch&amp;quot;,
            &amp;quot;type&amp;quot;: &amp;quot;cortex-debug&amp;quot;,
            &amp;quot;servertype&amp;quot;: &amp;quot;openocd&amp;quot;,
            &amp;quot;configFiles&amp;quot;: [
                &amp;quot;interface/stlink.cfg&amp;quot;,
                &amp;quot;target/stm32wlx.cfg&amp;quot;
            ],
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;5-lorawan-uplinks&#34;&gt;5. LoRaWAN uplinks&lt;/h1&gt;
&lt;p&gt;Register your device in a network server like &lt;a href=&#34;https://console.thethingsnetwork.org&#34;&gt;The Things Network&lt;/a&gt;,
then you should see the JoinRequest/JoinAccept!&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2022/01-rak3172/TTN-Uplink.png&#34; alt=&#34;TTN uplinks in the console&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            TTN uplinks in the console
        &lt;/div&gt;&lt;/p&gt;
    


&lt;p&gt;If you have any issue the project is available on &lt;a href=&#34;https://gitlab.com/oliv4945/rak3172-st-stack-template&#34;&gt;Gitlab&lt;/a&gt;. The project also &lt;a href=&#34;https://gitlab.com/oliv4945/rak3172-st-stack-template/-/blob/2b9e75040c10cc6b40b8757184d7ca96343cf8d3/LoRaWAN/App/lora_app.c#L218&#34;&gt;contains a populated&lt;/a&gt; &lt;code&gt;SendTxData()&lt;/code&gt; function to actually send uplinks :)&lt;/p&gt;
&lt;h1 id=&#34;6-next-steps&#34;&gt;6. Next steps&lt;/h1&gt;
&lt;p&gt;Now that we are connected to the network the next post should be about optimizing power consumption and enter in stop mode to only consume µAmps when not sending data.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Update iTead Sonoff Zigbee 3.0 USB Dongle Plus</title>
      <link>https://notes.iopush.net/blog/2021/12-itead-zigbee-dongle/</link>
      <pubDate>Sun, 12 Dec 2021 00:00:00 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2021/12-itead-zigbee-dongle/</guid>
      <description>&lt;p&gt;I recently bought a &lt;a href=&#34;https://itead.cc/product/sonoff-zigbee-3-0-usb-dongle-plus/&#34;&gt;Sonoff Zigbee 3.0 USB Dongle Plus&lt;/a&gt; from iTead to use it with Home Assistant.&lt;br&gt;
While it worked out of the box, the update itself was not complicated but you
have to find the right tools&amp;hellip;&lt;/p&gt;
&lt;h1 id=&#34;update-the-firmware&#34;&gt;Update the firmware&lt;/h1&gt;
&lt;p&gt;The nice Python script &lt;a href=&#34;https://github.com/JelmerT/cc2538-bsl/&#34;&gt;cc2538-bsl&lt;/a&gt; can be used, but the branch &lt;code&gt;feature/ITead_Sonoff_Zigbee-delay&lt;/code&gt; needs to be selected until the &lt;a href=&#34;https://github.com/JelmerT/cc2538-bsl/pull/114&#34;&gt;pull request&lt;/a&gt; is merged.&lt;/p&gt;
&lt;h2 id=&#34;install-cc2538-bsl&#34;&gt;Install cc2538-bsl&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/JelmerT/cc2538-bsl.git
cd cc2538-bsl
git checkout feature/ITead_Sonoff_Zigbee-delay
python3 -m venv .venv
source .venv/bin/activate
pip install wheel
python setup.py install
pip install intelhex python-magic
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;flash-the-dongle&#34;&gt;Flash the dongle&lt;/h2&gt;
&lt;p&gt;Download the firmware from Koenkk&amp;rsquo;s &lt;a href=&#34;https://github.com/Koenkk/Z-Stack-firmware/blob/develop/coordinator/Z-Stack_3.x.0/bin/CC1352P2_CC2652P_launchpad_coordinator_20211207.zip&#34;&gt;Z-Stack&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Then use the command&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python cc2538-bsl.py -e -v -w --bootloader-sonoff-usb ./CC1352P2_CC2652P_launchpad_coordinator_20211207.hex
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which should output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sonoff
Opening port /dev/ttyUSB0, baud 500000
Reading data from ./CC1352P2_CC2652P_launchpad_coordinator_20211207.hex
Firmware file: Intel Hex
Connecting to target...
CC1350 PG2.0 (7x7mm): 352KB Flash, 20KB SRAM, CCFG.BL_CONFIG at 0x00057FD8
Primary IEEE Address: 00:12:4B:00:25:6C:59:51
    Performing mass erase
Erasing all main bank flash sectors
    Erase done
Writing 360448 bytes starting at address 0x0000000
Write 104 bytes at 0x00057F980
    Write done                                
Verifying by comparing CRC32 calculations.
    Verified (match: 0x6dca550e)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After that you can use the nice &lt;a href=&#34;https://www.home-assistant.io/integrations/zha&#34;&gt;Zigbee Home Automation&lt;/a&gt; integration to easily setup the Zigbee dongle.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>nfcAudio - WiFi enabled MP3 player with NFC capability</title>
      <link>https://notes.iopush.net/blog/2020/12-nfcaudio-nfc-controlled-mp3-player/</link>
      <pubDate>Wed, 23 Dec 2020 00:00:00 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2020/12-nfcaudio-nfc-controlled-mp3-player/</guid>
      <description>&lt;p&gt;nfcAudio is an MP3 player, with audio files selected thanks to an NFC tag placed
on top of it. I build this two years ago for my kid so he can play by himself
his preferred nursery rhymes and songs, it is still used at least once a week
:-)&lt;/p&gt;
&lt;p&gt;It is powered by an ESP8266 to play audio from a remote server, an I2S DAC
driving the speaker and an NFC reader. Thanks to WiFi we can use it to play
local files or any webradio stream from the Internet.&lt;/p&gt;
    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2020/12-nfcaudio-nfc-controlled-mp3-player/nfcaudio-finished.jpg&#34; alt=&#34;Finished nfcAudio project&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Finished nfcAudio project
        &lt;/div&gt;&lt;/p&gt;
    


&lt;h1 id=&#34;hardware&#34;&gt;Hardware&lt;/h1&gt;
&lt;h2 id=&#34;electronics&#34;&gt;Electronics&lt;/h2&gt;
&lt;p&gt;I just used several evaluation boards, linked by soldered wires:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ESP8266: &lt;a href=&#34;https://www.wemos.cc/en/latest/d1/d1_mini.html&#34;&gt;Wemos Mini D1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NFC reader: &lt;a href=&#34;https://www.nxp.com/docs/en/nxp/data-sheets/PN532_C1.pdf&#34;&gt;PN532&lt;/a&gt;
board from Aliexpress&lt;/li&gt;
&lt;li&gt;I2S DAC:
&lt;a href=&#34;https://datasheets.maximintegrated.com/en/ds/MAX98357A-MAX98357B.pdf&#34;&gt;MAX98357A&lt;/a&gt;
board from Aliexpress&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The MAX98357A I2S DAC can easily be replaced by another I2S, or even a single
transistor: please see
&lt;a href=&#34;https://github.com/earlephilhower/ESP8266Audio#i2s-dacs&#34;&gt;ESP8266Audio&lt;/a&gt; project
which is wonderfully documented.&lt;/p&gt;
&lt;h2 id=&#34;case&#34;&gt;Case&lt;/h2&gt;
&lt;p&gt;I designed a laser-cut box to hold everything together and allow NFC tag
storage. All parts of the case are bolted, electronic boards are fixed thanks to
zip ties, then the speaker is hot glued.&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2020/12-nfcaudio-nfc-controlled-mp3-player/nfcaudio-case-speaker.jpg&#34; alt=&#34;Speaker under the case&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Speaker under the case
        &lt;/div&gt;&lt;/p&gt;
    





    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2020/12-nfcaudio-nfc-controlled-mp3-player/nfcaudio-case-opened.jpg&#34; alt=&#34;Top opened, with the PN532&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Top opened, with the PN532
        &lt;/div&gt;&lt;/p&gt;
    


&lt;h2 id=&#34;tags&#34;&gt;Tags&lt;/h2&gt;
&lt;p&gt;All RFID 14443 tags can be used with the PN532 reader. I saw some projects using
&amp;ldquo;credit card&amp;rdquo; sized tags which can be printed with some inkjet printers, but I
used small stickers so I can print an image on any printer, stick the tag on it,
then put everything in thermal laminated film.&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2020/12-nfcaudio-nfc-controlled-mp3-player/nfc-tag.jpg&#34; alt=&#34;Adhesive tag&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Adhesive tag
        &lt;/div&gt;&lt;/p&gt;
    


&lt;h1 id=&#34;software&#34;&gt;Software&lt;/h1&gt;
&lt;p&gt;The most complicated part, MP3 management, is made by the great
&lt;a href=&#34;https://github.com/earlephilhower/ESP8266Audio&#34;&gt;ESP8266Audio&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;Then I had to modify Adafruit&amp;rsquo;s PN532 library as it was only polling the NFC
chip, so I implemented interrupts to be able to detect new tags while playing
audio; my fork can be found &lt;a href=&#34;https://github.com/Oliv4945/nfcAudio&#34;&gt;here&lt;/a&gt;.
Adafruit never merged my pull request but two months ago another (cleaner) one
based on my work have been merged. As Adafruit changed all the library API since
2018 I am still using my fork.&lt;/p&gt;
&lt;p&gt;My code is really simple: wait for a tag to be detected, read its content then
play the associated file :-)&lt;/p&gt;
&lt;p&gt;I encode the MP3 URL directly in the tag in the standardized
&lt;a href=&#34;http://sweet.ua.pt/andre.zuquete/Aulas/IRFID/11-12/docs/NFC%20Data%20Exchange%20Format%20(NDEF).pdf&#34;&gt;NDEF&lt;/a&gt;
format so I wrote a small parser for it, then it was done. I program the tags
directly from my phone with the application
&lt;a href=&#34;https://play.google.com/store/apps/details?id=mr.nfcreader&amp;amp;hl=en&amp;amp;gl=US&#34;&gt;NFC Reader &amp;amp; Writer&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;project-sources&#34;&gt;Project sources&lt;/h1&gt;
&lt;p&gt;Everything, including case files and the wiring is available on
&lt;a href=&#34;https://github.com/Oliv4945/nfcAudio&#34;&gt;Github&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Automate shutters with an ESP and Home Assistant</title>
      <link>https://notes.iopush.net/blog/2020/automate-shutters-with-an-esp-and-home-assistant/</link>
      <pubDate>Sun, 12 Jul 2020 18:50:41 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2020/automate-shutters-with-an-esp-and-home-assistant/</guid>
      <description>&lt;p&gt;I recently did a proof of concept on shutters automation by hacking the remote
control: the idea is to wire the ESP in parallel with the remote control
buttons.&lt;br&gt;
My remotes are Bubendorff 41677 but it should work with a lot of other remote
controls.&lt;/p&gt;
    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2020/automate-shutters-with-an-esp-and-home-assistant/remote-esp-photo.jpg&#34; alt=&#34;Wemos &amp;amp; the remote control&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Wemos &amp;amp; the remote control
        &lt;/div&gt;&lt;/p&gt;
    


&lt;p&gt;After poking with a multi-meter it appears that two test points are connected to
the right signals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TP103: Up&lt;/li&gt;
&lt;li&gt;TP102: Down&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The signal is active low: there is a pull-up resistor and it must be grounded to
simulate the activation. A 680 Ohm resistor is used in series with each button
of the remote to prevent current overshoot and maybe reduce power consumption,
so I also used them:&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2020/automate-shutters-with-an-esp-and-home-assistant/schematic.png&#34; alt=&#34;Schematic&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Schematic
        &lt;/div&gt;&lt;/p&gt;
    


&lt;p&gt;You might not see the resistors on the top picture as I only had SMD 0603 on
hand; look carefully :)&lt;/p&gt;
&lt;p&gt;On the first attempt, I used the great &lt;a href=&#34;https://esphome.io/&#34;&gt;ESPHome&lt;/a&gt; project to
simulate pressing the pushbuttons. I just created 3 virtual switches as a proof
of concept but for correct integration, a
&lt;a href=&#34;https://esphome.io/components/cover/template.html&#34;&gt;cover component&lt;/a&gt; can be
used.&lt;br&gt;
I split the configuration into two files: one generic and the other only
specifying the shutter name (room) and timings.&lt;/p&gt;
&lt;p&gt;Per device file, called &lt;code&gt;shutters-office.yaml&lt;/code&gt; in this example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#f92672&#34;&gt;substitutions&lt;/span&gt;:
  &lt;span style=&#34;color:#75715e&#34;&gt;# Used for HASS identifier&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;office&lt;/span&gt;
  &lt;span style=&#34;color:#75715e&#34;&gt;# Used for friendly name&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;switch_name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bureau&amp;#34;&lt;/span&gt;
  &lt;span style=&#34;color:#75715e&#34;&gt;# Time from fully closed to fully opened&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;full_time&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;16s&amp;#34;&lt;/span&gt;
  &lt;span style=&#34;color:#75715e&#34;&gt;# Time from fully closed to slightly opened&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;partially_open_time&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;5s&amp;#34;&lt;/span&gt;
  &lt;span style=&#34;color:#75715e&#34;&gt;# Time for the &amp;#34;button pressed&amp;#34; event&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;on_time&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;150ms&amp;#34;&lt;/span&gt;

&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;: !&lt;span style=&#34;color:#ae81ff&#34;&gt;include shutters-common.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then the generic file called &lt;code&gt;shutters-common.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#f92672&#34;&gt;esphome&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shutters_${name}&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ESP8266&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;board&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;d1_mini&lt;/span&gt;

&lt;span style=&#34;color:#f92672&#34;&gt;wifi&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;ssid&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MY SSID&amp;#34;&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MY PASSWORD&amp;#34;&lt;/span&gt;

  &lt;span style=&#34;color:#75715e&#34;&gt;# Enable fallback hotspot (captive portal) in case wifi connection fails&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;ap&lt;/span&gt;:
    &lt;span style=&#34;color:#f92672&#34;&gt;ssid&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Shutter fallback hotspot&amp;#34;&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;12345678ABCDEF&amp;#34;&lt;/span&gt;

&lt;span style=&#34;color:#f92672&#34;&gt;captive_portal&lt;/span&gt;:

&lt;span style=&#34;color:#75715e&#34;&gt;# Enable logging&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;logger&lt;/span&gt;:

&lt;span style=&#34;color:#75715e&#34;&gt;# Enable Home Assistant API&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;api&lt;/span&gt;:

&lt;span style=&#34;color:#f92672&#34;&gt;ota&lt;/span&gt;:

&lt;span style=&#34;color:#f92672&#34;&gt;switch&lt;/span&gt;:
  &lt;span style=&#34;color:#75715e&#34;&gt;# Define with GPIOs are used&lt;/span&gt;
  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gpio&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;up&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;:
      &lt;span style=&#34;color:#f92672&#34;&gt;number&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;
      &lt;span style=&#34;color:#f92672&#34;&gt;inverted&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;yes&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;restore_mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ALWAYS_OFF&lt;/span&gt;
  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gpio&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;down&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;:
      &lt;span style=&#34;color:#f92672&#34;&gt;number&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;
      &lt;span style=&#34;color:#f92672&#34;&gt;inverted&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;yes&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;restore_mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ALWAYS_OFF&lt;/span&gt;

  &lt;span style=&#34;color:#75715e&#34;&gt;# Define template simulating the push on the button&lt;/span&gt;
  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;template&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Shutter ${switch_name} open&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;turn_on_action&lt;/span&gt;:
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;up&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;delay&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${on_time}&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_off&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;up&lt;/span&gt;

  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;template&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Shutter ${switch_name} close&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;turn_on_action&lt;/span&gt;:
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;down&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;delay&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${on_time}&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_off&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;down&lt;/span&gt;

  &lt;span style=&#34;color:#75715e&#34;&gt;# Define template for slightly opening the shutter&lt;/span&gt;
  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;template&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Shutter ${switch_name} slightly open&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;turn_on_action&lt;/span&gt;:
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;down&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;delay&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${on_time}&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_off&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;down&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;delay&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${full_time}&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;up&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;delay&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${on_time}&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_off&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;up&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;delay&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${partially_open_time}&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;up&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;delay&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${on_time}&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;switch.turn_off&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;up&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As there is no feedback information on the shutter state the &amp;ldquo;&lt;em&gt;slightly opened&lt;/em&gt;&amp;rdquo;
state is achieved by fully closing the shutter then opening it for a small
amount of time.&lt;br&gt;
Once the ESP8266 or ESP32 is flashed the only thing remaining is to add it to
&lt;a href=&#34;https://www.home-assistant.io/&#34;&gt;Home-Assistant&lt;/a&gt;, thanks to &lt;code&gt;Configuration&lt;/code&gt; =&amp;gt;
&lt;code&gt;Integrations&lt;/code&gt; =&amp;gt; &lt;code&gt;Set up a new integration&lt;/code&gt; =&amp;gt; Search for &lt;code&gt;ESPHome&lt;/code&gt; =&amp;gt; enter
the ESP IP address. Et voilà, you are good to go and create powerful automations
in Home-Assistant.&lt;/p&gt;
&lt;p&gt;On the next version, I used a more clever strategy to command shutters from 0 to
100%, and a LoRaWAN board to allow battery-powered operation - to be published
soon.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to monitor pellet stove&#39;s tank</title>
      <link>https://notes.iopush.net/blog/2019/how-to-monitor-pellet/</link>
      <pubDate>Tue, 26 Nov 2019 12:53:50 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2019/how-to-monitor-pellet/</guid>
      <description>&lt;p&gt;I have a great &lt;a href=&#34;https://www.rika.eu&#34;&gt;Rika&lt;/a&gt; pellet stove, but despite all the
embedded electronics, it is unable to warn me just before the pellets tank is
empty. As I already have my own low-power wireless devices and home automation
tools, I just added a distance sensor and designed some enclosures.&lt;/p&gt;
    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2019/how-to-monitor-pellet/stove.png&#34; alt=&#34;Pellet stove&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Pellet stove
        &lt;/div&gt;&lt;/p&gt;
    


&lt;h1 id=&#34;sensor-selection&#34;&gt;Sensor selection&lt;/h1&gt;
&lt;h2 id=&#34;ir-sensor&#34;&gt;IR sensor&lt;/h2&gt;
&lt;p&gt;Cheap usual
&lt;a href=&#34;https://global.sharp/products/device/lineup/data/pdf/datasheet/gp2y0a21yk_e.pdf&#34;&gt;Sharp sensor&lt;/a&gt;
needs to be at least 10 cm away from the pellets. It is a no go for this use
case as pellets are close to the lid when the tank is full&lt;/p&gt;
&lt;h2 id=&#34;ultrasonic-sensors&#34;&gt;Ultrasonic sensors&lt;/h2&gt;
&lt;p&gt;As common as the Sharp IR sensor, the
&lt;a href=&#34;https://www.mouser.com/datasheet/2/813/HCSR04-1022824.pdf&#34;&gt;HC-SR04&lt;/a&gt; was an
option but I discarded it for two reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dust generated by pellets: sensor difficult to clean&lt;/li&gt;
&lt;li&gt;Not working well with a power supply of 3.3 Vdc&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;stmicroelectronics-time-of-flight-sensor&#34;&gt;STMicroelectronics time of flight sensor&lt;/h2&gt;
&lt;p&gt;So I went with
&lt;a href=&#34;https://www.st.com/resource/en/datasheet/vl53l0x.pdf&#34;&gt;ST VL53L0X&lt;/a&gt;: range
adapted to my needs, low power, and it is easy to the clean sensor. Regarding
dust, I used it for several months without having to clean it but summer was
included, so let&amp;rsquo;s wait a full winter for feedback.&lt;/p&gt;
&lt;h1 id=&#34;hardware&#34;&gt;Hardware&lt;/h1&gt;
&lt;p&gt;I bought a cheap breakout board from eBay and plug the I2C lines into my
&lt;a href=&#34;https://notes.iopush.net/projects/noterf/&#34;&gt;NoteRF&lt;/a&gt; boards&lt;/p&gt;
&lt;h1 id=&#34;software&#34;&gt;Software&lt;/h1&gt;
&lt;p&gt;I just added the library from
&lt;a href=&#34;https://github.com/pololu/vl53l0x-arduino&#34;&gt;Pololu&lt;/a&gt; to my project then
translated the data in &lt;a href=&#34;https://nodered.org/&#34;&gt;Node-Red&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Javascript&#34; data-lang=&#34;Javascript&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// VL53L0X
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ( &lt;span style=&#34;color:#a6e22e&#34;&gt;sensorType&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt; ) {
    &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;topic&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`data/sensor/noterf_distance_&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sensorName&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/state`&lt;/span&gt;;

	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;payload&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;split&lt;/span&gt;( &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt; )[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;];
	&lt;span style=&#34;color:#a6e22e&#34;&gt;distance_percent&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;distance&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;590&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;;

	&lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;payload&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
	    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rssi&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;rssi&lt;/span&gt;,
	    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;battery&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;battery&lt;/span&gt;,
	};

	&lt;span style=&#34;color:#75715e&#34;&gt;// Filter abnormal values
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ( ( &lt;span style=&#34;color:#a6e22e&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; ) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ( &lt;span style=&#34;color:#a6e22e&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8000&lt;/span&gt; ) ) {
	    &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;payload&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;distance&lt;/span&gt;;
	    &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;payload&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;distance_percent&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;distance_percent&lt;/span&gt;;
	}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;home-assistant&#34;&gt;Home assistant&lt;/h1&gt;
&lt;p&gt;As for all other connected things in my house it reports to
&lt;a href=&#34;https://www.home-assistant.io/&#34;&gt;Home Assistant&lt;/a&gt;, which allows a nice interface,
that I rarely use thanks to the automation: I am notified on my phone (through
&lt;a href=&#34;https://www.pushbullet.com/&#34;&gt;pushbullet&lt;/a&gt;) when tank level or device battery
cross a threshold: the purpose of that device is achieved! Anyway, some fancy
displays can be setup in a few seconds:&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2019/how-to-monitor-pellet/stove-percent.png&#34; alt=&#34;Tank status gauge - color changes according to the value&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Tank status gauge - color changes according to the value
        &lt;/div&gt;&lt;/p&gt;
    





    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2019/how-to-monitor-pellet/stove-distance.png&#34; alt=&#34;Tank status in millimeters - useless as percentage is more descriptive&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Tank status in millimeters - useless as percentage is more descriptive
        &lt;/div&gt;&lt;/p&gt;
    





    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2019/how-to-monitor-pellet/stove-icons.png&#34; alt=&#34;Icons &amp;#43; values - I have view with it for all my devices&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Icons &amp;#43; values - I have view with it for all my devices
        &lt;/div&gt;&lt;/p&gt;
    


&lt;p&gt;Device battery needs calibration :-)&lt;/p&gt;
&lt;h1 id=&#34;mechanics&#34;&gt;Mechanics&lt;/h1&gt;
&lt;p&gt;I designed with OnShape two 3D printed boxes for the sensor and the
electronics/battery, both are using magnets to stick in place The sensor is on
the tank lid, while electronics and batteries are outside, hidden on the back of
the stove.&lt;/p&gt;
&lt;p&gt;Design files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://cad.onshape.com/documents/45d755613314d24a302a4f9d/w/8c3fbb3859e3d10773ac6731/e/be84d8417991516e8ee8feaf&#34;&gt;Time of flight forGYUL53 breakout board&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cad.onshape.com/documents/d18d8afd3ce6d5f171c0023e/w/541ec7d59e81f47be7c5d1c0/e/212bd88d468242fcb15d3269&#34;&gt;NoteRF box&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2019/how-to-monitor-pellet/sensor-tof.jpg&#34; alt=&#34;Time of flight sensor - Hot glued into 3D printed box&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Time of flight sensor - Hot glued into 3D printed box
        &lt;/div&gt;&lt;/p&gt;
    





    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2019/how-to-monitor-pellet/sensor-enclosure.jpg&#34; alt=&#34;Enclosure for the electronics and the battery&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Enclosure for the electronics and the battery
        &lt;/div&gt;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to compile KiCad 5.1.x for Debian 10</title>
      <link>https://notes.iopush.net/blog/2019/how-to-compile-kicad-5-1-x-for-debian-10/</link>
      <pubDate>Tue, 13 Aug 2019 19:39:24 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2019/how-to-compile-kicad-5-1-x-for-debian-10/</guid>
      <description>&lt;p&gt;I was looking to use &lt;a href=&#34;https://github.com/openscopeproject/InteractiveHtmlBom/&#34;&gt;InteractiveHtmlBom&lt;/a&gt; plugin for KiCad but unfortunately, Debian maintainers did not set &lt;code&gt;KICAD_SCRIPTING&lt;/code&gt; option in the official package. After a few failing attempts I even tested the official &lt;a href=&#34;http://kicad-pcb.org/download/flatpak/&#34;&gt;flatpak&lt;/a&gt; package but it is an old version (currently 4.x) and scripting is not enabled too.&lt;/p&gt;
&lt;p&gt;So I dug further until it actually succeeds to compile :-)&lt;/p&gt;
    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2019/how-to-compile-kicad-5-1-x-for-debian-10/kicad-interactive-html-bom.png&#34; alt=&#34;Pellet stove&#34;&gt;
        &lt;/span&gt;&lt;/p&gt;
        &lt;p&gt;&lt;div class=&#34;align-center&#34; style=&#34;font-weight: bold;&#34;&gt;
            Pellet stove
        &lt;/div&gt;&lt;/p&gt;
    


&lt;p&gt;Here is the thing: KiCad official documentation still recommend packages for python2, and v5.1.4 is &lt;a href=&#34;https://forum.kicad.info/t/building-on-debian-10-buster/17954/3&#34;&gt;not compatible&lt;/a&gt; with new versions of &lt;code&gt;libglm-dev&lt;/code&gt; if compiled with GCC; this is now &lt;a href=&#34;https://git.launchpad.net/kicad/commit/?id=5aa48e523dd46632564d3a118921f6c1f02abc2f&#34;&gt;fixed in master&lt;/a&gt;. So the commands I used are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# From http://kicad-pcb.org/download/debian/ without Python2 packages&lt;/span&gt;
apt install cmake doxygen libboost-context-dev &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  libboost-dev libboost-system-dev libboost-test-dev &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  libcairo2-dev libcurl4-openssl-dev libgl1-mesa-dev &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  libglew-dev libglm-dev libngspice-dev &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  liboce-foundation-dev liboce-ocaf-dev libssl-dev &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  libwxbase3.0-dev libwxgtk3.0-dev swig wx-common

&lt;span style=&#34;color:#75715e&#34;&gt;# Add Debian Buster/Python3 required packages&lt;/span&gt;
apt install python3-wxgtk4.0 libwxgtk3.0-gtk3-dev &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  libboost-filesystem-dev python3-dev

&lt;span style=&#34;color:#75715e&#34;&gt;# Add KiCad libraries&lt;/span&gt;
apt install kicad-libraries kicad-packages3d --no-install-recommends

&lt;span style=&#34;color:#75715e&#34;&gt;# Downgrade libdlm-dev - For 5.1.4 or older only&lt;/span&gt;
apt remove libglm-dev
wget http://ftp.us.debian.org/debian/pool/main/g/glm/libglm-dev_0.9.8.3-3_all.deb
dpkg -i libglm-dev_0.9.8.3-3_all.deb

&lt;span style=&#34;color:#75715e&#34;&gt;# Clone and build KiCad&lt;/span&gt;
git clone https://git.launchpad.net/kicad
mkdir -p kicad/build/release
cd kicad/build/release
cmake -DCMAKE_BUILD_TYPE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Release &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  -DKICAD_SCRIPTING_ACTION_MENU&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ON &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  -DwxWidgets_CONFIG_OPTIONS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;--toolkit=gtk3&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  -DKICAD_SCRIPTING_WXPYTHON_PHOENIX&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ON &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  -DKICAD_SCRIPTING_PYTHON3&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ON &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  -DwxWidgets_CONFIG_EXECUTABLE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/usr/bin/wx-config&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  ../..
make -j
make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you can use InteractiveHtmlBom which is really pleasant for big boards!&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>ESP32 / MQTT - BLE beacon tracker powered by microPython</title>
      <link>https://notes.iopush.net/blog/2017/mqtt-tracker/</link>
      <pubDate>Thu, 19 Oct 2017 13:47:55 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2017/mqtt-tracker/</guid>
      <description>&lt;p&gt;I am currently working with BLE beacons -only iBeacons for now- with Espressif&amp;rsquo;s
&lt;code&gt;esp-idf&lt;/code&gt; libraries. The aim is to use the ESP32 as a gateway to published
detected beacons to an MQTT broker. It was surprisingly easy and I will write
something about that when the
&lt;a href=&#34;https://github.com/Oliv4945/ESP-Beacon-Tracker&#34;&gt;code&lt;/a&gt; will be more polished.&lt;/p&gt;
&lt;p&gt;Anyway, by curiosity and to speed up development, I wanted to try
microPython port to ESP32, and I did. Unfortunately, BLE support is not yet
reliable enough and a lot of advertisements were lost with 4 to 6 beacons. This
post is to keep track of my work and, hopefully, use in the future when
microPython port will be more reliable :-)&lt;/p&gt;
&lt;h2 id=&#34;micropython-compilation&#34;&gt;microPython compilation&lt;/h2&gt;
&lt;p&gt;While compiling microPython was really straightforward, I had one issue
afterward: I was unable to use the MQTT library, neither by calling it &lt;code&gt;mqtt&lt;/code&gt; or
&lt;code&gt;umqtt&lt;/code&gt;, nor by putting it manually in flash. I did not investigate why but I
found that adding it to the &amp;ldquo;frozen&amp;rdquo; scripts worked.&lt;/p&gt;
&lt;p&gt;The code used is from &lt;a href=&#34;https://pycom.io/&#34;&gt;Pycom&lt;/a&gt; with Wipy 2.0 as target. I used
&lt;a href=&#34;https://github.com/pycom/pycom-micropython-sigfox/tree/c1a862b7733d01c7dd78f16d0287b7033ef9ffd3&#34;&gt;this&lt;/a&gt;
commit against
&lt;a href=&#34;https://github.com/pycom/pycom-esp-idf/tree/13a08ac00cb51f892611af86e81f979c2330ae60&#34;&gt;this version&lt;/a&gt;
of esp-idf.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clone both repositories, update esp-idf&amp;rsquo;s submodules&lt;/li&gt;
&lt;li&gt;Set PATH to xtensa compilation tools. Be careful to use only
&lt;a href=&#34;https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz&#34;&gt;version 1.22.0-61&lt;/a&gt;
for the mentioned Pycom &amp;amp; esp-idf commits.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;IDF_PATH&lt;/code&gt; to esp-idf directory&lt;/li&gt;
&lt;li&gt;Change directory to &lt;code&gt;pycom-micropython-sigfox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;run
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cd mpy-cross &amp;amp;&amp;amp; make clean &amp;amp;&amp;amp; make&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd ../ESP32/frozen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wget https://raw.githubusercontent.com/micropython/micropython-lib/a09b3ec20a745cfd1bccb7bd9db513bfe36968db/umqtt.simple/umqtt/simple.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd ..&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;make BOARD=WIPY TARGET=boot&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;make BOARD=WIPY TARGET=app&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;make BOARD=WIPY flash&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can now connect to microPython REPL on your ESP32!&lt;/p&gt;
&lt;p&gt;##Python BLE tracker Following is a quick and dirty code I used to test it. It
does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connect to WiFi&lt;/li&gt;
&lt;li&gt;Connect to MQTT server&lt;/li&gt;
&lt;li&gt;Scan for BLE advertisements&lt;/li&gt;
&lt;li&gt;Send one MQTT message by discovered device&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; network &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; Bluetooth, WLAN
&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; mqtt &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; MQTTClient
&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; binascii &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; hexlify
&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; machine
&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; time
&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ujson


&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hexlifyNone&lt;/span&gt;(object):
    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; None &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; object &lt;span style=&#34;color:#f92672&#34;&gt;is&lt;/span&gt; None &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; hexlify(object)


&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scan&lt;/span&gt;():
    devices &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {}
    &lt;span style=&#34;color:#66d9ef&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;***   Starting   ***&amp;#34;&lt;/span&gt;)
    bt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Bluetooth()
    &lt;span style=&#34;color:#66d9ef&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Scan...&amp;#34;&lt;/span&gt;, end&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
    bt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;start_scan(&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)
    time&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;sleep(&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)
    &lt;span style=&#34;color:#66d9ef&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;)
    advs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_advertisements()
    &lt;span style=&#34;color:#66d9ef&#34;&gt;print&lt;/span&gt;(advs)

    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; adv &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; advs:
        devices[hexlify(adv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;mac)] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Mac&amp;#34;&lt;/span&gt;: hexlify(adv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;mac),
            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Rssi&amp;#34;&lt;/span&gt;: adv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rssi,
            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Data&amp;#34;&lt;/span&gt;: hexlifyNone(adv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;data),
            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MfrData&amp;#34;&lt;/span&gt;: hexlifyNone(
                bt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;resolve_adv_data(adv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;data, Bluetooth&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ADV_MANUFACTURER_DATA)
            ),
            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NameShort&amp;#34;&lt;/span&gt;: hexlifyNone(
                bt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;resolve_adv_data(adv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;data, Bluetooth&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ADV_NAME_SHORT)
            ),
            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NameComplete&amp;#34;&lt;/span&gt;: hexlifyNone(
                bt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;resolve_adv_data(adv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;data, Bluetooth&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ADV_NAME_CMPL)
            ),
            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Flag&amp;#34;&lt;/span&gt;: bt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;resolve_adv_data(adv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;data, Bluetooth&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ADV_FLAG),
            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Appearance&amp;#34;&lt;/span&gt;: hexlifyNone(
                bt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;resolve_adv_data(adv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;data, Bluetooth&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ADV_APPEARANCE)
            ),
        }
        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        print( &amp;#39;MAC: {}&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;RSSI: {}&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Data: {}&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Name: {}&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;MfrData: {}&amp;#39;.format(
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                hexlify( adv.mac ),
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                adv.rssi,
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                hexlify( adv.data ),
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                bt.resolve_adv_data( adv.data, Bluetooth.ADV_NAME_SHORT ),
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                hexlify( bt.resolve_adv_data( adv.data, Bluetooth.ADV_MANUFACTURER_DATA ) )
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                )
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              )
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
    &lt;span style=&#34;color:#66d9ef&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;***********&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Devices: &amp;#34;&lt;/span&gt;, devices)
    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; key, data &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; devices&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;items():
        &lt;span style=&#34;color:#66d9ef&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;***********&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, data)
        msgJson &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ujson&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps(data)
        client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;publish(topic&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/test&amp;#34;&lt;/span&gt;, msg&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;msgJson)

    &lt;span style=&#34;color:#66d9ef&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;***   End   ***&amp;#34;&lt;/span&gt;)


&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sub_cb&lt;/span&gt;(topic, msg):
    &lt;span style=&#34;color:#66d9ef&#34;&gt;print&lt;/span&gt;(msg)


wlan &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; WLAN(mode&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;WLAN&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;STA)
wlan&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;connect(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SSID name&amp;#34;&lt;/span&gt;, auth&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;(WLAN&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WPA2, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;), timeout&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5000&lt;/span&gt;)
&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; wlan&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;isconnected():
    machine&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;idle()
&lt;span style=&#34;color:#66d9ef&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Connected to Wifi&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)

client &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; MQTTClient(
    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;device_id&amp;#34;&lt;/span&gt;,
    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MQTT broker address&amp;#34;&lt;/span&gt;,
    user&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user if any&amp;#34;&lt;/span&gt;,
    password&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;password if any&amp;#34;&lt;/span&gt;,
    port&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1883&lt;/span&gt;,
    ssl&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;True,
)
client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_callback(sub_cb)
client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;connect()
client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;subscribe(topic&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/test&amp;#34;&lt;/span&gt;)
client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;publish(topic&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/test&amp;#34;&lt;/span&gt;, msg&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Started&amp;#34;&lt;/span&gt;)
scan()

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>STM32 - Custom USB HID device step by step</title>
      <link>https://notes.iopush.net/blog/2016/stm32-custom-usb-hid-step-by-step-2/</link>
      <pubDate>Fri, 16 Dec 2016 20:49:40 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2016/stm32-custom-usb-hid-step-by-step-2/</guid>
      <description>&lt;p&gt;Step by step guide to do a custom USB HID device on STM32 using ST CubeMX. There
is already
&lt;a href=&#34;http://damogranlabs.com/2016/03/stm32-custom-usb-hid-device-yes-please/&#34;&gt;one page&lt;/a&gt;
addressing it but without any details for beginners.&lt;br&gt;
I will use &lt;a href=&#34;https://notes.iopush.net/projects/stm32l052-development-board/&#34;&gt;my custom board&lt;/a&gt; based on STM32L0,
but any Nucleo can be used by wiring a USB cable to 5V, GND, USB_D+, USB_D-.&lt;/p&gt;
&lt;h1 id=&#34;step-1---cubemx-open-it-start-a-project-to-select-your-processor-or-board&#34;&gt;Step 1 - CubeMX Open it, start a project to select your processor or board.&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;Pinout&lt;/code&gt; tab &lt;code&gt;configuration&lt;/code&gt;-&amp;gt;&lt;code&gt;peripheral&lt;/code&gt;-&amp;gt;&lt;code&gt;usb&lt;/code&gt; and check &lt;code&gt;Device (FS)&lt;/code&gt;.
It will tell CubeMX that we want to use USB pins.&lt;/li&gt;
&lt;li&gt;You can check &lt;code&gt;Activate OE&lt;/code&gt; if you want to see a led blink when there is
traffic on USB lines. Then connect a resistor+led on the pin.&lt;/li&gt;
&lt;li&gt;Now, to speed up development, we want to use ST&amp;rsquo;s USB library, so in
&lt;code&gt;configuration&lt;/code&gt; -&amp;gt; &lt;code&gt;USB_Device&lt;/code&gt; select &lt;code&gt;Human interface device class (HID)&lt;/code&gt;.
Be sure to avoid custom class, we want ST working example to test our setup.
It will generate a mouse device.&lt;/li&gt;
&lt;li&gt;Then in the &lt;code&gt;Clock configuration&lt;/code&gt; tab select &lt;code&gt;USBCLK&lt;/code&gt; from &lt;code&gt;RC 48 MHZ&lt;/code&gt; if your
µC is compatible: ST implemented a nice feature allowing us to avoid adding an
external quartz by trimming internal 48 MHz RC against USB clock sent by the
host. If your uC is not crystal-less you must find a way to have accurate 48
MHz on &lt;code&gt;USBCLK&lt;/code&gt; (hint: use HSE)&lt;/li&gt;
&lt;li&gt;Then in &lt;code&gt;Configuration&lt;/code&gt; tab select &lt;code&gt;Middlewares&lt;/code&gt;-&amp;gt;&lt;code&gt;USB_Devices&lt;/code&gt;. Here you can
customize the &lt;code&gt;Device descriptor&lt;/code&gt; tab with PID/VID, manufacturer&amp;hellip;&lt;/li&gt;
&lt;li&gt;Now, generate the project for your IDE.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;step-2---test-the-mouse-example-first-before-modifying-anything-we-will-try&#34;&gt;Step 2 - Test the mouse example First, before modifying anything, we will try&lt;/h1&gt;
&lt;p&gt;ST&amp;rsquo;s mouse example. The USB stack is handled by ST&amp;rsquo;s library so we just need to
call it to move the mouse.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modify &lt;code&gt;main.c&lt;/code&gt; to declare and initialise data to be send to the computer, in
&lt;code&gt;USER CODE BEGIN 1&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// HID Mouse
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; mouseHID_t {
      uint8_t buttons;
      int8_t x;
      int8_t y;
      int8_t wheel;
  };
  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; mouseHID_t mouseHID;
  mouseHID.buttons &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
  mouseHID.x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;;
  mouseHID.y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
  mouseHID.wheel &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Then send them in &lt;code&gt;USER CODE BEGIN 3&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Send HID report
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    mouseHID.x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;;
    USBD_HID_SendReport(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;hUsbDeviceFS, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;mouseHID, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; mouseHID_t));
    HAL_Delay(&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compile, then test: the mouse is now slowly drifting to the right :-)&lt;/p&gt;
&lt;h1 id=&#34;step-3---modifications-for-custom-hid-now-we-want-to-change-the-mouse-example&#34;&gt;Step 3 - Modifications for custom HID Now we want to change the mouse example&lt;/h1&gt;
&lt;p&gt;to our custom descriptor. For this tutorial, we will use the keyboard+consumer
device (media) descriptor explained in my
&lt;a href=&#34;https://notes.iopush.net/custom-usb-hid-device-descriptor-media-keyboard/&#34;&gt;previous post&lt;/a&gt;.&lt;br&gt;
We can add it in &lt;code&gt;Middlewares&lt;/code&gt;-&amp;gt;&lt;code&gt;...&lt;/code&gt;-&amp;gt;&lt;code&gt;Src&lt;/code&gt;-&amp;gt;&lt;code&gt;usbd_hid.c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Find &lt;code&gt;HID_MOUSE_ReportDesc&lt;/code&gt; array and comment or delete it, then add the custom
descriptor.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;__ALIGN_BEGIN &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; uint8_t HID_CUSTOM_ReportDesc[HID_CUSTOM_REPORT_DESC_SIZE]  __ALIGN_END &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
  &lt;span style=&#34;color:#75715e&#34;&gt;// 78 bytes
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x05&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;// Usage Page (Generic Desktop Ctrls)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x06&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;// Usage (Keyboard)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0xA1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;// Collection (Application)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x85&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Report ID (1)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x05&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x07&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage Page (Kbrd/Keypad)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x75&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Report Size (1)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x95&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x08&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Report Count (8)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x19&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xE0&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage Minimum (0xE0)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x29&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xE7&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage Maximum (0xE7)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x15&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Logical Minimum (0)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x25&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Logical Maximum (1)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x81&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x02&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x95&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x03&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Report Count (3)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x75&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x08&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Report Size (8)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x15&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Logical Minimum (0)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x25&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x64&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Logical Maximum (100)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x05&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x07&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage Page (Kbrd/Keypad)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x19&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage Minimum (0x00)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x29&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x65&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage Maximum (0x65)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x81&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC0&lt;/span&gt;,              &lt;span style=&#34;color:#75715e&#34;&gt;// End Collection
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x05&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0C&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;// Usage Page (Consumer)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;// Usage (Consumer Control)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0xA1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;// Collection (Application)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x85&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x02&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Report ID (2)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x05&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0C&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage Page (Consumer)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x15&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Logical Minimum (0)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x25&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Logical Maximum (1)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x75&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Report Size (1)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x95&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x08&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Report Count (8)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xB5&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage (Scan Next Track)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xB6&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage (Scan Previous Track)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xB7&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage (Stop)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xB8&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage (Eject)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xCD&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage (Play/Pause)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xE2&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage (Mute)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xE9&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage (Volume Increment)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x09&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xEA&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Usage (Volume Decrement)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x81&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x02&lt;/span&gt;,        &lt;span style=&#34;color:#75715e&#34;&gt;//   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC0&lt;/span&gt;,              &lt;span style=&#34;color:#75715e&#34;&gt;// End Collection
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then in &lt;code&gt;USBD_HID_CfgDesc&lt;/code&gt; change&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bInterfaceSubClass&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt;, the keyboard does not respect boot specifications&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nInterfaceProtocol&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt; (keyboard)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All references to &lt;code&gt;mouse&lt;/code&gt; in the file should be changed to &lt;code&gt;custom&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In &lt;code&gt;Middlewares&lt;/code&gt;-&amp;gt;&lt;code&gt;...&lt;/code&gt;-&amp;gt;&lt;code&gt;Src&lt;/code&gt;-&amp;gt;&lt;code&gt;usbd_hid.h&lt;/code&gt;, change:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HID_EPIN_SIZE&lt;/code&gt; to &lt;code&gt;5&lt;/code&gt;, the max report size&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HID_CUSTOM_REPORT_DESC_SIZE &lt;/code&gt; to &lt;code&gt;78&lt;/code&gt;, the length of our new descriptor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Finally in &lt;code&gt;main.c&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
Add reports initialization in &lt;code&gt;USER CODE BEGIN 1&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// HID Keyboard
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; keyboardHID_t {
      uint8_t id;
      uint8_t modifiers;
      uint8_t key1;
      uint8_t key2;
      uint8_t key3;
  };
  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; keyboardHID_t keyboardHID;
  keyboardHID.id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
  keyboardHID.modifiers &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
  keyboardHID.key1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
  keyboardHID.key2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
  keyboardHID.key3 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
  &lt;span style=&#34;color:#75715e&#34;&gt;// HID Media
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; mediaHID_t {
    uint8_t id;
    uint8_t keys;
  };
  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; mediaHID_t mediaHID;
  mediaHID.id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;;
  mediaHID.keys &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And send it in &lt;code&gt;USER CODE BEGIN 3&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Send HID report
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    mediaHID.keys &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; USB_HID_VOL_DEC;
    USBD_HID_SendReport(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;hUsbDeviceFS, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;mediaHID, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; mediaHID_t));
    HAL_Delay(&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;);
    mediaHID.keys &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
    USBD_HID_SendReport(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;hUsbDeviceFS, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;mediaHID, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; mediaHID_t));
    HAL_Delay(&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;);

    keyboardHID.modifiers &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; USB_HID_MODIFIER_RIGHT_SHIFT;
    keyboardHID.key1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; USB_HID_KEY_L;
    USBD_HID_SendReport(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;hUsbDeviceFS, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;keyboardHID, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; keyboardHID_t));
    HAL_Delay(&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;);
    keyboardHID.modifiers &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
    keyboardHID.key1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
    USBD_HID_SendReport(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;hUsbDeviceFS, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;keyboardHID, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; keyboardHID_t));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note: There is no need to use two structures if memory optimization is required,
but it simplifies the example.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compile, send to uC and&amp;hellip;&lt;/strong&gt;&lt;br&gt;
The volume is decreasing while &amp;lsquo;L&amp;rsquo; characters appear on your screen :-)&lt;/p&gt;
&lt;p&gt;Full code can be found on
&lt;a href=&#34;https://github.com/Oliv4945/STM32L052_Breadboard/tree/USB_HID&#34;&gt;Github&lt;/a&gt;, and
commit diff from example is
&lt;a href=&#34;https://github.com/Oliv4945/STM32L052_Breadboard/commit/fc3e6c0f586749aad904f5ef558a8c3e6ce585d8&#34;&gt;there&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Edit 21/02/17: Correction of consumer control descriptor size&lt;/p&gt;</description>
    </item>
    
  </channel>
</rss>
