oliexdev / openScale

Open-source weight and body metrics tracker, with support for Bluetooth scales
GNU General Public License v3.0
1.69k stars 296 forks source link

Wyze Scale (WHSCL1) Support #853

Open HerbFargus opened 2 years ago

HerbFargus commented 2 years ago

Wyze Scale (WHSCL1)

Vendor App: https://play.google.com/store/apps/details?id=com.hualai&hl=en_US&gl=US

Product Page https://www.wyze.com/products/wyze-scale

Step 1: Read the general reverse engineer process

Step 2: Acquiring some Bluetooth traffic Attach 3 log files with the corresponding true values, read here for further information.

  1. Bluetooth HCI Snoop log file user settings in the vendors app:
    sex male, body height: 6'4" ft, Year of Birth 1991

    measured true values in the vendors app for the 1. HCI Snoop log file:

Number 1
Date and Time 2022.05.05 09:27 PM
Weight 168.4lb
BMI 20.5
Body Fat 15.1%
Muscle Mass 134.2lb
Body Water 62.2%
Lean Body Mass 143.0lb
Bone Mass 8.8lb
Protein 17.5%
Visceral Fat 7
BMR 1771
Metabolic Age 27

Log 1: btsnoop_hci_168.4.log

  1. Bluetooth HCI Snoop log file user settings in the vendors app:
    sex male, body height: 6'4" ft, Year of Birth 1991

    measured true values in the vendors app for the 2. HCI Snoop log file:

Number 2
Date and Time 2022.05.05 09:31 PM
Weight 188.7lb
BMI 23.0
Body Fat 21.4%
Muscle Mass 139.3lb
Body Water 57.6%
Lean Body Mass 148.3lb
Bone Mass 9.0lb
Protein 16.2%
Visceral Fat 8
BMR 1823
Metabolic Age 27

Log 2: btsnoop_hci_188.7.log

  1. Bluetooth HCI Snoop log file user settings in the vendors app:
    sex male, body height: 6'4" ft, Year of Birth 1991

    measured true values in the vendors app for the 3. HCI Snoop log file:

Number 3
Date and Time 2022.05.05 09:35 PM
Weight 209.2lb
BMI 25.5
Body Fat 29.5%
Muscle Mass 138.4lb
Body Water 51.6%
Lean Body Mass 147.5lb
Bone Mass 9.0lb
Protein 14.5%
Visceral Fat 9
BMR 1815
Metabolic Age 29

Log 3: btsnoop_hci_209.2.log

Step 3: Discover Bluetooth services and characteristic Read here how to create the openScale debug file

OpenScale Log: openScale_2022-05-05_13-39[1].txt

BLE Scanner: WHSCL1DeviceInfo.txt

Wyze API example (from a separate project, may not be relevant for this but found it interesting) https://github.com/JoshuaMulliken/ha-wyzeapi/issues/93#issuecomment-970230075 ScaleVariables.txt

karanrajpal14 commented 1 year ago

So I'm trying to fetch the logs for the Wyze Scale X, but I wonder how you made sense of the data. Opening the btsnoop_hci.log in notepad results in gibberish and when I open it up in wireshark, I do see my phone and my device listed there, but I can't find the packets in which my weight or other details are listed. Mind helping me out?

HerbFargus commented 1 year ago

As the data in the logs is often obfuscated or in byte code I used the wyze app to pull the values associated with the logs eg I started the logging, weighed myself, noted the values in the wyze app, stopped the logging, saved the log, rinse and repeat etc. In theory logical data should be able to be derived from a comparison of the resulting tables and the logs but I didn't get much further than gathering the data as I moved on to other projects. I left the logs here as a basepoint for others to compare against. As a note I have the original wyze scale, don't know how much the API or Bluetooth logs differ between this and the X.

aatifsumar commented 1 year ago

I have both the OG scale and the Scale X, and would be happy to help y'all do any testing necessary

famewolf commented 9 months ago

Has adding this particular Hardware been abandoned?

JesusFreke commented 8 months ago

here's a hand-annotated protocol dump for you :)


-------------------------------------------------------------------------------
Send public key to scale
> 00f000089ad9fd9600000000
(public key = 0x96FDD99A)

-------------------------------------------------------------------------------

received public key from scale
< 42f000089cebc88600000000
(public key = 0x86C8EB9C)

-------------------------------------------------------------------------------

