バルス!さくらのクラウドに物理的に「バルス」を実装してみた

f:id:febc_yamamoto:20161210212946p:plain

本稿はさくらインターネット Advent Calendar 2016(その1)の19日目の記事です。
前日の記事は@BakeTanukiさんによるKUSANAGI + ウェブアクセラレータという組み合わせについてでした。

a-lab.biz

この記事の中で拙作「wp-sacloud-webaccel」についてもご紹介いただきました!ありがとうございました!!


さて、今回はさくらのIoT Platformを使ったネタを仕込んでみました。
成功例だけでなく、途中の失敗体験を含めて詰め込んでしまったために長い記事になってしまいました。すいません。

さくらのIoT Platformに取り組む/取り組まれている方の参考になれば幸いです。

言い訳:
筆者はWeb系エンジニアであり、ハードウェアについてはいわゆる「Lチカ」ができる程度です。また、IoTへの取り組みは今回初チャレンジでした。
このため、当記事で作成するものについて実用性や安全性など考慮出来ていませんので、当記事を参考する際はその辺りご注意ください。

はじめに:Terraformプラグイン開発中のお悩み

Advent Calendar1日目の前佛さんの記事「Terraform for さくらのクラウド入門チュートリアル」にてご紹介いただいた、 Terraform for さくらのクラウドというTerraformプラグインについてですが、プラグインを開発している時、実際にさくらのクラウド上にリソースを作成するテストも多いため、こんな悩みがあります。

さくらのクラウド上にゴミリソースが溜まっていく。。。」

実際にさくらのクラウド上にリソースを作成するようなテストを行う際、 テストの異常終了などでクリーンアップ処理が正常に行われず、ゴミが溜まっていくことがあります。

後でまとめて消しても良いのですが、対象リソースによっては作成数の上限があるため、 こまめに削除しないとテストの実行がままならないというものもあります。 例えばデーターベースアプライアンスは上限数が1のため、リソース作成済みだとテストで新たに作成しようとしてもエラーになってしまいます。

「手動でポチポチ削除するのめんどくさい、、、」

「めんどくさいなー」と思いつつ、さくらのクラウド上のコントロールパネルをポチポチ操作してリソースを削除しようとすると、

  • 電源を切ってからじゃないと削除できない
  • 他のリソースと接続している場合、切断してからじゃないと削除できない(スイッチとか)

といったことがあり、泣きながら個々のリソースの電源断/切断などを行なってから削除、という作業をしていました。

そこでふと思い浮かんだのが、、、

バルス」って叫んだら、さくらのクラウド上の全リソース消せないかな?

ということでした。(バルスとは:Wikipedia)

とりあえずやってみよう!ということで、「バルス on さくらのクラウド」を実装してみることにしました。

バルス」を実行するための構成要素は?

参考サイト:天空の城ラピュタ:Wikipedia

まずはどのような機能/要素が必要なのかの検討のため、「バルス」の動きを以下の図で表してみました。

f:id:febc_yamamoto:20161210144707p:plain

①飛行石に触れ②「バルス」と叫ぶことで飛行石が反応します。

バルス発動条件には諸説あるようですが、ここでは飛行石に接触した状態で「バルス」と言えば発動すると仮定しています。

続いて飛行石が③呪文が「バルス」かの判定を行います。

飛行石は他にもいくつかの呪文に反応するため、 飛行石自体が音声への反応/認識ができるようになっているものと思われます。

条件を満たすと、飛行石が④ラピュタの中枢にあるコンピューターへ破壊を指示し、 ⑤ラピュタの破壊処理が行われ、ラピュタが落ちることになります。

バルス」を現実世界に落とし込んでみる:その1(失敗編)

先ほど「バルス」の機能/要素を抽出したため、それを現実世界で実現可能な方法に落とし込んでみます。

後述しますが、この方法は結果的に失敗に終わりました。。。
このため、具体的なコードは最低限のもの以外省略しています。

f:id:febc_yamamoto:20161210144552p:plain

飛行石に触っているかの判定を実装する

