openpreppad.html 14 KB

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