โปรแกรมนี้เขียนด้วยภาษา Python โดยโปรแกรมจะรอรับค่าจากสัญญาน Bluetooth ที่ส่งมาจากเครื่องชั่งน้ำหนัก ตัวอย่างโปรแกรมจะแสดงข้อมูลออกทางหน้าจอ แต่สามารถนำไปประยุกต์ใช้สำหรับการเก็บข้อมูลลงฐานข้อมูล หรือแล้วแต่จินตนาการได้ ส่วนฉันใช้เก็บข้อมูลลงฐานข้อมูลและส่งเป็นข้อความเข้า LINE Messenger

0. Install library

เริ่มต้นด้วยการติดตั้งโปรแกรมและไลบรารีที่จำเป็นกันก่อน

# apt-get update
# apt-get install -y bluez* pkg-config libbluetooth-dev libglib2.0-dev
# apt-get install -y libboost-thread-dev libboost-python-dev python3-capstone

# pip3 install requests
# pip3 install bleak
# pip3 install asyncio

1. discover.py

จากนั้นทำการเขียนโปรแกรมสำหรับค้นหา MAC Address ของเครื่องชั่งน้ำหนัก XIAOMI

# nano discover.py
import sys
import asyncio
import time

from typing import Sequence
from bleak import BleakScanner
from bleak.backends.device import BLEDevice

async def findBluetoothDevice():
    devices: Sequence[BLEDevice] = await BleakScanner.discover(timeout=1)

    print("** Date Time: ", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), "**\n")

    for device in devices:
        print(device)

    print("--------------------------------------------------\n")

print("If you want to exit, you can press Ctrl + C.\n")

while True:
    try:
        loop = asyncio.get_event_loop()
        loop.run_until_complete(findBluetoothDevice())
    except KeyboardInterrupt:
        print("\nExit\n")
        sys.exit(0)
    except Exception as e:
        print("Exception Message:", str(e))
        time.sleep(1)

2. Find device address

ทำการรันคำสั่ง discover.py เพื่อหา MAC Address ของเครื่องชั่งน้ำหนัก เมื่อรันคำสั่งแล้วให้ขึ้นชั่งบนเครื่องชั่ง เพื่อให้เครื่องส่งข้อมูลออกมา โดยชื่อเครื่องชั่งน้ำหนักของ XIAOMI จะขึ้นต้นด้วย MIBFS

# python3 discover.py
Image

3. xiaomi-mi-body-composition-scale-2.py

ต่อไปเป็นโปรแกรมสำหรับรับค่าน้ำหนักจากเครื่องชั่งน้ำหนัก ให้แก้ไขค่าในตัวแปร XIAOMI_SCALE_ADDRESS เป็นค่า MAC Address ของเครื่องชั่งน้ำหนักของเรา

# nano xiaomi-mi-body-composition-scale-2.py
import sys
import asyncio
import struct
import requests
import time
import platform

from typing import Sequence
from bleak import BleakScanner
from bleak.backends.device import BLEDevice
from datetime import datetime

CURRENT_SYSTEM: str = platform.system()
XIAOMI_SCALE_ADDRESS = "88:22:XX:XX:0E:7F" # Change to your device address

oldTimestamp = 0

def getValueFromServiceData(unpackData):
    global oldTimestamp

    # hexData = [hex(dt) for dt in unpackData]
    # print("hexData : ", hexData)

    # Get Data
    isStabilized = unpackData[1] & (1<<5)
    weight = (((unpackData[12] & 0xFF) << 8) | (unpackData[11] & 0xFF)) / 200.0
    deviceDateTime = "{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(int(((unpackData[3] & 0xFF) << 8) | unpackData[2]), int(unpackData[4]), int(unpackData[5]), int(unpackData[6]), int(unpackData[7]), int(unpackData[8]))

    # Convert to Local Time Zone
    currentTimestamp = time.time()
    localTimeZoneOffset = datetime.fromtimestamp(currentTimestamp) - datetime.utcfromtimestamp(currentTimestamp)
    currentDateTime = datetime.strptime(deviceDateTime, "%Y-%m-%d %H:%M:%S") + localTimeZoneOffset
    currentTimestamp = datetime.timestamp(currentDateTime)

    # Check isStabilized and currentTimestamp > 10 seconds
    if isStabilized and currentTimestamp - oldTimestamp > 10:
        oldTimestamp = currentTimestamp

        print("Date Time: "+str(currentDateTime.strftime("%Y-%m-%d %H:%M:%S"))+"\t\tWeight : "+str(weight))

async def findBluetoothDevice():
    devices: Sequence[BLEDevice] = await BleakScanner.discover(timeout=1)

    for device in devices:
        if device.address == XIAOMI_SCALE_ADDRESS:
            if CURRENT_SYSTEM == "Windows":
                for detail in device.details:
                    if detail is not None:
                        for data in detail.advertisement.data_sections:
                            unpackData = [dt[0] for dt in struct.iter_unpack("<B", data.data)]
                            unpackData = unpackData[2:]

                            if data.data_type == 22 and len(unpackData) == 13:
                                getValueFromServiceData(unpackData)

            elif CURRENT_SYSTEM == "Linux":
                uuid = device.details.get("props").get("UUIDs")[0]
                data = device.details.get("props").get("ServiceData")[uuid]

                unpackData = [dt[0] for dt in struct.iter_unpack("<B", data)]

                if len(unpackData) == 13:
                    getValueFromServiceData(unpackData)

print("If you want to exit, you can press Ctrl + C.\n")

while True:
    try:
        loop = asyncio.get_event_loop()
        loop.run_until_complete(findBluetoothDevice())
    except KeyboardInterrupt:
        print("\nExit\n")
        sys.exit(0)
    except Exception as e:
        print("Exception Message:", str(e))
        time.sleep(1)

4. Run

สั่งรันคำสั่งเพื่อรอรับค่าจากเครื่องชั่งน้ำหนัก เมื่อรันโปรแกรมแล้ว ก็ลองไปชั่งน้ำหนักและดูการแสดงผล

# python3 xiaomi-mi-body-composition-scale-2.py
Image

5. การนำไปประยุกต์ใช้

สามารถนำไปใช้สำหรับส่งข้อมูลเข้า LINE Messenger ได้ ดังรูปตัวอย่าง แต่ต้องไปทำเพิ่มเองนะ ไม่ได้มีให้ในโค้ด แต่คิดว่าไม่น่ายากเกินไปนัก

6. ดูโค้ดทั้งหมดได้ที่ GitHub

GitHub - LookHin/xiaomi-mi-body-composition-scale-2
Contribute to LookHin/xiaomi-mi-body-composition-scale-2 development by creating an account on GitHub.