バルス発動条件である飛行石に触れるについては①タクトスイッチを押すことで実装できそうです。

バルス」と言われたかの判定を実装する

飛行石はそれ自体が音声を認識しているようですね。
現実世界においては音声認識モジュールなどを利用すれば実装できそうですが、音声認識モジュールは高価な部品です。
私のようなハードウェアに疎いエンジニアにとって、高価なハードウェアは使いこなせなかった時の心理的ダメージやトラブル時の対応への不安があるので出来るだけ避けたいものです。

複雑な処理はさくらのIoT Platformの通信モジュールを使ってリモートで全部処理しちゃえ!

そこで、今回は「さくらのIoT Platform」の通信モジュールを利用し、 ハードウェアは最小限の動き(AD変換とデータ送信)のみ行うようにすることで安価な部品で事足りるようにしてみました。

f:id:febc_yamamoto:20161210144610p:plain

さくらのIoT Platformは、公式サイトにて以下のように説明されています。

「さくらのIoT Platform」は、モノとネットワークでデータを送受信するための通信環境、データの保存や処理に必要なシステムを一体で提供するIoTのプラットフォームです。
モノに組み込むための「さくらの通信モジュール」と当社のデータセンターを、安全性を確保するためのLTE閉域網で接続し、ストレージ、データベースなどのバックエンドシステム、外部のクラウドやアプリケーションサービスとAPI連携システムを一体型で統合的に提供します。

さくらの通信モジュールは複雑な設定など必要なく、専用のシールドなどを利用してArduinoに接続すればすぐ使えるようになっています。
Arduinoで利用できるライブラリも提供されているため、簡単なメソッド呼び出しで通信を実現することができそうです。

マイク入力 + AD変換 + データ送信

②「バルス」と叫ぶと、

  • (③の1)マイクで音声を入力、ArduinoでAD変換
  • (③の2)変換したデータを通信モジュールでそのまま送信

という処理を行うようにします。

さくらのIoT Platformは外部との連携用にWebhookが使える

また、さくらのIoT Platformでは通信モジュールからのデータ受信時に外部のシステムと連携するためのOutgoing Webhookが用意されています。
今回はこれを利用して、Arukas上にバルス判定サーバーを立てて、そこにWebhookで通知、各種処理を行うようにします。

f:id:febc_yamamoto:20161210174514p:plain

ArukasはDockerコンテナのホスティング環境です。まだβ期間ということで無料で使えます。

バルス判定サーバーでの処理

バルス判定サーバーでは以下の処理を行います。

waveファイルは非常に単純なファイルフォーマットのため、簡単なバイナリーの操作(ヘッダの設定)で作成することができます。

今回はWebhookの受信処理やバイナリー操作を行うため、実装にはGo言語を採用しました。

さくらのクラウド上のリソース全消し処理

バルス」判定がOKだった場合はさくらのクラウド上のリソース全消しを行います。
これはさくらのクラウドAPIAPIライブラリを利用すればすぐに実装できますね。
バルス判定サーバーをGo言語で書いたため、こちらもGo言語で実装することとしました。


ここまでの処理をまとめると以下のような感じになります。
f:id:febc_yamamoto:20161215224045p:plain

では後はこれらが本当に実現可能かプロトタイピングしながら確認してみましょう。

プロトタイピングしてみる!

これらの機能要素が本当に実現できるのか、小分けにして実装を試してみました。

マイクの入力を扱う

まずはマイクとArduinoでどこまで音声が拾えるのか試してみました。

マイクは1個240円で売っていたノーブランド品のMAX4466を調達しました。
(2016年12月現在はノーブランドのものは品切れのようですが、スイッチサイエンスさんでも同等品を扱っているようでした)

エレクトレットマイクアンプモジュール

エレクトレットマイクアンプモジュール

Arduinoは永久保証の付いているスイッチサイエンスさんの品を選びました。
また、安価なArduino UNO互換品もありましたので、万が一に備えて予備として購入しておきました。

【永久保証付き】Arduino Uno

【永久保証付き】Arduino Uno

