Computer >> Hướng Dẫn Máy Tính >  >> Hệ Thống >> Mac

Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước

Bài viết gốc từ www.jaredwolff.com

Tôi từng thất bại. Cả đêm debug project Bluetooth Low Energy (BLE). Đau khổ, bực bội. Sắp bỏ cuộc.

Đó là những ngày đầu BLE. Giờ dễ dàng hơn rất nhiều. Particle Mesh Bluetooth Library không ngoại lệ.

Hướng dẫn này chỉ cách dùng Bluetooth API của Particle. Cấu hình LED và quan sát thay đổi trên tất cả thiết bị trong mạng Mesh. Dùng board Argon và Xenon.

Sẵn sàng? Bắt đầu!

P.S. Bài viết dài. Muốn tải PDF đẹp mắt, click đây.

Giai Đoạn 1: Thiết Lập Bluetooth

  1. Tải/cài Particle Workbench
  2. Tạo project mới. Chọn vị trí, đặt tên ble_mesh
  3. Vào thư mục /src/ mở file <project name>.ino
  4. Đảm bảo deviceOS version > 1.3.0

Viết Code

Thiết lập service với 3 characteristic. Mỗi characteristic tương ứng cường độ LED RGB. Cách setup Bluetooth:

  1. Trong Setup() bật điều khiển app cho LED:
    RGB.control(true);
    
  2. Định nghĩa UUID đầu file .ino:
    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 = định danh duy nhất. Phân biệt service/characteristic trên thiết bị.

    UUID trên dùng trong ví dụ Particle cũ. Tự tạo UUID: uuidgen trên OSX command line hoặc web Online GUID Generator.

    Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước

    Dùng setting trên để tự tạo UUID. Tạo service/characteristic UUID từ UUID sinh ra:

    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
    

    Không có đúng/sai. Chỉ tránh UUID reserved bởi Bluetooth SIG (hiếm). Check tại đây và tại đây nếu muốn. Tạm dùng set UUID đầu tiên.

  3. Trong Setup(), khởi tạo service:
    BleUuid rgbService(serviceUuid);
    

    Bước đầu "đăng ký" service. Chi tiết sau.

  4. Khởi tạo từng characteristic trong 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);
    

    Dùng property WRITE_WO_RSP (ghi không cần response). Tham số 1: tên characteristic. Tham số 2: property. Tham số 3: characteristic UUID. Tham số 4: service UUID. Tham số 5: callback function khi ghi data. Tham số 6: context.

    Callback dùng chung cho 3 characteristic. Cách biết characteristic nào được ghi (trong deviceOS) là qua context. Dùng chính UUID đã có.

  5. Sau khi định nghĩa characteristic, thêm để hiển thị:
    BLE.addCharacteristic(redCharacteristic);
    BLE.addCharacteristic(greenCharacteristic);
    BLE.addCharacteristic(blueCharacteristic);
    
  6. Setup callback function (đặt đầu file, trên Setup()):
    static void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) {
    }
    

    Sẽ định nghĩa chi tiết sau.

  7. Cuối Setup(), setup advertising để thiết bị có thể kết nối:
    BleAdvertisingData advData;
    advData.appendServiceUUID(rgbService);
    BLE.advertise(&advData);
    

    Tạo object BleAdvertisingData. Thêm rgbService (bước 3). Bắt đầu advertising – service và characteristic có thể khám phá được!

Test

