magnet spinners

なんとなく、こんな磁石を付けたハンドスピナーを作ってみた。



何で作ったか?聞かれるけど、何となく楽しそうな予感がしたから…という所だけだ。他に何の意味もない。

How to Make

作り方は非常に簡単だ。
必要な物は、ダイソー製の100円ハンドスピナー、同じくダイソーで購入できる8個入りのネオジム磁石、そしてペンチがあればOKだ。ちなみに、このペンチもダイソーで100円で購入できる。

まずはペンチを使ってスピナーの外周、金属になっている部分をうまく外す。

あとは外周の3点をペンチでカットして、磁石をくっつけるだけだ。数分もあれば出来るだろう。とっても簡単。

後は両面テープをベアリングが格納されている上蓋の所に貼って、床や板にペタッとくっつければ完成だ。
沢山作って、配置を決めて動かしてみた。



磁石の向きを色々と変えてみて動かして遊んでみるのも良いだろう。

Maker Faire Bay Area 2018

Exploratoriumに続いてMaker Faire Bay Area

会場全体はこんな感じ。

ざっくり東京ドーム3-4個がスッポリ入る感じの広さ。かなり広い。今年、感じたことは、

– Dark Roomが縮小された。ずーっと3のエリアで凄まじく広い所が今年はEducationになった。
– 8の所にMixed Realityのルームが出来た。
– Microsoftの出展がなくなった。いつも2の所とかにあったのに、今年はなぜか車のLEXUSが置いてあった。
– Droneレース・バトルがなくなった。来年は復活するだろうか。
– NINTENDO LABSがメインスポンサーで部屋を丸々1個使っていた。入場制限で超行列だった。
– 安定のFireと巨大ロボ感

スケジュールとしては、1日目はプレとパーティで来場者は少なめ、2,3日目が一般デーで凄まじく来場者が来る。初日のメインは…出展者とこの日のゲスト限定のパエリアパーティ。このサイズのパエリアが何個もあって、ゲストに振る舞われる。

ビールとパエリアは食べ放題(あまって持っていく人も)、はらっぱに座ったり寝転んで・作品を見ながら飲んで、食べて…といった感じ。まさに自由な空気を一番味わえる時になる。これは他のイベントではあまり無い感じで、自分はこの瞬間が一番好きだったりする。
久々に会った人との話を楽しんだり、自分はよく飲んじゃう方で、ビールを沢山のんでいた。


■ 自分の展示物
自分の所はこんな感じ。

セットアップしたら。あとは見に来る人でめちゃいっぱい。持っていった物は前スレに書いた通り、投影物・フラ・led rodの3点。

フラはいつも、どこからともなくガチのダンサーさんがやってきて広い所で好きに回してくれる。

New video by Hirotaka Niisato / Google Photos

led rodはKinectとか人の動きに合わせて動かすこともできる(実際、以前やった時はUnityとKinect v2連動させて多数動かした。一番近くの人の動きを見て寄って動くとか)。ただトラッキングした数は常に秒間数名は拾っている計算でのべ7万人ほど。凄まじく大量の人で、個別にトラッキングできる状況になかったからランダムで動かした。この辺は、また上手い見せ方があったかも知れない。

New video by Hirotaka Niisato / Google Photos

投影物とフラとled rodが合わさって、こんな遊べる空間にできた。これはキット?売らないのー?とか、ステージで使いたい等のリクエストがあったり。
サーボ・ステッパ・ドライバといった非常にシンプルな構成だから、何気に簡単に作れる。ステッパ・サーボの可動部の3Dモデルはあるから、自分でなんとかしてね:)って感じだったら、ご自由にどーぞ!!ってことでコードも込みで公開するかもだけど、自分の余裕のある時に…かな。

New video by Hirotaka Niisato / Google Photos


■ダークルームの住人達
自分のほかにもダークルームには色んな物がたくさん。今年は屋外が微妙に寒くて、LEDやら光りもの・閉ざされたダークルームは暖かくて過ごしやすかったのか、めちゃ人がたくさん。
ダークルームのMaker・クリエイター達はこんな感じ。

こちらはExploratoriumでも展示していた、音の波長・振幅を手前のトルグでいじって浮かばせてダンスする様子を楽しむもの。初めて見たのはかなり昔だと思うけど、何度見ても素晴らしい。

New video by Hirotaka Niisato / Google Photos

お隣の光るピアノ。もう弾かせてー&ヲレの弾く曲を聴いてくれ!!みたいな感じで、ピアノの音が鳴りやまない事はなくて、いつも曲が流れていて素敵だった。

New video by Hirotaka Niisato / Google Photos

全天球パックマン!!所々で途切れているのがじんわりと良い感じ。

New video by Hirotaka Niisato / Google Photos

こちらは乗って操作できる巨大ネコ。ベースは自動車かな。ちびっこが沢山キャーキャー言って動かしたり登ったりして遊んでいた。こういう巨大な物をドン!!と作って持って来れるのは羨ましくもあったりする。

半天球LEDで、さらに回りには360度でスピーカーが全周についているヘルメット。続々とチビッ子が「やってみて良い?」と被っていた。

こちらも毎年見ているような気もするけど、グラスとヘッドフォンと装着してまるでトリップしているような感じ。ディストピア感が漂ってくる。

Makezineにも載った鈴木さんのホネホネさんも。暗い所だとLEDが良い感じにキレイに見えてめちゃ良い。


■光の世界の住人たち

でかいクマの向こうに見えるのは、メインスポンサーさま、NINTENDO LABS。自分は入れなかった。凄い長さの行列が出来ていて、自分も並んで約1時間…でようやく半分弱まで進んだ。これからもう1時間以上、並んで待っていることは出来なくて挫折した。
Maker Faireは家族で来ている所も多くて、並んでいる自分の眼の前のご家族で子供と嫁さんが「ちょっと、あっちのホールに行ってくるから並んでいてちょうだい」と言われて一人並ばされていたお父さんに、なんとも郷愁を感じてしまった。ここに一緒にあと1時間以上、自分は並んでいる事は出来なかった…

こちらはいきなり出来ていたMixed Reality部屋。去年ってVR部屋とかあったっけ?ダークルームのSVVR(Silicon Valley Virtual Reality)は暗闇の住民だぞ、とか思いつつ中へと。もしかしてHololensが沢山あるのかなー?とか思ったら…

まずは小学校からニワトリになれるVR。小学生がVIVEで作ったもの。その名の通り…学校で飼っているニワトリになって餌を食べたり飛び立ったり。説明しているチビッコがかわゆすぎた:)

ルービック・キューブで各面がディスプレイになっているゲームコンソール。24面の立体ディスプレイといった感じ。

他にもステレオカメラ、Vuforiaを使ったものとか。MRというよりも、VR物は全部ここに集めたんだと思われ。ただ、SVVRはダークルームの住人だったけど。
そして次は定番の巨大ロボや制作物・ファイヤー!!なモノたち。まずは巨大ロボ。去年は水道橋重工とバトルを行ったMegaBots、そして今年は… Prosthesisの登場。

実際に歩いている所は少しだけ見れた。自分の身長だと遠くから…アスファルトの上をロボに人が乗り込んで操作するというのは夢があって良い。そして、去年も見たような、毎年見ているような気がするイカさん:)