こちらのサイトを参考に、マイク+Arduinoと手元のMacをUSB接続し、Processingでwaveファイルを作成してみました。
以下の流れで、マイクからの入力をシリアル接続(USB)経由で手元のMacに送ってwaveファイル作成を行なっています。

  • (1) 手元のMacにてProcessingを起動
  • (2) Arduinoにてマイク(MAX4466)からのアナログ入力を取得
  • (3) 取得した値はArduinoからシリアル出力
  • (4) Processingにてシリアル入力を読みwaveファイルを作成

f:id:febc_yamamoto:20161210144619p:plain:w400

結果、多少のノイズは乗っているものの、十分に声が判定できるwaveファイルが出来ました。
必要があればバルス判定サーバー上でwaveファイルに対して波形編集を行うことで音圧調整やノイズ除去などを行うようにします。

(なお、参考サイトのコードだとサンプリングレートが足りず、Arduinoレジスタ設定でanalogRead()の速度アップを行ったりしました。 )

Azure Cognitive Servicesで音声(wave)からテキストへ変換してみる

Azure Cognitive Servicesとはマイクロソフトが提供している、AIを利用して様々な「モノゴトを認識させる」ためのAPI群です。

f:id:febc_yamamoto:20161210170932p:plain

ここでは、先ほど作成した音声ファイルをAzure Cognitive ServicesのAPIを利用してテキストへ変換してみます。

REST形式でAPIを呼び出してみる

以下のドキュメントを参考に、REST形式でAPIを呼び出してみました。

Azure Cognitive Services(Bing speech API)ドキュメント

  • Azure側の準備

本稿では詳細な手順は省略しますが、APIを利用するには、AzureポータルにてCognitive Services APIsを有効化しておく必要があります。
こちらのサイトなどを参考に準備し、 APIの呼び出しに必要なキーを発行しておきましょう。

  • curlコマンドでAPIを呼び出し

APIの挙動を確かめるため、以下のようなシェルスクリプトcurlコマンドを利用してAPIを呼び出してみました。
対象の音声ファイルはカレントディレクトリにtest.wavという名前で配置しています。

#!/bin/sh

# 認証トークンの取得
curl -X POST -H "Ocp-Apim-Subscription-Key:[Azureポータルで取得したAPIキー]" -H "Content-Length:0" https://api.cognitive.microsoft.com/sts/v1.0/issueToken > test_token

# API呼び出し
VERSION=3.0
REQUEST_ID=`uuidgen`
APP_ID=D4D52672-91D7-4C74-8AD8-42B1D98141A5
FORMAT=json
LOCALE=ja-JP
INSTANCE_ID=`uuidgen`
DEVICE=test

curl -v -L -X POST -H "Authorization: Bearer `cat test_token`" \
     -H "Content-Type: audio/wav; samplerate=8192" \
     --data-binary @test.wav \
     -m 30 \
"https://speech.platform.bing.com/recognize?version=$VERSION&requestid=$REQUEST_ID&appID=$APP_ID&format=$FORMAT&locale=$LOCALE&device.os=$DEVICE&scenarios=ulm&instanceid=$INSTANCE_ID"

呼び出しが成功すると、以下のようなJSONが取得できます。

{
    "header": {
        "lexical": "バルス", 
        "name": "バルス", 
        "properties": {
            "HIGHCONF": "1", 
            "requestid": "xxxxxxxx-nnnn-xxxx-nnnn-xxxxxxxx10xx"
        }, 
        "scenario": "ulm", 
        "status": "success"
    }, 
    "results": [
        {
            "confidence": "0.8237563", 
            "lexical": "バルス", 
            "name": "バルス", 
            "properties": {
                "HIGHCONF": "1"
            }, 
            "scenario": "ulm"
        }
    ], 
    "version": "3.0"
}

無事認識されているようですね!
これと同等の処理をバルス判定サーバー上に実装すれば良さそうです。

さくらのIoT Platformとの連携用にGo言語でWebhook受信サーバーを立てる