Lúc này có chương trình tối thiểu. Compile nạp vào hardware Particle. Hoạt động trên mọi thiết bị Mesh-enabled (Xenon, Argon, Boron).

  1. Tạm thêm SYSTEM_MODE(MANUAL); đầu file. Ngăn kết nối mesh network. Nếu LED nháy xanh khi khởi động, setup qua Particle App trước.
  2. Tải image 1.3.0-rc.1 tại đây. Xenon cần xenon-system-part1@1.3.0-rc.1.bin. Các board khác tìm boron-system-part1@1.3.0-rc.1.bin và argon-system-part1@1.3.0-rc.1.bin. File ở cuối trang dưới Assets.
  3. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  4. Đưa thiết bị vào DFU mode: giữ Mode Button, nhấn chút Reset Button. Giữ Mode cho đến khi LED nháy vàng.
  5. Command line chuyển thư mục chứa file tải. Ví dụ: cd ~/Downloads/
  6. Chạy: particle flash --usb xenon-system-part1@1.3.0-rc.1.bin. Cài OS mới cho Xenon. Xong vẫn nháy vàng nhanh. Board khác đổi tên file cho khớp.
  7. Visual Code: Command + Shift + P → Particle: Compile application (local)
  8. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  9. Fix lỗi nếu có.
  10. Command menu → Flash application (local)
  11. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  12. Khi nạp xong, lấy điện thoại. Mở app BLE scanner. Tốt nhất: NRF Connect và Light Blue Explorer. Dùng Light Blue Explorer.
  13. Kiểm tra thiết bị tên "Xenon-<id>" đang advertising. Thay <id> bằng ID thiết bị.
  14. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  15. Click tên thiết bị.
  16. Xem danh sách service & characteristic. Có UUID service/characteristic đã set không? Ví dụ service UUID 6E400001-B5A3-F393-E0A9-E50E24DCCA9E?
  17. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  18. Nếu đúng như mong đợi, OK. Không thì kiểm tra lại hướng dẫn trước.

Giai Đoạn 2: Xử Lý Dữ Liệu

Tiếp theo: xử lý event ghi (write). Cập nhật function onDataReceived.

Viết Code

  1. Tạo struct lưu trạng thái LED (đầu file):
    typedef struct {
      uint8_t red;
      uint8_t green;
      uint8_t blue;
    } led_level_t;
    
  2. Tạo static variable kiểu này:
    static led_level_t m_led_level;
    

    Hai bước cho phép dùng 1 biến duy nhất biểu diễn 3 giá trị RGB.

  3. Kiểm tra lỗi cơ bản trong onDataReceive. Chỉ nhận 1 byte:
    if( len != 1 ) { return; }
    
  4. Xác định characteristic nào sinh event qua biến context:
    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];
    }
    

    Context = con trỏ string UUID red/green/blue. Set m_led_level để cập nhật RGB LED ngay cả khi chỉ 1 giá trị thay đổi.

  5. Ghi vào object RGB:
    RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
    

Test Code

Lặp quy trình flash như trước.

  1. Đưa thiết bị DFU mode (giữ Mode, nhấn Reset, giữ Mode đến khi LED nháy vàng).
  2. Command menu → Flash application (local)
  3. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  4. Khi nạp xong, kết nối thiết bị bằng Light Blue Explorer.
  5. Chạm characteristic LED đỏ.
  6. Ghi FF. LED đỏ sáng.
  7. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  8. Ghi 00. LED đỏ tắt.
  9. Làm tương tự 2 characteristic còn lại. Đã có điều khiển đầy đủ RGB LED qua BLE!

Giai Đoạn 3: Chia Sẻ Qua Mesh

Đã nhận BLE message thành công, giờ forward lên mạng Mesh.

Viết Code

  1. Bỏ MANUAL mode: comment SYSTEM_MODE(MANUAL);
  2. Đầu file thêm biến theo dõi cần publish:
    static bool m_publish;
    
  3. Khởi tạo trong Setup():
    m_publish = false;
    
  4. Sau khi set RGB LED trong onDataReceived, set true:
    RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
    m_publish = true;
    
  5. Thêm điều kiện trong loop() publish trạng thái LED lên Mesh:
    if( m_publish ) {
      m_publish = false;
      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 yêu cầu string cho 2 tham số. Dùng String::format tạo string từ giá trị red/green/blue.

  6. Subscribe cùng biến trong Setup() để thiết bị khác cũng điều khiển LED trên thiết bị này:
    Mesh.subscribe("red", meshHandler);
    Mesh.subscribe("green", meshHandler);
    Mesh.subscribe("blue", meshHandler);
    
  7. Đầu file tạo meshHandler:
    static void meshHandler(const char *event, const char *data) {
    }
    
  8. Trong meshHandler, chuyển event và data sang String để dùng hàm chuyển đổi/so sánh built-in:
    String eventString = String(event);
    String dataString = String(data);
    
  9. So sánh: kiểm tra tên event, set giá trị dataString cho led level tương ứng:
    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;
    }
    RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
    

    Cuối set màu RGB mới. Xử lý unknown state bằng return trong else – lọc lỗi sớm!

