Last active
August 29, 2015 06:54
-
-
Save lhchavez/25e2bc7cd0589ae024da to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# vim: set expandtab:ts=2:sw=2 | |
import argparse | |
import bluetooth | |
import struct | |
import sys | |
def checksum(msg): | |
checksum = 0 | |
for c in msg: | |
checksum ^= ord(c) | |
return checksum | |
def format_request(args): | |
msg = struct.pack('BBBBBB', | |
1, # group | |
args.gender == 'M', # 0 = Female, 1 = Male | |
1, # level. ??? | |
args.height, # height, in cm | |
args.age, # age. in years | |
1) # units. 1 = KG, 2 = LB, 4 = ST | |
return '\xfe' + msg + struct.pack('B', checksum(msg)) | |
def parse_reply(data): | |
assert data[0] == 0xcf or len(data) < 16, 'Invalid reply' | |
height = data[3] | |
weight = (data[4] << 8 | data[5]) / 10.0 | |
return { | |
'level': data[1] >> 4, | |
'group': data[1] & 0xF, | |
'gender': ["Female", "Male"][data[2] >> 7], | |
'age': data[2] & 0x7F, | |
'height': height, | |
'weight': weight, | |
'body_fat': (data[6] << 8 | data[7]) / 10.0, | |
'bone': data[8] / 10.0, | |
'muscle': (data[9] << 8 | data[10]) / 10.0, | |
'visceral_fat': data[11], | |
'body_water': (data[12] << 8 | data[13]) / 10.0, | |
'base_metabolic_rate': (data[14] << 8 | data[15]), | |
'body_mass_index': weight / (height / 100.0)**2 | |
} | |
def close(): | |
return '\xfd\x35\x00\x00\x00\x00\x00\x35' | |
def get_weight(args): | |
uuid = '00001101-0000-1000-8000-00805F9B34FB' | |
if not args.addr: | |
print 'Scanning...' | |
nearby_devices = bluetooth.discover_devices(duration=4, | |
lookup_names=True) | |
for addr, name in nearby_devices: | |
if name == 'Electronic Scale': | |
args.addr = addr | |
print 'Found', args.addr | |
break | |
assert args.addr, 'Scale not found' | |
service_matches = bluetooth.find_service(uuid=uuid, | |
address=args.addr) | |
assert len(service_matches) > 0, 'Scale service not found' | |
service = service_matches[0] | |
host = service['host'] | |
port = service['port'] | |
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) | |
sock.connect((host, port)) | |
sock.send(format_request(args)) | |
parsed_data = parse_reply(map(ord, sock.recv(1024))) | |
try: | |
sock.send(close()) | |
sock.close() | |
except: | |
pass | |
return parsed_data | |
def main(): | |
parser = argparse.ArgumentParser(description='Bathroom scale') | |
parser.add_argument('age', type=int, help='Age (in years)') | |
parser.add_argument('gender', choices=['M', 'F'], help='Gender') | |
parser.add_argument('height', type=int, help='Height (in cm)') | |
parser.add_argument('--addr', help='Bluetooth address of the scale') | |
args = parser.parse_args() | |
for k,v in get_weight(args).iteritems(): | |
print k, v | |
if __name__ == '__main__': | |
sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment