2016년 5월 12일 목요일

라즈베리 파이를 비콘으로 사용하기 (Using Raspberry Pi as a Beacon)

독립적으로 비콘 모듈을 사용할 수도 있지만 이미 라즈베리 파이를 가지고 있다면 별도의 비콘 모듈 없이 라즈베리 파이를 비콘으로 설정해 사용할 수 있다.


라즈베리 파이 3의 경우 무선랜/블루투스가 기본 내장되어 있어 별도의 추가 하드웨어가 필요 없어 더 경제적이다. 라즈베리 파이 1/2의 경우는 USB타입의 블루투스 동글을 추가해 주면 된다.


 비콘은 특별한 것이 아니고 BLE(Bluetooth Low Energy)의 advertising packet 안에 옵션 필드인 Manufacturer Specific Data 에 특정 값을 집어넣어 주기적으로 advertising 하는 것이다. 그러므로 이 필드에 들어갈 값을 알아야 한다.

필드의 구조는 다음과 같다.

  • ID (uint8_t) : 이 값은 항상 0x02
  • Data Len (uint8_t) : payload 나머지 부분의 길이 → 0x15 (21 bytes)
  • 128-bit UUID (uint8_t[16]) : 128-bit 식별자
  • Major (uint16_t) : Major value
  • Minor (uint16_t) : Minor value
  • TX Power (uint8_t) : RSSI 기반으로 거리를 추정하기 위해 사용됨
 예를 들어 다음은 유효한 iBeacon payload의 값이다.


블루투스 표준에 의하면 Company Identifier가 Manufacturer Specific Data 필드 앞에 와야만 한다. 여기서 사용할 Apple의 company identifier는 0x004C 이다.

라즈베리 파이가 비콘 데이터를 보내게 하려면 몇가지 툴을 설치해 줘야만 한다. 여기서 핵심은 Bluez(리눅스 블루투스 스택)이고 부가적으로 libusb와 몇개의 helper library가 필요하다.

순서대로 필요한 툴들을 설치, bluez를 다운받아 컴파일 및 설치 해 주면 된다.

pi@raspberrypi ~ $ sudo apt-get install libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-def

pi@raspberrypi ~ $ sudo mkdir bluez
pi@raspberrypi ~ $ cd bluez
pi@raspberrypi ~ $ sudo wget www.kernel.org/pub/linux/bluetooth/bluez-5.11.tar.xz
 
pi@raspberrypi ~ $ sudo unzx bluez-5.11.tar.xz 
pi@raspberrypi ~ $ sudo tar xvf bluez-5.11.tar
pi@raspberrypi ~ $ cd bluez-5.11
pi@raspberrypi ~ $ sudo ./configure --disable-systemd
pi@raspberrypi ~ $ sudo make
pi@raspberrypi ~ $ sudo make install



설치가 완료되었으면 블루투스 동글을 꼽고 재부팅 시켜주면 된다.

재부팅이 완료되면 먼저 시스템에 설치된 디바이스 목록을 확인한다.


pi@raspberrypi ~ $ hciconfig
hci0:  Type: BR/EDR    Bus: USB
       BD Address: 00:1A:7D:DA:71:12 ACL MTU: 310:10 SCO MTU: 64:8
       DOWN
       RX bytes: 495 acl:0 sco:0 events:21 errors: 0
       TX bytes: 89 acl:0 sco:0 commands: 21 errors: 0
pi@raspberrypi ~ $

만일 모든것이 정상적으로 설정되어 있으면 위와 같이 hci 디바이스가 보이게 된다. 이제 다음 명령으로 디바이스를 활성화 시켜 준다. 또한 advertising을 할 때 문제를 일으킬 수도 있으므로 device scanning은 꺼 준다.

pi@raspberrypi ~ $ sudo hciconfig hci0 up 
pi@raspberrypi ~ $ sudo hciconfig hci0 leadv3
pi@raspberrypi ~ $ sudo hciconfig hci0 noscan

이제 다시 hciconfig 명령을 수행해 보면 'DOWN' 대신 'UP  RUNNING'이 보여야 한다.

pi@raspberrypi ~ $ hciconfig
hci0:  Type: BR/EDR    Bus: USB
       BD Address: 00:1A:7D:DA:71:12 ACL MTU: 310:10 SCO MTU: 64:8
       UP RUNNING
       RX bytes: 1008 acl:0 sco:0 events:45 errors: 0
       TX bytes: 236 acl:0 sco:0 commands: 45 errors: 0
