GithubHelp home page GithubHelp logo

hertzg / metekcity Goto Github PK

View Code? Open in Web Editor NEW
16.0 3.0 8.0 3.35 MB

ETEKCITY smart nutrition scale protocol reverse engneering

License: MIT License

JavaScript 5.65% TypeScript 91.37% HTML 2.98%
etekcity ble protocol reverse-engineering node

metekcity's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

metekcity's Issues

Implement all researched packets

So far the notes.txt contains samples saved during research, this issue tries to collect the status of implementation of each packet type. Some of them might need their own issue but here they are represented all togeather.

Packet Types:

Unresearched packets

  • SET_NUTRITION (0xc2)
  • ?PING (0xc3)
  • ??? (0xd2)
  • ?PONG (0xd4)
  • ??? (0xe1)
  • ??? (0xe2)
  • ??? (0xe3)

Packet Details

Status Type Source(s) Payload Generic? Notes
SET_UNIT COMMAND unit uint8Parselizer
SET_TARE COMMAND shouldReset booleanParselizer
SET_AUTO_OFF COMMAND timeout uint8Parselizer
MEASUREMENT NOTIFY sign, value, unit uint8Parselizer
TARE_STATE NOTIFY isOn booleanParselizer (inverted)
AUTO_OFF_STATE NOTIFY timeout uint16Parselizer the value is the same as for command with the exception of extra 0 byte
ERROR_STATE NOTIFY isOn booleanParselizer (inverted)
ITEM_STATE NOTIFY isOn booleanParselizer (inverted)
UNIT_STATE NOTIFY unit uint8Parselizer
🛑 SET_NUTRITION COMMAND (complex object) need more samples to understad how data is encoded

Legend

Marker Category Description
Status Waiting (todo)
🛑 Status Blocked
Status Done
COMMAND Source(s) Command send to the Device
NOTIFY Source(s) Notification received from the Device

Data for newer scales

I bought this scale on Amazon last week. The data on mine does not match up to the research here. I don't know if I'll open a PR here for some of the documentation, or just link to a new repo with my test data.

I've so far been doing the detection and parsing in Swift, so it wouldn't be a drop in replacement.

Of note: the services are different and the UInt8 data array has a different length and position of values than what I see in the packet package here.

Thanks for the inspiration in this repo! It really help bootstrap me and where to look in the array for the various values and to combine the two UInt8 values for a single UInt16 for the weight value.

Update README

some information on readme is out of date or incorrect, update readme with latest updates and findings

Implement SET_NUTRITION packet

I do not have enough samples to understands this packet.

Having enough samples showing:

  • Diffenret fields populated with different values in app
  • Bytes sent to and from the BLE service

would (probably) help understand:

  • How float values are coded
  • Which fields are transfered vs computed
  • How are they coded in the packet.

It would be great if someone can provide that information using an Android phone (I no longer have one).

This can be done using adb and wireshark if anyone is willing to provide samples I can write up a guide how to do it.

Trouble Understading Nutrition Info Packet

I just bought one of these scales off of Amazon, and the data lines up perfectly.
I have never connected it to the app, so my theory is it cannot pull down new firmware.
I have written this code in Python to put nutrition info on the display, but nothing happens.
I am using Windows 10 and Bleak for Bluetooth, which is cross-platform. The check digit is also
correct, converted from TypeScript to Python. I am wondering what I did wrong to not get a result.
Here is my code
`import asyncio
from bleak import BleakClient # for bluetooh install with: pip install bleak
import struct

HEADER = bytearray(b"\xfe\xef\xc0\xa2") # Replace with your header bytes

def uint8(value):
return value & 0xff

def calculateChecksum(buffer, prevSum=0):
uint8_buffer = bytearray(buffer)
return sum(uint8_buffer, prevSum) & 0xff

def uint8ArrayBufferAppend(buffer, data, offset=0):
buffer[offset: offset + len(data)] = data
return offset + len(data)

def makePacket(header, type, payload, payloadLength=None, checksum=None):
# packet = header + type (1 byte) + length (1 byte) + payload + checksum (1 byte)
packetLength = len(header) + 3 + len(payload)
buffer = bytearray(packetLength)

cursor = 0
# header
cursor = uint8ArrayBufferAppend(buffer, header, cursor)

checksumOffset = cursor
# type (1 byte) + length (1 byte)
cursor = uint8ArrayBufferAppend(buffer, [uint8(type), uint8(payloadLength)] if payloadLength is not None else [uint8(type)], cursor)

# payload
cursor = uint8ArrayBufferAppend(buffer, payload, cursor)

checksumData = buffer[checksumOffset: cursor]
# checksum (1 byte)
uint8ArrayBufferAppend(buffer, [uint8(checksum)] if checksum is not None else [uint8(calculateChecksum(checksumData))], cursor)

return buffer

def create_set_nutrition_payload(calories, calories_from_fat, total_fat, saturated_fat, trans_fat,
cholesterol, sodium, potassium, total_carbs, dietary_fiber,
sugars, protein):
payload = bytearray(36)

# Set the nutrition data fields
fields = [calories, calories_from_fat, total_fat, saturated_fat, trans_fat,
          cholesterol, sodium, potassium, total_carbs, dietary_fiber,
          sugars, protein]

for i in range(len(fields)):
    value = int(fields[i] * 10)  # Multiply by 10 to match the scale's format
    payload[i * 3: 3 + i * 3] = struct.pack('>H', value)

return payload

async def run():
# Replace "Device Name" and "Device Address" with the name and address of your Bluetooth device
async with BleakClient("xx:xx:xx:xx:xx:xx") as client: # Your device mac adrr
header = HEADER
packet_type = 0xc2
header = HEADER
packet_type = 0xc2
calories = 1500
calories_from_fat = 200
total_fat = 15
saturated_fat = 7
trans_fat = 0
cholesterol = 100
sodium = 2000
potassium = 300
total_carbs = 50
dietary_fiber = 10
sugars = 40
protein = 20
payload = create_set_nutrition_payload(calories, calories_from_fat, total_fat, saturated_fat, trans_fat,
cholesterol, sodium, potassium, total_carbs, dietary_fiber,
sugars, protein)
payload_length = len(payload)
packet = makePacket(header, int(packet_type), payload, payload_length)
print(packet)
await client.write_gatt_char("00002c11-0000-1000-8000-00805f9b34fb", packet, True)
exit()
while True:
await asyncio.sleep(1)

if name == "main":
asyncio.run(run())

`
Any help into what I am not doing correctly would be amazing.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.