お約束とも思えるファイヤーなRabid Transit。2017年のBurning Manでもやっていたみたいね。ググるとよく出てくるけど、Maker Faire Bay Areaに出展して、Burning Manでも出ている…というのは見かける。Burning Manの方は行った事は無いけど、何となく行ってみたい。
見て分かると思うけど、”柵”は無い。周りに消火器は置いてあるものの、好きな距離で見ることが出来る。といっても、自分が撮っているこの距離でも火炎の熱気を感じて、これ以上近づくことが出来ない。この熱気が見えない柵としても機能しているような気がする。

New video by Hirotaka Niisato / Google Photos

そしてこんなモノも…そう、IBMの量子コンピュータQ
パット見で…お寺の大伽藍かと思ったよ。ただ、こういうのもMakerとして持ってくるIBMのキップの良さが素敵だ。

今更ながら欲しくなってきたTinyFPGA。Arduino物はモチロンだけど、いろんなマイコンが売っていたりもする。KickStarterを始めとしたクラウドファウンディングに出している所は、ほぼ見かけるような物ばかり。ただ、ビジネス展とは違って、売る気満々という訳じゃなく、「これはどや!!これ使って何を作る!?」といった感じ。

同じ目的のものがすれ違った瞬間

もちろん、IT的なものや電気を通した物ばかりじゃなく、手芸や自家製の食べ物といったのもある。いわゆる物づくりの本質で、必ずしも光ったり電気的な物やセンサー類を使った物が展示の対象という訳でもない。自分でMakeした物、自分で作ることの楽しみ・経験・体験が尊いんだよね。

食べ物は沢山。そしてワイン・ビールもある。美味しい物を食べて、飲みながら面白い物を見て回って楽しめる。

最後にこちらは、Particleから貰ったお土産。もう少しで出てくる新製品Meshの話とか、6LoWPANやネットワークの伝播の仕組だったり機能の話を聞いていて、面白いなーと思っていたら…

「いま、Meshはプレオーダー出来るよ」
「プレオーダーで、確か3個ずつオーダーしているよ」
「おぉ、ありがとう!!これで何か作る予定なの?」
「一応、MQTT(TLS)とか、もうcontributeしていてね」
「マジか!? ヲマエはhirotakasterか!?」
「うん、マジで自分だよ。」
「あのイケてるlibrary作ったのヲマエか。ヲレはコミュで話しているpeekayで、こっちは…」
「おー、マジっすか!? 会えてめっちゃ嬉しいよ」
「これ持ってけよ」
(以降、キャッキャ)

という事で、Tシャツとかトート・NRF・ステッカー類を貰った。何気に目の前にある現物=Meshが欲しかったけどw
ParticleのMesh(ESP32/nRF52搭載)はマジで期待度が高くて、話を聞いていたらすげーオモシロ機能満載でオススメ感(日本で技適的なあれで使えるかどーか不明だけど…)。エンジニアもオモシロ&優しい人たちだし。
こういう出会いがあったりして、何気に楽しい。

Maker Faire行っても一般向けだから売れないし、行ってもしょうがない…という事はたまに聞いたりする。ビジネス向けの展示会では無いから、そりゃそーだというのもあるんだけど、売ろうと思えば売れるし話になったりもする。クラウドファンディングに出しているプロダクトの出展も沢山あるし。
とは言っても、そもそも何で?という所には「楽しいから」という答えがベースにある。ビジネス目的で行っている訳じゃないからね。この辺は、仕事をしただけ儲かる社会から、文化的な所や精神的な物にも価値を見出していくという、価値と文化が社会でどういう扱いで成長・形成していくのか?という部分や、個々人の価値基準に依存する部分だからね。
「クリエイターやMaker・何か作っているひとはマジで楽しいから行ってみたほうが良いよ!!」とは心から思う。ただ、それは押し付けでも何でもなくて、気になったらどうかな…って感じ。

ただ、”楽しいから”、”ヲレの作ったものを見てみない!?”とかが動機で全然良いんじゃないかなーと。後のことは、あとの事でも良いんだろうし。まず自分でやってみる所から。小さいモノでも大モノでも何でも。

ということで、今年も楽しかった!!来年も楽しみに行くと思われっす:)

Maker Faire Bay Area 2018 – Exploratorium After Dark

Maker Faire Bay Area 2018 報告会も終わって、ようやくblogを書く気になってきた。
報告会はゆるい感じで良かった。飲み・食いものは自分で持ってきてね:)ということで、本当にありがたい事に大量の差し入れで、これは無くならないんじゃ…と思ったけど、きれいに無くなってビックリした。
ちなみに自分は始まる前から、すでに酔っていた。あまりに太ってしまったせいで、ココナッツオイル(MCT)減量を懲りずにはじめいた。昼を食べてなかったせいもあって、空きっ腹にアルコール。すぐ良い感じになってしまった。

という事で、今年も行ってきたMaker Faire Bay Area 2018について。まずはExploratoriumから。

■スケジュール
今年はこんな感じの予定で行ってきた。
5/16:出国
5/17:Exploratorium After Dark
5/18-20:Maker Faire Bay Area 2018
5/21-22:LAでぶらり
5/23-24:帰国

■持っていった物
Slime Lamp

距離もの

LED Hula Hoop

LED ROD

ボツったもの
– 扇風機でLED POV
理由 : 扇風機の電源が100Vのみ(米国は120V)、荷物的に入らないことが判明という2重の理由で

– Typing Machine
理由:荷物的にこれ以上は入らないから却下。

– 作ろうと思っていたアイテム
理由:時間的に見せられるレベルまで作り上げるのはムリだと判断

ということで、トータル4個のアイテムを持っていった。荷物の写真を撮っておくのを忘れたけど、キャリーは23kgギリギリで着替えとかはバックパックに入れて、PCはまた別のバック…ということで、トータルで30kgオーバーの重量だったと思う。30kgの米俵をずっと持ってあるいて移動していると思えば楽勝だ。

■ Exploratorium After Dark

Exploratoriumは知っている人も多いと思うけど、日本でいうところの科学未来館のような感じ。After Darkは毎週木曜日の夜に大人限定のイベントで、エッジの効いたアーチスト・研究者のデモをやったりしているとのこと。ワインやビールのアルコールを飲みながらOK、ということもあって雰囲気も良い感じ。

脈拍に合わせて点灯する版を持っていって、お互いの光を混ぜ合わせて光が伝播する様子を見せて、「こうやって、二人のHeart Beatが混じり合って…」といった、大人の夜に合わせたような感じの見せ方をした。夜も深まって、真っ暗になってきたらフラも出して、好きに回して遊んでもらった。

自分の他にも日本からデカ顔さんも。

exploratoriumでの展示で思ったのは…
– スタッフが凄まじく良い。現場で「こうやった方がうまく見せれるかも…」と思って、ちょっとお願いした事を何でもOKといった感じですぐにやってくれる。素晴らしいすぎた。一緒に良いものをゲストに見せて感動を!!という気持ちが伝わってきた。
– 多分、自分の知る限り、Maker FaireのプレイベントでExploratoriumで開催されたのは初だと思われ。SNSやプロモーションで色んな媒体に出て、チケットは完売だったみたい。その辺も力を入れていて、集客もしっかり。素晴らしい。
– 場所も人もとても良い。場所は近くにSFMOMAがあったり、回って見るには良い感じだと思う。自分の苦手はオシャンティ層が来るのかしら…と思ったら、みんな興味津々、気さくで良い感じ。

長くなってきたから、本編のMaker Faireは次に続く…

Make the Solenoid Keyboard.

Solenoid Keyboard(Typing Machine) is funny item. I would describe how to make the this works.

– Typing Board(solenoid typing machine)