Test Code

  1. Mở Particle App trên điện thoại.
  2. Setup Argon trước. Nếu không nháy xanh, giữ Mode button đến khi nháy xanh.
  3. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước

    Lưu ý: nếu đã nạp app, LED tắt mặc định. Giữ Mode 5 giây rồi tiếp tục.

  4. Làm theo quy trình pairing app. Nhớ mật khẩu Admin mesh network.
  5. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  6. Nạp firmware mới (1.3.0) cho Argon (xem Giai đoạn 1 - Test - Bước 2)
  7. Khi nháy vàng nhanh, nạp app Tinker cho Argon. Tải tại release page.
  8. Khi LED cyan đẹp (kết nối Particle Cloud), nạp app. Dùng Cloud Flash trong menu.
  9. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước

    Particle buộc thiết bị flash locally vào safe mode khi kết nối cloud. Có thể do setup của tôi. Best practice: dùng Cloud Flash.

    Chọn đúng deviceOS version (1.3.0-rc1), device type (Argon), device name (tên đặt lúc setup).

  10. Kết nối Xenon qua phone app
  11. Kết nối Xenon vào Mesh network qua phone app
  12. Flash Xenon dùng Cloud Flash. Dùng tên đặt lúc setup app. Miễn thiết bị kết nối Particle Cloud hoặc safe mode (LED tím), sẽ nạp được.
  13. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  14. Khi kết nối xong, phần vui: mở Light Blue Explorer. Kết nối Argon HOẶC Xenon.
  15. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước
  16. Chọn 1 characteristic LED, thay đổi giá trị.
  17. Làm Chủ Bluetooth API Của Particle: Hướng Dẫn Bước Đi Bước

    LED thay đổi trên TẤT CẢ thiết bị!

Code Hoàn Chỉnh

Code full ghép lại. Dùng để kiểm tra vị trí đặt code!

/*
 * 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) {
  String eventString = String(event);
  String dataString = String(data);
  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;
  }
  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) {
  if( len != 1 ) { return; }
  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];
  }
  RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
  m_publish = true;
}
// setup() runs once, when the device is first turned on.
void setup() {
  RGB.control(true);
  m_led_level.red = 0;
  m_led_level.green = 0;
  m_led_level.blue = 0;
  m_publish = false;
  Mesh.subscribe("red",meshHandler);
  Mesh.subscribe("green",meshHandler);
  Mesh.subscribe("blue",meshHandler);
  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);
  BLE.addCharacteristic(redCharacteristic);
  BLE.addCharacteristic(greenCharacteristic);
  BLE.addCharacteristic(blueCharacteristic);
  BleAdvertisingData advData;
  advData.appendServiceUUID(rgbService);
  BLE.advertise(&advData);
}
// loop() runs over and over again, as quickly as it can execute.
void loop() {
  if( m_publish ) {
    m_publish = false;
    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));
  }
}

Kết Luận

Hướng dẫn này chỉ cách thêm Bluetooth vào project Particle Mesh. Khả năng vô tận. Ví dụ: thêm app user/admin vào trải nghiệm. Tuyệt vời! 😊

Mong đợi thêm nội dung như này trong sách sắp ra mắt: The Ultimate Guide to Particle Mesh. Đăng ký mailing list nhận update và nội dung độc quyền. Subscriber sớm được giảm giá khi phát hành! Đăng ký tại đây.