위 동영상(건강데이터 수집 및 기록 시스템 데모) 중 스마트 체중계의 체중정보를 모바일에서 실시간으로 받아오는 기능을 따라하기로 진행합니다.

스마트 체중계에서 체중정보 수신앱 만들기

❑ 앱소개

앱소개

이 앱은 스마트체중계와 블루투스 LE로 연결 해 체중정보를  실시간으로 받아와 화면에 표시하는 앱입니다.

 

따라하기의 목적

스마트 체중계 연결을 통해 블루투스 LE 인터페이스를 제공하는 다양한 기기(또는 센서)에 연결하고 데이터를 수신하는 방법을 이해합니다.

 

따라하기에서는 다음 내용을 다룹니다.

  • RAD Studio로 멀티-디바이스(안드로이드, iOS, 윈도우, OS X) 앱 프로젝트 생성 및 화면 디자인
  • TBluetoothLE 컴포넌트로 스마트 체중계와 연결 및 데이터 수신(구독)
  • 실 기기에 배포 및 테스트(안드로이드 폰, 아이폰)

따라하기

0, 사전 준비사항

1, 빈 멀티-디바이스 애플리케이션 프로젝트 생성

2, 메인 UI 제작

3, 블루투스LE 컴포넌트 추가

4, 주변의 디바이스 탐색

5, 탐색된 디바이스 목록에서 디바이스 선택 후 서비스 탐색

6, 탐색된 서비스 목록에서 서비스를 선택 후 특성 구독

7, 특성 데이터 수신 후 체중 데이터 가져오기

8, 블루투스 권한설정 

9, 디바이스에 배포 및 테스트

0, 사전 준비사항

개발도구 준비하기

델파이(또는 RAD Studio)를 이용해 실습 진행합니다.(이 실습은 델파이 10 시애틀 버전으로 작성되었습니다. 델파이 XE8 이상에서 따라할 수 있습니다.) 

만약, 델파이가 설치되지 않았다면 아래의 페이지에서 델파이를 다운로드 받아 설치 후 진행하시기 바랍니다. 

 

스마트 체중계 준비하기

따라하기에서는 Wahoo Balance Bluetooth Smart Scale 제품을 이용해 실습을 진행합니다.

https://www.underarmour.com/en-us/wahoo-balance-bluetooth-smart-scale/pid1276806-100-OSFA

 

Wahoo Balance Bluetooth Smart Scale은 다음과 같은 디바이스 이름과 UUID를 갖습니다.

디바이스 이름 : Wahoo Scale v1.3

서비스 UUID : 00001901-0000-1000-8000-00805F9B34FB

특성 UUID : 00002B01-0000-1000-8000-00805F9B34FB

위 정보는 구현에 필요한 정보입니다.(시중의 다른 스마트 체중계는 위 값들이 다릅니다.)

 

BLE 구조에 대한 소개

블루투스 LE는 프로파일(Profile), 서비스(Service), 특성(Characteristic) 기반으로 아래 그림과 같이 프로파일은 하나 이상의 서비스를 갖고, 서비스는 하나이상의 특성을 갖는 계층구조로 구성되어 있습니다.

 

 