1. Simple solenoid test with Arduino Uno
First of all, it have to control the solenoid from Arduino. Here is just 1 solenoid version fritzing circuit. (note)This push type solenoid have 8gf power on 5V from datasheets.

– Parts list.
1. Arduino Uno or Mega
2. 5V solenoid ROB-11015
3. Panjit 1S3 Schottky Barrier Rectifier Diode
4. NPN Transistor 2SC3558-Y
5. 5.6K carbon resistor

– Arduino Sketch

void setup(){
  pinMode(2, OUTPUT);
}

void loop(){
  digitalWrite(2, LOW);
  delay(1000);
  digitalWrite(2, HIGH);
  delay(100);
}

2. set on the keyboard
Test the many solenoid with same circuit. Modify Arduino sketch for many solenoid pin out control.

Next, make the base board for up-setting on the keyboard and solenoid. It have to be checked the Macbook Air keyboard size and solenoid pushing height before make the base-board. Then I used the 2-wood/alminium board/some screw.

Set the solenoid on the base board. I use the 10x100mm Aluminum Frame for solenoid and base board connectivity, bend the Aluminum Frame 90 degree and cut(checking the solenoid length).
When this work, it’s very important checking the keyboard/solenoid setting position and solenoid push length before the setting the solenoid on the base board. This solenoid push power is only 8gf with 5V. Therefore if top of the solenoid position is too near or far to the keyboard, solenoid could not type the keyboard. Solenoid position setting is point of the this typing machine.

Arduino source code is here.

#define SOLENOID_1_PIN_START 2
#define SOLENOID_1_PIN_END 11

#define SOLENOID_2_PIN_START 22
#define SOLENOID_2_PIN_END 51

#define KEYBORAD_5_KEY    22
#define KEYBORAD_4_KEY    23
#define KEYBORAD_3_KEY    24
#define KEYBORAD_2_KEY    25
#define KEYBORAD_1_KEY    26

#define KEYBORAD_Q_KEY    27
#define KEYBORAD_W_KEY    28
#define KEYBORAD_E_KEY    29
#define KEYBORAD_R_KEY    30
#define KEYBORAD_T_KEY    31

#define KEYBORAD_A_KEY    51
#define KEYBORAD_S_KEY    50
#define KEYBORAD_D_KEY    49
#define KEYBORAD_F_KEY    48
#define KEYBORAD_G_KEY    47

#define KEYBORAD_Z_KEY    46
#define KEYBORAD_X_KEY    45
#define KEYBORAD_C_KEY    44
#define KEYBORAD_V_KEY    43
#define KEYBORAD_SPACE_KEY    42

#define KEYBORAD_6_KEY    11
#define KEYBORAD_7_KEY    10
#define KEYBORAD_8_KEY    9
#define KEYBORAD_9_KEY    8
#define KEYBORAD_0_KEY    7

#define KEYBORAD_Y_KEY    6
#define KEYBORAD_U_KEY    5
#define KEYBORAD_I_KEY    4
#define KEYBORAD_O_KEY    3
#define KEYBORAD_P_KEY    2

#define KEYBORAD_H_KEY    41
#define KEYBORAD_J_KEY    40
#define KEYBORAD_K_KEY    39
#define KEYBORAD_L_KEY    38

#define KEYBORAD_B_KEY    37
#define KEYBORAD_N_KEY    36
#define KEYBORAD_M_KEY    35
#define KEYBORAD_ENTER_KEY    34


void setup() {
  for (int i = SOLENOID_1_PIN_START; i <= SOLENOID_1_PIN_END; i++) {
    pinMode(i, OUTPUT);
  }

  for (int i = SOLENOID_2_PIN_START; i <= SOLENOID_2_PIN_END; i++) {
    pinMode(i, OUTPUT);
  }
  
  Serial.begin(9600);
}

void keyput(int key) {
  digitalWrite(key, LOW);
  delay(100);
  digitalWrite(key, HIGH);
  delay(50);
  digitalWrite(key, LOW);
}

void loop() {   
  int input = Serial.read();
  if(input != -1 ){
    if (input == '5')  keyput(KEYBORAD_5_KEY);
    if (input == '4')  keyput(KEYBORAD_4_KEY);
    if (input == '3')  keyput(KEYBORAD_3_KEY);
    if (input == '2')  keyput(KEYBORAD_2_KEY);
    if (input == '1')  keyput(KEYBORAD_1_KEY);
    if (input == 'q')  keyput(KEYBORAD_Q_KEY);
    if (input == 'w')  keyput(KEYBORAD_W_KEY);
    if (input == 'e')  keyput(KEYBORAD_E_KEY);
    if (input == 'r')  keyput(KEYBORAD_R_KEY);
    if (input == 't')  keyput(KEYBORAD_T_KEY);
    if (input == 'a')  keyput(KEYBORAD_A_KEY);
    if (input == 's')  keyput(KEYBORAD_S_KEY);
    if (input == 'd')  keyput(KEYBORAD_D_KEY);
    if (input == 'f')  keyput(KEYBORAD_F_KEY);
    if (input == 'g')  keyput(KEYBORAD_G_KEY);
    if (input == 'z')  keyput(KEYBORAD_Z_KEY);
    if (input == 'x')  keyput(KEYBORAD_X_KEY);
    if (input == 'c')  keyput(KEYBORAD_C_KEY);
    if (input == 'v')  keyput(KEYBORAD_V_KEY);
    if (input == ' ')  keyput(KEYBORAD_SPACE_KEY);
    if (input == '6')  keyput(KEYBORAD_6_KEY);
    if (input == '7')  keyput(KEYBORAD_7_KEY);
    if (input == '8')  keyput(KEYBORAD_8_KEY);
    if (input == '9')  keyput(KEYBORAD_9_KEY);
    if (input == '0')  keyput(KEYBORAD_0_KEY);
    if (input == 'y')  keyput(KEYBORAD_Y_KEY);
    if (input == 'u')  keyput(KEYBORAD_U_KEY);
    if (input == 'i')  keyput(KEYBORAD_I_KEY);
    if (input == 'o')  keyput(KEYBORAD_O_KEY);
    if (input == 'p')  keyput(KEYBORAD_P_KEY);

    if (input == 'h')  keyput(KEYBORAD_H_KEY);
    if (input == 'j')  keyput(KEYBORAD_J_KEY);
    if (input == 'k')  keyput(KEYBORAD_K_KEY);
    if (input == 'l')  keyput(KEYBORAD_L_KEY);

    if (input == 'b')  keyput(KEYBORAD_B_KEY);
    if (input == 'n')  keyput(KEYBORAD_N_KEY);
    if (input == 'm')  keyput(KEYBORAD_M_KEY);
    if (input == '\n')  keyput(KEYBORAD_ENTER_KEY);
  }
}

toioで遊んでキャッキャしてみる

toioのフルキットが届いたから、遊んで行こう。まずはフルキットの壮観な感じでドーン!!

■ とりあえず遊んでみる。
まずは何にしても動かしてみよーってことで、ゲズンロイドの”めだま生物”を動かしてみる。

どこを向いても目玉が向いておいかけてくる。まるで何かの生き物のよう…というか、工作生物という設定でこの子達は全て生き物ってことで、こんどはシャクトリー。

ぶっちゃけ…ずーっと見ていても飽きない。まるで何かの意思を持った人工生物(ここでは工作生物)のように動き続ける。ぼーっと見ていると思うのだけど、この2個のキューブが絶対位置を知りながら、協調動作をしているというのが何気にすごい。大抵は外部のセンサーで位置を補足するんだけど、自己位置同定をして動いている。専用マットの外に出ようとすると、検知して方向を変える。なんかスゲーよ…

