LINE Things StarterをNefry BTで動かしてみよう #linethings


こんにちは[n0bisuke](https://dotstud.io/members/n0bisuke)です。

アドベントカレンダーの借金を返した感じがするので心が晴れています。
Nefryアドベントカレンダー15日目です！

今日はLINE Thingsを簡単に試せるLINE Things StarterをNefry BTで動かしてみたいと思います。

* [LINE Things Starter](https://github.com/line/line-things-starter)

## 作るもの

<img src="https://i.gyazo.com/b8424ea2da330ef0c7cb71dee059be6e.gif" width="400">

> https://www.instagram.com/p/BqrcdGnDg-Y/

こんな感じで、LIFFアプリ側でボタンを押すとNefry BTのLEDが反応して、Nefry BTのボタンを押すとLIFFアプリに反映されるものを作ります。

## 1. LINE Things Starterと友達になったり下準備

[さっそくLINE Thingsを触ってみた（ESP32でリモートLチカ） #linedevday](https://qiita.com/n0bisuke/items/b0541a32f01007f938a4)の記事のSTEP3の部分を進めましょう。

> <img src="https://camo.qiitausercontent.com/d5fc448024b024e9a26716e8272b2958e3ccd553/68747470733a2f2f692e6779617a6f2e636f6d2f33613239633966613333396638646335396335326462333035376533666130652e706e67" width="300">

↑のQRコードでLINE Things Starterアカウントと友達になりつつ、有効化します。

## 2. Nefry BTにLINE Things Starter向けのファームを書き込む

[Nefry BT向けのArduino IDEの環境構築](https://dotstud.io/docs/nefrybt-setup-arduino-ide/)を参考に、Arduino IDEでNefry BTの開発ができるようにします。

この時のライブラリのバージョンは1.4.1以上にしましょう。（執筆時点の最新）

> 1.4.0以前だとLINE Things向けのファームがうまくコンパイル出来ません。

以下のコードで動きます。

```linethingsstarter.ino
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include<Nefry.h> //Nefryライブラリの読み込み

// Device Name: Maximum 30 bytes
#define DEVICE_NAME "LINE Things Trial ESP32"

// User service UUID: Change this to your generated service UUID
#define USER_SERVICE_UUID "91E4E176-D0B9-464D-9FE4-52EE3E9F1552"
// User service characteristics
#define WRITE_CHARACTERISTIC_UUID "E9062E71-9E62-4BC6-B0D3-35CDCD9B027B"
#define NOTIFY_CHARACTERISTIC_UUID "62FBD229-6EDD-4D1A-B554-5C4E1BB29169"

// PSDI Service UUID: Fixed value for Developer Trial
#define PSDI_SERVICE_UUID "E625601E-9E55-4597-A598-76018A0D293D"
#define PSDI_CHARACTERISTIC_UUID "26E2B12B-85F0-4F3F-9FDD-91D114270E6E"

BLEServer* thingsServer;
BLESecurity *thingsSecurity;
BLEService* userService;
BLEService* psdiService;
BLECharacteristic* psdiCharacteristic;
BLECharacteristic* writeCharacteristic;
BLECharacteristic* notifyCharacteristic;

bool deviceConnected = false;
bool oldDeviceConnected = false;

volatile int btnAction = 0;

class serverCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
   deviceConnected = true;
  };

  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
  }
};

class writeCallback: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *bleWriteCharacteristic) {
    std::string value = bleWriteCharacteristic->getValue();
    if ((char)value[0]) {
      Serial.println("LED ON!");
      Nefry.setLed(0,100,0); //NefryBTのフルカラーLEDを緑に
    }else{
      Nefry.setLed(0,0,0); //NefryBTのフルカラーLEDをOFFに
    }
  }
};

void setup() {
  Nefry.enableSW(); //NefryBTのスイッチの有効化
  
  BLEDevice::init("");
  BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_NO_MITM);

  // Security Settings
  BLESecurity *thingsSecurity = new BLESecurity();
  thingsSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
  thingsSecurity->setCapability(ESP_IO_CAP_NONE);
  thingsSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);

  setupServices();
  startAdvertising();
  Serial.println("Ready to Connect");
}

void loop() {
  uint8_t btnValue;
  
  while (Nefry.readSW() && deviceConnected) {
    Serial.println("SW!");
    btnAction = 0;
    btnValue = Nefry.readSW();
    notifyCharacteristic->setValue(&btnValue, 1);
    notifyCharacteristic->notify();
  }
  
  notifyCharacteristic->setValue(&btnValue, 1);
    notifyCharacteristic->notify();
  // Disconnection
  if (!deviceConnected && oldDeviceConnected) {
    delay(500); // Wait for BLE Stack to be ready
    thingsServer->startAdvertising(); // Restart advertising
    oldDeviceConnected = deviceConnected;
  }
  // Connection
  if (deviceConnected && !oldDeviceConnected) {
    oldDeviceConnected = deviceConnected;
    
  }
}

void setupServices(void) {
  // Create BLE Server
  thingsServer = BLEDevice::createServer();
  thingsServer->setCallbacks(new serverCallbacks());

  // Setup User Service
  userService = thingsServer->createService(USER_SERVICE_UUID);
  // Create Characteristics for User Service
  writeCharacteristic = userService->createCharacteristic(WRITE_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_WRITE);
  writeCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
  writeCharacteristic->setCallbacks(new writeCallback());

  notifyCharacteristic = userService->createCharacteristic(NOTIFY_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY);
  notifyCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
  BLE2902* ble9202 = new BLE2902();
  ble9202->setNotifications(true);
  ble9202->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
  notifyCharacteristic->addDescriptor(ble9202);

  // Setup PSDI Service
  psdiService = thingsServer->createService(PSDI_SERVICE_UUID);
  psdiCharacteristic = psdiService->createCharacteristic(PSDI_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ);
  psdiCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);

  // Set PSDI (Product Specific Device ID) value
  uint64_t macAddress = ESP.getEfuseMac();
  psdiCharacteristic->setValue((uint8_t*) &macAddress, sizeof(macAddress));

  // Start BLE Services
  userService->start();
  psdiService->start();
}

void startAdvertising(void) {
  // Start Advertising
  BLEAdvertisementData scanResponseData = BLEAdvertisementData();
  scanResponseData.setFlags(0x06); // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
  scanResponseData.setName(DEVICE_NAME);

  thingsServer->getAdvertising()->addServiceUUID(userService->getUUID());
  thingsServer->getAdvertising()->setScanResponseData(scanResponseData);
  thingsServer->getAdvertising()->start();
}

void buttonAction() {
  btnAction++;
}
```

## 3. 試す

[LINE ThingsのLIFFアプリ(とデバイス)を自前で作る](https://qiita.com/n0bisuke/items/0c09ae5da43b551e98b1#%E8%A9%A6%E3%81%99)の記事の”試す”部分を試します。

ファームがうまく書き込まれてNefry BTが起動すると、BLEアドバタイズをしてくれて、LINEアプリ側でデバイスを見つけることができます。

> <img src="https://camo.qiitausercontent.com/b69370acbf88b072db8d7ecb5cd410dd6abe958d/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f33353338372f66376235316137612d376438372d303063312d313030332d3637643737623330383336322e6a706567" width="300">

(今回は"LINE Things Starter"って表示になってると思いますが)、選択するとLIFFアプリが起動して試すことができます。

<img src="https://i.gyazo.com/b8424ea2da330ef0c7cb71dee059be6e.gif" width="200">

> 最初のGIFと一緒です。
> https://www.instagram.com/p/BqrcdGnDg-Y/

## まとめ

Nefry BTでもLINE Thingsが動きます。

公式対応のESP32 DevkitCでやれたのでわみさんに連絡したら、すぐに対応してくれたのがさすがです。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35387/466dc583-ec9b-4c19-908c-7e28c93c8122.png" width="400">

<img src="https://qiita-image-store.s3.amazonaws.com/0/35387/2ccff69f-4ce6-e5b4-56dd-1fd461e8e3cd.png" width="300">

Nefry BTもESP32なので色々と活用考えられそうですね！

Nefry BT持ってる人は是非試してみて下さい〜 :)