続いて音声データをさくらのIoT Platformから受け取るために、Go言語でWebhook受信用サーバーを実装してみました。
さくらのIoT PlatformとのWebhookやりとり部分は今後も汎用的に使いそうなので「sakura-iot-go」という名前でライブラリとして切り出してみました。

このライブラリを利用すれば、以下のようなコードでさくらのIoT PlatformからのWebhook受信サーバーを実装できます。

package main

import (
    "fmt"
    sakura "github.com/yamamoto-febc/sakura-iot-go"
    "net/http"
)

func main() {

    // パス"/"で待ち受け
    http.Handle("/", &sakura.WebhookHandler{

        // IoT Platformの管理画面(Outgoing Webhook)で設定したSecret
        Secret: "[put your secret]",

        HandleFunc: func(p sakura.Payload) {
            // [ここにWebhook 受信時の処理を書く]
        },
    })
    // ポート番号8080で待ち受け
    http.ListenAndServe(":8080", nil)
}

これで無事にIoT PlatformからのWebhookを受信できました。
バルス判定サーバーはこのライブラリを利用して実装するようにします。

Arukasで動かすためにDockerイメージ化

Arukas上で動かすためには、DockerイメージをDockerHubで公開しておく必要があります。
そこで、Go言語で実装したバルス判定サーバーを実行するDockerイメージを作成し公開することにします。

Dockerfileの作成

Dockerfileは以下のようになります。
Go言語でアプリケーションを実装すると、実行ファイル1つにパッケージングすることができるので、Dockerイメージ化は非常に楽です。
実行ファイルをADDしてENTRYPOINTに指定するだけ済んじゃいます。非常にシンプルですね。

FROM alpine:3.4
LABEL maintainer="Kazumichi Yamamoto <yamamoto.febc@gmail.com>"
MAINTAINER Kazumichi Yamamoto <yamamoto.febc@gmail.com>

RUN set -x && apk add --no-cache --update ca-certificates

ADD 作成した実行ファイル /bin/

ENTRYPOINT ["/bin/作成した実行ファイル"]

いよいよ通信モジュールを繋いでみる

f:id:febc_yamamoto:20161210144838p:plain

次に実際に通信モジュールを繋いでさくらのIoT Platform経由で音声データを送ってみます。

音声データのサイズはどれくらい?

今回は1秒間の音声データを取得することにします。
音声認識をするためには、サンプリングレート8000程度は欲しいところです。

1回のサンプリング(Arduino上でanalogRead()を実行する)で1byte(0〜255)の値を取得するようにすると、
1秒 × 8000回 × 1byte = およそ8Kbyte となります。

バッファが足りない、、、!?

通信モジュールが1回で送信できるデータには限りがあります。 (通信モジュールβ版ではバッファ/データキューは32個とのことでした。参考:データシート)
このため、溢れたデータはArduino上のメモリなどのバッファに置いておかないと消失してしまいます。

そして今回利用しているArduino(UNO)には利用可能なメモリとして2KbyteのSRAM、1KbyteのEEPROMしかありません。
このままではおよそ8Kbyteある音声データが溢れて消えてしまいます。

このため、バッファリング用のSRAMモジュール(32Kbyte)を個別に追加して対応しています。

F-RAMモジュール FM25W256

F-RAMモジュール FM25W256

音声データを送信してみる

タクトスイッチを押している間、マイクからの入力を取り込むことにします。
入力データは一旦バッファに置いて、順次通信モジュールで送信してみました。

ここで問題が!!!

ここまでは順調だったのですが、とうとう問題が発生してしまいました。その問題とは、、、

  • 通信モジュールからCMD_ERROR_BUSYというエラーが返ってくる
  • 1秒分のデータを送信完了するまで40秒以上かかる

という2つです。40秒では支度できないということですね。困りました。。。

何が悪いのか?

Arduino側で、以下のようなコードでデータ送信を行なっていました。