このめだめ生物を応用して、目玉をとってLEDライトを付けて、ターゲットに”くつ”を使うと…

延々と靴をLEDで照らしつづけることが出来る。これは…何か面白い用途というか、可能性を感じる。そう、何かに使えそうなのよね。例えば、キューブにもう少し大きい箱を被せて、影絵をずっと照らし続けるとかでも面白そう。

んで、次にネタでダイソーで買ってきたサイリウムと粘土を使ってレースコースを作って…

部屋を真っ暗にすると、幻想的な雰囲気でtoioレースが楽しめる。というか、この時点ではまだ操作が上手くなくって、カクカクしまくっているwww

■ チビッコとガチバトル
そして今度はチビッコとクラフトファイターバトル。

もちろんガチで戦っている。これもダイソーでゲットしてきたキャラを搭載させて、アルティメットバトルの様相になってきている。必殺技とバランスが何気にキーになってくる。自分も、「てめー!!」とか普通に言っている…そう、自分も激しく負けず嫌いだから、この手の勝負&バトルになると相手がチビッコでもマジになる。

シャクトリーの工作(といっても紙を切って貼り付けるだけで超簡単)とかを一通り遊んだら、自分に勝つまで止めないとか恐ろしい事を言い始めてきて、それでも負けないでバトルをしていた最終戦。

負けてしまった…これで開放される。約2時間ほど、あっという間だった。このまま延々と全部やるまで止めない!!とか言われたらどうしよう…とか思っちゃったもん。

そして後日…都内の某所にて飲みの場で持って行って飲んでいたら、さらにカヲスな環境に。

こんな状況でも青いマットの上でtoioのキューブはちゃんと安定的に動作してくれた。”うに”のした、ヱビスビールの横にキューブが光って見える。もちろんだけど、自分も激しく酔っていた。

■ 少し技術的な視点で

やっぱり何か技術的な視点でも見たくなってくる。といっても、モノの持つ力が強くって、触って遊んでいると技術的にどーか?はどーでも良くなってくる。toioは専用のコンソールと動くキューブがBLEで通信して、iPhone/Android的なアプリは今のところは無い。
ただ、
「BLEなら見れるだろう」->
「スマホからキューブに接続出来るだろう」->
「勝手アプリやらが作れてtoioで遊べちゃうだろう」->
「ひゃっはー!!」
と思って…思わずsniffer

WireSharkでtoioが通信しているのを全力でsnifferして見て、何か面白いことが無いかなーと思って見てみたら…位置情報らしき物が秒間30以上で通知されていたり、モーターを動かす情報が飛んでいたり、凄いスピードで流れていく。キューブの操作や動きがリアルタイムに感じて、応答性がめちゃ良いのはこのレスポンシビリティの良さか…とか思いつつ、データを見ていたけど、全然分からん!!ってことで…次はiPhoneのLight Blueからキューブに接続してみた



Light Blueから接続できて、色んなサービスが見えてきた。センサー情報、バッテリー情報が見れたり、ブザーやモーターに値を入れたら音を鳴らしたり動かすことが出来た。そして、notificationをオンにしたら、キューブの動きと連動してデータが取得できるサービスが何個かあって、恐らくこれが位置情報をやりとりしているモノだろう…と思って、キューブを動かしながらデータをぼーっと見ていた。キューブがマット上の印字を読み取って絶対座標の同定を行っているようで(参考)、Bluetoothの動き的に予想したのは次のとおり。

1) ほんの少しの動きでもnotificationが飛んでくるから、精度はかなり良さそう。
2) マット内にゼロ点 or マット外に仮想のx-yのゼロ点(データを受け取るコンソール側で変換)が多分あるはず。
3) ヘッダ、位置情報(x-y?)、精度/印字のID(?)、位置情報の小数点以下(?)、Checksum…etcといったデータ構造かな。

とかとか思ったり、カンで多分これかな〜と思って久々にswiftでBTつなげてiPhoneアプリを適当に作って見てみたら、なんとなく位置情報が取れてるっぽい。

コードはこんな感じ(適当)。

import UIKit
import CoreBluetooth

class ViewController: UIViewController {

    let toioCubeUUID = "toioの-U-U-I-D"
    let toioCubeIDDetectionUUID = "id detectの-U-U-I-D"
    
    var centralManager: CBCentralManager!
    var peripheral: CBPeripheral!
    var serviceUUID : CBUUID!
    var charcteristicUUID: CBUUID!
    var layer: CAShapeLayer! = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        centralManager = CBCentralManager(delegate: self, queue: nil)
        serviceUUID = CBUUID(string: toioCubeUUID)
        charcteristicUUID = CBUUID(string: toioCubeIDDetectionUUID)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    private func drawCircle(xpoint: Int, ypoint : Int) {

        let path = UIBezierPath(arcCenter: CGPoint(x: xpoint, y: ypoint), radius: 10,  startAngle: 0.0, endAngle: CGFloat(Double.pi * 2.0), clockwise: true)
        if (layer != nil) {
            layer.removeFromSuperlayer()
        }
        layer = CAShapeLayer()
        layer.fillColor = UIColor.orange.cgColor
        layer.path = path.cgPath
        
        self.view.layer.addSublayer(layer)
    }
}

extension ViewController: CBCentralManagerDelegate {
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case CBManagerState.poweredOn:
            let services: [CBUUID] = [serviceUUID]
            centralManager?.scanForPeripherals(withServices: services, options: nil)
        default:
            break
        }
    }
    
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,
                        advertisementData: [String : Any], rssi RSSI: NSNumber) {
        self.peripheral = peripheral
        centralManager?.stopScan()
        central.connect(peripheral, options: nil)
    }
    
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        peripheral.delegate = self
        peripheral.discoverServices([serviceUUID])
    }
}

extension ViewController: CBPeripheralDelegate {
    
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        if error != nil {
            print(error.debugDescription)
            return
        }
        peripheral.discoverCharacteristics([charcteristicUUID], for: (peripheral.services?.first)!)
    }
    
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        
        if error != nil {
            print(error.debugDescription)
            return
        }
        
        peripheral.setNotifyValue(true, for: (service.characteristics?.first)!)
    }
    
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        
        if error != nil {
            print(error.debugDescription)
            return
        }
        
        updateWithData(data: characteristic.value!)
    }
    
    private func updateWithData(data : Data) {
        let toioData = data.withUnsafeBytes {
            [UInt8](UnsafeBufferPointer(start: $0, count: data.count))
        }
        
        // 0x03 : cube not set-on the mat
        if (toioData.first != nil) && toioData.first == 0x03 {
            print("Data: \(toioData)")
            
        // 0x01 : get id detection(x-y coordinate)
        } else if (toioData.first != nil) && 0x01 == 0x01 {
            let y : UInt16 = UInt16(toioData[5]) + UInt16(toioData[6]) << 8
            let x : UInt16 = UInt16(toioData[3]) + UInt16(toioData[4]) << 8
            print("x-y :  \(x) , \(y)")
            drawCircle(xpoint: Int(x), ypoint: Int(y))
        }
    }
}

本当にこれで正しいかどうかは分からないけど、何となく雰囲気的には座標が取れて動いているっぽい。更にモーターやブザー(音)を動かしたりする勝手SDKを誰が作っちゃいそーな予感がしている。

