+++ date = "2017-01-15T19:31:00+08:00" title = "OpenPrepPad" tags = [ "hardware", "bluetooth" ] +++ 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 [stepped up][1] to continue maintaining it. Another casualty of the IoT boom was the [Orange Chef][2] [Prep Pad][3]. 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. **Note** I just found out as I was writing this post that it *may* get supported by [another company][4]. So the app is useless, but at least you can use it as a scale, right? ![Prep Pad](/galleries/openpreppad/preppad.jpg) 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. ## Reverse Engineering 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 `bluetoothctl` which is essentially a CLI for managing bluetooth devices so I started there. I started up `bluetoothctl` and turned on the Prep Pad. And it showed up! ```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 ``` I then connected to it, which was surprisingly easy. ```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 ``` 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. 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. ```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]# ``` 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. ```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 ``` 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 *could* 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. ```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 ``` 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 `0x0002a35b`, `0x0002a355`, `0x0002a359` or 172891, 172855, 172899. The values also decrease as you exert more effort on the scale. So assuming you take the initial value as *tare*, you simply subtract any succeeding value from that *tare* and you get the "weight". 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. ## OpenPrepPad With all that figured out, I went ahead and made a [simple CLI application][5] to interface with the Prep Pad. Ironically, node was the simplest thing I found that had [nice bluetooth library support][6] so that's what I wrote it in. I also added most of the technical details in the README for that as well. While this is all well and cool, I doubt the intersection of Linux users and people who got ripped off 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. [1]: http://rebble.io/ [2]: http://theorangechef.com/ [3]: https://www.amazon.com/Orange-Chef-Smart-Scale-Silver/dp/B00KFW8L90 [4]: http://www.prnewswire.com/news-releases/perfect-company-acquires-orange-chefs-prep-pad-related-ip-continues-momentum-in-the-connected-kitchen-300383178.html [5]: https://github.com/thatsmydoing/openpreppad [6]: https://github.com/sandeepmistry/noble