이 게시물의 출처는 www.jaredwolff.com입니다.
패배했습니다.
나는 Bluetooth Low Energy 프로젝트를 작동시키기 위해 밤새도록 노력했습니다. 고통스러웠다. 실망스러웠다. 저는 포기할 준비가 되어 있었습니다.
Bluetooth Low Energy의 초창기였습니다. 그 이후로 점점 더 쉽게 개발할 수 있게 되었습니다. 파티클 메시 블루투스 라이브러리도 예외는 아닙니다.
이 연습에서는 Particle의 Bluetooth API를 사용하는 방법을 보여 드리겠습니다. 일부 LED를 구성하고 메시 네트워크의 모든 장치에서 변경되는 것을 지켜보겠습니다. 우리는 아르곤과 제논 보드를 사용할 것입니다.
준비가 된? 시작하겠습니다!
추신 이 게시물은 깁니다. 다운로드할 항목이 있으면 여기를 클릭하여 멋진 형식의 PDF를 다운로드하십시오.
1단계:블루투스 설정
-
Particle Workbench 다운로드/설치
-
새 프로젝트를 만듭니다. 적절한 위치를 선택한 다음 이름을
ble_mesh
로 지정했습니다. -
/src/
로 이동 디렉토리를 열고<your project name>.ino
을 엽니다. 파일 -
그런 다음 deviceOS의 버전을> 1.3.0으로 변경했는지 확인합니다.
코드 작성
3가지 특징을 가진 서비스를 구축하고자 합니다. 특성은 각각 RGB LED의 강도와 관련이 있습니다. 블루투스 설정 방법은 다음과 같습니다.
-
Setup()
에서 기능 활성화 앱 제어 LEDRGB.control(true);
-
.ino
상단에 UUID를 설정하세요. 파일const char* serviceUuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; const char* red = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"; const char* green = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"; const char* blue = "6E400004-B5A3-F393-E0A9-E50E24DCCA9E";
UUID는 고유 식별자 또는 주소입니다. 기기에서 다양한 서비스와 특성을 차별화하는 데 사용됩니다.
위의 UUID는 이전 Particle 예제에서 사용되었습니다. 자신 만의 것을 만들고 싶다면
uuidgen
을 사용할 수 있습니다. OSX 명령줄에서. 온라인 GUID 생성기와 같은 웹사이트로 이동할 수도 있습니다.위의 설정을 사용하여 고유한 UUID를 가져옵니다. 그런 다음 생성된 이 항목에서 서비스 및 특성 UUID를 만들 수 있습니다.
const char* serviceUuid = "b425040**0**-fb4b-4746-b2b0-93f0e61122c6"; //service const char* red = "b4250401-fb4b-4746-b2b0-93f0e61122c6"; //red char const char* green = "b4250402-fb4b-4746-b2b0-93f0e61122c6"; //green char const char* blue = "b4250403-fb4b-4746-b2b0-93f0e61122c6"; //blue char
이 작업을 수행하는 데 옳고 그른 방법은 없습니다. 그러나 Bluetooth SIG에서 예약한 UUID를 사용하지 않도록 주의해야 합니다. 이것은 가능성이 매우 낮습니다. 재확인을 원하시면 여기와 여기로 가시면 됩니다.
지금은 첫 번째 UUID 세트를 사용하겠습니다.
-
Setup()
에서 , 서비스를 초기화하십시오.// Set the RGB BLE service BleUuid rgbService(serviceUuid);
서비스 "등록"의 첫 번째 단계입니다. 자세한 내용은 아래를 참조하세요.
-
Setup()
에서 각 특성을 초기화합니다.BleCharacteristic redCharacteristic("red", BleCharacteristicProperty::WRITE_WO_RSP, red, serviceUuid, onDataReceived, (void*)red); BleCharacteristic greenCharacteristic("green", BleCharacteristicProperty::WRITE_WO_RSP, green, serviceUuid, onDataReceived, (void*)green); BleCharacteristic blueCharacteristic("blue", BleCharacteristicProperty::WRITE_WO_RSP, blue, serviceUuid, onDataReceived, (void*)blue);
이 설정에서는
WRITE_WO_RSP
을 사용합니다. 재산. 이것은 우리가 데이터를 쓸 수 있게 하고 응답을 기대하지 않게 합니다.
UUID를 다음 두 매개변수로 참조했습니다. 첫 번째는 특성 UUID입니다. 두 번째는 서비스 UUID입니다.다음 매개변수는 콜백 함수입니다. 이 콜백에 데이터가 기록되면 이 함수가 실행됩니다.
마지막으로 마지막 매개변수는 컨텍스트입니다. 이것이 정확히 무엇을 의미합니까? 우리는 세 가지 특성 모두에 대해 동일한 콜백을 사용하고 있습니다. 어떤 특성이 기록되었는지 알 수 있는 유일한 방법은(적어도 deviceOS에서는) 컨텍스트를 설정하는 것입니다. 이 경우 이미 사용 가능한 UUID를 사용합니다.
-
특성을 정의한 직후 표시되도록 추가해 보겠습니다.
// Add the characteristics BLE.addCharacteristic(redCharacteristic); BLE.addCharacteristic(greenCharacteristic); BLE.addCharacteristic(blueCharacteristic);
-
콜백 기능을 설정합니다.
// Static function for handling Bluetooth Low Energy callbacks static void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) { }
파일 상단(
Setup()
이상)에서 이 작업을 수행할 수 있습니다. ) 나중에 더 자세히 정의하겠습니다. -
마지막으로 장치를 연결할 수 있으려면 광고를 설정해야 합니다. 이 코드를
Setup()
끝에 배치합니다. 기능// Advertising data BleAdvertisingData advData; // Add the RGB LED service advData.appendServiceUUID(rgbService); // Start advertising! BLE.advertise(&advData);
먼저
BleAdvertisingData
를 만듭니다. 물체.rgbService
을 추가합니다. 3단계부터. 마지막으로, 우리의 서비스와 특성을 발견할 수 있도록 광고를 시작할 수 있습니다!
테스트 시간
이 시점에서 우리는 최소한의 실행 가능한 프로그램을 가지고 있습니다. 이를 컴파일하고 파티클 하드웨어에 프로그래밍해 보겠습니다. 이것은 모든 Mesh 지원 장치에서 작동해야 합니다. (제논, 아르곤, 붕소)
-
테스트를 시작하기 전에 임시로
SYSTEM_MODE(MANUAL);
를 추가하세요. 파일 상단으로 이동합니다. 이렇게 하면 장치가 메시 네트워크에 연결되지 않습니다. 시작 시 기기가 파란색으로 깜박이면 계속하기 전에 파티클 앱으로 기기를 설정해야 합니다. -
여기에서 1.3.0-rc.1 이미지를 다운로드하십시오. Xenon의 경우 [email protected]이 필요합니다. 다른 사람들은 [email protected]을 찾으세요. 및 [email protected] 파일은 저작물 아래 페이지 하단에 있습니다.
-
장치를 DFU 모드로 전환하십시오. 모드 버튼 길게 누르기 잠시 후 재설정을 클릭합니다. 버튼. 모드 버튼을 계속 누르고 있습니다. LED가 노란색으로 깜박일 때까지
-
명령줄 창에서 다운로드한 파일을 저장한 디렉터리로 변경합니다. 제 경우 명령은
cd ~/Downloads/
입니다. -
그런 다음 실행:
particle flash --usb [email protected]
그러면 Xenon에 최신 OS가 설치됩니다. 완료되면 노란색으로 계속 빠르게 깜박입니다. 다른 파티클 메시 장치가 있는 경우 다시 일치하도록 파일 이름을 변경합니다.
-
Visual Code에서 Command + Shift + P 사용 명령 메뉴를 팝업하는 키 조합. 입자:애플리케이션 컴파일(로컬)을 선택합니다.
-
나타날 수 있는 오류를 수정하십시오.
-
그런 다음 동일한 메뉴를 열고 Flash 애플리케이션(로컬)을 선택합니다.
-
프로그래밍이 완료되면 전화기를 꺼냅니다. 그런 다음 좋아하는 Bluetooth Low Energy 앱을 엽니다. 가장 좋은 것은 NRF Connect입니다. 및 하늘색 탐색기 이 예에서는 Light Blue Explorer를 사용하겠습니다.
-
이름이 "Xenon-
" 인 기기인지 확인 광고하고 있습니다.삽입 장치의 고유 ID로. -
기기를 찾아 이름을 클릭합니다.
-
서비스 및 특성 목록을 확인하세요. 지금까지 설정한 서비스 및 특성 UUID가 포함되어 있습니까? 예를 들어 서비스 UUID는 6E400001-B5A3-F393-E0A9-E50E24DCCA9E로 표시됩니까? ?
모든 것이 예상대로 표시되면 좋은 위치에 있는 것입니다. 모든 항목이 일치하는지 확인하려면 이전 지침을 따르세요.
2단계:데이터 처리
우리 프로젝트의 다음 단계는 쓰기 이벤트를 처리하는 것입니다. onDataReceived
를 업데이트하겠습니다. 기능.
코드 작성
-
먼저 LED의 상태를 유지할 구조체를 만들어 보겠습니다. 파일 상단에서 수행할 수 있습니다.
// Variables for keeping state typedef struct { uint8_t red; uint8_t green; uint8_t blue; } led_level_t;
-
후반부는 이 데이터 유형을 사용하여 정적 변수를 만드는 것입니다.
// Static level tracking static led_level_t m_led_level;
처음 두 단계에서는 하나의 단일 변수를 사용하여 RGB LED의 세 가지 값을 나타낼 수 있습니다.
-
다음으로
onDataReceive
내부의 기본 오류를 확인하겠습니다. function 예를 들어 우리는 1바이트만 수신하고 있는지 확인하고 싶습니다.// We're only looking for one byte if( len != 1 ) { return; }
-
다음으로 이 이벤트가 어떤 특성에서 비롯되었는지 확인하고 싶습니다.
context
을 사용할 수 있습니다. 이를 결정하는 변수입니다.// Sets the global level if( context == red ) { m_led_level.red = data[0]; } else if ( context == green ) { m_led_level.green = data[0]; } else if ( context == blue ) { m_led_level.blue = data[0]; }
이 경우 컨텍스트는 빨간색, 녹색 또는 파란색 UUID 문자열의 포인터와 같습니다. 또한
m_led_level
를 설정하고 있음을 알 수 있습니다. . 이렇게 하면 값이 하나만 변경되더라도 RGB led를 업데이트할 수 있습니다. -
마지막으로, 일단 설정되면
RGB
에 쓸 수 있습니다. 개체// Set RGB color RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
코드 테스트
장치를 플래시하기 위해 이전과 동일한 절차를 진행해 봅시다.
-
장치를 DFU 모드로 전환하십시오. 모드 버튼 길게 누르기 재설정을 클릭합니다. 버튼. 모드 버튼을 계속 누르고 있습니다. LED가 노란색으로 깜박일 때까지
-
그런 다음 동일한 메뉴를 열고 Flash 애플리케이션(로컬)을 선택합니다.
-
프로그래밍이 완료되면 Light Blue Explorer를 사용하여 기기에 연결합니다. .
-
빨간색 LED에 적용되는 특성을 탭하세요.
-
FF 쓰기 . 빨간색 LED가 켜져야 합니다.
-
00 쓰기 . 빨간색 LED가 꺼져야 합니다.
-
다른 두 특성에 대해서도 동일한 작업을 수행합니다. 이제 Bluetooth Low Energy를 통해 RGB LED를 완전히 제어할 수 있습니다!
3단계:메시를 통한 공유
마지막으로 BLE 메시지를 성공적으로 수신했으므로 이제 메시 네트워크로 전달할 차례입니다.
코드 작성
-
먼저 MANUAL 모드를 제거하겠습니다.
SYSTEM_MODE(MANUAL);
주석 처리 -
파일 상단에 게시해야 하는 경우 추적하는 데 사용할 변수를 추가합니다.
// Tracks when to publish to Mesh static bool m_publish;
-
그런 다음
Setup()
에서 초기화합니다.// Set to false at first m_publish = false;
-
그런 다음
onDataReceived
에서 RGB led를 설정한 후 콜백을 true로 설정해 보겠습니다.// Set RGB color RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue); // Set to publish m_publish = true;
-
loop()
에 조건문을 추가해 보겠습니다. 기능. 그러면 메시 네트워크에 LED 상태가 게시됩니다.if( m_publish ) { // Reset flag m_publish = false; // Publish to Mesh Mesh.publish("red", String::format("%d", m_led_level.red)); Mesh.publish("green", String::format("%d", m_led_level.green)); Mesh.publish("blue", String::format("%d", m_led_level.blue)); }
Mesh.publish
두 입력 모두에 문자열이 필요합니다. 따라서String::format
를 사용하고 있습니다. 빨강, 초록, 파랑 값으로 문자열을 만듭니다. -
그런 다음
Setup()
에서 동일한 변수를 구독해 보겠습니다. . 그렇게 하면 다른 장치로 인해 이 장치의 LED도 업데이트될 수 있습니다.Mesh.subscribe("red", meshHandler); Mesh.subscribe("green", meshHandler); Mesh.subscribe("blue", meshHandler);
-
meshHandler
을 생성하려는 파일의 상단으로// Mesh event handler static void meshHandler(const char *event, const char *data) { }
-
이 애플리케이션에서는
event
가 필요합니다. 매개변수 및data
매개변수. 사용하려면String
으로 변경해야 합니다. 유형. 그렇게 하면 내장된 변환 및 비교 기능을 사용할 수 있습니다. 따라서meshHandler
내부 기능 추가:// Convert to String for useful conversion and comparison functions String eventString = String(event); String dataString = String(data);
-
마지막으로 우리는 몇 가지 비교를 수행합니다. 먼저 이벤트 이름이 일치하는지 확인합니다. 그런 다음
dataString
값을 설정합니다. 해당 led 수준으로.// Determine which event we recieved if( eventString.equals("red") ) { m_led_level.red = dataString.toInt(); } else if ( eventString.equals("green") ) { m_led_level.green = dataString.toInt(); } else if ( eventString.equals("blue") ) { m_led_level.blue = dataString.toInt(); } else { return; } // Set RGB color RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
그런 다음 마지막에 새로운 RGB 색상을 설정합니다.
return
를 추가하여 알 수 없는 상태를 처리하는 방법에 주목하세요.else
의 문 부분. 혼란을 일으키기 전에 오류 조건을 걸러내는 것은 항상 좋은 일입니다!
코드 테스트
-
휴대전화에서 파티클 앱을 엽니다.
-
먼저 아르곤을 설정해 보겠습니다. 파란색으로 깜박이지 않으면 파란색으로 깜박일 때까지 모드 버튼을 누르고 있습니다.
참고:이미 앱을 프로그래밍한 경우 LED는 기본적으로 꺼집니다. 모드 버튼을 5초 동안 누른 다음 계속합니다.
-
페어링 과정을 거칩니다. 앱이 모든 단계를 안내합니다. 메시 네트워크의 관리자 비밀번호를 기억해야 합니다.
-
최신 펌웨어(1.3.0)로 아르곤 프로그래밍(1단계 - 테스트 시간 - 2단계 참조) 이 작업을 수행하는 방법에 대한 알림)
-
노란색으로 빠르게 깜박이면 Tinker 앱으로 아르곤을 프로그래밍합니다. 출시 페이지에서 다운로드할 수 있습니다.
-
멋진 시안색 LED(파티클 클라우드에 연결됨)가 생기면 앱을 프로그래밍합니다. 클라우드 플래시 사용 드롭다운 메뉴의 옵션입니다.
내가 말할 수 있는 한, 파티클은 클라우드에 연결할 때 로컬로 플래시된 모든 장치를 안전 모드로 강제 실행합니다. 제 설정일 수도 있습니다. 마일리지는 여기에서 다를 수 있습니다. Cloud Flash를 사용하는 것이 가장 좋습니다. .
올바른 deviceOS 버전(1.3.0-rc1 ), 기기 유형(아르곤 ) 및 기기 이름(설정 시 지정한 이름 )
-
전화 앱을 사용하여 Xenon에 연결
-
전화 앱을 사용하여 Xenon을 Mesh 네트워크에 연결합니다.
-
Cloud Flash를 사용하여 Xenon 플래시 . 전화 앱을 설정할 때 지정한 이름을 사용합니다. 장치가 Particle Cloud에 연결되어 있거나 안전 모드(보라색 LED)에 있는 한 프로그래밍해야 합니다.
-
일단 연결되면 재미있는 부분으로 가자. 하늘색 탐색기를 엽니다. 아르곤 또는 제논 .
-
LED 특성 중 하나를 선택하고 값을 변경합니다.
모든 장치에서 LED가 변경되어야 합니다!
최종 코드
다음은 모든 조각을 합친 최종 코드입니다. 이것을 사용하여 올바른 위치에 놓았는지 확인할 수 있습니다!!
/*
* Project ble_mesh
* Description: Bluetooth Low Energy + Mesh Example
* Author: Jared Wolff
* Date: 7/13/2019
*/
//SYSTEM_MODE(MANUAL);
// UUIDs for service + characteristics
const char* serviceUuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
const char* red = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
const char* green = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
const char* blue = "6E400004-B5A3-F393-E0A9-E50E24DCCA9E";
// Set the RGB BLE service
BleUuid rgbService(serviceUuid);
// Variables for keeping state
typedef struct {
uint8_t red;
uint8_t green;
uint8_t blue;
} led_level_t;
// Static level tracking
static led_level_t m_led_level;
// Tracks when to publish to Mesh
static bool m_publish;
// Mesh event handler
static void meshHandler(const char *event, const char *data)
{
// Convert to String for useful conversion and comparison functions
String eventString = String(event);
String dataString = String(data);
// Determine which event we recieved
if( eventString.equals("red") ) {
m_led_level.red = dataString.toInt();
} else if ( eventString.equals("green") ) {
m_led_level.green = dataString.toInt();
} else if ( eventString.equals("blue") ) {
m_led_level.blue = dataString.toInt();
} else {
return;
}
// Set RGB color
RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
}
// Static function for handling Bluetooth Low Energy callbacks
static void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) {
// We're only looking for one byte
if( len != 1 ) {
return;
}
// Sets the global level
if( context == red ) {
m_led_level.red = data[0];
} else if ( context == green ) {
m_led_level.green = data[0];
} else if ( context == blue ) {
m_led_level.blue = data[0];
}
// Set RGB color
RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
// Set to publish
m_publish = true;
}
// setup() runs once, when the device is first turned on.
void setup() {
// Enable app control of LED
RGB.control(true);
// Init default level
m_led_level.red = 0;
m_led_level.green = 0;
m_led_level.blue = 0;
// Set to false at first
m_publish = false;
// Set the subscription for Mesh updates
Mesh.subscribe("red",meshHandler);
Mesh.subscribe("green",meshHandler);
Mesh.subscribe("blue",meshHandler);
// Set up characteristics
BleCharacteristic redCharacteristic("red", BleCharacteristicProperty::WRITE_WO_RSP, red, serviceUuid, onDataReceived, (void*)red);
BleCharacteristic greenCharacteristic("green", BleCharacteristicProperty::WRITE_WO_RSP, green, serviceUuid, onDataReceived, (void*)green);
BleCharacteristic blueCharacteristic("blue", BleCharacteristicProperty::WRITE_WO_RSP, blue, serviceUuid, onDataReceived, (void*)blue);
// Add the characteristics
BLE.addCharacteristic(redCharacteristic);
BLE.addCharacteristic(greenCharacteristic);
BLE.addCharacteristic(blueCharacteristic);
// Advertising data
BleAdvertisingData advData;
// Add the RGB LED service
advData.appendServiceUUID(rgbService);
// Start advertising!
BLE.advertise(&advData);
}
// loop() runs over and over again, as quickly as it can execute.
void loop() {
// Checks the publish flag,
// Publishes to a variable called "red" "green" and "blue"
if( m_publish ) {
// Reset flag
m_publish = false;
// Publish to Mesh
Mesh.publish("red", String::format("%d", m_led_level.red));
Mesh.publish("green", String::format("%d", m_led_level.green));
Mesh.publish("blue", String::format("%d", m_led_level.blue));
}
}
결론
이 튜토리얼에서는 파티클 메시 프로젝트에 블루투스를 추가하는 방법을 배웠습니다. 상상할 수 있듯이 가능성은 무한합니다. 예를 들어 사용자/관리 앱을 경험에 추가할 수 있습니다. 정말 대단합니다. ?
다음 책에서 이와 같은 콘텐츠를 더 기대할 수 있습니다. 파티클 메시에 대한 궁극적인 가이드 . 업데이트 및 내부 콘텐츠에 대한 내 목록을 구독하십시오. 또한 모든 초기 구독자는 출시될 때 할인을 받습니다! 여기를 클릭하여 가입하세요.