send CMD_SYNC_TIME
(raw)
> [22, 0, 7, 0, 1, -88, -85, -58, -68, 101, 1]
(rawhex)
> 16 00 07 00 01 A8 AB C6 BC 65 01
(encrypted)
> 1101000bd2d3e619fd6e58d6dfb23437dbc5486a

time = 0x65BCC6AB = time in seconds since epoch = Friday, February 2, 2024 10:40:43 AM GMT
os = 0x01  (probably specifies the type of timestamp? 0x01 being unix timestamps?)

-------------------------------------------------------------------------------

receive sync type reply
(raw)
< 53010007aff48a08e48a47ff
(unencrypted)
< 2201030001a800

last byte = 00 = success

-------------------------------------------------------------------------------

send CMD_USER_LIST_NEW

(raw)
> [22, 0, 2, 0, 13, -88]
(encrypted)
> 1201000668e95d0a577b99ff

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 54010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_USER_LIST_NEW response

(raw)
< 55010020542e23a5086cd3aa4fd800f6c5846ad1e40f592000525f04ed8cc484d0ddd71a
(unencrypted)
< 22011c000da801 2f319e4a8a8db394f3fa7ef7f9fdaa7f a618 01 2c b4 01 00 440c

user id = 2f319e4a8a8db394f3fa7ef7f
weight = 18A6 = 6310/100 = 63.1kg
sex = 1 = M
age = 2c = 44
height = b4 = 180cm = ~5'11"
athlete mode = 1
only weight = 0
last impedence = 0c44 = 3140

-------------------------------------------------------------------------------

send CMD_UPDATE_USER

(raw)
> [22, 0, 27, 0, 10, -88, 47, 49, -98, 74, -118, -115, -77, -108, -13, -6, 126, -9, -7, -3, -86, 127, -100, 24, 1, 44, -76, 1, 0, 68, 12]
(raw hex)
> 1601B000AA8 2F319E4A8A8DB394F3FA7EF7F9FDAA7F 9C18 01 2C B4 01 00 440C
(same data format as CMD_USER_LIST_NEW above)
(encrypted)
> 1301001f238da6606738035f7a0b9e248c4425eee9abcef013ec18704b00a25a67b61b97

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 56010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_UPDATE_USER response

(raw)
< 5701000784ca88c0aa083ca5
(unencrypted)
< 220103000aa800

last byte = 00 = success

-------------------------------------------------------------------------------

send CMD_CURRENT_USER_NEW

(raw)
> [22, 0, 27, 0, 14, -88, 47, 49, -98, 74, -118, -115, -77, -108, -13, -6, 126, -9, -7, -3, -86, 127, 0, 0, 1, 44, -76, 1, 0, 68, 12]
(rawhex)
> 16001B000EA8 2F319E4A8A8DB394F3FA7EF7F9FDAA7F 0000 01 2C B4 01 00 440C
(same data format as CMD_USER_LIST_NEW above)

(encrypted)
> 1401001f1bed79bee2fa41fe7a0b9e248c4425ee8502f6a177eb46dd4b00a25a67b61b97

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 58010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_CURRENT_USER_NEW response

(raw)
< 59010007074cec7f57017c55
(unencrypted)
< 220103000ea800

last byte = 00 = success

-------------------------------------------------------------------------------

received CMD_HISTORY_WEIGHT_DATA message

(raw)
5a010035eff26c5502366821b6dfd8281e9021297835b63beb35103b4f3873cc93d4251d09e4bd155a1416685d1594d262adf844c466b564917154c6
(unencrypted)
2201310009a801 5859bb65 2f319e4a8a8db394f3fa7ef7f9fdaa7f 01 2c b4 01 00 b018 440c 3200 3302 25 b702 c400 5802 06 8206 29 c300

timestamp = 0x65bb5958  = 1706776920 (seconds since epoch) =  Thursday, February 1, 2024 8:42:00 AM
user id = 2f319e4a8a8db394f3fa7ef7f9fdaa7f
sex = 01 = M
age = 2C = 44
height = b4 = 180cm
athlete mode = 01 = true
only weight = 00 = false
weight = 0x18b0 = 63.2kg
impedance = 0c44 = 3140
bfp = 0x0032
muscleMass = 0x0233
boneMass = 0x25
water = 0x02b7
protein = 0x00c4
lbm = 0x0258
vfal = 0x06
bmr = 0x0682
bodyAge = 0x29 = 41
bmi = 0x00c3 = 195/10 = 19.5