このtoioを色々触ってみて思ったのが...技術は抜きに面白い!!ということだった。プログラミングのエッセンスを少し入れると、生き物のように動く。しかも、外部センサー無しに自分の位置を自分で分かった上で。これが良い感じで、外部のKinectのような赤外線・カメラで画像認識・超音波...etcを使うと、電源どーするよ?外部センサー連動&フィードバックどーするよ?とか、何気に面倒なことが起きる。これを考えなくてもOK!!というのは、何気に良い感じだと思われ。
思わずGoogle Homeを乗せてみたらあっさり動いたし、モーターも小型サイズなのにめちゃ強い。ということは...他のセンサー連動で、声や音声を認識して動いたり...といった事もアリな気がするよ。

MQTTとセキュリティ

ふらっと見ていたら、こんな記事を発見した。

刑務所のドア開放や電車の不正操作も? 無防備なMQTTのM2M接続

2分くらいで読める内容だからチェックしてみた方が良いと思われ。自分も端末向けにMQTT(TLS)を出していて、現時点で平文とTLS(暗号/認証)で利用されているアプリケーションの比率は…

MQTT(平文) 44.94K
MQTT(TLS) 1.69K

約26倍もの利用で平文の方が圧倒的に多い。これは、それぞれのライブラリを使っているアプリの数で、実際に端末に配布されている数はもっと多いだろうから、凄く多くの端末が平文で通信を行っているということになる。別に平文を使ってはいけない!!という訳じゃなく、このほぼIoT的なシステムでデファクト気味になっているMQTTを、IoT的な端末で安全に使う方法を少し書いておこう。

1) GWを使う構成
そもそもMQTTは産業向けのプロトコルで使われる想定だったようで、インターネットから閉ざされた閉空間またはセキュリティが担保されたルータやスイッチ配下の端末間ネットワークを構成するために利用される、という方法がメインだったろう。こういったネットワークの場合、内部に悪意のあるモノが無いという前提のもと、平文でやりとりされるのもアリ。
(このような方法に似たもので、Load BalancerでTLS(443)をインターネット側から終端して、バックエンドの通信は平文で行うことでTLSの負荷を軽くする、といった方法はよくある)

MQTT Broker上ではメッセージを終端して、外部との通信はセキュアに行うといったもの。
まぁ、この場合は平文でもOKかなと。ただ、内部に侵入された時も守りたい!!という時は暗号化/認証すればOK。まぁ侵入された時点でノックアウトされているようなもんだけど。

2) インターネット上のサーバに直接接続
これは端末が直接WiFiやルータと接続して、外部と通信を行うものになる。これは当然、暗号/認証をTLSのようなもので行ってセキュアに通信を行う必要がある。ルータ以下はセキュアに守られていても、インターネット上に平文の通信を流すというのは行ってはいけないですね。

3) せめて暗号化
これは、本文のメッセージを平文でインターネット上に流して使いたい…というワガママさんに、どうしても&しょうがなく…といったケースでは仕方なく(本当はダメ)。
この場合の問題点は、認証をどうするよ…ということだ。データを暗号化しても認証を行わないと、不正にデータを取られたり予想外の攻撃を受けたりする。よく証明書を利用すれば、”暗号化されてOK!!”というのを聞いたりするけど、証明書の利用はもちろん暗号化も一つだけど、”相手を認証する”という部分もある。”相手が誰か証明”するってことね。例えば、誰かと話そうと思っている時、その誰かは本当にその人ですか?という時に証明書を取り出して、”自分が本当にその人ですよ”と証明をする。丁度、パスポートや免許で自分の証明をするのと同じような感じ。
この部分的に暗号化を行うとデータ自体は守られそうだけど、接続する時にどうやって認証するのか?というリスクが発生する。MQTT BrokerとID/Passwordで認証すれば?と思うかもしれないけど、このときTLSを利用していないとID/Passwordが平文で流れて見事にヤバい、というか被害が悪化する。これは接続する時はIDだけを変えて、データを垂れ流す時だけだろうか…気合でPub/Subでアプリケーション間で認証するのは出来なくは無いけど。

■ 本当に暗号&認証って必要?
「暗号化とか認証とかめんどくせーし、やってられないし、いいよ平文で見れても気にしないし」という人も居ると思われ。鍵なんか使って暗号化しなくても大丈夫!!ネットを使う人が盗聴とか攻撃を一切しない幸せな世の中だと良いね!!、と自分自身思っているけど、理想と現実は違う。現実は攻撃・盗聴・搾取…etc何でもありで痕跡も消して…というカヲス状態だ。便利なネットだけど、光には影が出来る、というのに似ている。正しいことは、一方からの風景にしか過ぎない。

セキュリティとか必要ないし〜と思う人には、実際にリスクを目の前に見せたりもするんだけど、それで対応するかどうかは…そこ次第。リスクをよくよく理解した上で対応しない、という選択肢もアリ。問題を分かっているという事と、知らないことは大きな差があるからね。まぁ普通は流しているデータを見られてもOK!!という人はあまり居ないと思うのと、本当に理解していたら大抵は後回しでも対応するんだけどね。ま、別に他人事だしどーでもいいけど。

ということで、冒頭の記事が本当なのか、オープンになっているMQTTサーバに接続して、全トピックをSubscribeしてみることにしよう。これはハックでもクラックでも無い。MQTTとして普通にSubscribeしているだけ。これらは平文で流れているもので、ぼーっと見ていただけで何もしていないし、情報にはマスクをしている。というか全部マスクしているw

1) AWSの情報が流れている…
{“arn:XXX:XXX:XX-XXXX-1:xxxxxxx:XXXXXXXXX/XXXX/XXXXXXXXXXXXXX/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx”,….

2) WiFiに接続する証明書が流れている
{“XXXXX”:”XXXXXXXXXXXXXX”,”XXXX”:”XXXXXXXX”}
以下証明書のPEM

3) 某社のIDと入管記録
{“XXXXX” : “XXXXX” ,
“XXXXXX” : “XXX XXX XXX XXX ” ,
“XXXXXX_XXXX” : “XXXX-XX-XX XX:XX:XX” ,
“XXXXXX_XXXX” : “XXXX-XX-XX XX:XX:XX”}

4) 某デバイスや車の位置情報
{latitude”:xx.xxxxxxx,”longitude”:xxx.xxxxxxxxx”,….}

6) その他もろもろ(メアド、環境センサのデータ、 端末名、MAC、IP、PC(Mac/Win)、スマホのデータ、WiFiのデータ、ドアの開閉状態…etc)

あと、この辺の落とし穴として…MQTTサーバだと1883(平文)、8883(TLS)になっていて、8883の方に接続していて暗号化をしていても、1883(平文)の方にもサクットそのまま接続できて、8883側に流しているデータを1883側でSubscribeできる。つまり…オープンなMQTTサーバにヤバいデータは流すな!!ということに尽きるし、余計なポートは閉じれ!!といった感じ。
この皆さんの問題点はデータが見れる他に、トピック名も分かるから偽装のデータを投げたり、当該トピックに大量に流して溢れさせたり(大抵、この手の端末はスペックが低くて大量に投げると止まる)、外部から端末制御…といった、冒頭の記事で言っている内容と同じことが出来る。

こういう平分で全部見れちゃうぜー!!とか眺めていると、もう暗号化しなくてオール平文でも良いんじゃね?って気が、0.0001nmくらい感じてくる。感じるだけで、自分はやらないけどね。
結果…暗号&認証は必要でつ

続・mbedTLSの組込で分かったこと

現在、Particle Photon/Electron向けにMQTT/CoAP/TLS周辺のcommunity libraryを公開している。