pi@raspberrypi ~ $

이제 마지막으로 해 줘야 할 일은 advertising data에 beacon 값을 넣어주는 것이다. 다음과 같이 명령을 입력해 준다. (좀 길지만 한 줄에 다 입력해 준다.)


pi@raspberrypi ~ $ sudo tools/hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A 
FF 4C 00 02 15 E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 00 00 00 00 C8 00

위의 값들 중에서 FF는 Manufacturer Specific Data의 시작을 알려 주고, 4C 00은 Apple의 Company ID(0x004C), 그리고 나머지 부분부터 C8까지가 beacon의 payload이다.

이제 라즈베리 파이는 비콘으로 동작하게 된다. 확인해 보려면 iOS7 이후 버젼을 OS를 사용하는 아이폰/아이패드/아이팟 터치 또는 안드로이드 폰에 beacon toolkit 또는 유사한 앱을 설치해 실행하면 된다.

앱을 시작해 listen 모드로 들어가면 아래와 유사한 화면을 볼 수 있을 것이다.



이제 동작하는건 확인했지만 라즈베리 파이를 부팅할 때 마다 매번 위의 명령을 입력하기 힘드니 스크립트를 사용하는것이 편하다.

pi@raspberrypi ~ $ cat /home/pi/beacon.sh

#!/bin/bash
# ref: http://www.theregister.co.uk/Print/2013/11/29/feature_diy_apple_ibeacons/
set -x
# inquiry local bluetooth device
#hcitool dev
export BLUETOOTH_DEVICE=hci0
#sudo hcitool -i hcix cmd <OGF> <OCF> <No. Significant Data Octets> <iBeacon Prefix> <UUID> <Major> <Minor> <Tx Power> <Placeholder Octets>

#OGF = Operation Group Field = Bluetooth Command Group = 0x08
#OCF = Operation Command Field = HCI_LE_Set_Advertising_Data = 0x0008
#No. Significant Data Octets (Max of 31) = 1E (Decimal 30)
#iBeacon Prefix (Always Fixed) = 02 01 1A 1A FF 4C 00 02 15

export OGF="0x08"
export OCF="0x0008"
export IBEACONPROFIX="1E 02 01 1A 1A FF 4C 00 02 15"

#uuidgen  could gerenate uuid
export UUID="4a 4e ce 60 7e b0 11 e4 b4 a9 08 00 20 0c 9a 66"

export MAJOR="00 02"
export MINOR="00 01"
export POWER="C5 00"


# initialize device
sudo hciconfig $BLUETOOTH_DEVICE up
# disable advertising
sudo hciconfig $BLUETOOTH_DEVICE noleadv
# stop the dongle looking for other Bluetooth devices
sudo hciconfig $BLUETOOTH_DEVICE noscan

sudo hciconfig $BLUETOOTH_DEVICE pscan


sudo hciconfig $BLUETOOTH_DEVICE leadv

# advertise
sudo hcitool -i $BLUETOOTH_DEVICE cmd 0x08 0x0008 $IBEACONPROFIX $UUID $MAJOR $MINOR $POWER
sudo hcitool -i $BLUETOOTH_DEVICE cmd 0x08 0x0006 A0 00 A0 00 00 00 00 00 00 00 00 00 00 07 00
sudo hcitool -i $BLUETOOTH_DEVICE cmd 0x08 0x000a 01

echo "complete"


pi@raspberrypi ~ $

/home/pi/beacon.sh 라는 파일을 만들어 위의 파란색 부분의 내용을 넣어주면 된다. 위의 스크립트 중에 hcitool cmd 0x08 0x0006 a0 00 a0 00 .. 에서 첫번째/두번째 바이트 (0xa0 0x00)은 minimum interval, 세번째/네번째 바이트(0xa0 0x00)은 maximum interval이다. 0xa0 0x00은 0x00a0 (big endian)이 되므로 10진수로는 160이 된다. BLE에서 시간 granularity는 0.625ms이므로 최소/최대 인터벌은 모두 160 * 0.625ms = 100ms가 된다. 즉 매 0.1초마다 한번씩 비콘 신호를 advertising하게 된다.

파일을 만들었으면 chmod 명령으로 실행 퍼미션을 추가해 준다.

pi@raspberrypi ~ $ chmod +x beacon.sh

이제부터는 ./beacon.sh 만 입력해 주면 라즈베리 파이가 비콘으로 동작한다.

