openpreppad.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. <!DOCTYPE html>
  2. <html lang="en-us">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="generator" content="Hugo 0.88.0" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <link rel="stylesheet" href="/assets/css/theme.css">
  8. <link rel="alternate" href="/rss.xml" type="application/rss+xml" title="Pleasant Programmer">
  9. <script type="text/javascript" src="//use.typekit.net/iwm5axp.js"></script>
  10. <script type="text/javascript">try{Typekit.load();}catch(e){}</script>
  11. <title>OpenPrepPad - Pleasant Programmer</title>
  12. </head>
  13. <body>
  14. <header id="header" role="banner">
  15. <div id="thomas">
  16. <img src="/assets/img/thomas.gif" alt="DJ THOMAS IN DA HAUS">
  17. <img src="/assets/img/thomas.png" alt="Pleasant Programmer">
  18. </div>
  19. <h1 class="site-title"><a href="/">Pleasant Programmer</a></h1>
  20. <nav id="menu" role="navigation">
  21. <ul>
  22. <li class="twitter">
  23. <a href="http://twitter.com/pleasantprog">@pleasantprog</a>
  24. </li>
  25. <li><a href="/pages/projects.html">projects</a></li>
  26. <li><a href="/posts.html">archives</a></li>
  27. <li><a href="/tags.html">tags</a></li>
  28. <li><a href="/rss.xml">rss</a></li>
  29. </ul>
  30. </nav>
  31. </header>
  32. <div id="container">
  33. <main id="content" role="main">
  34. <article itemscope itemtype="http://schema.org/BlogPosting">
  35. <h1 class="p-name entry-title" itemprop="headline name">
  36. <a href="/posts/openpreppad.html">OpenPrepPad</a></h1>
  37. <small>
  38. <span class="dateline">Posted: <time itemprop="datePublished" datetime="2017-01-15">2017-01-15</time></span>
  39. | More posts about
  40. <a class="tag p-category" href="/tags/hardware.html" rel="tag">
  41. hardware
  42. </a>
  43. <a class="tag p-category" href="/tags/bluetooth.html" rel="tag">
  44. bluetooth
  45. </a>
  46. </small>
  47. <div class="e-content entry-content" itemprop="entry-text">
  48. <p>Smart electronics and IoT (Internet of Things) are all the rage these days. You
  49. have a lot of companies sprout up trying to make the next big thing, which also
  50. leads to a lot of failures big and small. Pebble, the maker of my smartwatch,
  51. got bought out by Fitbit recently. This left watch owners without any official
  52. support, but thankfully, community members <a href="http://rebble.io/">stepped up</a> to continue
  53. maintaining it.</p>
  54. <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&rsquo;s a
  55. bluetooth connected weighing scale to make it easy to track your calories and
  56. carb/fat/protein intake. My dad bought it last year only to find out that the
  57. app was incredibly buggy. The search function doesn&rsquo;t work which makes the whole
  58. thing practically useless. I also found out later that you can&rsquo;t even download
  59. the app to use the scale anymore.</p>
  60. <p><strong>Note</strong> I just found out as I was writing this post that it <em>may</em> get supported
  61. 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>
  62. <p>So the app is useless, but at least you can use it as a scale, right?</p>
  63. <p><img src="/galleries/openpreppad/preppad.jpg" alt="Prep Pad"></p>
  64. <p>Nope. The device has no display whatsoever. The only controls on it are the
  65. on/off button and a green LED that isn&rsquo;t even that useful at telling you whether
  66. it&rsquo;s on or not. At this point, it&rsquo;s just a giant paperweight.</p>
  67. <h2 id="reverse-engineering">Reverse Engineering</h2>
  68. <p>Since I essentially had nothing to lose, I tried poking at the thing to figure
  69. out how it works. I didn&rsquo;t really have experience with bluetooth besides trying
  70. to get my bluetooth mouse connected on Linux. The main thing I used then was
  71. <code>bluetoothctl</code> which is essentially a CLI for managing bluetooth devices so I
  72. started there.</p>
  73. <p>I started up <code>bluetoothctl</code> and turned on the Prep Pad. And it showed up!</p>
  74. <div class="highlight"><pre tabindex="0" 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
  75. [CHG] Controller ... Class: 0x00010c
  76. Changing power on succeeded
  77. [CHG] Controller ... Powered: yes
  78. [bluetooth]# scan on
  79. Discovery started
  80. [CHG] Device 1C:BA:8C:21:7C:BB RSSI: -51
  81. [CHG] Device 1C:BA:8C:21:7C:BB Name: CHSLEEV_00
  82. [CHG] Device 1C:BA:8C:21:7C:BB Alias: CHSLEEV_00
  83. </code></pre></div><p>I then connected to it, which was surprisingly easy.</p>
  84. <div class="highlight"><pre tabindex="0" 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
  85. Attempting to connect to 1C:BA:8C:21:7C:BB
  86. [CHG] Device 1C:BA:8C:21:7C:BB Connected: yes
  87. [CHG] Device 1C:BA:8C:21:7C:BB Name: CH BTScale_00
  88. [CHG] Device 1C:BA:8C:21:7C:BB Alias: CH BTScale_00
  89. </code></pre></div><p>Now normally, when you turn the device on, the green light flashes occasionally.
  90. Once I connected to it, the green light stayed on permanently. Clearly, I was
  91. making progress. A lot of services were also discovered but I had no idea what
  92. those things were at that point.</p>
  93. <p>After a lot of poking around, I could check the general device information. You
  94. could get the hardware, software and firmware version. There&rsquo;s also the device
  95. serial number which was nowhere on the actual physical device.</p>
  96. <div class="highlight"><pre tabindex="0" 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
  97. [CH BTScale_00:/service0010/char0017]# attribute-info
  98. Characteristic - Firmware Revision String
  99. UUID: 00002a26-0000-1000-8000-00805f9b34fb
  100. Service: /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010
  101. Value: 0x31
  102. Value: 0x2e
  103. Value: 0x31
  104. Value: 0x33
  105. Value: 0x41
  106. Value: 0x00
  107. Flags: read
  108. [CH BTScale_00:/service0010/char0017]# read
  109. Attempting to read /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017
  110. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x31
  111. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x2e
  112. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x31
  113. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x33
  114. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x41
  115. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x00
  116. 31 2e 31 33 41 00 1.13A.
  117. [CH BTScale_00:/service0010/char0017]#
  118. </code></pre></div><p>There was also a service which contained Accel Enable, Accel Range, Accel
  119. X-Coordinate, Accel Y-Coordinate, and Accel Z-Coordinate. I guess it stands for
  120. accelerometer, which is probably what it uses to weigh things.</p>
  121. <div class="highlight"><pre tabindex="0" 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
  122. [CH BTScale_00:/service0023/char0024/desc0026]# read
  123. Attempting to read /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026
  124. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x41
  125. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x63
  126. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x63
  127. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x65
  128. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x6c
  129. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x20
  130. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x45
  131. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x6e
  132. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x61
  133. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x62
  134. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x6c
  135. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x65
  136. 41 63 63 65 6c 20 45 6e 61 62 6c 65 Accel Enable
  137. </code></pre></div><p>I couldn&rsquo;t read from any of the Accel Coordinates. It kept saying permission
  138. denied. I could however, notify on them. But that didn&rsquo;t yield anything as well.
  139. What I <em>could</em> read was Accel Enable, which was set to 00. I guess that means it
  140. was off. After writing 01 to Accel Enable, I found I could get values out of
  141. Accel X-Coordinate! Also, the green LED which was permanently on turned off.</p>
  142. <div class="highlight"><pre tabindex="0" 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
  143. [CH BTScale_00:/service0023/char0024]# write 01
  144. Attempting to write /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024
  145. [CH BTScale_00:/service0023/char0024]# select-attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a
  146. [CH BTScale_00:/service0023/char002a]# notify on
  147. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Notifying: yes
  148. Notify started
  149. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x5b
  150. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0xa3
  151. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x02
  152. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x00
  153. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x55
  154. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0xa3
  155. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x02
  156. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x00
  157. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x59
  158. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0xa3
  159. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x02
  160. [CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x00
  161. </code></pre></div><p>I tried pressing the scale down a few times, and the values changed accordingly.
  162. Now, I just had to figure out how to convert the values into grams. It looked
  163. like the values were 32-bit integers sent as 4 bytes. In the above example it
  164. would be <code>0x0002a35b</code>, <code>0x0002a355</code>, <code>0x0002a359</code> or 172891, 172855, 172899. The
  165. values also decrease as you exert more effort on the scale. So assuming you take
  166. the initial value as <em>tare</em>, you simply subtract any succeeding value from that
  167. <em>tare</em> and you get the &ldquo;weight&rdquo;.</p>
  168. <p>The values I got didn&rsquo;t seem to be in grams though. After weighing some things
  169. on an actual scale and comparing the values I got, I found I can just divide the
  170. values by 14 and get something in grams. That 14 is entirely a magic number
  171. though and I have no idea whether other Prep Pad&rsquo;s would have the same constant.</p>
  172. <h2 id="openpreppad">OpenPrepPad</h2>
  173. <p>With all that figured out, I went ahead and made a <a href="https://github.com/thatsmydoing/openpreppad">simple CLI application</a>
  174. to interface with the Prep Pad. Ironically, node was the simplest thing I found
  175. that had <a href="https://github.com/sandeepmistry/noble">nice bluetooth library support</a> so that&rsquo;s what I wrote it in. I
  176. also added most of the technical details in the README for that as well.</p>
  177. <p>While this is all well and cool, I doubt the intersection of Linux users and
  178. people who <!-- raw HTML omitted -->got ripped off<!-- raw HTML omitted --> bought the Prep Pad is anyone besides me. In
  179. light of that, I&rsquo;m in the process of making a React Native version of the app,
  180. but that&rsquo;s still a work in progress. Who knows, if the new owners of Prep Pad
  181. are good, I might not even need to finish it.</p>
  182. </div>
  183. <aside class="postpromonav">
  184. <nav>
  185. <ul class="pager clearfix">
  186. <li class="previous">
  187. <a href="/posts/haproxy-charset.html" rel="prev" title="Haproxy Charset">&larr; Previous post</a>
  188. </li>
  189. <li class="next">
  190. <a href="/posts/audventure.html" rel="next" title="Audventure">Next post &rarr;</a>
  191. </li>
  192. </ul>
  193. </nav>
  194. </aside>
  195. <section class="comments">
  196. <script
  197. data-isso="https://isso.pleasantprogrammer.com/"
  198. data-isso-require-author="true"
  199. data-isso-vote="false"
  200. src="https://isso.pleasantprogrammer.com/js/embed.min.js">
  201. </script>
  202. <section id="isso-thread"></section>
  203. </section>
  204. </article>
  205. </main>
  206. <footer id="footer" role="contentinfo">
  207. <p>
  208. <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/deed.en_US">
  209. <img alt="CC-BY-SA" style="border-width:0" src="https://licensebuttons.net/l/by-sa/3.0/80x15.png">
  210. </a> &copy; 2020 Thomas Dy - Powered by <a href="http://gohugo.io">Hugo</a></p>
  211. </footer>
  212. </div>
  213. <script src="/assets/js/konami.js"></script>
  214. <script>
  215. var easter_egg = new Konami();
  216. easter_egg.code = function() {
  217. var el = document.getElementById('thomas');
  218. if(el.className == "whoa") {
  219. el.className = "";
  220. }
  221. else {
  222. el.className = "whoa";
  223. }
  224. document.body.scrollTop = document.documentElement.scrollTop = 0;
  225. }
  226. easter_egg.load();
  227. </script>
  228. </body>
  229. </html>