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

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

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



    
    
        
        
        
        
    

    
    
    

    
    







  


    

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


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



    
    
        
        
        
        
    

    
    
    

    
    







  


    

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


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



    
    
        
        
        
        
    

    
    
    

    
    







  


    

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


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



    
    
        
        
        
        
    

    
    
    

    
    







  


    

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


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



    
    
        
        
        
        
    

    
    
    

    
    







  


    

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


&lt;pre&gt;&lt;code&gt;| Value | Displayed        |           Hublol         |         Trendline        |
|  Hex  | temperature (°C) | temperature (°C) | delta | temperature (°C) | delta |
+ ----- + ---------------- + ---------------- + ----- + ---------------- + ----- +
| 4080  |       2.0        |        -0.80     |  2.8  |         2.4      | -0.4  |
| 4500  |      10.2        |         8.20     |  2.0  |        10.2      |    0  |
| 4600  |      11.9        |        10.20     |  1.7  |        11.9      |    0  |
| 4700  |      13.7        |        12.20     |  1.5  |        13.7      |    0  |
| 4800  |      15.4        |        14.20     |  1.2  |        15.4      | -0.1  |
| 4900  |      17.2        |        16.20     |  1.0  |        17.2      |    0  |
| 4A00  |      18.8        |        18.20     |  0.6  |        18.9      | -0.1  |
| 4B00  |      20.5        |        20.20     |  0.3  |        20.7      | -0.1  |
| 4C00  |      22.4        |        22.20     |  0.2  |        22.4      |    0  |
| 4D00  |      24.0        |        24.20     | -0.2  |        24.1      | -0.1  |
| 4E00  |      25.6        |        26.20     | -0.6  |        25.9      | -0.3  |
| 4EAD  |      26.8        |        27.55     | -0.8  |        27.0      | -0.2  |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;=&amp;gt; The function is &lt;code&gt;encoded_value = temperature_celsius * 0.0068 - 109.91&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&#34;6-code&#34;&gt;6. Code&lt;/h1&gt;
&lt;p&gt;The library to create the payload, as well as the whitening and CRC, is on available on &lt;a href=&#34;https://gitlab.com/oliv4945/rika-temperature-sensor-encoding&#34;&gt;Gitlab&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;7-conclusion&#34;&gt;7. Conclusion&lt;/h1&gt;
&lt;p&gt;I am now able to replace Rika&amp;rsquo;s temperature sensor, so I will be able to create a &amp;ldquo;smart thermostat&amp;rdquo; and remotely control my stove to rise the temperature when I am returning from vacation, or prevent its start when the sun will heat the house in the next hour or so. Next step is to create a dedicated board to be able to control the remote from LoRaWAN.&lt;/p&gt;
&lt;p&gt;I tested it against Rika pellet stove Filo and Sumo, but I am surprised that the temperature encoding differs so much from Hublol&amp;rsquo;s findings; he might have a more recent stove where they changed the electronics, I will ask him&amp;hellip;&lt;/p&gt;</description>
    </item>
    
  </channel>
</rss>