void flushSamples(){

  // Tx Queue
  uint8_t ret;
  uint8_t avail;
  uint8_t queued;
  uint8_t buf[8] = {0};

  // SRAMに置いたデータを順次処理する  
  for(int i = 0;i < MAX_DATA_LEN;i++){

    // バッファ(8byte)にデータが溜まったら通信モジュールのキューに入れる
    if (i > 0 && i % 8 == 0){
      ret = sakuraio.enqueueTx(DATA_CHANNEL, buf);
      // キューに入れたらバッファをクリア
      memset(buf , 0 , sizeof(buf));
    }

    buf[i%8] = (uint8_t)data.read(i);

    // 通信モジュールのキューの現在サイズを取得    
    sakuraio.getTxQueueLength(&avail, &queued);
    if(queued >= 30){  // 30個キューに溜まったら送信実施
      ret = sakuraio.send(); // [ここでCMD_ERROR_BUSYというエラーが頻発]
      while(ret != 1){       // send()が成功するまでインターバルを入れながらループする
        delay(500);
        digitalWrite(STATUS_LED_PIN, HIGH);
        delay(500);
        digitalWrite(STATUS_LED_PIN, LOW);
        ret = sakuraio.send();
        Serial.print(".");
        if (ret == 1){
          Serial.println("Done.");
        }
      }
    }
  }  
  
  // コントロール用のチャンネルに終了コードを入れておく
  sakuraio.enqueueTx(CONTROL_CHANNEL, END_CODE);

  sakuraio.send(); // キューに残っているデータを送信
}

とにかく短時間で大量のデータを送る必要があるのがネックなようです。
CMD_ERROR_BUSYとなったらインターバルを入れているため、さらに時間がかかることになります。。。

データ量を減らせばなんとかなるか?

データ量を減らしつつ、「バルス」を送信できないか、、、

と悩んでいると、ふと違うやり方を思いつきました。

そうだ!モールス信号があるじゃないか!

音声入力の代わりにモールス信号で「バルス」という文字を入力してもらうようにすればデータ量を減らせそうです。

しかもモールス信号の復号程度ならArduinoだけで処理ができるため、飛行石自体が「バルス」という言われたか認識するという元の処理に近い形が取れそうです。

ということで設計から見直して再チャレンジしてみました。

バルス」を現実世界に落とし込んでみる:その2(成功編)

f:id:febc_yamamoto:20161210144601p:plain

シンプル!非常に単純になりました。

Arduino①モールス信号入力を処理します。信号の入力にはタクトスイッチを利用することにしました。

入力されたモールス信号が「バルス」だった場合は通信モジュールで②データ送信を行います。

サーバー側はデータが到着したらリソース全消し処理を呼び出すだけです。

いけそう!実装してみる!

ということで、以下のような回路にしてみました。

Arduino + LEDが数個 + 入力用のタクトスイッチという非常にシンプルな構成です。

f:id:febc_yamamoto:20161210144546p:plain

入力は「バルス」の英語表現である「balus」をモールス信号にて行います。

注:英語表記はbalus以外にも諸説あるようです。

モールス信号で1文字正しく入力するごとにLEDを点灯させるようにしました。

こんな感じに仕上がりました。

上から見た写真:
f:id:febc_yamamoto:20161210144817p:plain

Arduinoのスケッチはこんな感じです。(抜粋)

#include <SakuraIO.h>
#include "constants.h"
#include "morse_code.h"

// モールス信号で入力するキーワード[ l = long , s = short]
String magicalSpell = "balus"; // [ lsss , sl , slss , ssl , sss]
const byte spellLen = 5;

// モールス信号入力用バッファ
String inputBuf[spellLen];
// バッファの現在位置
byte bufIndex = 0;

// タイマー(スイッチON開始時刻、スイッチOFF開始時刻、最終操作時刻)
unsigned long startTime , endTime , silentTime;

// モールス信号での文字入力ごとに点灯させるLEDの配列
int LEDs[] = {LED1,LED2,LED3,LED4,LED5};

// 文字区切り連続入力防止用
bool isSpacePushed = false;

// バルス処理中フラグ
bool isSpellCasting = false;

// さくらの通信モジュール(I2C)
SakuraIO_I2C sakuraio;

// -------------------------------------------------------------------