-------------------------------------------------------------------------------

sending CMD_HISTORY_WEIGHT_DATA response
(I believe this is what causes the scale to delete this weight record from its cache)

> (raw)
[22, 0, 3, 0, 9, -88, 0]
> (encrypted)
15010007cfe3996cd84441fe

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 5b010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

received CMD_HISTORY_WEIGHT_DATA message

(raw)
< 5c010035a032ddbcf744f3c32428de44c0f974ab7835b63beb35103b4f3873cc93d4251dc0087481fa43d47eea5c20685e15c628dfe5e6bd2ae334f8
(unencrypted)
< 2201310009a801c09abc652f319e4a8a8db394f3fa7ef7f9fdaa7f012cb40100a6180000000000000000000000000000000000c300

-------------------------------------------------------------------------------

sending CMD_HISTORY_WEIGHT_DATA response

(raw)
> [22, 0, 3, 0, 9, -88, 0]
(encrypted)
> 16010007cfe3996cd84441fe

-------------------------------------------------------------------------------

more uninteresting empty CMD_CUR_WEIGHT_DATA messages

(encrypted)
5d010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(encrypted)
5e010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(encrypted)
5f010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

sending CMD_SET_UNIT command

(raw)
> [22, 0, 3, 0, 4, -88, 1]
(encrypted)
> 17010007ab0e171ea32daa02

1 = lb, 0 = kg?

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA messages

(raw)
< 50010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
< 51010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
<22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

------------------------------------------------------------------------------

CMD_SET_UNIT response

(raw)
< 520100074ef5ff79730a6d8d
(unencrypted)
< 2201030004a800

last byte = 00 = success

-------------------------------------------------------------------------------

send CMD_SET_HELLO

(raw)
> [22, 0, 3, 0, 5, -88, 0]
(encrypted)
> 180100077d672d3be2b4d174

0 = no hello?

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 53010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_SET_HELLO response

(raw)
< 5401000739f2a50482b55de6
(unencrypted)
< 2201030005a800

last byte = 00 = success

-------------------------------------------------------------------------------

send CMD_BROAD_TIME
(broadcast time.. whatever that is)

(raw)
> [22, 0, 4, 0, 7, -88, 0, 0]
(encrypted)
> 1901000844bf4f1e6fc839cf

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA messages

(raw)
< 55010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unecrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
< 56010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_BROAD_TIME response

(raw)
< 570100073bea9f9b77972b1f
(unencrypted)
< 2201030007a800

last byte = 00 = success

-------------------------------------------------------------------------------

send CMD_DEV_BIND_STATE

(raw)
> [22, 0, 2, 0, 12, -88]
(encrypted)
> 1a010006b9cafd3fdfcde557

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 58010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_DEV_BIND_STATE response

(raw)
< 5901000810e429f07761449f
(unencrypted)
< 220104000ca80100

color = 01 ??
status = 00 = success

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA messages

(raw)
< 5a010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
< 5b010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
< 5c010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

sending CMD_CURRENT_USER_NEW (again??)

(raw)
> [22, 0, 27, 0, 14, -88, 47, 49, -98, 74, -118, -115, -77, -108, -13, -6, 126, -9, -7, -3, -86, 127, -100, 24, 1, 44, -76, 1, 0, 68, 12]
(rawhex)
> 16001B000EA8 2F319E4A8A8DB394F3FA7EF7F9FDAA7F 9C18 01 2C B4 01 00 440C
(encrypted)
> 1b01001f1bed79bee2fa41fe7a0b9e248c4425eee9abcef013ec18704b00a25a67b61b97

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 5d010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_CURRENT_USER_NEW response

(raw)
< 5e010007074cec7f57017c55
(unencrypted)
< 220103000ea800

status = 00 = success

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA messages

(raw)
> 5f010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 50010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 51010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

sending CMD_SET_UNIT

(raw)
> [22, 0, 3, 0, 4, -88, 1]
(encrypted)
> 1c010007ab0e171ea32daa02

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 52010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_SET_UNIT response

(raw)
< 530100074ef5ff79730a6d8d
(unencrypted)
< 2201030004a800

status = 00 = success

-------------------------------------------------------------------------------

sending CMD_SET_HELLO

