Hello World fra min Badevægt

Der er mange der med succes har brugt Wii Balance Board (Wii-Fit) som badevægt. Der er da også ganske meget information tilgængelig:

Plus dem vi så på i mit sidste indlæg Badevægt, problemet med de løsninger var permanent parring. så det skal vi lige have styr på først.

Der er sket meget med bluetooth på Linux siden 2008, da den oprindelige kode blev skrevet, dengang klarede applikationerne stortset det hele selv.  Og de løsninger jeg præsenterede sidste gang baserede sig alle på den rå bluetooth adgang.

I dag er abstrakstions niveauet hævet, og mange af de basale operationer klares af Bluez, som bluetooth frame-work hedder under Linux. Dermed kan man parre Wii-Fit direkte fra en GUI Bluetooth manager, eller hvis man er mere til kommando-linien så brug bluetoothctl således:

$ bluetoothctl
[NEW] Controller B8:27:EB:C6:64:03 raspberrypi [default]
[NEW] Device 34:AF:2C:2D:A8:C2 Nintendo RVL-WBC-01
[CHG] Device 34:AF:2C:2D:A8:C2 Connected: yes
[CHG] Device 34:AF:2C:2D:A8:C2 Connected: no
[CHG] Device 34:AF:2C:2D:A8:C2 Connected: yes
# herover kommer der løbende status
# nedenfor en kommando prompt - prøv help
[bluetooth]# scan on
[bluetooth]# pair 34:AF:2C:2D:A8:C2
[bluetooth]# trusted 34:AF:2C:2D:A8:C2
# når man trykker på knappen bliver enheden tændt og forbundet
# for at bruge enheden udfør nedenstående
[bluetooth]# connect 34:AF:2C:2D:A8:C2
# og når vi er færdige med at bruge den
[bluetooth]# disconnect 34:AF:2C:2D:A8:C2


Der er allerede en driver hid-wiimote installeret under Linux, og når enheden først er parret vil den dukke op når Wii-Fit bliver tændt og fjernet når man disconnecter. Nedenfor er output fra dmesg:

$ dmesg
...
wiimote 0005:057E:0306.0004: unknown main item tag 0x0
wiimote 0005:057E:0306.0004: hidraw2: BLUETOOTH HID v6.00 Gamepad [Nintendo RVL-WBC-01] on b8:27:eb:c6:64:03
wiimote 0005:057E:0306.0004: New device registered
wiimote 0005:057E:0306.0004: detected device: Nintendo Wii Balance Board
wiimote 0005:057E:0306.0004: detected extension: Nintendo Wii Balance Board
input: Nintendo Wii Remote Balance Board as /devices/platform/soc/3f201000.uart/tty/ttyAMA0/hci0/hci0:13/0005:057E:0306.0004/input/input3
...
wiimote 0005:057E:0306.0004: Device removed

Så prøver vi: batteri, ud, batteri ind igen og Wii-Fit bliver automatisk detekteret igen når vi trykker på knappen, men ikke med den samme device.  Så problemet er allerede løst, der er en hid-driver, så nu kommer vi til det svære LÆS MANUALEN: man xwiimote

Her står bl.a. hvor man kan finde sin wii-fit device i mit tilfælde:

ls -l /sys/module/hid_wiimote/drivers/hid:wiimote/0005:057E:0306.0005

-r--r--r-- 1 root root 4096 Jan 27 02:42 bboard_calib
-r--r--r-- 1 root root 4096 Jan 27 02:42 country
-r--r--r-- 1 root root 4096 Jan 27 02:42 devtype
lrwxrwxrwx 1 root root    0 Jan 27 02:42 driver -> ../../../../../../../../../bus/hid/drivers/wiimote
-rw-rw-r-- 1 root root 4096 Jan 27 02:42 extension
drwxr-xr-x 3 root root    0 Jan 27 02:31 hidraw
drwxr-xr-x 3 root root    0 Jan 27 02:41 input
drwxr-xr-x 3 root root    0 Jan 27 02:42 leds
-r--r--r-- 1 root root 4096 Jan 27 02:42 modalias
drwxr-xr-x 2 root root    0 Jan 27 02:42 power
drwxr-xr-x 3 root root    0 Jan 27 02:42 power_supply
-r--r--r-- 1 root root 4096 Jan 27 02:42 report_descriptor
lrwxrwxrwx 1 root root    0 Jan 27 02:42 subsystem -> ../../../../../../../../../bus/hid
-rw-r--r-- 1 root root 4096 Jan 27 02:42 uevent

Og der er jo det hele.  HID device med Kalibrerings data, lysdiode, batteri information, osv.