pi@raspberrypi ~ $ ./beacon.sh
+ export BLUETOOTH_DEVICE=hci0
+ BLUETOOTH_DEVICE=hci0
+ export OGF=0x08
+ OGF=0x08
+ export OCF=0x0008
+ OCF=0x0008
+ export 'IBEACONPROFIX=1E 02 01 1A 1A FF 4C 00 02 15'
+ IBEACONPROFIX='1E 02 01 1A 1A FF 4C 00 02 15'
+ export 'UUID=4a 4e ce 60 7e b0 11 e4 b4 a9 08 00 20 0c 9a 66'
+ UUID='4a 4e ce 60 7e b0 11 e4 b4 a9 08 00 20 0c 9a 66'
+ export 'MAJOR=00 01'
+ MAJOR='00 01'
+ export 'MINOR=00 00'
+ MINOR='00 00'
+ export 'POWER=C5 00'
+ POWER='C5 00'
+ sudo hciconfig hci0 up
+ sudo hciconfig hci0 noleadv
+ sudo hciconfig hci0 noscan
+ sudo hciconfig hci0 pscan
+ sudo hciconfig hci0 leadv
+ sudo hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 4a 4e ce 60 7e b0 11 e4 b4 a9 08 00 20 0c 9a 66 00 01 00 00 C5 00
< HCI Command: ogf 0x08, ocf 0x0008, plen 32
  1E 02 01 1A 1A FF 4C 00 02 15 4A 4E CE 60 7E B0 11 E4 B4 A9
  08 00 20 0C 9A 66 00 01 00 00 C5 00
> HCI Event: 0x0e plen 4
  01 08 20 00
+ sudo hcitool -i hci0 cmd 0x08 0x0006 A0 00 A0 00 00 00 00 00 00 00 00 00 00 07 00
< HCI Command: ogf 0x08, ocf 0x0006, plen 15
  A0 00 A0 00 00 00 00 00 00 00 00 00 00 07 00
> HCI Event: 0x0e plen 4
  01 06 20 0C
+ sudo hcitool -i hci0 cmd 0x08 0x000a 01
< HCI Command: ogf 0x08, ocf 0x000a, plen 1
  01
> HCI Event: 0x0e plen 4
  01 0A 20 0C
+ echo complete
complete 

pi@raspberrypi ~ $

이제 라즈베리 파이를 비콘으로 사용하려면 부팅될 때 마다 자동으로 위의 스크립트가 실행되도록 설정해 주면 된다.

라즈베리 파이에서 특정 프로그램이 부팅될 때 실행되게 하는 방법은 몇가지가 있지만 /etc/rc.local을 수정하는 방법 또는 cron을 사용하는 방법은 문제가 있다. 라즈베리 파이에서 블루투스가 활성화 된 이후에 위의 스크립트가 실행되어야만 하는데 두가지 방법은 스크립트가 먼저 실행되어 버리기 때문에 비콘으로 동작하지 못한다.

그러므로 systemd를 사용해 준다. 먼저 /lib/systemd/system 디렉토리에 두개의 파일을 만들어 준다. 각각 파일의 내용은 아래와 같다.

pi@raspberrypi ~ $ cat /lib/systemd/system/beacon.service
[Unit]
Description=Beacon service
After=bluetooth.target

[Service]
Type=forking
ExecStart=/home/pi/beacon.sh
ExecReload=/home/pi/beacon.sh

[Install]
WantedBy=bluetooth.target


pi@raspberrypi ~ $ cat /lib/systemd/system/beacon.target
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Beacon
Documentation=man:systemd.special(7)
StopWhenUnneeded=yes


pi@raspberrypi ~ $ sudo systemctl daemon-reload
pi@raspberrypi ~ $ sudo systemctl enable beacon.service
Synchronizing state for beacon.service with sysvinit using update-rc.d...
Executing /usr/sbin/update-rc.d beacon defaults
Executing /usr/sbin/update-rc.d beacon enable


pi@raspberrypi ~ $

이제 시스템을 리부팅 하면 항상 자동으로 비콘이 시작된다.





아이폰에서 Beecon 앱으로 확인해 본 결과이다. 스크립트에서 설정한 UUID(4a4e......9a66) , Major(2), Minor(1) 를 확인할 수 있다.






댓글 2개:

  1. raspberry pi 3를 advertise하고 싶은데, 그자체를 비콘으로 만드는 방법으로 이렇게 하면 되는건가요?? ccs를 활용해서 wi-fi모듈과 연결하는 작업 진행중입니다

    답글삭제