void setup(){

  Serial.begin(9600);

  // Arduino各ピンの入出力モード設定
  setupPinMode();

  // さくらの通信モジュールがオンラインなるまで待つ
  connecToSakuraIoT();

  // 初期化完了をシリアル出力でお知らせ
  printInitMessage(magicalSpell);

  // 初期化完了をLEDでお知らせ
  blinkLED(BLINK_INIT);

}

void loop(){

  // バルス処理呼び出し中か?
  if (isSpellCasting){
    checkSakuraResponse();
    return;
  }

  // 無操作になって一定時間経過したら文字の区切りとする
  if (isMorseSilent()){
    Serial.println("space");
    pushMorse(CODE_SILENT);
    isSpacePushed = true;
  }

  if (digitalRead(SW) == SW_ON){     // タクトスイッチが押されている
    digitalWrite(LED_STATUS , HIGH); 
    if (startTime == 0) {
      startTime = millis(); // スイッチONにした時刻
      silentTime = 0;
      isSpacePushed = false;
    }
  }else{                            // タクトスイッチを離した
    digitalWrite(LED_STATUS , LOW);
    if (startTime > 0 && endTime == 0) {
      endTime = millis(); // スイッチをOFFにした時刻
      isSpacePushed = false;
    }
  }

  // タクトスイッチのON/OFF両方の時刻から信号の長短(ツー/トン)を判定
  if (startTime > 0 && endTime > 0){
    if ( isMorseShort() ){      // short(トン)か?

      // 入力バッファへプッシュ
      Serial.println("short");
      pushMorse(CODE_SHORT);
      
    }else if ( isMorseLong() ){ // long(ツー)か?

      // 入力バッファへプッシュ
      Serial.println("long");
      pushMorse(CODE_LONG);
    }

    //判定したら時刻をクリア
    resetStartTime(); 

    // 無操作時間の開始時刻を保持しておく
    silentTime = millis();
  }

  // 無操作時間が閾値(RESET_DUR)を超えたら、それまでの入力をリセット
  if (silentTime > 0){
    if ( millis() - silentTime > RESET_DUR) {
      resetAll();
      blinkLED(BLINK_TIMER_RESET);
    }
  }


}

// 入力バッファにモールス信号を登録
void pushMorse(String code){
  
  if (code.equals(CODE_SHORT)){
    inputBuf[bufIndex].concat(CODE_SHORT);
  }else if (code.equals(CODE_LONG)){
    inputBuf[bufIndex].concat(CODE_LONG);    
  }else if (code.equals(CODE_SILENT)){

    // 単語区切りを受信した。キーワードの文字数までは1文字づつ正答確認を行う。    
    if (bufIndex < magicalSpell.length()-1){
      // 入力されたモールス信号(1文字分)をシリアル出力
      printInputedMorseCode(bufIndex, inputBuf[bufIndex]);
      
      if (isInputMorseOK(bufIndex)) {   // 正しい(キーワードと合致した)モールス信号が入力されたか?
        digitalWrite(LEDs[bufIndex] , HIGH);
        bufIndex++;
      }else{
        // 間違ったコードが入力されたため、メッセージを表示して入力リセット
        printWrongInputMessage();
        
        resetAll();
        blinkLED(BLINK_NOT_CASTED);
        return;
      }
      
    }else{

      // === 入力信号が「バルス」だった場合の処理 ===

      // 入力OKメッセージをシリアル出力
      printOKInputMessage(magicalSpell);
      
      blinkLED(BLINK_CASTED);
    
      sendToSakuraIoT();
    }
  }
}

// さくらのIoT Platformへ指示(処理開始コード)を送信する
void sendToSakuraIoT(){
  sakuraio.enqueueTx((uint8_t)SAKURA_IOT_CHANNEL, (uint32_t)SAKURA_IOT_START_CODE);
  uint8_t ret = sakuraio.send();
  if (ret == CMD_ERROR_NONE) {
    // エラーがなかったら呼び出し中フラグを立てる
    isSpellCasting = true;
  }
}

