かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

IoT初心者がobnizと戯れてみて、"簡単に"とは何かについて考えてみたメモ。

これはobniz Advent Calendar 201812日目の記事です。

はじめまして。
IoTデバイスを触ったり、回路作ったり自体が初めてのド素人です。
obnizのハンズオンに参加してJavaScriptSDKを使って"簡単に"LEDを光らせたりモーターを動かしたりができたので、調子に乗って自分で考えた機能を作ろうと思い立ったものの、いざやり始めてみたら壁に激突してしまいました。
その経験からobnizに限らず様々なIoTデバイスでよく謳われている"簡単に"とは何かを考えてみることにしました。
Advent Calendarでは比較的作ってみた系が多い中、チョット毛色の違う読み物的な記事かもしれません。

IoTド素人なので、認識などに間違いがあるかと思います。
認識違いなどがあれ是非教えてください。 ヨロシクオネガイシマス!

obniz, Arduino, RaspberryPiの違いについて考える

Rasbperry PI / Arduino / obniz

バイス 特徴
Raspberry Pi
Linuxコンピューター (small single-board computers)
Raspberry Pi上のOSからプログラムを実行する
  • PCでできることはだいたいできる。
  • Linuxライブラリの恩恵を受けることができる
  • 処理をマルチタスクで実行できる
  • OSのインストールとかセットアップが大変 (な印象
  • PCなので雑に扱うと壊れやすい
Arduino
マイコン (Single-board microcontroller)
Arduino上のメモリ領域にプログラムを書き込んで実行する
  • リアルタイム性のある処理が得意
  • 比較的 安価 (OSSなので超安価な互換機も多い)
  • 機能を追加する拡張パーツが多い
  • 1つのタスクしか動かせない
  • プログラムを書き込める容量に制限がある
obniz
マイコン (API maneged IO)
クラウド/ネット上にあるプログラムをAPI経由でobnizで実行する
  • WEB開発の資産が利用できる
  • プログラムのサイズを心配する必要はない
  • 日本発なので日本語のドキュメントが豊富
  • インターネット環境必須
  • ネット回線に動作が左右される

Raspberry Piはもともと学生のための安価なコンピューターとして考案され、Arduinoは学生のためのハードウェアの試作の為のシンプルなツールとして考案されたそうです。

obnizはどちらかといえばArduinoに近い印象です。
そしてインターネットが必要という特徴から、IoTに特化したAPISDKを含めたツール群と言った感じでしょうか。

簡単とはなにか

Raspberry PiArduino、obnizに限らず、多くの開発ボードが「簡単に」できるを謳っているように思います。
似ていると感じた、obniz / Arduino のそれぞれのWEBサイトに掲載されているコンセプトを見てみましょう。

obniz

obnizには、難しくてあきらめることも、 できないストレスも、細かく膨大な準備もありません。 スマートフォンでプログラムページを開けば、 センサーやモーターの遠隔操作も思いのまま。 あなたが作ってみたいと思っていたものも、作れないと思っていたものも、 obnizならずっと簡単に
obnizには、難しくてあきらめることも、 できないストレスも、細かく膨大な準備もありません。 スマートフォンでプログラムページを開けば、 センサーやモーターの遠隔操作も思いのまま。 あなたが作ってみたいと思っていたものも、作れないと思っていたものも、 obnizならずっと簡単に

Arduino

Arduino is an open-source electronics platform based on easy-to-use hardware and software. It's intended for anyone making interactive projects.
Arduino is an open-source electronics platform based on easy-to-use hardware and software. It's intended for anyone making interactive projects.

どちらも簡単に使えるよ的な事が書かれています。

コードで見る"簡単に"とはなにか

よくあるLEDを光らせるサンプルコードを比べてみます。 ※ obnizはJavaScriptSDKを使った場合で

obniz

f:id:kikiki-kiki:20181212073844j:plain

const obniz = new Obniz("<OBNIZ_ID>");
obniz.onconnect = async function() {
  // LEDのアノードを0、カソードを1に接続
  const led = obniz.wired("LED", {anode:0, cathode:1});
  // LEDを点灯
  led.on();
  // LEDを消灯
  led.off();
};

cf. obniz: Make everything online

Arduino

f:id:kikiki-kiki:20181212073903j:plain

// LEDのアノードをデジタルピン13に接続
const int LED = 13;
void setup() {
  // デジタルピンを出力に設定
  pinMode(LED, OUTPUT);
}
void loop {
  // HIGHを出力してLEDを点ける
  digitalWrite(LED, HIGH);
  // LOWを出力してLEDを消す
  digitalWrite(LED, LOW);
}

定番とも言えるLEDを点けるような処理でも、ArduinoではHIGH/LOWといった回路的な用語が使用されます。
対してobniz(JavaScriptSDK)はLEDキーワードでオブジェクトを作り、ON/OFFにするという直感的な感じです。 (GitHubで公開されているobnizのコードを追って見た感じだと、 obnizeの処理の裏側ではanodeに割り当てられたピンに対しwebsocketからIOをONにするiox.output(true)相当の命令が送られているようでした。)

ここからも Arduinoはハードウェアの学習に主眼が置かれており、ハードウェアの試作が"簡単に"であり、 obnizはIoTの製作に主眼が置かれており、ハードウェアを意識することなくIoTの製作が"簡単に"である。という思想が見てとれるのではないでしょうか。

"簡単に"が内包する問題

このようにobnizでは用意されたSDKを利用することでハードウェアを意識することなく、様々な機器をドキュメントにあるコードを参考に動作させることが出来ます。

例えばDCMotorであれば
cf. obniz: Make everything online

const obniz = new Obniz("<OBNIZ_ID>");
obniz.onconnect = async function() {
  const motor = obniz.wired("DCMotor", {forward:0, back:1});
  motor.forward();
};

のように、たったこれだけの記述でDCMotorを動作させることが可能です。
forwardbackで指定されたピンはioで5v push-pullに設定していることなどを知る必要もありません。
cf. obniz/parts/Moving/DCMotor at master · obniz/obniz · GitHub

距離センサ(HC-SR04)なら
cf. obniz: Make everything online

const obniz = new Obniz("<OBNIZ_ID>");
obniz.onconnect = async function() {
  const hcsr04 = obniz.wired("HC-SR04", {gnd:0, echo:1, trigger:2, vcc:3});
  hcsr04.measure(function( distance ){
    console.log("distance " + distance + " mm");
  });
};

単にセンサーを動作させ値を取得することを目的とするなら、
割り当てているピンのgnd, echo, trigger, vccが何なのかも、センサーからどのように値を取っているのかも知る必要もありません。
cf. obniz/parts/DistanceSensor/HC-SR04 at master · obniz/obniz · GitHub

更に用意されているブロックプログラミングを利用すればJavaScriptのコードすら知る必要もありません。 obnizのブロックプログラミング

簡単に実際のパーツを動かして試せる = IoTの実験に注力できる反面、ややこしい部分をSDKが良い感じにラップしているので回路的な事を学ぶ機会は少なくなるように感じます。
故に私のようなIoTド素人の場合、リファレンスに載っていないパーツを使って自分で考えたモノを作ろうとした時に、vccって何?gndって何?どのピンにどれを繋いでどう設定すればいいの?という壁に当たる事になるでしょう。(Pin Peripheralsのようなリファレンスもありますが、ド素人的には用語の意味を知っている事が前提のように感じました。)

Team obniz に期待したいこと

obnizならずっと"簡単に"。 とは現状、

  • JavaScriptを知っていれば "簡単に" をIoTできる但し、リファレンスにあるパーツを使えば
  • ブロックプログラミングを使えばJavaScriptを知らなくても "簡単に" に作ることができる。但し、登録されているパーツを使えば
  • "簡単に" JavaScript SDKを使ってIoTなモノを作ることができる。但し、ある程度回路的な知識があれば

のような省略された但し書きの条件の上での"簡単に"ではないかと思います。

obnizはブロックプログラミングも用意されており、実際に動くモノを(リファレンスにあるパーツを使えば)"簡単に"作れ、成功体験を得られ、モチベーションを維持しやすい、という仕組みができていると思います。
なのでIoT初学者やプロトタイプ作り、教育の現場ではとても向いているのではないかと強く感じました。
一方、そこからリファレンスにないパーツを使ったりした独自の仕組みを作れるようになるステップアップの方法が"簡単"さを実現するために難しいくなっている気がします。回路的な知識を得ることができるようなコンテンツが用意されれば、よりobnizを選択する動機づけになるのではないかと感じました。

おまけ

ワタシハIoTチョットデキル
作ってみたが力不足で出来なかったので、イラストを描いてみました!


[参考]

JavaScript 該当する文字を全部変換したいメモ

例えば次のようなテキストを

"藤堂ユリカ\n一ノ瀬かえで\n神崎美月"

👇

"藤堂ユリカ 一ノ瀬かえで 神崎美月"

のように置き換えたい時

JavaScriptにはreplaceAllのようなメソッドがないので、

const str = "藤堂ユリカ\n一ノ瀬かえで\n神崎美月";
str.replace("\n", " ");
// => "藤堂ユリカ 一ノ瀬かえで\n神崎美月"

単純にstr.replace()を使っても最初にマッチした文字しか置き換えられません。

str.replace() で正規表現を使って置き換える

正攻法。
str.replace() の検索文字を正規表現( RegExp )にする方法。
g(グローバルサーチ)オプションを使うことで全てのマッチを置き換えることができます。

const str = "藤堂ユリカ\n一ノ瀬かえで\n神崎美月";
str.replace(/\n/g, ' ');
// => "藤堂ユリカ 一ノ瀬かえで 神崎美月"

str.split().join() で置き換える

split()メソッドが指定した区切り文字全てで分割して配列をかえすことを利用して、str.split('検索文字').join('変換文字')としてしまえば一括変換に利用できます。

const str = "藤堂ユリカ\n一ノ瀬かえで\n神崎美月";
str.split("\n").join(' ');
// => "藤堂ユリカ 一ノ瀬かえで 神崎美月"

splitで配列になっているので、reduce()で値を弄ったりして合算することも出来ます。

const str = "藤堂ユリカ\n一ノ瀬かえで\n神崎美月";
str.split("\n").reduce((sum, val)=> {
  if( /^神崎美月$/.test(val) ) {
    val = 'レジェンド美月';
  }
  return `${val}🌟${sum}`;
});
// => "レジェンド美月🌟一ノ瀬かえで🌟藤堂ユリカ"

 

単一な文字を一括して変換したい時、str.split('検索文字').join('変換文字')はハック的だけど簡潔で良いなと思いました。
処理的には正攻法な正規表現の方が関数呼び出しも1つだし高速な気もしますが…

おまけ str.replace() の第二引数(置換える文字)は関数にできる

str.replace()のドキュメントを見ていて、第二引数に関数が取れる事を知ったので試してみました。

str.replace(regexp|substr, newSubstr|function)
function (replacement)
新しい部分文字列を生成するために実行される関数で、regexpsubstr でマッチしたものを置き換えるのに使われます。この関数に渡される引数は下記の "Specifying a function as a parameter" で述べられています。

const str = "藤堂ユリカ\n一ノ瀬かえで\n神崎美月";
str.replace(/(.+)\n/g, (...val)=> {
    console.log(val);
    return 'ジョニー別府 ';
});
// => [ '藤堂ユリカ\n', '藤堂ユリカ', 0, '藤堂ユリカ\n一ノ瀬かえで\n神崎美月' ]
// => [ '一ノ瀬かえで\n', '一ノ瀬かえで', 6, '藤堂ユリカ\n一ノ瀬かえで\n神崎美月' ]
// res => "ジョニー別府 ジョニー別府 神崎美月"

第二引数を関数にした場合の引数は、

  • match: マッチした文字列
  • p1, p2, ...: 正規表現の場合、キャプチャされたサブマッチ文字列
  • offset: マッチした箇所のオフセット
  • strings: 元の文字列

として渡され、return した値に第一引数のマッチした部分が置き換えられるようです。

cf. 引数としての関数の指定セクション
正規表現で一括変換マッチさせて、サブマッチ文字列をjoinさせるサンプルが書かれてて興味深かったです。


[参考]

スラスラ読める JavaScript ふりがなプログラミング (ふりがなプログラミングシリーズ)

スラスラ読める JavaScript ふりがなプログラミング (ふりがなプログラミングシリーズ)

HTML target="_blank" の時の rel="noopener" ってなに?

WordPressの投稿で別ウィンドウで開くリンクtarget="_blank"を作成すると、

<a href="{URL}" target="_blank" rel="noopener">LINK TEXT</a>

のようなrel="noopener"属性を持ったaタグが出力されます。

rel="noopener" の意味

1. target="_blank" のセキュリティ上の脆弱性の問題を避ける

Without this, the new page can access your window object via window.opener. Thankfully the origin security model of the web prevents it reading your page, but no-thankfully some legacy APIs mean it can navigate your page to a different URL using window.opener.location = newURL.
出典: The performance benefits of rel=noopener - JakeArchibald.com

target="_blank"で開かれたページは、元のページをwindow.openerオブジェクトとして持つので、リンク先のページからwindow.opener.location = "danger site url" のように元ページを操作することが出来てしまうようです。

rel="noopener" を使うことで、新しく開いたページからwindow.openerオブジェクトを使って元ページの操作をできなくできるようです。no・openerですね。

DEMO
noopener DEMO

noopener demo page | github.io

rel="noopener"のないリンク先から元ページを操作しているのが解るかと思います。

2. パフォーマンス低下の問題を避ける

This means JavaScript running on one domain runs on a different thread to a window/tab running another domain.
However, due to the synchronous cross-window access the DOM gives us via window.opener, windows launched via target="_blank" end up in the same process & thread. The same is true for iframes and windows opened via window.open.

出典: The performance benefits of rel=noopener - JakeArchibald.com

target="_blank"で開かれたページは、元ページとJavaScriptが同じプロセス・スレッドで動作するようです。
なので、target="_blank"で開かれたページに負荷の高いJavaScriptが実行されていると、元ページのパフォーマンス低下など影響がある可能性があるようです。

Google的見解

監査に合格する方法
レポートを確認して、Lighthouse で特定された各リンクに rel="noopener" を追加します。 一般的に、外部リンクを新しいウィンドウまたはタブで開く場合は、必ず rel="noopener" を追加してください。
出典: Links to cross-origin destinations are unsafe  |  Tools for Web Developers  |  Google Developers

Goolge的には基本的にtarget="_blank"を使用したリンクにはrel="noopener"をつけたほうが良さそうな雰囲気っぽいです。
 

JavaScriptから元ページを操作できるのってJavaScriptwindow.open()した時だと思っていました。
まさかHTMLのリンクタグのtarget="_blank"からも操作できるとは思ってなかったです… そして、target="_blank"で開かれたページが元ページと同じプロセスになるってのは、開かれたページからwindow.openerが使えるって部分からなんとなく納得。
というか同じプロセスになる仕様だからwindow.openerが使えちゃうってって感じでしょうか?

それよりtarget="_blank"で新しく開いたページからwondow.openerで元ページを操作できるってのが衝撃的だったので、新しく開くリンクにはrel="noopener"積極的につけていこうと思いました。


[参考]

貝印 密閉 栓抜き Kai House Select DH-7034

貝印 密閉 栓抜き Kai House Select DH-7034

おまけ rel 属性 のメモ
意味
nofollow 重要でないリンク・リンク先のリンクをクロールしない
信頼できないコンテンツ・ユーザー投稿に含まれるリンクなどに指定
noreferrer リンク先にリファラを送信しない
noopener リンク先のページでwindow.openerによる元ページの操作を禁止する
alternate 代替ドキュメントへのリンク
author 著者へのリンク
license ライセンス文章へのリンク
help ヘルプへのリンク
bookmark このページをブックマークできる固定リンク
prev 前のページへのリンク
next 次のページへのリンク
prefetch リンク先を予めキャッシュする
tag このページのタグ
search 検索機能
icon アイコン・ファビコンとか e.g. <link rel="icon" href="/favicon.ico">
stylesheet CSSの読み込み ※ linkタグのみで使用可

昔のWordPresstarget="_blank"のリンクに出力されるのrel="noreferrer"だったような気がしてたのですが、
WordPress v4.7.4 以降では rel="noreferrer noopener"で、
WordPress v4.8 から rel="noopener" だけになったみたいです。
テーマ作ってばかりで管理画面からの投稿はほぼ使ってないので気づいてませんでした…
(定期的にソース開く癖つけないとダメですね)

[参考]