利用しているアプリケーションの総数は上記のようになっている。わりと使っているアプリも多くてメンテを何度辞めようか…と思いながらも続けている。それぞれの用途は名前の通り、次のような機能になる。

MQTT : 素のMQTT
MQTT-TLS : TLS向けのMQTT
TlsTcpClient: TLS(TCP)クライアント
coap : 素のCoAP

TLSのベースはmbedTLSの現時点での最新版(2.6.0)を利用している。それぞれの説明はgithub上にて。まえに”mbedTLSの組込で分かったこと“にも記載したけど、今回もmbedTLSを実装して分かったことや、端末の特性上つらいポイントを少し残しておく。

■ 容量との果てしない戦い
ひたすらTLSの容量を削っていく。現時点でのTLS library単体のサイズは50kbytes台になっている。これをアプリに組み込むと…

TlsTcpClient : 63Kbyte

MQTT-TLS : 61Kbyte

証明書は2048bitでPEM形式でソースコードに埋め込んで利用する。その分やアプリサイズを引くと50Kbyte台になる。以前、商用のTLSライブラリは大体50Kbyte程度で、そのくらいまで落とすのも出来るはず…と言ったけど、本当にそういう事に。対応しているCipher SuiteはTLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256だけになってしまった。寂しい…繋げる環境に依ってビルドを変えてターゲットを絞っていく感じを想定して、とりあえず最小にしている。

なぜ容量を減らすか?

これは非常に簡単な理由からで、TLSで容量を沢山使うと、他のlibraryやアプリの実装に容量を使えなくなってしまうから。issueやcommunity上で、「容量でかい・メモリの限界」と言われまくってきたけど、もうこれだけ減らせば十分でしょう。
メモリや容量が大きいと…アプリが書けない、他のlibraryが使えない、TLSのネゴシエーション中の処理でmalloc errorで落ちる、といった様々な問題が起きる。そもそも接続以前に、ネゴシエーション中に落ちるのは心が折れる。
アルゴリズムや実装の選定はmbedTLSの設定(config.h)で追加・除去が簡単に出来る。この設定を調整して実装の選定をしてく。

■ ソースコード修正/関数追加
Particleのビルドは arm-none-eabi-gcc で行われて基本的にはC++で記載していく。ただ、mbedTLSはCだからC++にしていく作業が必要になる。これは拡張子を変えて、キャストを変えたり、関数を変えたり…といった地味な作業になる。

そして必要な関数を用意する。
例えば、TLSで利用する証明書には有効期限という概念がある。ある時刻を過ぎれば証明書は失効する。その証明書が正しいかどうか?を判別するには、端末で時間をちゃんと保持しておく必要がある。ただし、time/gettimeofdayのような関数はもちろんParticleの環境には存在しない。そして、この手の端末だと追加で電池を搭載していないから(電源を切ってもPCとかが日時を保持しているのは、ハードウェアクロック(RTC: Real Time Clock)と電池が搭載されていて端末の電源を落としても時刻を保持してくれている)、起動してネットワークに接続した後に時間を同期して保持&読み出せる必要がある。

これらを用意して証明書をverifyする時に有効期限をちゃんと検証(verify)できるようにする。具体的にはmbedtls/timing.cpp内に、こんな感じのラッパを用意して叩けるようにしておく。

#include "rtc_hal.h"
#include "timer_hal.h"
extern "C" int _gettimeofday( struct timeval *tv, void *tzvp )
{
    uint32_t t = HAL_Timer_Milliseconds();  // get uptime
    tv->tv_sec = HAL_RTC_Get_UnixTime();    // get rtc time before Particle.syncTime()
    tv->tv_usec = ( t % 1000 )*1000;        // get remaining microseconds
    return 0;
} // end _gettimeofday()

そして起動してネットワークに接続後に時刻の同期を行うようにしておく。わりと苦肉の策で、秒については時刻を同期したタイミングで。ただしマイクロ秒については同期しても取れないから、仕方なくuptimeから取得してくることにした(なう)。verifyの時に有効期限を切ってOKにしてしまえば…というのも考えられるけど、さすがにそれはダメかなと。

ここで更に問題になるのが…uint32_tだ。そう、いわゆる2038年問題というやつだ。この秒を扱っているHAL_RTC_Get_UnixTime()の戻りはtime_t(uint32_t)で定義されている。これをuint64_tにすれば問題無しな訳だけど、さらに根っこのfirmware側とMCU側のSDKまで波及しているから、ここだけ修正してもなんともならないという訳ですな。まだこれは20年も先の話なわけだけど、サーバ側だけならまだしも、この手の組込み物だと近くなってきたらドキドキ感が上がってくると思われ(まだ20年も先だけど)。

■ オイコラ技適どーするよ?
これはメンテ上で発生する問題で地味に切ない。現時点でParticleが提供している(していた)端末は次の通り。

– Core(WiFi:技適:日本国内OK、ただしもう入手不能&売ってない)
– Photon(WiFi:技適なし)
– Electron(SIM Cellular 2G/3G:技適なし)

ベースになるライブラリMQTTは、Coreの技適がOKの時に作ってPublishした。その後、Photon、Electronという2つの端末が出てきて主力になっている。ただし、Coreは既に終了している。つまり…
技適がOKの時に作ったライブラリで、その後は技適が無い端末しか無い状態でメンテナンスする」という事が発生する。さらには、「2Gでも動くの?」という質問も来たりする。国内は無いからもちろん海外からだけだけど。そもそも2Gは日本国内には無いだが…

Electronは持ってないし、しょうがないから「検証よろしくね!!」「diffちょうだい!!」という事にしているけど、この辺はなんとかならないかなーと思ったりする。

地味にまだ使っているひと、まだまだ素のMQTTはもう4万アプリ越えてくるし、たまに「もー、絶対にやらん、やーめったっと!!」とかって思ったりするけど、仕方なくメンテを続けて行きそうな感じ。

Alexaで開発する流れ(日本語UI)

Alexaで日本語で開発できるようになったから、サクット作る流れをメモで残しておく。詳細はAmazonの資料だけど、見てもなかなか分からなかったり、謎な部分のお助けになれば。

■ 利用するもの
登録はやっておきましょう。
– Alexaの管理画面(日本版) : https://alexa.amazon.co.jp
– Alexaの管理画面(こっちは米国版) : https://alexa.amazon.com
– Amazonの開発者ポータル : https://developer.amazon.com/edw/home.html#/
– AWS Lambda : https://console.aws.amazon.com/lambda/

ここではサンプルで使われるLambdaのサンプルにもある「色をAlexaに言わせるスキル」の簡易版を作る。どういったものか?と言うと、Alexaに向かって、
自分:「好きな色は赤です。」
Alexa:「あなたの好きな色は赤ですね。」
と色を反芻して言ってくれるもので、基礎的だけど初歩としては簡単な1歩になると思われ。ということで進めていく。

■ Amazonの開発者ポータルで情報を入力する
1. Alexaの開発者ポータルにログイン

2. 新しいスキルを作っていくボタンをぽちる

3.1. スキルの情報を入れていく

言語で日本語を選択できる。スキルの種類については、こちらを参照。自分が使いやすくて感動したのはスマートホームスキル。

3.2. スキルの情報をいれた結果

適当に名前を入れる。呼び出し名は「Alexa、なんちゃらかんちゃら」とスキルを起動するときの”なんちゃらかんちゃら”の部分。名前と呼び出し名を一緒にしておくと、分かりやすくて良いと思われ。もちろん、日本語名が使える。
そして、アプリケーションIDが発行される。この”アプリケーションID“のIDはあとでLambdaで利用する。

