Archive

Tag Archives: Beurer

Beurer and Omron are part of my routine every morning:

  • weight (Beurer)
  • orthostatic test (6min lying/3min standing) (Windlink)
  • blood sugar (CareSensN)
  • blood pressure (twice both arms) (Omron)

After all this is done i launch a small udev listener:

#!/usr/bin/env python
import pyudev
import subprocess

context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.start()
monitor.filter_by('usb', 'usb_device')
print "Started:", monitor.started

for device in iter(monitor.poll, None):
    print device.action, device.subsystem, device
    try:
        atts = device.attributes
        vendor = atts["idVendor"]
        product = atts["idProduct"]
        name = atts["product"]
        print "%s %s:%s" % (name, vendor, product)
    except KeyError:
        continue
    if device.action !="add":
        continue
    if vendor == "04d9": #idProduct = 8010
        print "call"
        subprocess.call("./beurer.sh")
        print "done"
    if vendor == "0590": #idProduct = 0028
        print "call"
        subprocess.call("./omron.sh")
        print "done"

This will launch device specific scripts when a device is connected.
beurer.sh:

#!/bin/zsh

W=data/weight.csv
OLD=data/backup/weight.csv.`date +%FT%H:%M`
T='x.csv'
~/projects/usb/beurer/beurer.py >$T || exit $?

# backup
cp $W $OLD

# merge
tail -q -n +2 $OLD | sort -u $T - | cat $W.header - >$W

#feedback
cat $T

omron.sh

#!/bin/zsh

W=data/pressure.csv
OLD=data/backup/pressure.csv.`date +%FT%H:%M`
T='x.csv'

~/projects/usb/omron/omron.py >$T || exit $?

# backup
cp $W $OLD

# merge
tail -q -n +2 $OLD | sort -u $T - | cat $W.header - >$W

#feedback
cat $T

CareSensN is producing only one number and it is easier to enter it directly. My alias for this is:

alias rrs='>>~/monitor/data/sugar.csv     echo `date +%FT%H:%M`'

“Reports” is next.

This scale can measure your weight and percentage of different body components. The control panel is recording 12 variables:

  1. weight kg
  2. body fat %
  3. water %
  4. muscles %
  5. bones kg
  6. date
  7. upper body fat % (not for BG64)
  8. lower body fat % (not for BG64)
  9. upper body muscles % (not for BG64)
  10. lower body muscles % (not for BG64)
  11. BMR
  12. AMR

All values are 16 bit words.
Up to 10 users can store thier data for 32 measurements.
Beacause date has no time only one measurement per day is possible.

The following python program produces a CSV file with all variables available on BG64 for the first user (can be specified as a command parameter):

#!/usr/bin/env python

"""
ID 04d9:8010 Holtek Semiconductor, Inc. 
"""
import usb.core
import usb.util as util
from array import array
import sys
from optparse import OptionParser, make_option
import pickle
from struct import unpack

dev = None

VID = 0x04d9
PID = 0x8010

# define HID constants

REQ_HID_GET_REPORT   = 0x01 
REQ_HID_GET_IDLE     = 0x02 
REQ_HID_GET_PROTOCOL = 0x03 

REQ_HID_SET_REPORT   = 0x09 
REQ_HID_SET_IDLE     = 0x0A 
REQ_HID_SET_PROTOCOL = 0x0B 

HID_REPORT_TYPE_INPUT   = 1<<8
HID_REPORT_TYPE_OUTPUT  = 2<<8
HID_REPORT_TYPE_FEATURE = 3<<8

def openDev():
    global dev
    dev = usb.core.find(idVendor=VID, idProduct=PID)
    if dev is None:
        raise ValueError('Device not found')

    if dev.is_kernel_driver_active(0):
        dev.detach_kernel_driver(0)
    dev.set_configuration() # do reset and set active conf. Must be done before claim.
    util.claim_interface(dev, None)

def setReport(reportId, data):
    r = dev.ctrl_transfer(
        util.build_request_type(util.CTRL_OUT, util.CTRL_TYPE_CLASS, util.CTRL_RECIPIENT_INTERFACE), # bmRequestType,
        REQ_HID_SET_REPORT,
        HID_REPORT_TYPE_OUTPUT | reportId,
        0,                 # feature_interface_num
        data,              # data
        3000               # timeout (1000 was too small for C_FREE)
    )
    return r

def read():
    openDev()
    try:
        dev.read(0x81,64) #flush 
    except usb.core.USBError:
        pass
    
    setReport(9, array('B',(0x10,0,0,0,0,0,0,0)))

    # Every user can have upto 12 variables
    # and additional 8*64 for user data
    r = []
    for i in xrange(120+8):
        x = dev.read(0x81,64)
        if not x:
            print >> sys.stderr, "Read failed"
            exit(1)
        if x[0]==0xff and (i<120):
            print >> sys.stderr,"Invalid data",x
            exit(1)
        r.append(x)    

    # Each variable can have upto 32 values
    frmt = "!" + "H"*32
    s = []
    for i in xrange(120) :
        x = unpack(frmt, r[i])
        
        # Variables 5 .. 10 are not available on my scale
        if i>5 and i<10:
            err = [item for item in x if item!=0]
        else:
            err = [item for item in x if item==0xffff]
        if len(err):
            print >> sys.stderr, "INVALID:", err
            exit(1)

        s.append(x)
    return s

def printUser(s, user):
    # Transpose from 12x32 to 32x12 and format

    j = 12*user
    for i in xrange(32):
        x = s[j+5][i] # date
        if not x:
           break
        print "{:d}-{:02d}-{:02d}T07:00:00 {:.1f} {:.1f} {:.1f} {:.1f} {:.1f} {:d} {:d}".format(
           1920+(x>>9), x>>5&0xf, x&0x1f,
           s[j+0][i]/10., s[j+1][i]/10., s[j+2][i]/10., s[j+3][i]/10., s[j+4][i]/10., s[j+10][i], s[j+11][i])

def main():

    option_list = [
        make_option("-c", "--cached", action="store_true", dest="cached"),
        #make_option("-w", "--write",action="store",      dest="output_file"),
        make_option('-u', '--user', action='store',      dest='user'),
    ]

    parser = OptionParser(option_list=option_list, usage='Usage: %prog [options]')
    options, args = parser.parse_args()

    if options.cached:
        with open("dump.pickle") as f: s = pickle.load(f)
    else:
        s = read()
        with open("dump.pickle","w") as f: pickle.dump(s,f)

    user = 0
    if options.user:
        user=int(options.user)-1

    printUser(s, user)


if __name__ == '__main__':
    main()


To call it enter at command prompt:

./beurer.py > user1.csv

I have Polar WindLink, Nike Sportband, Omron HEM-7301 and Beurer BG64 connected to my Linux laptop. Because all these are HID devices i used for this libusb and small python scripts. The intention is to describe them here starting from the simplest: BG64.