// さくらのIoT Platformからの応答をチェック
void checkSakuraResponse(){
  uint8_t avail , queued;
  // 受信キューの状態を問い合わせ(現在利用可能なキュー長、キューの中のデータ数)
  sakuraio.getRxQueueLength(&avail, &queued);

  // キューにデータがあれば
  if (queued > 0) {
    uint8_t channel;    // チャンネル
    uint8_t type;       // データのタイプ[i,I,l,L,f,d,b]
    uint8_t values[8];  // データ
    int64_t offset;     // オフセット
    
    uint8_t ret = ret = sakuraio.dequeueRx(&channel, &type, values, &offset);
    if (ret == CMD_ERROR_NONE) {
      // エラーがなかったらデータの確認
      if (channel == SAKURA_IOT_CHANNEL){
        if (values[0] == SAKURA_IOT_END_CODE){

          // 正常終了コードを受信
          blinkLED(BLINK_NORMAL_END);
          isSpellCasting = false;
          return;
          
        }else if (values[0] == SAKURA_IOT_ERROR_CODE){
          // エラーコードを受信
          blinkLED(BLINK_ERROR_END);
          isSpellCasting = false;
          return;          
        }

        // 未知の値は無視
      }
      // 未知のチャンネルでの受信は無視
    }
  }
  blinkLED(BLINK_WAITING_RESPONSE);
}

サーバー側実装

後はサーバー側の実装ですが、こちらはさくらのクラウドAPIを順次呼び出して削除処理を行うだけです。
せっかくなので先ほどの「sakura-iot-go」を利用するために、Go言語で実装してみました。

sacloud-delete-all

なお、この処理は汎用的に使えそうなのでGitHubで独立したリポジトリとして公開しています。

実行!

では順番に実行していきます。

ArukasやさくらのIoT Platformの設定を適切に行なった上で、モールス信号で「balus」と入力してみましょう!

やった!無事動きました!
さくらのクラウドのコントロールパネルを見ると、無事リソースが削除されていることも確認できました!

9Vの電池をつなげて動かすこともできますので、外出先でも「バルス」できますね!

まとめ

ということで、さくらのIoT Platformを使って悪ふざけをしてみましたw

今回の処理内容について

今回の処理の流れは

  • 信号の入力があったら
  • さくらのIoT Platformを通じて通信し
  • サーバー上で削除処理を実行

というものですが、ちょっとしたアイディアで色々な応用ができそうですね。

例えばサーバー上で商品の注文処理を実装すれば Amazon Dashボタンのような動きをさせることもできます。
夢が広がりますね!

失敗/設計変更について

最初の設計では、通信時のBUSYエラーや通信時間が結構かかるという辺りで躓いてしまいました。
大量のデータを短期間で送るということがそもそも通信モジュールの特性とマッチしてないように感じました。

結局、何がおきているのか/何が原因でダメなのかがわからず、設計変更で逃げるような対応となりました。
ハードウェアの絡む問題が発生した際はやはり詳しい専門家のアドバイスが欲しいなーと思いました。 (今回みたいにそもそも設計がダメとかあるだろうし)

とはいえ、さくらのIoT Platformならお試しするための敷居が低いため、まずはプロトタイプで検証という動き方をするのがいいのかなとも思いました。

感想

今回IoT初挑戦だったのですが、めんどくさそうな通信や連携の部分が思ったよりすんなりと書けたことが驚きでした。

電子工作=Lチカというレベルでも、さくらのIoT Platformを使うことで簡単に通信/外部との連携処理まで実装でき、しかもセキュリティーやその後のスケールアップはプラットフォーム側に任せてしまって関心のあるサービスの実装に注力できるというのはいいなーと思いました。

おまけ:今回の副産物

今回のものは悪ふざけで作成したものですが、そんな中でも副産物として実用できるライブラリが数個収穫できましたので以下にまとめておきます。

ついでに今回使ったコードについても全部(ダメだった方も)公開しています。

失敗した方がどんなソースだったのか気になる方は参照してみてください。

ライブラリ

今回のコード(失敗バージョン)

今回のコード(成功バージョン)

以上です。ここまでお読みいただきありがとうございました。