<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>BlocNotes</title>
    <link>https://notes.iopush.net/</link>
    <description>Recent content on BlocNotes</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 30 Sep 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://notes.iopush.net/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Fix Home-Assistant statistics and energy erroneous values</title>
      <link>https://notes.iopush.net/blog/2025/09-hass-fix-statistics/</link>
      <pubDate>Tue, 30 Sep 2025 00:00:00 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2025/09-hass-fix-statistics/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I have been experimenting with solar panels, &lt;a href=&#34;https://www.home-assistant.io/&#34;&gt;Home Assistant&lt;/a&gt; and my electricity meter lately. This French meter from the utility is called Linky. It provides a small power supply (130 mW) and a serial link hidden via amplitude modulation.&lt;br&gt;
To avoid using batteries, I built a prototype that harvests this power, demodulates the serial link, and feeds the data into an nRF52 development kit. It works well enough that I never bothered turning this messy setup into a proper PCB.&lt;/p&gt;
&lt;p&gt;However, every now and then—despite CRC checks—I get an erroneous reading that messes up the Home Assistant Energy panel. Here&amp;rsquo;s how to fix incorrect statistics in the Home Assistant database.&lt;/p&gt;
&lt;h4 id=&#34;preparation&#34;&gt;Preparation&lt;/h4&gt;
&lt;p&gt;Before editing the database, it is strongly recommended to stop Home Assistant to avoid concurrent access that could corrupt the database.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connect to the system running Home Assistant&lt;/li&gt;
&lt;li&gt;Install SQLite3 if needed. For example, on Debian-based systems: &lt;code&gt;apt install sqlite3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Locate the &lt;code&gt;home-assistant_v2.db&lt;/code&gt; database file in Home-Assistant data folder and create a backup&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;open-the-database-for-editing&#34;&gt;Open the database for editing&lt;/h4&gt;
&lt;p&gt;Open the database using SQLite and set a more readable output mode:&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;$ sqlite3 home-assistant_v2.db&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;span style=&#34;color:#75715e&#34;&gt;# Then enter the commands&lt;/span&gt;
sqlite&amp;gt; .header on
sqlite&amp;gt; .mode column
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;find-the-data-id&#34;&gt;Find the data id&lt;/h4&gt;
&lt;p&gt;Identify Home Assitant&amp;rsquo;s internal identifier, it is called &lt;code&gt;metadata_id&lt;/code&gt;. Replace &lt;code&gt;easf02&lt;/code&gt; with Home-Assistant&amp;rsquo;s Entity ID you are looking for.&lt;br&gt;
Using &lt;code&gt;LIKE &#39;%PARTIAL_ENTITY_STRING%&lt;/code&gt; allows for easier search by matching any string containing &lt;code&gt;PARTIAL_ENTITY_STRING&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-SQL&#34; data-lang=&#34;SQL&#34;&gt;sqlite&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt; id, statistic_id &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; statistics_meta &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; statistic_id &lt;span style=&#34;color:#66d9ef&#34;&gt;LIKE&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%easf01%&amp;#39;&lt;/span&gt;;
id  statistic_id            
&lt;span style=&#34;color:#75715e&#34;&gt;--  ------------------------
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;   sensor.linky_easf01     
&lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;  sensor.linky_easf01_cost
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case &lt;code&gt;id = 6&lt;/code&gt; is the one we want to fix, and &lt;code&gt;id = 15&lt;/code&gt; is the associated cost.&lt;/p&gt;
&lt;h4 id=&#34;search-for-erroneous-data&#34;&gt;Search for erroneous data&lt;/h4&gt;
&lt;p&gt;We let&amp;rsquo;s ask the database for any sudden jump in the data, e.g change greater than 10,000 Wh. Adjust &lt;code&gt;metadata_id = 6&lt;/code&gt; and the threshold (&lt;code&gt;&amp;gt; 10000&lt;/code&gt;) as needed.&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-SQL&#34; data-lang=&#34;SQL&#34;&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WITH&lt;/span&gt; ordered_stats &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; (
  &lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
    id,
    created_ts,
    &lt;span style=&#34;color:#66d9ef&#34;&gt;sum&lt;/span&gt;,
    metadata_id,
    LAG(&lt;span style=&#34;color:#66d9ef&#34;&gt;sum&lt;/span&gt;) OVER (PARTITION &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; metadata_id &lt;span style=&#34;color:#66d9ef&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; created_ts) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; previous_sum,
    LAG(created_ts) OVER (PARTITION &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; metadata_id &lt;span style=&#34;color:#66d9ef&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; created_ts) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; previous_created_ts
  &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;statistics&lt;/span&gt;
  &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; metadata_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;
)
&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
  id,
  datetime(created_ts, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;unixepoch&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;localtime&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; date,
  &lt;span style=&#34;color:#66d9ef&#34;&gt;ABS&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; previous_sum) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; difference
&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; ordered_stats
&lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ABS&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; previous_sum) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; id &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;LIMIT&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In a nutshell, this query:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Selects statistics data for the entity and associates each value with the previous one.&lt;/li&gt;
&lt;li&gt;Displays the five most recent entries where the difference between consecutive values exceeds the threshold.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example result:&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-SQL&#34; data-lang=&#34;SQL&#34;&gt;id      date                 difference
&lt;span style=&#34;color:#75715e&#34;&gt;------  -------------------  ----------
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;229351&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2025&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;08&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;18&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;00&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;20676793&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;span style=&#34;color:#ae81ff&#34;&gt;38711&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;2025&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;01&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;28&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;00&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;20020401&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;Looks like we found the 20.6 MWh spike reported in the Energy panel :-)&lt;/p&gt;
&lt;h4 id=&#34;update-the-value&#34;&gt;Update the value&lt;/h4&gt;
&lt;p&gt;Since Home Assistant records cumulative sums, we need to subtract the erroneous difference from all entries starting from the anomaly. Use the following query:&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-SQL&#34; data-lang=&#34;SQL&#34;&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;UPDATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;statistics&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;SET&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;20676793&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; metadata_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;and&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;229351&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace &lt;code&gt;20676793.0&lt;/code&gt; and &lt;code&gt;229351&lt;/code&gt; with your actual values.&lt;/p&gt;
&lt;p&gt;Once done, exit SQLite by pressing &lt;code&gt;Ctrl + D&lt;/code&gt;. The database is now fixed, and the energy panel displays accurate values!&lt;/p&gt;



    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2025/09-hass-fix-statistics/hass_panel_after.png&#34; alt=&#34;Fixed Home-Assistant energy panel&#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;
            Fixed Home-Assistant energy panel
        &lt;/div&gt;&lt;/p&gt;
    


</description>
    </item>
    
    <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>UBports part 1 - Compiling and booting for Samsung S7</title>
      <link>https://notes.iopush.net/blog/2021/01-ubports-part-1/</link>
      <pubDate>Fri, 29 Jan 2021 00:00:00 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2021/01-ubports-part-1/</guid>
      <description>&lt;p&gt;I went down the hole of installing Linux on my phone (Samsung Galaxy S7). The
easiest path is compiling and installing &lt;a href=&#34;https://www.ubports.com/&#34;&gt;UBports&lt;/a&gt;,
some people have heavily started the process but it is still a work in progress.&lt;/p&gt;
&lt;p&gt;This is the first part: step by step description to build and boot the system,
with helpers scripts to setup the system once flashed.&lt;/p&gt;
    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2021/01-ubports-part-1/ubports-home.jpg&#34; alt=&#34;UBports screenshot&#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;
            UBports screenshot
        &lt;/div&gt;&lt;/p&gt;
    


&lt;p&gt;The first part is my notes gathered during the initial build. You can install
TWRP then jump directly to the step by step at the end of this page.&lt;/p&gt;
&lt;h1 id=&#34;state&#34;&gt;State&lt;/h1&gt;
&lt;p&gt;This is the status of working features with my current build, some others are
more advanced.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ X ] Wi-Fi&lt;/li&gt;
&lt;li&gt;[ X ] Web browsing&lt;/li&gt;
&lt;li&gt;[ X ] MP4 playback&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Bluetooth&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Camera&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Sim card&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Phone calls&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; SMS&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; MMS&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;documentation&#34;&gt;Documentation&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.halium.org/en/latest/porting/first-steps.html&#34;&gt;https://docs.halium.org/en/latest/porting/first-steps.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.doof.me.uk/2020/04/06/installing-gnu-linux-on-my-samsung-s7/&#34;&gt;https://www.doof.me.uk/2020/04/06/installing-gnu-linux-on-my-samsung-s7/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.halium.org/en/latest/supplementary/devices/herolte.html&#34;&gt;https://docs.halium.org/en/latest/supplementary/devices/herolte.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Halium/projectmanagement/issues/48&#34;&gt;https://github.com/Halium/projectmanagement/issues/48&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;twrp-installation&#34;&gt;TWRP installation&lt;/h1&gt;
&lt;p&gt;Just follow official instructions
&lt;a href=&#34;https://forum.xda-developers.com/t/recovery-exynos-official-twrp-for-galaxy-s7-herolte.3333770/&#34;&gt;https://forum.xda-developers.com/t/recovery-exynos-official-twrp-for-galaxy-s7-herolte.3333770/&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;issue-custom-binary-blocked-by-frp-lock&#34;&gt;Issue &amp;ldquo;Custom binary blocked by FRP lock&amp;rdquo;&lt;/h1&gt;
&lt;p&gt;Go to Android developer options, activate &lt;code&gt;enable OEM unlock&lt;/code&gt; slider.&lt;/p&gt;
&lt;h1 id=&#34;halium-compilation&#34;&gt;Halium compilation&lt;/h1&gt;
&lt;p&gt;Under Debian Bullseye it is not in the docs and might be obvious, but ADB must
be installed &lt;code&gt;apt install adb&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;first-steps&#34;&gt;First steps&lt;/h2&gt;
&lt;h3 id=&#34;set-up-your-build-device&#34;&gt;Set up your build device&lt;/h3&gt;
&lt;p&gt;Package &lt;code&gt;python-markdown&lt;/code&gt; does not exists, to be replaced by &lt;code&gt;python3-markdown&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The error &lt;code&gt;E: Unable to locate package repo&lt;/code&gt; is because &lt;code&gt;contrib&lt;/code&gt; repo needs to
be activated in &lt;code&gt;/etc/apt/sources.list&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;get-halium-source&#34;&gt;Get Halium source&lt;/h2&gt;
&lt;h3 id=&#34;adding-device-specific-source&#34;&gt;Adding device-specific source&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;android_device_[manufacturer]_[device]&lt;/code&gt;=&lt;code&gt;android_device_samsung_herolte&lt;/code&gt;
lineage.dependencies file on
&lt;a href=&#34;https://github.com/LineageOS/android_device_samsung_herolte/blob/lineage-18.1/lineage.dependencies&#34;&gt;Github&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;File &lt;code&gt;halium/devices/manifests/[manufacturer]_[device].xml&lt;/code&gt;already exists:
&lt;code&gt;halium/devices/manifests/samsung_herolte.xml&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;vendor-blobs&#34;&gt;Vendor blobs&lt;/h3&gt;
&lt;p&gt;Nothing to do? At least I did not for now.&lt;/p&gt;
&lt;h2 id=&#34;build-halium&#34;&gt;Build Halium&lt;/h2&gt;
&lt;h3 id=&#34;modify-the-kernel-configuration&#34;&gt;Modify the kernel configuration&lt;/h3&gt;
&lt;p&gt;Clone &lt;code&gt;mer-kernel-check&lt;/code&gt; outside of &lt;code&gt;BUILDDIR&lt;/code&gt; . Then the command for Samsung S7
kernel is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ./mer_verify_kernel_config ../halium/kernel/samsung/universal8890/arch/arm64/configs/exynos8890-herolte_defconfig
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Options I had to set:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
# https://cateee.net/lkddb/web-lkddb/QUOTA.html
# If you say Y here, you will be able to set per-user limits for disk usage
# It does not work for me, the kernel is not able to mount partitions without.
CONFIG_QUOTA_NETLINK_INTERFACE=y