4.1.対話モデルを作っていく

スキルビルダーをポチって画面遷移

4.2.スキルビルダー画面

ここで対話モデルを作っていく。ザックリだと、

1. Alexaに話しかける話の構造(Intent)
2. 話しかけた結果から取得できる変数の設定(Slot)
3. 変数に割り当てることができる値の定義(SlotTypeに値を割り当て)

といった感じ。ここで設定した名前が後でAWS Lambdaのプログラム側で利用できるようになる。例えば、次から設定する流れだと、

1.1. Intentの名前を決める(MyColorsIntent)
1.2. 話しかける内容をつくる(“好きな色は {Color} です”と話かけられるようにする。ここで {Color} は可変の値。)
2.1. 変数(Slot)の設定を行う。
2.1. Slotのタイプを作る(Color_ITEM_LIST)
3.1. 変数に割当られる値の定義(緑、赤、青…etc)を入れていく

つまり、Alexaに話かける内容はここで決める。「怪しい {Color} は何ですか?」「{Color}をもう一度言ってくれますか」といった話を入れていったりする。
なにはともあれ、”Intentの+”ボタンをクリック。

4.3.Intentの名前を決める

ここでは”MyColorsIntent”という名前にする。この名前はあとでLambdaで利用する。この名称に日本語は利用できない。

4.4.話しかける内容をつくる

「好きな色は {Color} です。」と入れて”+”をクリック。この時、{}の前後に半角スペースを1個いれる。これを入れないとモデルを作る時にエラーになる。

4.5.Slotの設定を行う

右側のタブに”Color”という項目が追加されるので、その下にある”Choose a slot type…”をクリックするとリストが出てくる。ここで、新規に”COLOR_ITEM_LIST”を追記&作成して”+”をクリック。
割り当てたSlot(変数)には型が必要で、デフォルトで利用できるもので、AMAZON.City, AMAZON.DATE…etcが並んでいる。TEXTやStringといった文字列が無いのが辛い(少し昔はあったけど、無くなってしまった)。自作スキルでデフォルトで利用できる型があればそれを使った方がOK。大抵の場合は使いたい型が無いと思うので、自分で型を作ることになると思われ。

4.6.Slotに割当られる値の定義

「赤、緑、青…etc」を入れて”+”を押して、Slotに割当られる値を定義していく。ここで割り当てた値が、あとで作るLambdaで利用することが出来る。
設定関係はここまで。

5.作ったモデルを見てみる

“Code Editor”をクリックすると、作ったモデルのJSONの表現が見れる。ここで直接、モデルを記載していってもOK。

6.モデルの保存とビルド

“Save Model” -> “Build Model”で作ったモデルをビルドしておく。終わったら”Configuration”ボタンをクリックして、作ったスキルの設定をしていく。

7.Alexaの設定画面

ここでAWS Lambda(プログラム側)との連携の設定をする。サービスエンドポイントはAWS Lambda(HTTPS側で自前サーバも可)で、デフォルトのテキストボックスの所にLambda側のARNエンドポイントを入れる。まだLambad側は作っていないので、とりあえずAlexa側の設定はここまで。次にLambdaでプログラム側の設定をしていく。

■ LambdaでAlexaスキルを作っていく
1. Lambdaの関数を作る。

AWS Lambdaの詳しい説明はググればOK。ザックリだと、サーバを作らなくてもアプリでスケールしてくれるPaaSといった感じ。何はともあれ「関数の作成」をクリック。

2. 関数の作成

テキストボックスの所に”Alexa”と入れると、Alexaで利用できる関数一覧が出てくるので、”Alexa-skills-kit-color-expert-python”をクリック。

3. 関数の設定

作成する関数の”名前”、ロールは既存のロールで、”service-role/alexa-skill”を選択。
ページの一番下にある”関数の作成”ボタンをクリック。

4. 関数の作成完了

これでLambda側の関数が作成できた。サンプル通りで非常に簡単。次に赤枠にある部分のARNという部分をコピーしておいて、実際にAlexa側と連携させてテストをする。

■ Amazonの開発者ポータルでスキルのテスト
1. AlexaとLambdaの連携

作ったLamdaのARNを”デフォルト”という部分に入れて(arn:lambda:…という文字列)、”次へ”をクリック

2. Alexa上でテスト

Alexaのテスト画面。”無効”となっているため、クリックして有効にする。

3. サービスシュミレーター

少し画面のしたに行くと”サービスシュミレーター”があるから「好きな色は赤です」と入れて、”色を呼ぶを呼び出す”をクリックすると結果が表示される。

スキルの開発の流れはここまでで終わり。シュミレータでテストを行ったり、いちいちAlexaに話しかけるのが面倒な時はボイスシュミレーターで話させたりも出来る。
あとは自分でアプリを作ったり、音声で遊んだり。外部連携をLambdaでやって、カメラと連動させて「いまのお家の状態を写真を撮ってメールで送って」といったセキュリティデバイス化させたり、LINEと連動させたりするのも面白いと思われ。
スキルタイプで、カスタムは一般的な対話で遊べるけど、スマートホームAPIは使ってみるとかなり面白いと思う。自分はスマートホームAPIでデバイス連携をさせた時、簡単で美しい流れにちょっぴり感動してしまった。

あとプログラムを書くのが苦手で、とりあえずRSSフィードだけ読ませてみたい…という時はフラッシュブリーフィングでサクット作るのもアリだと思われ。”マイチャンネル”みたいな扱いとしても使える。

■ その他
1. Lambdaの応答の日本語化
サンプルのColor-me-expertは日本語を戻していない。ただ、普通にPythonのプログラムで応答の文字列の部分を日本語にしてutf-8(# coding:utf-8)をコードの頭に追加すれば、日本語を利用することができる。以下はサンプル中に日本語をいれたもの(超簡単)。
日本語とは関係ないけど、ここでの注意点は”lambda_handler(event, context):”でAlexaアプリのIDを指定して、作ったAlexaスキルからしか実行できないように制限をしている。

# coding:utf-8

from __future__ import print_function


# --------------- Helpers that build all of the responses ----------------------

def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Simple',
            'title': "SessionSpeechlet - " + title,
            'content': "SessionSpeechlet - " + output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }


def build_response(session_attributes, speechlet_response):
    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }


# --------------- Functions that control the skill's behavior ------------------

def get_welcome_response():
    """ If we wanted to initialize the session to have some attributes we could
    add those here
    """

    session_attributes = {}
    card_title = "ようこそ"
    speech_output = "これは好きな色のサンプルアプリでーす "
    reprompt_text = "好きな色を言ってね。 "
    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def handle_session_end_request():
    card_title = "おわりです"
    speech_output = "サンプルを使ってもらってありがと" 
    should_end_session = True
    return build_response({}, build_speechlet_response(
        card_title, speech_output, None, should_end_session))


def create_favorite_color_attributes(favorite_color):
    return {"favoriteColor": favorite_color}


