<!DOCTYPE html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta name="generator" content="Hugo 0.69.2" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/assets/css/theme.css"> <link rel="alternate" href="/rss.xml" type="application/rss+xml" title="Pleasant Programmer"> <script type="text/javascript" src="//use.typekit.net/iwm5axp.js"></script> <script type="text/javascript">try{Typekit.load();}catch(e){}</script> <title>OpenPrepPad - Pleasant Programmer</title> </head> <body> <header id="header" role="banner"> <div id="thomas"> <img src="/assets/img/thomas.gif" alt="DJ THOMAS IN DA HAUS"> <img src="/assets/img/thomas.png" alt="Pleasant Programmer"> </div> <h1 class="site-title"><a href="/">Pleasant Programmer</a></h1> <nav id="menu" role="navigation"> <ul> <li class="twitter"> <a href="http://twitter.com/pleasantprog">@pleasantprog</a> </li> <li><a href="/pages/projects.html">projects</a></li> <li><a href="/posts.html">archives</a></li> <li><a href="/tags.html">tags</a></li> <li><a href="/rss.xml">rss</a></li> </ul> </nav> </header> <div id="container"> <main id="content" role="main"> <article itemscope itemtype="http://schema.org/BlogPosting"> <h1 class="p-name entry-title" itemprop="headline name"> <a href="/posts/openpreppad.html">OpenPrepPad</a></h1> <small> <span class="dateline">Posted: <time itemprop="datePublished" datetime="2017-01-15">2017-01-15</time></span> | More posts about <a class="tag p-category" href="/tags/hardware.html" rel="tag"> hardware </a> <a class="tag p-category" href="/tags/bluetooth.html" rel="tag"> bluetooth </a> </small> <div class="e-content entry-content" itemprop="entry-text"> <p>Smart electronics and IoT (Internet of Things) are all the rage these days. You have a lot of companies sprout up trying to make the next big thing, which also leads to a lot of failures big and small. Pebble, the maker of my smartwatch, got bought out by Fitbit recently. This left watch owners without any official support, but thankfully, community members <a href="http://rebble.io/">stepped up</a> to continue maintaining it.</p> <p>Another casualty of the IoT boom was the <a href="http://theorangechef.com/">Orange Chef</a> <a href="https://www.amazon.com/Orange-Chef-Smart-Scale-Silver/dp/B00KFW8L90">Prep Pad</a>. It’s a bluetooth connected weighing scale to make it easy to track your calories and carb/fat/protein intake. My dad bought it last year only to find out that the app was incredibly buggy. The search function doesn’t work which makes the whole thing practically useless. I also found out later that you can’t even download the app to use the scale anymore.</p> <p><strong>Note</strong> I just found out as I was writing this post that it <em>may</em> get supported by <a href="http://www.prnewswire.com/news-releases/perfect-company-acquires-orange-chefs-prep-pad-related-ip-continues-momentum-in-the-connected-kitchen-300383178.html">another company</a>.</p> <p>So the app is useless, but at least you can use it as a scale, right?</p> <p><img src="/galleries/openpreppad/preppad.jpg" alt="Prep Pad"></p> <p>Nope. The device has no display whatsoever. The only controls on it are the on/off button and a green LED that isn’t even that useful at telling you whether it’s on or not. At this point, it’s just a giant paperweight.</p> <h2 id="reverse-engineering">Reverse Engineering</h2> <p>Since I essentially had nothing to lose, I tried poking at the thing to figure out how it works. I didn’t really have experience with bluetooth besides trying to get my bluetooth mouse connected on Linux. The main thing I used then was <code>bluetoothctl</code> which is essentially a CLI for managing bluetooth devices so I started there.</p> <p>I started up <code>bluetoothctl</code> and turned on the Prep Pad. And it showed up!</p> <div class="highlight"><pre style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[bluetooth]# power on [CHG] Controller ... Class: 0x00010c Changing power on succeeded [CHG] Controller ... Powered: yes [bluetooth]# scan on Discovery started [CHG] Device 1C:BA:8C:21:7C:BB RSSI: -51 [CHG] Device 1C:BA:8C:21:7C:BB Name: CHSLEEV_00 [CHG] Device 1C:BA:8C:21:7C:BB Alias: CHSLEEV_00 </code></pre></div><p>I then connected to it, which was surprisingly easy.</p> <div class="highlight"><pre style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[bluetooth]# connect 1C:BA:8C:21:7C:BB Attempting to connect to 1C:BA:8C:21:7C:BB [CHG] Device 1C:BA:8C:21:7C:BB Connected: yes [CHG] Device 1C:BA:8C:21:7C:BB Name: CH BTScale_00 [CHG] Device 1C:BA:8C:21:7C:BB Alias: CH BTScale_00 </code></pre></div><p>Now normally, when you turn the device on, the green light flashes occasionally. Once I connected to it, the green light stayed on permanently. Clearly, I was making progress. A lot of services were also discovered but I had no idea what those things were at that point.</p> <p>After a lot of poking around, I could check the general device information. You could get the hardware, software and firmware version. There’s also the device serial number which was nowhere on the actual physical device.</p> <div class="highlight"><pre style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[CHSLEEV_00]# select-attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 [CH BTScale_00:/service0010/char0017]# attribute-info Characteristic - Firmware Revision String UUID: 00002a26-0000-1000-8000-00805f9b34fb Service: /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010 Value: 0x31 Value: 0x2e Value: 0x31 Value: 0x33 Value: 0x41 Value: 0x00 Flags: read [CH BTScale_00:/service0010/char0017]# read Attempting to read /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x31 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x2e [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x31 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x33 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x41 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x00 31 2e 31 33 41 00 1.13A. [CH BTScale_00:/service0010/char0017]# </code></pre></div><p>There was also a service which contained Accel Enable, Accel Range, Accel X-Coordinate, Accel Y-Coordinate, and Accel Z-Coordinate. I guess it stands for accelerometer, which is probably what it uses to weigh things.</p> <div class="highlight"><pre style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[CHSLEEV_00]# select-attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 [CH BTScale_00:/service0023/char0024/desc0026]# read Attempting to read /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x41 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x63 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x63 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x65 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x6c [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x20 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x45 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x6e [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x61 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x62 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x6c [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x65 41 63 63 65 6c 20 45 6e 61 62 6c 65 Accel Enable </code></pre></div><p>I couldn’t read from any of the Accel Coordinates. It kept saying permission denied. I could however, notify on them. But that didn’t yield anything as well. What I <em>could</em> read was Accel Enable, which was set to 00. I guess that means it was off. After writing 01 to Accel Enable, I found I could get values out of Accel X-Coordinate! Also, the green LED which was permanently on turned off.</p> <div class="highlight"><pre style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[CHSLEEV_00]# select-attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024 [CH BTScale_00:/service0023/char0024]# write 01 Attempting to write /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024 [CH BTScale_00:/service0023/char0024]# select-attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a [CH BTScale_00:/service0023/char002a]# notify on [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Notifying: yes Notify started [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x5b [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0xa3 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x02 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x00 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x55 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0xa3 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x02 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x00 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x59 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0xa3 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x02 [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x00 </code></pre></div><p>I tried pressing the scale down a few times, and the values changed accordingly. Now, I just had to figure out how to convert the values into grams. It looked like the values were 32-bit integers sent as 4 bytes. In the above example it would be <code>0x0002a35b</code>, <code>0x0002a355</code>, <code>0x0002a359</code> or 172891, 172855, 172899. The values also decrease as you exert more effort on the scale. So assuming you take the initial value as <em>tare</em>, you simply subtract any succeeding value from that <em>tare</em> and you get the “weight”.</p> <p>The values I got didn’t seem to be in grams though. After weighing some things on an actual scale and comparing the values I got, I found I can just divide the values by 14 and get something in grams. That 14 is entirely a magic number though and I have no idea whether other Prep Pad’s would have the same constant.</p> <h2 id="openpreppad">OpenPrepPad</h2> <p>With all that figured out, I went ahead and made a <a href="https://github.com/thatsmydoing/openpreppad">simple CLI application</a> to interface with the Prep Pad. Ironically, node was the simplest thing I found that had <a href="https://github.com/sandeepmistry/noble">nice bluetooth library support</a> so that’s what I wrote it in. I also added most of the technical details in the README for that as well.</p> <p>While this is all well and cool, I doubt the intersection of Linux users and people who <!-- raw HTML omitted -->got ripped off<!-- raw HTML omitted --> bought the Prep Pad is anyone besides me. In light of that, I’m in the process of making a React Native version of the app, but that’s still a work in progress. Who knows, if the new owners of Prep Pad are good, I might not even need to finish it.</p> </div> <aside class="postpromonav"> <nav> <ul class="pager clearfix"> <li class="previous"> <a href="/posts/haproxy-charset.html" rel="prev" title="Haproxy Charset">← Previous post</a> </li> <li class="next"> <a href="/posts/audventure.html" rel="next" title="Audventure">Next post →</a> </li> </ul> </nav> </aside> <section class="comments"> <script data-isso="https://isso.pleasantprogrammer.com/" data-isso-require-author="true" data-isso-vote="false" src="https://isso.pleasantprogrammer.com/js/embed.min.js"> </script> <section id="isso-thread"></section> </section> </article> </main> <footer id="footer" role="contentinfo"> <p> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/deed.en_US"> <img alt="CC-BY-SA" style="border-width:0" src="https://licensebuttons.net/l/by-sa/3.0/80x15.png"> </a> © 2020 Thomas Dy - Powered by <a href="http://gohugo.io">Hugo</a></p> </footer> </div> <script src="/assets/js/konami.js"></script> <script> var easter_egg = new Konami(); easter_egg.code = function() { var el = document.getElementById('thomas'); if(el.className == "whoa") { el.className = ""; } else { el.className = "whoa"; } document.body.scrollTop = document.documentElement.scrollTop = 0; } easter_egg.load(); </script> </body> </html>