(raw)
> [22, 0, 3, 0, 5, -88, 0]
(encrypted)
> 1d0100077d672d3be2b4d174

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 54010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_SET_HELLO response

(raw)
< 5501000739f2a50482b55de6
(unencrypted)
< 2201030005a800

status = 00 = success

-------------------------------------------------------------------------------

sending CMD_BROAD_TIME

(raw)
> [22, 0, 4, 0, 7, -88, 0, 0]
(encrypted)
> 1e01000844bf4f1e6fc839cf

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA message

(raw)
< 56010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

-------------------------------------------------------------------------------

CMD_BROAD_TIME response

(raw)
< 570100073bea9f9b77972b1f
(unencrypted)
< 2201030007a800

status = 00 = success

-------------------------------------------------------------------------------

sending CMD_DEV_BIND_STATE

(raw)
> [22, 0, 2, 0, 12, -88]
(encrypted)
> 1f010006b9cafd3fdfcde557

-------------------------------------------------------------------------------

CMD_DEV_BIND_STATE response

(raw)
< 5901000810e429f07761449f
(unencrypted)
< 220104000ca80100

status = 00 = success

-------------------------------------------------------------------------------

uninteresting empty CMD_CUR_WEIGHT_DATA messages

(raw)
> 5a010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5b010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5c010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5d010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5e010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5f010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 50010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 51010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 52010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 53010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 54010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 55010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 56010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 57010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 58010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 59010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5a010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5b010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5c010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5d010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300

The encryption used is XXTEA, with keys exchanged via the classic Diffie–Hellman key exchange.

some POC python code:

    def _enable_encryption(self):
        base = 5
        modulus = 0xFFFFFFC5

        private_key = secrets.randbits(32)

        print("private key: %08x" % private_key)
        public_key = pow(base, private_key, modulus)
        print("public key: %08x" % public_key)

        message = io.BytesIO()
        message.write(struct.pack('b', self._get_next_frame()))
        message.write(b'\xf0\x00\x08')
        message.write(struct.pack('<I', public_key))
        message.write(b'\x00\x00\x00\x00')

        print("Sending public key to scale")
        self._write_queue.put(message.getvalue())

        encryption_reply: EncryptionReply = self.wait_for_message(EncryptionReply)
        if encryption_reply is None:
            raise Exception("Didn't get a public key back from the scale")

        shared_key = pow(encryption_reply.other_public_key, private_key, modulus)
        self._xxtea_key = struct.pack("@8s8x", bytes("%08x" % shared_key, "utf-8"))

        print("shared key = %08x, %s" % (shared_key, hex(shared_key)))
        print("xxtea key = %s" % binascii.hexlify(self._xxtea_key))
def _handle_encrypted_message(self, buf):
        assert len(buf) >= buf[3] + 4
        assert (len(buf) - 4) % 8 == 0

        payload_length = buf[3]

        message = io.BytesIO()

        for i in range(0, int(len(buf) / 8)):
            decrypted = xxtea.decrypt(buf[i * 8 + 4: (i+1) * 8 + 4], self._xxtea_key, padding=False)
            message.write(decrypted)

        decrypted_buf = message.getvalue()
        print("decrypted data: %s" % binascii.hexlify(decrypted_buf, ","))

        reply_class = REPLY_MAP.get(decrypted_buf[4])
        if not reply_class:
            print("Received unexpected message type: 0x%02x" % decrypted_buf[4])
            return

        self._read_queue.put(reply_class(decrypted_buf[0:payload_length]))
def send_message(self, buf):
        print("sending message: %s" % binascii.hexlify(buf))
        message = io.BytesIO()
        message.write(struct.pack("4b", self._get_next_frame() + 0x10, 1, 0, len(buf)))

        padded_payload = io.BytesIO()
        padded_payload.write(buf)
        while len(padded_payload.getvalue()) % 8 > 0:
            padded_payload.write(b'\x00')

        for i in range(0, int(len(padded_payload.getvalue()) / 8)):
            message.write(xxtea.encrypt(padded_payload.getvalue()[i*8:(i+1)*8], self._xxtea_key,  padding=False))

        self._write_queue.put(message.getvalue())
JesusFreke commented 8 months ago

I forgot to mention, this is from a wyze scale x

JesusFreke commented 8 months ago

I've published some proof-of-concept (python) code for talking to the scale: https://github.com/JesusFreke/wyze_scale_tool

There should be enough info there to be able to implement the protocol in java for android