def set_color_in_session(intent, session):
    card_title = intent['name']
    session_attributes = {}
    should_end_session = False

    # この Color がSlotで設定した名前
    # intent['slots']['Color']['value'] で値を取得できる。
    if 'Color' in intent['slots']:
        favorite_color = intent['slots']['Color']['value']
        session_attributes = create_favorite_color_attributes(favorite_color)
        speech_output = "あなたの好きな色は " + \
                        favorite_color + \
                        "ですね。 " \
                        "他に好きな色は?"
        reprompt_text = "好きな色を言ってね。 "
    else:
        speech_output = "色が分からなかったよ。もういちど言って " 
        reprompt_text = "色が分からなかったよ。 " \
                        "好きな色は赤ですとかって言って "
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def get_color_from_session(intent, session):
    session_attributes = {}
    reprompt_text = None

    if session.get('attributes', {}) and "favoriteColor" in session.get('attributes', {}):
        favorite_color = session['attributes']['favoriteColor']
        speech_output = "あなたの好きな色は " + favorite_color + \
                        "です。終わります。"
        should_end_session = True
    else:
        speech_output = "私はあなたが好きな色が分からないです。 " \
                        "好きな色は赤ですとかって言って。"
        should_end_session = False

    return build_response(session_attributes, build_speechlet_response(
        intent['name'], speech_output, reprompt_text, should_end_session))


# --------------- Events ------------------

def on_session_started(session_started_request, session):
    """ Called when the session starts """

    print("on_session_started requestId=" + session_started_request['requestId']
          + ", sessionId=" + session['sessionId'])


def on_launch(launch_request, session):
    """ Called when the user launches the skill without specifying what they
    want
    """

    print("on_launch requestId=" + launch_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # Dispatch to your skill's launch
    return get_welcome_response()


def on_intent(intent_request, session):
    """ Called when the user specifies an intent for this skill """

    print("on_intent requestId=" + intent_request['requestId'] +
          ", sessionId=" + session['sessionId'])

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    # この部分でIntentで設定した名前で処理を分岐することができる
    if intent_name == "MyColorIsIntent":
        return set_color_in_session(intent, session)
    elif intent_name == "WhatsMyColorIntent":
        return get_color_from_session(intent, session)
    elif intent_name == "AMAZON.HelpIntent":
        return get_welcome_response()
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return handle_session_end_request()
    else:
        raise ValueError("Invalid intent")


def on_session_ended(session_ended_request, session):
    """ Called when the user ends the session.

    Is not called when the skill returns should_end_session=true
    """
    print("on_session_ended requestId=" + session_ended_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # add cleanup logic here


# --------------- Main handler ------------------

def lambda_handler(event, context):
    print("event.session.application.applicationId=" +
          event['session']['application']['applicationId'])

    """
    ここの部分でAlexaアプリのID(applicationId)を設定しておく。このlambdaの関数がAlexaの当該アプリからしか実行できないようにしておく必要あり。
    """
    if (event['session']['application']['applicationId'] != "amzn1.ask.skill.XXXXXXXXXXXXXXXXXXXXXXXX"):
        raise ValueError("Invalid Application ID")

    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])

    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])


2. Alexaの管理画面
作ったアプリはAlexaのスキルで確認できる。

これはAlexa側のスキル管理画面。この右上に、自分がいれたスキル一覧が分かるボタンがあって、見てみると。

作ったスキル”色を呼ぶ”が入っている。スキルの追加は、スキル一覧から選んで有効にする必要があるが、開発版のタグ(devJP)が付いて、正規のアプリとパット見で区別して分かるのは良い感じ。

2.1. 自作スキルをAlexaに追加するには?
米国版のスキルだと開発するとすぐAlexaのスキル一覧に表示されて分かるのだけど、日本版では「スキルのベータテスト」から追加する流れのようだ(2017/11/15現在)。

開発者コンソールで、アイコンや色々な情報を入れてリリース申請の直前まで行える状態になると、このボタンが押せるようになる。

すると次のような画面になる。

ここでAlexaに登録している人のメアド等を入れて”テストを開始”ボタンを押すと招待URLが送信される。メールの中に”JP customers: To get started, follow this link:”という方のURLリンクがあるから(別の方はUS側のリンク)、そっちをクリックするとスキル一覧に追加されて、実機Echoでテストを進めることが出来る。

3. Lambda利用料金
AWSは従量課金で沢山使うほど課金される。基本的に何かをやろうとすると有料で、Alexaスキルを作ってみたいけど有料なのはなぁ…と思うかもしれない。
自分はAmazonの回し者でも何でもないけど、Lambdaは超安いです。Alexaスキルをさらっと作って動かして開発するくらいなら、課金額は10円もかからないと思われ。サンプルを動かすくらいなら、1円もかからない。気軽に動かしてみよっとー、って感じで全然大丈夫なはず。

4. リリース
実際にスキルを一般にリリースするには、公開情報の設定(スキルのアイコンや説明文)などの設定が必要になる。開発版なら、自分のスキル一覧上で使えるから特に気にする必要はないけど。
設定を適当に入れてリリースすれば一般利用者にすぐ使って貰えるか?と思ったら…Amazonによるリリース判定が待っていた。申請内容はこちら
スキルの説明文や、Alexaに話しかける内容をちゃんと作らないと、あっさりNGが来る。申請すればすぐ通るんじゃん!!と思ってやってみたら、全くそんな事が無かった(まぁ、ちゃんと作らないとダメというのは当然と言えば、当然だけど)。

上モノフェス

上モノフェスが10/8, 9に長野 上田市で開催されて行ってきた。

場所はサントミューゼというオシャレ空間でした。ぼーっと原っぱに座って寝ているだけでも何か満たされそうな感じ。

自分の展示空間は暗室独り占めー!!ひゃーっほい。

実はこの暗室空間はコンサートホールとエントランスの間にある踊り場の空間で、設置当日に準備をしてもらって感謝です。こういう滅多に使えない場所を使えるというのは実験をしたくなってくる。

投影する方向は、開けたらすぐというコンサートホールの扉に決めた。まさか、こういう所でKinect v2/XtionでDepthを取って投影したりサーボやステッパを動かして、LEDフラを回しまくる!!という非日常は無いだろうと…

諸々のものを設置。物としては、Kinect v2/Xtion、プロジェクタで投影もの、PCx2、LEDフラx2、ステッパ&サーボx9の最近製作しているものを持って来ました!!といった感じ。この青いLEDバーもゴッツリ動く(Kinect v2連動でUnityから制御)。

予想外だったのが…めっちゃ人。マジでめっちゃ人たくさん。はい、凄かったっす。たまに脱走して戻ってきたら、この暗室に自分が入れない…という状態になっているほど人たくさん。「こういう謎のオモシロ展で、人がどれくらいかなぁ…」と思っていたら、すげーかった。時間があっと言うまに過ぎて、他の皆さんのを見て回る余裕が無いくらい凄かった。あんまり他の所の写真を撮れてなかった…

1日目が終わって、ふと前スレのDepth輪郭に手を入れて見ようか…と思って、声をバーっと出すと投影しているのが分身/分裂するようにしてみたら…チビッコ達がワーキャー!!と声を上げてくれて、展示の3要素と思っている「光る(LED群)・大きい(バーが全体的に動く)・音がなる(人間の声)」が揃った。対応の忙しさに自ら火に油を注いでしまったか…と思ったけど、チビッコがキャーキャーしてむしろ楽しかった。

分裂しているのがブレてよく撮れて無いっすね。背丈ほどのフラを持って、声を出して、謎の動きをするバーの前のチビッコという謎のこの状態の写真が何気に面白い。

新聞に掲載されて、「新聞でこの光るのを見て、何かと思って来てみた」という年配の方とか、わざわざ来てくれた方とかいたり有り難かった。
とにかく、めっちゃ沢山のお客さんで凄かった。運営・手配して頂いたみなさん、ありがとうございます&次回or来年も楽しみにしています。