openpreppad.html 14 KB

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