CONFIG_QFMT_V2=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_IP_NF_MATCH_RPFILTER=y
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Patch against 1046b86e869d6a77bc1f905b3a61bbd5e5478ee1: TODO&lt;/p&gt;
&lt;h3 id=&#34;include-your-device-in-fixup-mountpoints&#34;&gt;Include your device in fixup-mountpoints&lt;/h3&gt;
&lt;p&gt;Nothing to do, already included.&lt;/p&gt;
&lt;h3 id=&#34;building-the-systemimg-and-hybris-bootimg&#34;&gt;Building the system.img and hybris-boot.img&lt;/h3&gt;
&lt;h4 id=&#34;mka-hybris-boot&#34;&gt;mka hybris-boot&lt;/h4&gt;
&lt;p&gt;Error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x50): multiple definition of `yylloc&#39;; scripts/dtc/dtc-lexer.lex.o:(.bss+0x0): first defined here
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Due to a redundant declaration. Let&amp;rsquo;s make it extern in&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;./kernel/samsung/universal8890/scripts/dtc/dtc-lexer.l&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;./kernel/samsung/universal8890/scripts/dtc/dtc-parser.tab.c_shipped&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkbootimg: command not found
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add it to the system path after compiling it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export PATH=./system/core/mkbootimg/:$PATH
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;halium-reference-rootfs&#34;&gt;Halium reference rootfs&lt;/h2&gt;
&lt;h1 id=&#34;flash-halium&#34;&gt;Flash Halium&lt;/h1&gt;
&lt;p&gt;Restart it download mode, flash hybris boot:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;heimdall flash --BOOT out/target/product/herolte/hybris-boot.img
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Install Halium rootfs and system&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./halium-install -p halium ../halium-rootfs-20170630-151006.tar.gz ../halium/out/target/product/herolte/system.img
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;i-gave-up-halium-rootfs&#34;&gt;I gave up Halium rootfs&lt;/h1&gt;
&lt;p&gt;But I did not succeed to make Halium rootfs boot: I had a constant reboot loop.
When I asked on Halium&amp;rsquo;s Telegram channel someone told me that it is a 4 years
old rootfs and I should move on UBports rootfs, so I did :-)&lt;/p&gt;
&lt;h1 id=&#34;ubports&#34;&gt;UBports&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://www.ubports.com/&#34;&gt;UBports&lt;/a&gt; is a touch-friendly Ubuntu flavor maintained
by a community, since Canonical dropped the
&lt;a href=&#34;https://ubuntu.com/blog/ubuntu-edge&#34;&gt;Edge project&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;building-the-images&#34;&gt;Building the images&lt;/h2&gt;
&lt;h3 id=&#34;fix-mount-points&#34;&gt;Fix mount points&lt;/h3&gt;
&lt;p&gt;No edit necessary to the fstab file, found at:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;device/samsung/hero-common/ramdisk/fstab.samsungexynos8890
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;fix-defconfig&#34;&gt;Fix defconfig&lt;/h3&gt;
&lt;p&gt;Command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./halium/halium-boot/check-kernel-config kernel/samsung/universal8890/arch/arm64/configs/exynos8890-herolte_defconfig -w
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First time I ran the command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Config file checked, found no errors.

 Made 110 fixes.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Run it again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Config file checked, found no errors.

 Made 1 fixes.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But the
line&lt;code&gt;CONFIG_DEFAULT_SECURITY is set, but to &amp;quot;selinux&amp;quot; y not &amp;quot;apparmor&amp;quot;.&lt;/code&gt;is never
fixed. Fix it manually with &lt;code&gt;CONFIG_DEFAULT_SECURITY=&amp;quot;apparmor&amp;quot;&lt;/code&gt; then run it
again without the &lt;code&gt;-w&lt;/code&gt; argument:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Config file checked, found no errors.
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;ubuntu-touch-requires-setting-consoletty0&#34;&gt;Ubuntu Touch requires setting console=tty0&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;console=tty0&lt;/code&gt; is already defined in the kernel config file, so nothing required&lt;/p&gt;
&lt;h3 id=&#34;fix-apparmor&#34;&gt;Fix Apparmor&lt;/h3&gt;
&lt;p&gt;I did not try to understand why, but it is recommended in Github issue by and
hoster in UBports Github, so let&amp;rsquo;s do it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd kernel/samsung/universal8890/security/
rm -r apparmor/
wget  https://raw.githubusercontent.com/ubports/apparmor-backports-ut/master/apparmor-3.18.tar.bz2
tar -xf apparmor-3.18.tar.bz2
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;build-halium-bootimg-and-systemimg&#34;&gt;Build halium-boot.img and system.img&lt;/h3&gt;
&lt;p&gt;Build as instructed&lt;/p&gt;
&lt;h2 id=&#34;installing-ubports&#34;&gt;Installing UBports&lt;/h2&gt;
&lt;p&gt;As instructed in tge &lt;a href=&#34;https://pad.ubports.com/p/porting-faq&#34;&gt;UBPort FAQ&lt;/a&gt;, use
&lt;code&gt;xenial-hybris-edge-rootfs-arm64&lt;/code&gt; from
&lt;code&gt;https://ci.ubports.com/job/xenial-hybris-edge-rootfs-arm64&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget https://ci.ubports.com/job/xenial-hybris-edge-rootfs-arm64/lastStableBuild/artifact/out/ubuntu-touch-hybris-xenial-edge-arm64-rootfs.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Flash boot image il download mode (phone off, long press on power+home+volume
down)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./Heimdall/build/bin/heimdall flash --BOOT files/halium-boot.img
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Reboot in recovery, flash system.img+rootfs&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/halium-install -p ut ../files/ubuntu-touch-hybris-xenial-edge-arm64-rootfs.tar.gz ../files/system.img
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;halium-logging-in&#34;&gt;Halium logging in&lt;/h2&gt;
&lt;h3 id=&#34;wi-fi&#34;&gt;Wi-fi&lt;/h3&gt;
&lt;p&gt;As described &lt;code&gt;nmtui&lt;/code&gt; then select &lt;code&gt;Activate a connection&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;ubpots---the-graphical-ui&#34;&gt;UBpots - The graphical UI&lt;/h2&gt;
&lt;h3 id=&#34;udev-rules&#34;&gt;udev rules&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo -i
cat /var/lib/lxc/android/rootfs/ueventd*.rc|grep ^/dev|sed -e &#39;s/^\/dev\///&#39;|awk &#39;{printf &amp;quot;ACTION==\&amp;quot;add\&amp;quot;, KERNEL==\&amp;quot;%s\&amp;quot;, OWNER=\&amp;quot;%s\&amp;quot;, GROUP=\&amp;quot;%s\&amp;quot;, MODE=\&amp;quot;%s\&amp;quot;\n&amp;quot;,$1,$3,$4,$2}&#39; | sed -e &#39;s/\r//&#39; &amp;gt;/usr/lib/lxc-android-config/70-herolte.rules
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;edit-layout-from-github&#34;&gt;Edit layout (From Github)&lt;/h3&gt;
&lt;p&gt;Edit &lt;code&gt;/etc/ubuntu-touch-session.d/android.conf&lt;/code&gt; to add&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GRID_UNIT_PX=29
QTWEBKIT_DPR=3.0
NATIVE_ORENTATION=portrait
FORM_FACTOR=handset
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;add-user-to-update&#34;&gt;Add user to update&lt;/h3&gt;
&lt;p&gt;Step described in Github issue, why?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo adduser --force-badname --system --home /nonexistent --no-create-home --quiet _apt || true
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;install-xenial-fix-dataspace&#34;&gt;Install xenial fix dataspace&lt;/h3&gt;
&lt;p&gt;Again, from Github. Probably linked to the new user creation to update packages&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo ubports-qa install xenial_-_fix-dataspace
sudo ubports-qa remove xenial_-_fix-dataspace
sudo reboot
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;step-by-step-with-to-flash-systemimg-and-halium-bootimg-and-boot&#34;&gt;Step by step with to flash system.img and halium-boot.img and boot&lt;/h1&gt;
&lt;p&gt;This step by step guide is working for me, if you have an issue please read the
previous chapter which might help to understand it. In all cases please leave a
comment so I can fix the instructions.&lt;/p&gt;
&lt;h1 id=&#34;backup&#34;&gt;Backup&lt;/h1&gt;
&lt;p&gt;Backup your user data if you want. This process will also create a TWRP backup
for Android itself.&lt;/p&gt;
&lt;h1 id=&#34;install-twrp&#34;&gt;Install TWRP&lt;/h1&gt;
&lt;p&gt;Follow official instructions
&lt;a href=&#34;https://forum.xda-developers.com/t/recovery-exynos-official-twrp-for-galaxy-s7-herolte.3333770/&#34;&gt;https://forum.xda-developers.com/t/recovery-exynos-official-twrp-for-galaxy-s7-herolte.3333770/&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;setup-ubports&#34;&gt;Setup UBports&lt;/h1&gt;
&lt;h2 id=&#34;reboot-in-recovery&#34;&gt;Reboot in recovery&lt;/h2&gt;
&lt;p&gt;Reboot in recovery, it can be done with &lt;code&gt;adb reboot recovery&lt;/code&gt; or switch off the
phone then &lt;code&gt;power&lt;/code&gt; + &lt;code&gt;volume down&lt;/code&gt; + &lt;code&gt;home&lt;/code&gt; keys.&lt;/p&gt;
&lt;h2 id=&#34;twrp-backup-optional&#34;&gt;TWRP backup (optional)&lt;/h2&gt;
&lt;p&gt;If you want to be able to easily switch back to Android backup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;boot&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;system&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;format-data-partition&#34;&gt;Format data partition&lt;/h2&gt;
&lt;p&gt;In TWRP:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Touch &lt;code&gt;Wipe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Touch &lt;code&gt;Format Data&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;yes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Go back to home menu thanks to the home button&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;flash-the-boot-and-file-system-to-the-device&#34;&gt;Flash the boot and file system to the device&lt;/h2&gt;
&lt;p&gt;Still in TWRP:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Clone &lt;a href=&#34;https://gitlab.com/JBBgameich/halium-install&#34;&gt;Halium install&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Download
&lt;a href=&#34;https://ci.ubports.com/job/xenial-rootfs-armhf/lastSuccessfulBuild/artifact/out/ubports-touch.rootfs-xenial-armhf.tar.gz&#34;&gt;UBports rootfs&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With sudo, or as root:
&lt;code&gt;./halium-install -v -p ut ./path/to/ubports-touch.rootfs-xenial-armhf.tar.gz ./path/to/system.img&lt;/code&gt;
Note add &lt;code&gt;-i&lt;/code&gt; if your want to have your &lt;code&gt;id_rsa.pub&lt;/code&gt; key copied&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the password for the phone&amp;rsquo;s new user.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When finished, then reboot in download mode. In TWRP:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Touch &lt;code&gt;reboot&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Touch &lt;code&gt;Download&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Download and compile &lt;a href=&#34;https://gitlab.com/BenjaminDobell/Heimdall&#34;&gt;Heimdall&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once in Download mode, flash the bootloader with
&lt;code&gt;heimdall flash --BOOT ./path/to/files/halium-boot.img&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The phone will reboot, &lt;code&gt;Unity&lt;/code&gt; will appear, the screen goes back, the phone
restarts then &lt;code&gt;Unity&lt;/code&gt; hangs. It is expected, then&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter &lt;code&gt;ip address show&lt;/code&gt; in a terminal, it should make display a new
interface. Mine returns:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;9: enp0s20u2: &amp;lt;BROADCAST,MULTICAST&amp;gt; mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the new interface name is &lt;code&gt;enp0s20u2&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&#34;7&#34;&gt;
&lt;li&gt;
&lt;p&gt;Download helpers files from &lt;a href=&#34;https://github.com/Oliv4945/uports-herolte-helpers&#34;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the script to setup the connection, send required files to the phone and
connect to it: &lt;code&gt;bash helper-install-host.sh interface_name&lt;/code&gt;. Ex:
&lt;code&gt;bash helper-install-host.sh enp0s20u2&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You should obtain a terminal on: &lt;code&gt;phablet@ubuntu-phablet:~$&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup Wi-Fi thanks to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enter &lt;code&gt;nmtui&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;Activate a connection&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Select your SSID&lt;/li&gt;
&lt;li&gt;Enter your Wi-Fi password&lt;/li&gt;
&lt;li&gt;Push &lt;code&gt;tab&lt;/code&gt; to select &lt;code&gt;&amp;lt;Quit&amp;gt;&lt;/code&gt; then &lt;code&gt;enter&lt;/code&gt; to exit&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start the configuration script thanks to &lt;code&gt;bash helper-install-phone.sh&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Answer &lt;code&gt;y&lt;/code&gt; when prompted (twice)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The phone should reboot, then you are in! :-)&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Python script to change temperature setpoint into gcode</title>
      <link>https://notes.iopush.net/blog/2021/01-python-script-gcode-set-temperature/</link>
      <pubDate>Fri, 01 Jan 2021 00:00:00 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2021/01-python-script-gcode-set-temperature/</guid>
      <description>&lt;p&gt;Small hacky script to set regular temperature changes in 3D printer gcode, to
easily use &amp;ldquo;&lt;em&gt;Temperature towers&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
    
    
        
        
        
        
    

    
    
    

    
    







  


    

    
        &lt;p&gt;&lt;span class=&#34;image center&#34;&gt;
            &lt;img src=&#34;https://notes.iopush.net/blog/2021/01-python-script-gcode-set-temperature/temperature_tower.jpg&#34; alt=&#34;Temperature tower&#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;
            Temperature tower
        &lt;/div&gt;&lt;/p&gt;
    


&lt;p&gt;I personally use &lt;a href=&#34;https://www.thingiverse.com/thing:3127899&#34;&gt;this one&lt;/a&gt;, which is
a bit small but fast to print.&lt;/p&gt;
&lt;h1 id=&#34;usage&#34;&gt;Usage&lt;/h1&gt;
&lt;p&gt;Use is simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Slice your temperature tower with filament temperature set to the highest
temperature&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Export your gcode to a file, ex: &lt;code&gt;tower.gcode&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the python script with correct parameters:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;file&lt;/code&gt;: Input gcode file to be parsed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tower_steps&lt;/code&gt;: Tower steps in mm&lt;/li&gt;
&lt;li&gt;&lt;code&gt;temperature&lt;/code&gt;: First step temperature in degrees Celcius&lt;/li&gt;
&lt;li&gt;&lt;code&gt;temperature_step&lt;/code&gt;: Temperature steps in degree Celcius&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The generated filename is the input name with &lt;code&gt;out_&lt;/code&gt; prefix, ex:
&lt;code&gt;out_tower.gcode&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Integrated help&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There is an integrated help thanks to the &lt;code&gt;-h&lt;/code&gt; option:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;➜ python temperature.py -h
usage: temperature.py [-h] file tower_steps temperature temperature_step

positional arguments:
  file              Input GCode file to be parsed
  tower_steps       Tower steps in mm
  temperature       First step temperature in degrees °C
  temperature_step  Temperature steps in °C

optional arguments:
  -h, --help        show this help message and exit
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;➜ python temperature.py tower.gcode 8 215 5
Height 8 mm: temperature set to 215°C
Height 16 mm: temperature set to 210°C
Height 24 mm: temperature set to 205°C
Height 32 mm: temperature set to 200°C
Height 40 mm: temperature set to 195°C
Height 48 mm: temperature set to 190°C
Height 56 mm: temperature set to 185°C
Height 64 mm: temperature set to 180°C
Height 72 mm: temperature set to 175°C
Height 80 mm: temperature set to 170°C
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;code&#34;&gt;Code&lt;/h1&gt;
&lt;script type=&#34;application/javascript&#34; src=&#34;https://gist.github.com/Oliv4945/6fc57ba41e442a1c0fe78b6d830da9ee.js&#34;&gt;&lt;/script&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>Switch to static site generator: Hugo</title>
      <link>https://notes.iopush.net/blog/2020/12-static-site-generator-hugo/</link>
      <pubDate>Sat, 19 Dec 2020 00:00:00 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2020/12-static-site-generator-hugo/</guid>
      <description>&lt;p&gt;For the fifth year of this blog, I switched from &lt;a href=&#34;https://ghost.org/&#34;&gt;Ghost&lt;/a&gt; to &lt;a href=&#34;https://gohugo.io/&#34;&gt;Hugo&lt;/a&gt;. I used to like
Ghost as a small and simple tool when I started the blog.&lt;/p&gt;
&lt;p&gt;Ghost is now a powerful content management system but far more complex than the
simple tool I am looking for, even writing a full post in markdown became less
and less easy over the years. As I do not need fancy stuff and like the
simplicity to pre-generate the pages and drop the HTML files somewhere I looked
at static site generators, I gave a try to Hugo and I liked it. Let&amp;rsquo;s see what it can
do in production but I already enjoy to avoid Ghost, Node, and NPM maintenance :)&lt;/p&gt;
&lt;p&gt;This might break RSS feed thought, sorry if you receive 10 updates for old pages.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Wireguard and Pi-hole in Docker containers</title>
      <link>https://notes.iopush.net/blog/2020/wireguard-and-pi-hole-in-docker/</link>
      <pubDate>Wed, 18 Nov 2020 21:32:24 +0000</pubDate>
      
      <guid>https://notes.iopush.net/blog/2020/wireguard-and-pi-hole-in-docker/</guid>
      <description>&lt;p&gt;I had to move my previous Wireguard VPN + Pi-hole ad blocker to another server,
but this time I was not able to expose Pi-hole DNS port (53) to the host
machine. It was also better to have Wireguard VPN inside a Docker container&amp;hellip;
so I did!&lt;/p&gt;
&lt;p&gt;As a reminder, Wireguard is a stateless and easy to configure VPN: share a pair
of public keys between the client(s) and server then you are good to go!
Moreover, stateless is great when used from a phone as there is no power-hungry
keep-alive like OpenVPN, nor reconnection time when switching from Wi-FI to 4G.&lt;/p&gt;
&lt;h2 id=&#34;dns-address-issue&#34;&gt;DNS address issue&lt;/h2&gt;
&lt;p&gt;The main issue I had is the way to provide Pi-hole address to Wireguard
container: &lt;code&gt;docker-compose&lt;/code&gt; does
&lt;a href=&#34;https://github.com/docker/compose/issues/6180&#34;&gt;not yet&lt;/a&gt; accept do translate a
container name in &lt;code&gt;dns&lt;/code&gt; section. The easiest workaround is to set a fixed IP for
the Pi-hole container, not pretty, but hey&amp;hellip; it works :-)Then both services
must be in the same &lt;code&gt;docker-compose.yml&lt;/code&gt; file to avoid any issue related to a
network race condition when the docker daemon restarts.&lt;/p&gt;
&lt;h2 id=&#34;pi-hole&#34;&gt;Pi-hole&lt;/h2&gt;
&lt;p&gt;Pi-Hole configuration is straightforward and well documented on their
&lt;a href=&#34;https://hub.docker.com/r/pihole/pihole&#34;&gt;Docker Hub page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;wireguard&#34;&gt;Wireguard&lt;/h2&gt;
&lt;p&gt;Instead of creating my own Dockerfile I used the image from
&lt;a href=&#34;https://github.com/linuxserver/docker-wireguard/&#34;&gt;linuxserver.io&lt;/a&gt;, which has
been beautifully implemented. Then
&lt;a href=&#34;https://hub.docker.com/r/linuxserver/wireguard&#34;&gt;follow the documentation&lt;/a&gt;.
Thanks to Wireguard&amp;rsquo;s QR Code feature, the phone setup is dumb-proof: just scan
it from the container&amp;rsquo;s logs.&lt;/p&gt;
&lt;h2 id=&#34;docker-compose-file&#34;&gt;docker-compose file&lt;/h2&gt;
&lt;p&gt;The resulting &lt;code&gt;docker-compose&lt;/code&gt; file is:&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;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.5&amp;#34;&lt;/span&gt;

&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;wireguard&lt;/span&gt;:
    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;linuxserver/wireguard&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;depends_on&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;pihole&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;dns&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;172.29.0.2&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;cap_add&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;NET_ADMIN&lt;/span&gt;
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;SYS_MODULE&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;sysctls&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;net.ipv4.conf.all.src_valid_mark=1&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;unless-stopped&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;../../data/wireguard:/config&lt;/span&gt;
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;/lib/modules:/lib/modules&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;51820&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;51820&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;/udp&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;TZ=Europe/Paris&lt;/span&gt;
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;SERVERURL=host_server.yourdomain.com&lt;/span&gt;
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;SERVERPORT=1194&lt;/span&gt;
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;PEERS=Android_phone&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;networks&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;network-pihole&lt;/span&gt;

  &lt;span style=&#34;color:#f92672&#34;&gt;pihole&lt;/span&gt;:
    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pihole/pihole:latest&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;../../data/pi-hole/etc/:/etc/pihole/&lt;/span&gt;
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;../../data/pi-hole/dnsmasq.d:/etc/dnsmasq.d&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:
      &lt;span style=&#34;color:#f92672&#34;&gt;TZ&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Europe/Paris&amp;#34;&lt;/span&gt;
      &lt;span style=&#34;color:#f92672&#34;&gt;PROXY_LOCATION&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pihole&lt;/span&gt;
      &lt;span style=&#34;color:#f92672&#34;&gt;VIRTUAL_HOST&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pihole.yourdomain.com&lt;/span&gt;
      &lt;span style=&#34;color:#f92672&#34;&gt;VIRTUAL_PORT&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;
      &lt;span style=&#34;color:#f92672&#34;&gt;LETSENCRYPT_EMAIL&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;email@yourdomain.com&lt;/span&gt;
      &lt;span style=&#34;color:#f92672&#34;&gt;LETSENCRYPT_HOST&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pihole.yourdomain.com&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;unless-stopped&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;networks&lt;/span&gt;:
      &lt;span style=&#34;color:#f92672&#34;&gt;network-pihole&lt;/span&gt;:
        &lt;span style=&#34;color:#f92672&#34;&gt;ipv4_address&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;172.29.0.2&lt;/span&gt;

&lt;span style=&#34;color:#f92672&#34;&gt;networks&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;network-pihole&lt;/span&gt;:
    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dns-pihole&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
  </channel>
</rss>