(출처: GENERIC ATTRIBUTE PROFILE (GATT) - https://developer.bluetooth.org/TechnologyOverview/Pages/GATT.aspx)

 

블루투스 LE 인터페이스를 제공하는 장비와 연결하고 데이터를 받기 위해 다음 과정이 필요합니다.(실제 구현도 다음 단계대로 진행합니다.)

1, 주변의 블루투스 LE 프로파일을 탐색합니다.

2, 탐색된 프로파일에서 서비스를 탐색합니다.

3, 탐색된 서비스에서 특성을 찾아 구독(subscribe)합니다.

4, 구독한 특성에서 발생되는 특성값에서 필요한 데이터를 추출합니다.

1, 빈 멀티-디바이스 애플리케이션 프로젝트 생성

  1. File > New > Multi-Device Application - Delphi 메뉴를 선택 하고, Blank Application을 선택해 프로젝트를 생성합니다.
  2. File > Save all 메뉴를 선택 해 유닛이름을 "MainForm.pas"로 프로젝트 이름을 "SmartScale.dproj"로 저장합니다.

2, 메인 UI를 제작

모바일 앱 스타일로 화면 구성하기 위해 폼디자이너 스타일을 Android로 변경합니다.

 

다음화면과 표를 이용해 체중정보 수신 앱 메인 UI를 개발합니다.

 

상위 오브젝트 

오브젝트 

속성 

값(또는 설명) 

 Form1

 ToolBar1

 

 

 Layout1

 Align

 Top
 Height  81
 Memo1

 Align

 Client

 ToolBar1

 Label1

 Align

 Client

 Text

 스마트 체중계 데모

 TextSettings.HorzAlign

 Center

 Switch1  Align  Right
 Layout1  Text1

 Align

 Center

 Text

 0.0
 TextSettings.Font.Size

 30

 TextSettings.HorzAlign  Trailing
 Width  114
 Text1  Text2  Position.X  120
 Text  Kg

 TextSettings.HorzAlign

 Leading

3, 블루투스 LE 컴포넌트 추가

블루투스 LE 컴포넌트 추가

Tool Palette에서 TBluetoothLE 컴포넌트 선택 해 폼에 추가합니다.

 

필요한 변수, 메소드, 상수 추가

구현에 필요한 변수(디바이스, 서비스, 특성), 메소드 선언(시작, 중지), 상수(장비명과 서비스, 특성 UUID)를 아래와 같이 추가합니다.

 

01 <p>  private
02     { Private declarations }
03     FBLEDevice: TBluetoothLEDevice;
04     FBLEGattService: TBluetoothGattService;
05     FBLEGattChar: TBluetoothGattCharacteristic;
06  
07     procedure StartScale;// 체중계 연결 동작 시작(블루투스LE 활성화, 주변 디바이스 탐색)
08     procedure StopScale;// 체중계 연결 동작 중지(블루투스LE 비활성화, 특성 구독 해제)
09   public
10     { Public declarations }
11   end;
12  
13 const
14   ScaleDeviceName = 'Wahoo';
15  
16   WEIGHT_SERVICE: TBluetoothUUID          = '{00001901-0000-1000-8000-00805F9B34FB}';
17   WEIGHT_CHARACTERISTIC: TBluetoothUUID   = '{00002B01-0000-1000-8000-00805F9B34FB}';</p>

메소드 구현부 생성

StartScale, StopScale 메소드 구현부를 자동 생성하기 위해 procedure StartScale;에 마우스 커서를 옮기고 키보드에서 Ctrl + Shift + C를 동시에 누릅니다.

 

4, 주변의 디바이스 탐색

주변 디바이스 탐색

Switch1의 OnSwitch 이벤트 핸드러 생성(Switch1 컴포넌트 선택 > Object Inspector 창에서 Event 탭 선택 > OnSwitch 우측의 콤보박스 더블클릭) 후 아래 코드를 입력합니다.

1 procedure TForm1.Switch1Switch(Sender: TObject);
2 begin
3   if Switch1.IsChecked then
4     StartScale
5   else
6     StopScale;
7 end;

 

StartScale 메소드에서 블루투스 LE를 활성화하고, 주변 디바이스를 탐색하는 코드를 다음과 같이 입력합니다.
(StopScale은 제일 마지막에 다시 구현합니다.)

1 procedure TForm1.StartScale;
2 begin
3   BluetoothLE1.Enabled := True;
4   BluetoothLE1.DiscoverDevices(1000);// 1초(1000 ms)동안 주변 디바이스 탐색, 완료 시 OnEndDiscoveryDevices 이벤트 발생
5 end;

5, 탐색된 디바이스 목록에서 디바이스 선택 후 서비스 탐색

StartScale 메소드의 DiscoverDevices 메소드 호출하면 (주변의 디바이스 탐색 후) OnEndDiscoverDevices 이벤트가 발생합니다. 

OnEndDiscoverDevices 이벤트는 파라메터로 탐색된 디바이스 목록(ADeviceList)을 제공합니다.

이 디바이스 목록에서 'Wahoo'(위에서 ScaleDeviceName 상수로 선언)로 시작하는 디바이스를 선택합니다.

디바이스를 선택했다면, 디바이스에서 제공하는 서비스 탐색을 시도합니다.

 

01 procedure TForm1.BluetoothLE1EndDiscoverDevices(const Sender: TObject;
02   const ADeviceList: TBluetoothLEDeviceList);
03 var
04   Device: TBluetoothLEDevice;
05 begin
06   if ADeviceList.Count = 0 then
07   begin
08     Memo1.Lines.Add('발견된 디바이스가 없습니다.');
09     Switch1.IsChecked := False;// 디바이스 미발견 시 스위치 끄기
10     Exit;
11   end;
12  
13   FBLEDevice := nil;
14   Memo1.Lines.Add('Device List');
15   for Device in ADeviceList do
16   begin
17     Memo1.Lines.Add(' - ' + Device.DeviceName);// 로그-디바이스 이름
18  
19     // 디바이스 이름으로 디바이스 선택
20     if Device.DeviceName.StartsWith(ScaleDeviceName) then
21     begin
22       FBLEDevice := Device;
23       Memo1.Lines.Add('디바이스를 찾았습니다.');
24     end;
25   end;
26  
27   if FBLEDevice = nil then
28     Exit;
29  
30   // [TIP] 서비스 발견이 실패하는 경우가 종종 있음
31     // 실패한 경우 한번더 발견요청
32   if not FBLEDevice.DiscoverServices then
33     FBLEDevice.DiscoverServices;// 서비스 탐색 완료 시 OnEndDiscoverServices 이벤트 발생
34 end;

6, 탐색된 서비스 목록에서 서비스를 선택 후 특성 구독

서비스 탐색(DiscoverServices)이 완료되면 OnEndDiscoverServices 이벤트가 발생합니다.

OnEndDiscoverServices 이벤트는 파라메터로 탐색된 서비스 목록(AServiceList)을 제공합니다.

이 서비스 목록에서 서비스 UUID와 같은 UUID를 갖는 서비스를 선택합니다.

선택한 서비스에서 특성 UUID로 특성을 찾습니다.

특성에서 체중정보를 포함한 특성데이터를 수신할 수 있도록 구독(SubscribeToCharacteristic) 합니다.

 

01 procedure TForm1.BluetoothLE1EndDiscoverServices(const Sender: TObject;
02   const AServiceList: TBluetoothGattServiceList);
03 var
04   Service: TBluetoothGattService;
05 begin
06   Memo1.Lines.Add('Service List');
07   for Service in AServiceList do
08   begin
09     Memo1.Lines.Add(' - ' + Service.UUID.ToString);// 로그-디바이스 이름
10     if Service.UUID = WEIGHT_SERVICE then
11     begin
12       FBLEGattService := Service;
13       Memo1.Lines.Add('서비스를 찾았습니다.');
14     end;
15   end;
16  
17   if FBLEGattService = nil then
18   begin
19     Memo1.Lines.Add('서비스를 찾지 못했습니다.');
20     Exit;
21   end;
22  
23   // [TIP][예외] 특성목록을 생성하기 위해 아래 코드 호출
24     // GetCharacteristic 바로 호출 시 특성을 가져오지 못해
25     // GetCharacteristics을 먼저 호출
26   BluetoothLE1.GetCharacteristics(FBLEGattService);
27  
28   FBLEGattChar := BluetoothLE1.GetCharacteristic(FBLEGattService, WEIGHT_CHARACTERISTIC);
29   if FBLEGattChar = nil then
30   begin
31     Memo1.Lines.Add('서비스 특성을 찾지 못했습니다.');
32     Exit;
33   end;
34  
35   if BluetoothLE1.SubscribeToCharacteristic(FBLEDevice, FBLEGattChar) then// 구독하면 OnCharacteristicRead 이벤트를 통해 특성 값을 받음
36     Memo1.Lines.Add('특성에 구독했습니다.');
37 end;

7, 특성 데이터 수신 후 체중 데이터 가져오기

특성에 구독(SubscribeToCharacteristic)하면 TBluetooth 컴포넌트의 OnCharacteristicRead 이벤트로 특성 값을 받을 수 있습니다. 스마트 체중계의 경우 체중계의 체중이 변경될 때마다 특성 값을 받을 수 있습니다.

Wahoo Balance Blueeoth Smart Scale은 다음과 같은 코드로 특성값에서 체중 정보를 가져옵니다.

(특성 값을 분석하는 방법은 서비스마다 다릅니다.)

01 procedure TForm1.BluetoothLE1CharacteristicRead(const Sender: TObject;
02   const ACharacteristic: TBluetoothGattCharacteristic;
03   AGattStatus: TBluetoothGattStatus);
04 var
05   Weight: Single;
06 begin
07   Weight := (ACharacteristic.GetValueAsInteger shr 8) / 10;
08     // 특성 값에서 앞의 3byte 이용, 마지막 숫자는 소숫점이므로 10으로 나누기
09  
10   Text1.Text := Format('%3.1f', [Weight]);
11 end;

 

마지막으로 앞에서 선언한 StopScale에 특성 구독을 해지하고, 블루투스 LE를 비활성화하는 코드를 추가합니다.

1 procedure TForm1.StopScale;
2 begin
3   if Assigned(FBLEDevice) and Assigned(FBLEGattChar) then
4     BluetoothLE1.UnSubscribeToCharacteristic(FBLEDevice, FBLEGattChar);
5   BluetoothLE1.Enabled := False;
6 end;

8, 블루투스 권한설정

 

(이 과정은 안드로이드 플랫폼을 사용하지 않는 경우 생략할 수 있습니다.)

비콘은 블루투스 LE(Low Energy) 기반으로 통신합니다.  블루투스 사용권한을 설정합니다.

Project > Options 메뉴를 선택 후 Uses Permissions 화면으로 이동합니다.

 

Bluetooth와 Bluetooth admin 두개의 권한을 사용하도록 설정합니다.

9, 디바이스에 배포 및 테스트

 

처음 디바이스에 배포하는 경우 먼저 모바일 개발환경 설정하고 진행하기 바랍니다.

 

개발을 완료했습니다. 이제 준비된 개발환경으로 플랫폼 선택 후 Run > Run Without Debugging 메뉴를 이용해 실행하고 테스트 합니다.

 

 

테스트 방법:

  1. 디바이스의 블루투스 기능을 킵니다.
  2. 앱을 실행 후 스위치를 커서 주변의 블루투스 LE를 탐색해 스마트 체중계와 연결합니다.
    (메모 컨트롤에 "디바이스를 찾았습니다." > "서비스를 찾았습니다." > "특성에 구독했습니다." 메시지가 표시되면 정상 연결된 것입니다.)
  3. 체중계에 올라가면 실시간으로 앱에 체중정보가 표시되는 것을 확인합니다.
 
번호 제목 글쓴이 날짜 조회 수
공지 [DelphiCon 요약] 코드사이트 로깅 실전 활용 기법 (Real-world CodeSite Logging Techniques) 관리자 2021.01.19 22583
공지 [UX Summit 요약] 오른쪽 클릭은 옳다 (Right Click is Right) 관리자 2020.11.16 21024
공지 [10.4 시드니] What's NEW! 신기능 자세히 보기 관리자 2020.05.27 23071
공지 RAD스튜디오(델파이,C++빌더) - 고객 사례 목록 관리자 2018.10.23 28870
공지 [데브기어 컨설팅] 모바일 앱 & 업그레이드 마이그레이션 [1] 관리자 2017.02.06 30050
공지 [전체 목록] 이 달의 기술자료 & 기술레터 관리자 2017.02.06 25393
공지 RAD스튜디오(델파이, C++빌더) - 시작하기 [1] 관리자 2015.06.30 46347
공지 RAD스튜디오(델파이,C++빌더) - 모바일 앱 개발 사례 (2020년 11월 업데이트 됨) 험프리 2014.01.16 182308
583 (작성 중) 파이어몽키 모바일 개발에 대한 FAQ [1] 험프리 2015.12.01 519
582 이 달의 기술자료 - 2015년 12월 file 험프리 2015.11.27 580
581 [업데이트][10 시애틀] RAD Studio 10 시애틀 서브스크립션 업데이트 1 [3] file 험프리 2015.11.25 1629
580 [발표자료] 20151124 온라인세미나: 델파이 코드 마이그레이션 Step by Step 관리자 2015.11.25 627
579 BPL(패키지)를 이용해 프로그램 모듈화 하기 험프리 2015.11.24 1183
578 [발표자료] 20151119 델파이 소스코드의 재발견 관리자 2015.11.20 677
577 [마이그레이션][팁] 유니코드 검토 대상 분석 도구 다운로드 [1] file 험프리 2015.11.16 1948
576 [마이그레이션][팁] 설치된 컴포넌트 확인 팁 file 험프리 2015.11.12 870
575 [마이그레이션][팁] 배치파일(커맨드 명령어)을 이용해 손쉽게 소스파일 갯수를 파악할 수 있습니다. file 험프리 2015.11.12 2716
574 [안드로이드] 배포파일, 아이콘, 스플래쉬 등이 잘 배포되었는지 확인하기 file 험프리 2015.11.11 1571
573 이 달의 기술자료 - 2015년 11월 file 험프리 2015.10.30 795
572 [발표자료] 20151019 David I 초청 워크샵: 윈도우 애플리케이션 개발자를 위한 DeepDive! 관리자 2015.10.20 650
571 [시애틀] 블루투스 LE를 지원하는 디바이스에서 비콘 광고데이터를 발생할 수 있습니다. file Humphery 2015.10.06 727
570 [시애틀] 모든 종류의 안드로이드 인텐트(Intent)를 처리할 수 있습니다. Humphery 2015.10.06 900
569 [시애틀] BSON(Binary JSON)을 처리하고, JSON 데이터를 스트리밍 모델로 읽고, 쓸수 있습니다. file Humphery 2015.10.05 1795
568 [시애틀] IDE 메모리 개선으로 더 큰 프로젝트를 더 빠르게 코딩하고, 더 빠르게 컴파일 할 수 있습니다. 험프리 2015.10.05 474
567 [시애틀] 작업 중 비정상 종료 시 저장하지 않은 작업을 복구할 수 있습니다. file Humphery 2015.10.05 1078
566 [시애틀][VCL] 고해상도 모니터(4K 모니터와)와 멀티 모니터(모니터 당 DPI)를 지원합니다. [1] Humphery 2015.10.05 1350
» [따라하기] 건강데이터 수집 및 기록 시스템 #1 - BLE 기반 스마트 체중계에서 실시간 데이터 받기 [1] Humphery 2015.10.02 6073
564 [다시보기] RAD Studio 10 시애틀 딥다이브 세션 다시보기(영문) Humphery 2015.10.02 596