레이블이 TI SensorTag인 게시물을 표시합니다. 모든 게시물 표시
레이블이 TI SensorTag인 게시물을 표시합니다. 모든 게시물 표시

2015년 3월 12일 목요일

Python으로 SensorTag 사용하기 (Control TI SensorTag using python)

파이선에서 SensorTag를 사용하기 위해 Ian Harvey의 bluepy(https://github.com/IanHarvey/bluepy) 모듈을 사용한다.
링크에서 다운받으면 다음과 같은 파일이 들어있다. bluepy 디렉토리로 가서 make 명령을 실행한다. 이 모듈은 실행하기 위해서 bluepy-helper라는 프로그램이 필요해 make를 실행하면 이 프로그램을 컴파일 해 준다.

# ls -scF
     4 bluepy/         4 README.md       4 bluez-5.4/
     4 docs/           0 __init__.py
# cd bluepy
# make
gcc -L. -O0 -g -DHAVE_CONFIG_H -I../bluez-5.4/attrib -I../bluez-5.4 -I../bluez-5.4/lib -I../bluez-5.4/src -I../bluez-5.4/gdbus -I../bluez-5.4/btio `pkg-config glib-2.0 dbus-1 --cflags` -o bluepy-helper bluepy-helper.c ../bluez-5.4/lib/bluetooth.c ../bluez-5.4/lib/hci.c ../bluez-5.4/lib/sdp.c ../bluez-5.4/lib/uuid.c ../bluez-5.4/attrib/att.c ../bluez-5.4/attrib/gatt.c ../bluez-5.4/attrib/gattrib.c ../bluez-5.4/attrib/utils.c ../bluez-5.4/btio/btio.c ../bluez-5.4/src/log.c `pkg-config glib-2.0 --libs`
# ls -scF
Makefile         bluepy-helper    btle.py          sensortag.py
__init__.py      bluepy-helper.c  btle.pyc


두개의 파이선 파일이 들어있는데 btle.py는 BLE 관련 클래스가 정의되어 있고 sensortag.py는 btle 모듈을 사용해 SensorTag에 연결해 센서값을 읽어오는 기능을 하는 코드가 들어있다. 먼저 btle.py를 사용하면 BLE 디바이스의 service, characteristic 관련 정보를 확인할 수 있다.

# python btle.py BC:6A:29:C3:54:33
Connecting to: BC:6A:29:C3:54:33, address type: public
Service <uuid=Generic Access handleStart=1 handleEnd=11> :
Characteristic <Device Name>, supports READ
-> 'TI BLE Sensor Tag'
Characteristic <Appearance>, supports READ
-> '\x00\x00'
Characteristic <Peripheral Privacy Flag>, supports READ WRITE
-> '\x00'
Characteristic <Reconnection Address>, supports READ WRITE
-> '\x00\x00\x00\x00\x00\x00'
Characteristic <Peripheral Preferred Connection Parameters>, supports READ
-> 'P\x00\xa0\x00\x00\x00\xe8\x03'
Service <uuid=f000aa10-0451-4000-b000-000000000000 handleStart=43 handleEnd=53> :
Characteristic <f000aa11-0451-4000-b000-000000000000>, supports NOTIFY READ
-> '\x00\x00\x00'
Characteristic <f000aa12-0451-4000-b000-000000000000>, supports READ WRITE
-> '\x00'
Characteristic <f000aa13-0451-4000-b000-000000000000>, supports READ WRITE
-> 'd'
Service <uuid=Generic Attribute handleStart=12 handleEnd=15> :
Characteristic <Service Changed>, supports INDICATE
Service <uuid=ffe0 handleStart=93 handleEnd=97> :
Characteristic <ffe1>, supports NOTIFY
Service <uuid=f000aa30-0451-4000-b000-000000000000 handleStart=62 handleEnd=72> :
Characteristic <f000aa31-0451-4000-b000-000000000000>, supports NOTIFY READ
-> '\x00\x00\x00\x00\x00\x00'
Characteristic <f000aa32-0451-4000-b000-000000000000>, supports READ WRITE
-> '\x00'
Characteristic <f000aa33-0451-4000-b000-000000000000>, supports READ WRITE
-> '\xc8'
Service <uuid=f000aa00-0451-4000-b000-000000000000 handleStart=35 handleEnd=42> :
Characteristic <f000aa01-0451-4000-b000-000000000000>, supports NOTIFY READ
-> '\x00\x00\x00\x00'
Characteristic <f000aa02-0451-4000-b000-000000000000>, supports READ WRITE
-> '\x00'
Service <uuid=f000aa60-0451-4000-b000-000000000000 handleStart=98 handleEnd=104> :
Characteristic <f000aa61-0451-4000-b000-000000000000>, supports READ
-> '3\x00'
Characteristic <f000aa62-0451-4000-b000-000000000000>, supports READ WRITE
-> '\x00'
Service <uuid=f000aa50-0451-4000-b000-000000000000 handleStart=85 handleEnd=92> :
Characteristic <f000aa51-0451-4000-b000-000000000000>, supports NOTIFY READ
-> '\x00\x00\x00\x00\x00\x00'
Characteristic <f000aa52-0451-4000-b000-000000000000>, supports READ WRITE
-> '\x00'
Service <uuid=f000aa20-0451-4000-b000-000000000000 handleStart=54 handleEnd=61> :
Characteristic <f000aa21-0451-4000-b000-000000000000>, supports NOTIFY READ
-> '\x00\x00\x00\x00'
Characteristic <f000aa22-0451-4000-b000-000000000000>, supports READ WRITE
-> '\x00'
Service <uuid=Device Information handleStart=16 handleEnd=34> :
Characteristic <System ID>, supports READ
-> '3T\xc3\x00\x00)j\xbc'
Characteristic <Model Number String>, supports READ
-> 'N.A.\x00'
Characteristic <Serial Number String>, supports READ
-> 'N.A.\x00'
Characteristic <Firmware Revision String>, supports READ
-> '1.0 (Dec 10 2012)\x00'
Characteristic <Hardware Revision String>, supports READ
-> 'N.A.\x00'
Characteristic <Software Revision String>, supports READ
-> 'N.A.\x00'
Characteristic <Manufacturer Name String>, supports READ
-> 'Texas Instruments\x00'
Characteristic <IEEE 11073-20601 Regulatory Cert. Data List>, supports READ
-> '\xfe\x00experimental'
Characteristic <PnP ID>, supports READ
-> '\x01\r\x00\x00\x00\x10\x01'
Service <uuid=f000ffc0-0451-4000-b000-000000000000 handleStart=105 handleEnd=65535> :
Characteristic <f000ffc1-0451-4000-b000-000000000000>, supports READ WRITE NO RESPONSE WRITE
-> Error from Bluetooth stack (comerr)
Characteristic <f000ffc2-0451-4000-b000-000000000000>, supports READ WRITE NO RESPONSE WRITE
-> Error from Bluetooth stack (comerr)
Service <uuid=f000aa40-0451-4000-b000-000000000000 handleStart=73 handleEnd=84> :
Characteristic <f000aa41-0451-4000-b000-000000000000>, supports NOTIFY READ
-> '\x00\x00\x00\x00'
Characteristic <f000aa42-0451-4000-b000-000000000000>, supports READ WRITE
-> '\x00'
Characteristic <f000aa43-0451-4000-b000-000000000000>, supports READ
-> '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
#

SensorTag가 제공하는 각 서비스마다 characteristic에 관한 정보를 출력해준다.

sensortag.py는 실행하면 SensorTag에 연결해 원하는 센서값을 지속적으로 읽어온다.

# python sensortag.py --all BC:6A:29:C3:54:33
Connecting to BC:6A:29:C3:54:33
('Temp: ', (26.03125, 26.074251481475812))
('Humidity: ', (26.394373168945314, 41.00469970703125))
('Barometer: ', (26.645779013633728, 1016.758906206612))
('Accelerometer: ', (0.15625, 0.59375, 0.828125))
('Magnetometer: ', (-20.20263671875, 22.4609375, 95.458984375))
('Gyroscope: ', (7.95745849609375, 10.711669921875, -69.57244873046875))
** Right button DOWN
('Temp: ', (26.0625, 25.675194203681826))
('Humidity: ', (26.394373168945314, 41.00469970703125))
('Barometer: ', (26.760699868202209, 1016.8384757575767))
** Right button UP
('Accelerometer: ', (0.171875, 0.75, 0.515625))
('Magnetometer: ', (-22.857666015625, 25.787353515625, 92.315673828125))
** Right button DOWN
('Gyroscope: ', (4.44793701171875, -15.93017578125, -25.39825439453125))
** Right button UP
('Temp: ', (26.09375, 28.389209302147549))
('Humidity: ', (26.394373168945314, 41.00469970703125))
('Barometer: ', (26.8482586145401, 1017.0108461132135))
('Accelerometer: ', (0.15625, 0.765625, 0.625))
('Magnetometer: ', (-22.857666015625, 25.787353515625, 92.315673828125))
('Gyroscope: ', (6.591796875, 3.23486328125, 3.387451171875))
** Left button DOWN
('Temp: ', (26.15625, 29.185403134000069))
** Right button DOWN
('Humidity: ', (26.394373168945314, 41.00469970703125))
** Both buttons UP
('Barometer: ', (26.922136306762695, 1017.0096061331639))
('Accelerometer: ', (0.21875, 0.703125, 0.671875))
('Magnetometer: ', (-22.15576171875, 24.627685546875, 93.20068359375))
^C#

파이선 소스코드를 분석하면 SensorTag에 어떻게 연결하고 필요한 센서를 활성화 한 후 값을 읽어오는 방법을 확인할 수 있다.

여기서는 예제로 에디슨 보드에서 파이선 쉘을 실행해 직접 온습도 센서값을 읽어와 보도록 하겠다.

# rfkill unblock bluetooth
# hciconfig hci0 up
# hcitool lescan
LE Scan ...
D0:39:72:D3:4A:AF (unknown)
D0:39:72:D3:4A:AF Bean
EC:C3:09:E2:18:A4 (unknown)
BC:6A:29:C3:54:33 (unknown)
BC:6A:29:C3:54:33 SensorTag
# python
>>> import struct
>>> from btle import UUID, Peripheral, DefaultDelegate
>>> sensorOn = struct.pack("B",0x01)
>>> sensorTag = Peripheral("BC:6A:29:C3:54:33")
>>> svcUUID = "f000aa20-0451-4000-b000-000000000000"
>>> dataUUID = "f000aa21-0451-4000-b000-000000000000"
>>> ctrlUUID = "f000aa22-0451-4000-b000-000000000000"
>>> svc = sensorTag.getServiceByUUID(svcUUID)
>>> data = svc.getCharacteristics(dataUUID)[0]
>>> ctrl = svc.getCharacteristics(ctrlUUID)[0]
>>> ctrl.write(sensorOn, withResponse=True)
>>> data.read()
'\xb8l\xdfD'
>>> data.read()
'\xb8l\xb2D'
>>> (rT,rH) = struct.unpack('<HH',data.read())
>>> temp = -46.85+175.72*(rT/65536.0)
>>> RH = -6.0+125.0*((rH&0xfffc)/65536.0)
>>> temp
27.8610302734375
>>> RH
27.57696533203125
>>> def tempHum(d):
...  (rT, rH) = struct.unpack('<HH', d.read())
...  temp = -46.85+175.72*(rT/65536.0)
...  RH = -6.0+125.0*((rH&0xfffc)/65536.0)
...  return (temp, RH)
...
>>> tempHum(data)
(27.689428710937499, 25.34918212890625)
>>> tempHum(data)
(27.689428710937499, 25.31103515625)
>>> tempHum(data)
(27.692109985351557, 25.34918212890625)
>>> sensorTag.disconnect()
>>> 

예제에서 svcUUID, dataUUID, ctrlUUID는 위에서 btle.py를 실행한 결과로 출력된 UUID 값이다. 

...
Service <uuid=f000aa20-0451-4000-b000-000000000000 handleStart=54 handleEnd=61> :
Characteristic <f000aa21-0451-4000-b000-000000000000>, supports NOTIFY READ
-> '\x00\x00\x00\x00'
Characteristic <f000aa22-0451-4000-b000-000000000000>, supports READ WRITE
-> '\x00'
...

다른 센서들도 이와 유사한 방법으로 사용하면 된다.

2015년 3월 11일 수요일

Ti SensorTag UUIDs

TMP006 IR Temperature Sensor

Type
UUID
Handle
Read/Write
Format
<Data>
AA01 *
0x25
Read/Notify
ObjLSB ObjMSB AmbLSB AmbMSB (4 bytes) 
<DataNotification>

0x26
R/W
2 bytes
<Configuration>
AA02 *
0x29
R/W
1 byte
<Period>
AA03 *

R/W
1 byte

Kionix KXTJ9 Accelerometer

Type
UUID
Handle
Read/Write
Format
<Data>
F000 AA11 *
0x2D
Read/Notify
X : Y : Z (3 bytes)
<DataNotification>

0x2E
R/W
2 bytes
<Configuration>
F000 AA12 *
0x31
R/W
1 byte
<Period>
F000 AA13 *
0x34
R/W
1 byte


Sensirion SHT 21 Humidity Sensor

Type
UUID
Handle
Read/Write
Format
<Data>
AA21 *
0x38
Read/Notify
TempLSB TempMSB HumLSB HumMSB (4 bytes) 
<DataNotification>

0x39
R/W
2 bytes
<Configuration>
AA22 *
0x3B
R/W
1 byte
<Period>
AA23 *

R/W
1 byte


Freescale MAG3100 Magnetometer

Type
UUID
Handle
Read/Write
Format
<Data>
AA31 *
0x40
Read/Notify
XLSB XMSB YLSB YMSB ZLSB ZMSB (6 bytes)
<DataNotification>

0x41
R/W
2 bytes
<Configuration>
AA32 *
0x44
R/W
1 byte
<Period>
AA33 *
0x47
R/W
1 byte


Epcos T5400-C953 Barometric Pressure Sensor

Type
UUID
Handle
Read/Write
Format
<Data>
AA41 *
0x4B
Read/Notify
TempLSB TempMSB PressLSB PressMSB (4 bytes)
<DataNotification>

0x4C
R/W
2 bytes
<Configuration>
AA42 *
0x4F
R/W
1 byte
<Calibration>
AA43 *
0x52
Read only
C1LSB C1MSB .. C8LSB C8MSB (16 bytes)
<Period>
AA44 *

R/W
1 byte


Invensense IMU-3000 Gyroscope

Type
UUID
Handle
Read/Write
Format
<Data>
AA51 *
0x57
Read/Notify
XLSB XMSB YLSB YMSB ZLSB ZMSB (6 bytes)
<DataNotification>

0x58
R/W
2 bytes
<Configuration>
AA52 *
0x5B
R/W
1 byte
<Period>
AA53 *

R/W
1 byte

Simple Key Service

Type
UUID
Handle
Read/Write
Format
<Data>
FFE1
0x5F
Notification only
Bit2: side key, Bit1: right key, Bit0: left key


















에디슨에서 SensorTag 사용하기 (Using TI SensorTag in Intel Edison)

에디슨에서 SensorTag에 연결하기 위해서는 먼저 블루투스 기능을 활성화 시켜줘야 한다. (TI SensorTag에 대한 소개는 이전 포스트 참조)

# rfkill unblock bluetooth
# hciconfig hci0 up
# rfkill list
0: phy0: wlan
Soft blocked: no
Hard blocked: no
1: brcmfmac-wifi: wlan
Soft blocked: no
Hard blocked: no
2: bcm43xx Bluetooth: bluetooth
Soft blocked: no
Hard blocked: no
3: hci0: bluetooth
Soft blocked: no
Hard blocked: no
#

위와 같이 출력되면 블루투스를 사용할 수 있게 된 것이다. 다음은 주변의 SensorTag를 검색한다. 검색을 하기 전에 SensorTag 왼쪽 옆면에 있는 pairing 버튼을 눌러준다. 그러면 녹색 LED가 빠르게 점멸할것이다. (빨간색 실리콘 케이스를 씌워놓으면 LED 점멸은 보이지 않음)



# hcitool lescan
LE Scan ...
D0:39:72:D3:4A:AF (unknown)
D0:39:72:D3:4A:AF Bean
EC:C3:09:E2:18:A4 (unknown)
BC:6A:29:C3:54:33 (unknown)
BC:6A:29:C3:54:33 SensorTag
^C#
# hcitool lecc BC:6A:29:C3:54:33
Connection handle 64

위에서 형광색으로 된 부분은 검색에서 발견한 SensorTag의 MAC address(여기서는 BC:6A:29:C3:54:33)를 넣어주면 된다. 이제 gatttool을 사용해 직접 명령을 주고받아 본다. (에디슨에 디폴트로는 gatttool은 설치되어 있지 않다. 설치하는 방법은 '에디슨에 gatttool 설치' 참조)

# gatttool -b BC:6A:29:C3:54:33 --interactive
[BC:6A:29:C3:54:33][LE]> connect
Attempting to connect to BC:6A:29:C3:54:33
Connection successful
[BC:6A:29:C3:54:33][LE]> char-read-hnd 0x25
Characteristic value/descriptor: 00 00 00 00
[BC:6A:29:C3:54:33][LE]> char-write-cmd 0x29 01
[BC:6A:29:C3:54:33][LE]> char-read-hnd 0x25
Characteristic value/descriptor: 52 ff d8 0b

핸들 0x25는 온도 센서값을 의미한다. 처음 읽을때는 00이었지만 센서를 활성화(0x29에 1을 써줌)시킨 후에 다시 읽어보면 현재 센서 값이 읽혀진다. 핸들에 대한 자세한 정보는 http://processors.wiki.ti.com/index.php/SensorTag_User_Guide#Gatt_Server 를 참조하면 된다.

[BC:6A:29:C3:54:33][LE]> char-write-cmd 0x26 0100
Notification handle = 0x0025 value: 42 ff d8 0b
Notification handle = 0x0025 value: 42 ff d8 0b
Notification handle = 0x0025 value: 40 ff d8 0b
Notification handle = 0x0025 value: 3f ff d8 0b
Notification handle = 0x0025 value: 41 ff d8 0b
Notification handle = 0x0025 value: 3c ff d8 0b
Notification handle = 0x0025 value: 3b ff d8 0b
Notification handle = 0x0025 value: 42 ff dc 0b
Notification handle = 0x0025 value: 39 ff dc 0b
Notification handle = 0x0025 value: 3e ff dc 0b
[BC:6A:29:C3:54:33][LE]> char-write-cmd 0x26 0000
[BC:6A:29:C3:54:33][LE]> 

온도센서 값을 지속적으로 읽고 싶으면 0x26에 0100을 써 주면 위와 같이 지속적으로 센서값이 리포트된다. 리포팅을 끝내려면 0x26에 0000을 써 주면 된다.

푸쉬버튼 입력 같은 경우는 버튼의 상태를 지속적으로 폴링하는건 매우 비효율적이기 때문에 버튼이 눌린걸 notify 하도록 설정할 수 있다. 아래와 같이 request하면 푸쉬버튼의 상태가 바뀔때 마다 상태값이 통보된다.

[BC:6A:29:C3:54:33][LE]> char-write-req 0x67 80
Characteristic value was written successfully
[BC:6A:29:C3:54:33][LE]> char-write-req 0x60 0100
Characteristic value was written successfully
Notification handle = 0x005f value: 02
Notification handle = 0x005f value: 00
Notification handle = 0x005f value: 01
Notification handle = 0x005f value: 00
[BC:6A:29:C3:54:33][LE]>



왼쪽 버튼이 bit1, 오른쪽 버튼이 bit0이므로 위에서는 먼저 왼쪽 버튼을 눌렀다 뗀 후, 오른쪽 버튼을 눌렀다 뗀 것이다. 버튼이 둘 다 눌리면 03이 통보된다.

이런식으로 SensorTag를 에디슨에 연결해 다양한 동작을 할 수 있다. 여러개의 SensorTag를 집안 곳곳에 설치해 놓고 에디슨에서 센서값들을 읽어들어 IoT 모니터링 시스템을 구축하는등의 다양한 응용이 가능하다.