På manualsiden var der også en henvisning til  xwiishow, et C-program med kildetekst, der viser status på alle Wii-enheder dynamisk, med fin character grafik. Alle sensor-værdierne kan ses og lysdioden kan tændes og slukkes, knappen er dog ikke med.

HID enheder kan normalt bruges uden at der skal installeres drivere.

Hello World

I min verden er det første program man laver et der skriver “Hello World”, blot for at få alt det basale på plads og vise at der er hul igennem, så det vil jeg også gøre her. Den eneste output enhed der er på Wii-Fit er den blå lysdiode, så det bliver den.

Jeg vil gerne måle vægten automatisk hver gang der er nogen der bruger den, ikke noget med at man skal starte et program via GUI eller kommando-linie

Under Linux er det udev der holder styr på devices der kommer og går.  Vi kan følge med i hvad der sker via:

$ udevadm monitor # only relevant lines shown

monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

KERNEL[275.636718] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256 (bluetooth)
UDEV  [275.639448] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256 (bluetooth)
KERNEL[275.702511] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid)
KERNEL[275.712277] add      /module/hid_wiimote (module)
KERNEL[275.712913] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/hidraw/hidraw1 (hidraw)
KERNEL[275.713030] add      /bus/hid/drivers/wiimote (drivers)
UDEV  [275.713266] add      /module/hid_wiimote (module)
UDEV  [275.713363] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid)
UDEV  [275.715145] add      /bus/hid/drivers/wiimote (drivers)
UDEV  [275.718351] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/hidraw/hidraw1 (hidraw)
KERNEL[275.771624] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/leds/0005:057E:0306.0002:blue:p0 (leds)
UDEV  [275.776623] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/leds/0005:057E:0306.0002:blue:p0 (leds)
KERNEL[275.841784] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18 (input)
KERNEL[275.841969] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/event16 (input)
KERNEL[275.842166] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/js1 (input)
KERNEL[275.842271] change   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid)
UDEV  [275.847737] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18 (input)
KERNEL[275.851425] change   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/power_supply/wiimote_battery_34:af:2c:2d:69:fe (power_supply)
UDEV  [275.854009] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/js1 (input)
...
KERNEL[277.005331] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/event16 (input)
KERNEL[277.028347] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/js1 (input)
KERNEL[277.060483] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18 (input)
KERNEL[277.060543] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/leds/0005:057E:0306.0002:blue:p0 (leds)
UDEV  [277.070917] add      /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/event16 (input)
UDEV  [277.075802] change   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid)
UDEV  [277.079230] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/event16 (input)
UDEV  [277.079341] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/js1 (input)
UDEV  [277.079990] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/leds/0005:057E:0306.0002:blue:p0 (leds)
UDEV  [277.080135] change   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/power_supply/wiimote_battery_34:af:2c:2d:69:fe (power_supply)
UDEV  [277.081084] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18 (input)
KERNEL[277.084245] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/power_supply/wiimote_battery_34:af:2c:2d:69:fe (power_supply)
KERNEL[277.084431] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/hidraw/hidraw1 (hidraw)
KERNEL[277.084509] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid)
UDEV  [277.086365] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/power_supply/wiimote_battery_34:af:2c:2d:69:fe (power_supply)
UDEV  [277.088054] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/hidraw/hidraw1 (hidraw)
UDEV  [277.089331] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid)
KERNEL[279.064318] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256 (bluetooth)
UDEV  [279.065836] remove   /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256 (bluetooth)

Den enkleste måde at få vores program til at starte når Wii-Fit bliver tændt er at lave en en ny regel: /etc/udev/rules.d/99-wiibb.rules

# to see what we have available just print all ENV to file
# you could get same information using this command "udevadm monitor -p"
DRIVERS=="wiimote", RUN+="/bin/sh -c '(date;set) >>/tmp/wiibb-log'"

FIXME: Virker ikke under Ubuntu-16.10 efter reboot, da / var monteret read-only da systemd-udevd  blev startet  see discussion here: http://askubuntu.com/questions/883843/udev-rules-scripts-has-only-read-only-access-to-ubuntu16-10

Så tænder vi og slukker et par gange, og kigger på de mange variable vi kan se i /tmp/wiibb-log,  Her lægger vi specielt mærke  til:

  • Der bliver oprettet flere devices, den sidste har ACTION=change SUBSYSTEM=hid, det bruger vi reglen for at kalde vores program
  • HID_NAME=“Nintendo RVL-WBC-01” udelukker andre Wii enheder
  • HID_UNIQ er mac-adressen for Wii-Fit
  • DEVPATH fortæller hvor vi kan få fat i enheden denne gang

Næste trin er at lade udev kalde et program der morser “hello world” og derefter slukker enheden, og det er præcis hvad dette shell-script gør:

#!/bin/bash
# wiibb.sh Copyright Peter@Lorenzen.us Januar 2017, This is BSD-style free software
# called with DEVPATH and HID_UNIQ set
export PATH=/usr/local/bin:/usr/local/sbin:$PATH
LED=/sys/$DEVPATH/leds/$(basename $DEVPATH):blue:p0/brightness
MAC=$(echo $HID_UNIQ | tr a-f A-F)

h="...."; e="."; l=".-.."; o="---"; w=".--"; r=".-."; d="-.."

led_on() { (echo 1; sleep $1; echo 0) > $LED; }

echo Wii Board $MAC installed at $DEVPATH | sudo tee /dev/kmsg >/dev/console

echo connect $MAC | bluetoothctl

text="hello world"

for word in $text; do
        chars=(`echo $word | fold -w1`)
        for ch in "${chars[@]}"; do
                eval 'morse="${'"$ch"'}"'
                c_array=(`echo $morse | fold -w1`)
                for cm in "${c_array[@]}"; do
                        case $cm in
                        .) led_on 1; sleep 1;;
                        -) led_on 3; sleep 1;;
                        esac
                done
                sleep 2
        done
        sleep 4
done
echo 1 > $LED; sleep 1; # when it turns off it indicates device is off

echo disconnect $MAC | bluetoothctl

echo Wii Board $MAC done | sudo tee /dev/kmsg >/dev/console

Hmm – Det virkede ikke for mig og ganske rigtigt der er en BUG i bluetoothctl der kun kommer til udtryk når man kører det fra et script, interaktivt virker det fint.  Ubuntu-16.10 har bluez-5.41,  Raspian har bluez-5.23.  Problemet er løst i bluez-5.43.  Jeg har beskrevet hvordan man installerer den nyeste version fra Zesty under Ubuntu 16.04 eller 16.10 her http://askubuntu.com/a/884062/655086, Der sker følgende:

#!/bin/bash
sudo apt-get install devscripts debhelper dh-autoreconf flex bison libdbus-glib-1-dev libglib2.0-dev  libcap-ng-dev libudev-dev l
ibreadline-dev libical-dev check dh-systemd libebook1.2-dev

wget https://launchpad.net/ubuntu/+archive/primary/+files/bluez_5.43.orig.tar.xz
wget https://launchpad.net/ubuntu/+archive/primary/+files/bluez_5.43-0ubuntu1.debian.tar.xz
wget https://launchpad.net/ubuntu/+archive/primary/+files/bluez_5.43-0ubuntu1.dsc

tar xf bluez_5.43.orig.tar.xz
cd bluez-5.43
tar xf ../bluez_5.43-0ubuntu1.debian.tar.xz
# install patches relevant for rpi-3 bluetooth
. /etc/os-release
if [ $ID = raspbian ]; then
    wget https://gist.github.com/pelwell/c8230c48ea24698527cd/archive/3b07a1eb296862da889609a84f8e10b299b7442d.zip
    cd debian/patches
    unzip ../../3b07a1eb296862da889609a84f8e10b299b7442d.zip
    for i in c8230c48ea24698527cd-3b07a1eb296862da889609a84f8e10b299b7442d/*;do
        mv $i .
        basename $i >> series
    done
    rmdir c8230c48ea24698527cd-3b07a1eb296862da889609a84f8e10b299b7442d
    cd ../..
fi
# end of Raspian related patches
debchange --local=~lorenzen 'Backport to Xenial'
debuild -b -j4
cd ..
sudo dpkg -i *.deb

Ovenstående virker også under Raspian, alternativt se her

http://stackoverflow.com/questions/41707164/connect-ble-devices-with-raspberry-pi-3-b

Man kunne også blot  installere bluez fra debian stretch, eller vente et par måneder så er det standard

how-to-use-stretch-testing-packages

Når det så virker installeres shell-scriptet i /usr/local/sbin/wiibb.sh, og  en opdateret version af vores udev-rule /etc/udev/rules.d/99-wiibb.rules skal være som nedenfor

# Whenever a Wii Balance Board is turned on wiibb.sh is called
# wiibb.sh reads the weight and turns the device off when done
SUBSYSTEM=="hid", ENV{HID_NAME}=="Nintendo RVL-WBC-01" ACTION=="change", DRIVERS=="wiimote", RUN+="/usr/sbin/wiibb.sh"

Hvis man så er radio-amatør (oz1dmk),  kan man forvisse sig om at hele frame-worket virker, der er endda log-entries i dmesg.

Det var sådan set det hele, resten er blot at skrive et program til at læse vægten.  Vælg et programmerings-sprog og kom igang.

Næste gang laver vi lige et sådant program i C

This entry was posted in Bluetooth, Linux. Bookmark the permalink.