web-i2cエレメントをより使いやすくしました。
Monday, September 24, 2018 03:41:00 PM
先日のMaker Faire Tokyo 2018 に CHIRIMENコミュニティで参加しましたで web-i2c-element はどうなの?
に記述した改良ポイントを使ったchirimen-pianoをアップしました。
変更したポイント:
変更の概要は以下のとおりです。
no-web-i2c
スロットを指定すると、非対応メッセージを表示できるようになったWebI2cSensorElement
を使って、センサー毎の共通実装をなくし、より簡単にセンサーのカスタムエレメントが実装できるようになった- Polymer使ってなくても、タグだけを使ってセンサーの値が取得できるようなサンプルに変更した
では、それぞれの変更を詳しく見ていきましょう。
非対応メッセージの表示
chirimen-pianoのリポジトリにあるindex.htmlファイルを見てましょう。
<web-i2c>
<grove-touch slave-address="0x5a"></grove-touch>
<grove-gesture slave-address="0x73"></grove-gesture>
<div slot="no-web-i2c">
このデバイスはCHIRIMENではありませんが、ピアノ演奏はお楽しみいただけます。
</div>
</web-i2c>
web-i2c
タグの内側に no-web-i2c
というslot名のタグを記述することで、
もしCHIRIMEN以外のデバイス(例えばPCなど)から、このページを表示するとメッセージを表示することができるようになります。
試しに、PCからchirimen-pianoのデモページにアクセスしてみてください。
WebI2cSensorElementを利用したカスタムエレメントの記述
最初のバージョンでは、 PolymerElement
を使っていたため共通的な実装が多くなっていたのですが、
いくつかのセンサー実装をしてみて共通化できそうな箇所もわかってきたので、I2C用の親クラスを作ることにしました。
WebI2cSensorElement
を使ったセンサーのクラスとして、GROVEタッチとGROVEジェスチャーのカスタムエレメントを作りました。
例としてchirimen-pianoのリポジトリにあるgrove-touch.jsファイルを見てましょう。
class GroveTouch extends WebI2cSensorElement {
async init() {
this._autoRead = true;
await this._i2cSlave.write8(0x2b,0x01);
await this._i2cSlave.write8(0x2c,0x01);
await this._i2cSlave.write8(0x2d,0x01);
await this._i2cSlave.write8(0x2e,0x01);
await this._i2cSlave.write8(0x2f,0x01);
await this._i2cSlave.write8(0x30,0x01);
await this._i2cSlave.write8(0x31,0xff);
await this._i2cSlave.write8(0x32,0x02);
for(var i=0;i<12*2;i+=2){
// console.log(i);
var address = 0x41+i;
// console.log(address);
await this._i2cSlave.write8(address,0x0f);
await this._i2cSlave.write8(address+1,0x0a);
}
await this._i2cSlave.write8(0x5d,0x04);
await this._i2cSlave.write8(0x5e,0x0c);
}
async read() {
const value = await this._i2cSlave.read16(0x00);
// console.log(value);
var array = [];
for(var cnt = 0; cnt < 12; cnt ++){
array.push(((value & (1 << cnt)) != 0)?true:false);
}
if (!this.value || (JSON.stringify(array) != JSON.stringify(this.value))) {
this._setValue(array);
}
}
}
window.customElements.define('grove-touch', GroveTouch);
まず WebI2cSensorElement
を継承したクラスを定義します。
このクラスには2つのオーバライド可能なメソッドがあります。
- init
- read
どちらも async
メソッドにすることで I2Cスレーブデバイスからの応答を待ち合わせる(await
)ことができるようになっています。
WebI2cSensorElement
は、 init
呼び出し時にメンバー変数として _i2cSlave
が利用可能になっています。
これはWeb I2Cのスレーブオブジェクトで、どんなメソッドが使えるかはWeb I2C API Specificationの 4.6 Reading the value
や 4.8 Writing a value
を参照ください。
サンプルコードの slaveDevice
が _i2cSlave
と同じものになります。
init を実装する
init ではI2Cデバイスの初期化コードを記述します。 とくに戻り値は必要ありません。
もしセンサーが読み取り可能なら、 this._autoRead = true;
のように設定してください。
これを設定すると、インターバル間隔(デフォルトは100ミリ秒)ごとに read
メソッドを呼び出してくれます。
read を実装する
init で _autoRead
を true
に設定した場合、インターバル間隔ごとに呼び出されます。
センサーの値を読み取って、値が変わった場合は this._setValue(value)
を呼び出してください。
エレメントの value
プロパティに値が保持されると同時に、 value-changed
イベントが発行されます。
普通のHTMLからセンサーを取り扱う
ふたたびchirimen-pianoのリポジトリにあるindex.htmlファイルを見てましょう。
<script>
document.querySelector('grove-touch').addEventListener('value-changed', e => {
document.querySelector('chirimen-piano-app').touchChanged(e.detail.value);
});
document.querySelector('grove-gesture').addEventListener('value-changed', e => {
document.querySelector('chirimen-piano-app').gestureChanged(e.detail.value);
});
</script>
センサー値の変更を受け取るには、センサーエレメントに対して value-changed
イベントのリスナーを設定します。
値はイベントオブジェクトの detail.value
に入っていて、センサーによってセットされる値(型も含め)が違います。
たとえば grouve-touch
エレメントは、タッチセンサーの数分のBoolean配列がセットされ、 grove-gesture
エレメントは、発生したジェスチャー名がセットされます。
さいごに
このようにHTMLからセンサーの値をコントロールできたり、センサーのエレメントを簡単に実装できるようになりました。
今後は、それぞれのエレメントやベースクラスを npm install
で取得できるようにしたいと思っています。
また、以前作った WebGpioElement
も Polymer3
で書き換えていきたいなと思っています。
WebComponents と CHIRIMEN の融合は、私がそれぞれのコミュニティに参加して得られたもののアウトプットです。 もしこれらの活動に興味がありましたら、Polymer Japan CHIRIMEN Open Hardware Polymer.co-edo などの活動に参加ください。
Polymer.co-edo meetup #17 を開催しました
Monday, September 24, 2018 11:49:00 AM
今年8回目となる Polymer.co-edo ミートアップ を開催しました。
今回の議題は
Polymer3 を使って、カスタムエレメントを作ってみよう!
ということで、またまたcodelabsにある、Polymer1系のエレメント作成では定番の Build your first Polymer element ですが、 これをPolymer3用に移植しました!(ついでに日本語化もしたよ!)
codelabsのはじめかた
はじめての Polymer 3 エレメントの作り方を順番に読み進めるだけで大丈夫です。 イベント中でも特にはまりどころはありませんでした。 (スクショが微妙に違うという指摘を受けましたが、これはPolymer1のベースが間違っているという…)
Polymer1や2は触ったことがあるけど、3はまだ、という人にはオススメの教材になっていると思います。
GDG DevFest の codelab にも採用されました
GDG DevFest Tokyo 2018 CodelabsのWEBカテゴリにもリンクされました。 WEBは#20 Your First Progressive Web Appと、はじめての Polymer 3 エレメントの作り方でした。 WEB自体、トライしてくれる人は少なかったのですが、当日は何名かの方にPolymerを試してもらえて良かったです(Polymer Japanステッカーを差し上げました!)。
次回は
9月にも開催を予定していたのですが、日程が調整できず、10月に予定どおり開催できる見込みです。 Doorkeeperのコミュニティページに今年の予定も書いてあるので参考にしてください。
前回も書きましたが、そろそろ、edoエレメントの開発をしないとなー、なんて思っています…
Maker Faire Tokyo 2018 に CHIRIMENコミュニティで参加しました
Monday, August 13, 2018 04:17:00 PM
MFTokyo(昨年まではMFTと省略していましたが、今年からこのように変更となりました)のデモ準備として、 先日 CHIRIMEN Raspi setupという記事を書きましたが、これはその結果報告です。
デモ準備
実際にソースを書いて、動かしてみると 開封したばかりのGroveタッチセンサーが4つのうち1つだけ反応しません 。 ハブ側の裏にあるハンダ部分を触って通電させるとタッチ状態になるので、静電側が異常だということを認識し、 処理不良だから書い直せば大丈夫…と思い、前日の金曜日に秋葉原へ向かいしました。
実は8/3は半透明なブギーボード BB-11 の発売日で、翌日にMFTokyoへ持って行くなら量販店で買うしかない!と思いアキヨドにも行くつもりだったのです。 参考:13.8インチで半透明、ブギーボード新モデルが8月3日発売
何を作ったか
chirimen-piano という、ピアノアプリを作りました。
このアプリの特徴は以下のとおりです。
- Polymer3で作られていて、以下のCustomElementsの実装評価を兼ねていた
- web-i2c タグ
- grove-gesture タグ
- grove-touch タグ
- CHIRIMENでなくても動作するWebアプリである
- 4鍵(タッチセンサーの4つが対応)しかないが、左右に手を振ることでジェスチャーセンサーが反応し、音階が移動する。CHIRIMENでない場合は左右ボタンで移動
ちなみに昨年は Echigo という B2G OS ベースのボードで web-gpio エレメントを検証するために polymerchirimen というサンプルを作っていました。 これは人感センサーに反応すると、LEDが点灯するというものでした。
先日購入したものに追加して、以下の部品が必要になります。
- Grove - I2Cタッチセンサー
- Grove - I2C Hub
- GROVE - ジェスチャー
- Grove 4ピンコネクタ - ジャンパーピン変換ケーブル
- ラズパイに接続できるスピーカー, USBマウス(ちょっとした操作用), 電源アダプター
完成画像は以下のとおりです。
苦労したこと
CHIRIMENでなくても動作するWebアプリ
を目指して作り始めたら、Raspberry Pi版のpolyfillにいくつか問題があることがわかって、それを修正しながら進めたのでギリギリまで時間がかかりました。
こちら、まだchirimen-pianoにしか入っていませんが、近いうちに公式版へPRを送る予定です。
あとはセンサーの初期不良は、まぁあるものと思っていた方が良いですね。 最近あんまりハズレを引かなかったので忘れていました。
web-i2c-element はどうなの?
現時点はまだデモプログラム内での評価用ですが、今回思ったよりもうまく動作しそうなので、こちらもちゃんとエレメントとして分割したいです。 いくつか改善したいポイントがあります。
no-web-i2c 対応
まず CHIRIMEN 以外で動作させていたとき、 noscript
タグみたいにして書けるようにする予定です。
現在は web-i2c.js
にベタ打ちになっていますが
<div class="message">
このデバイスはCHIRIMENではありませんが、ピアノ演奏はお楽しみいただけます。
</div>
これを利用側から指定できるようにしたいと思います。
<web-i2c>
<div slot="no-web-i2c">
このデバイスはCHIRIMENではありませんが、ピアノ演奏はお楽しみいただけます。
</div>
</web-i2c>
WebI2cSensorElement 対応
センサーのタグは PolymerElement
を継承して作るようにしていますが、これを WebI2cSensorElement のように親クラスを作って、センサータグ実装を楽にしたいと思っています。
現在のgrove-touchエレメントのソースコード を、以下のように書けるようにしたいと思っています。
class GroveTouch extends WebI2cSensorElement {
async init(i2cSlave) {
await i2cSlave.write8(0x2b,0x01);
await i2cSlave.write8(0x2c,0x01);
await i2cSlave.write8(0x2d,0x01);
await i2cSlave.write8(0x2e,0x01);
await i2cSlave.write8(0x2f,0x01);
await i2cSlave.write8(0x30,0x01);
await i2cSlave.write8(0x31,0xff);
await i2cSlave.write8(0x32,0x02);
for(var i=0;i<12*2;i+=2){
var address = 0x41+i;
await i2cSlave.write8(address,0x0f);
await i2cSlave.write8(address+1,0x0a);
}
await i2cSlave.write8(0x5d,0x04);
await i2cSlave.write8(0x5e,0x0c);
}
read(i2cSlave) {
i2cSlave.read16(0x00).then((v)=>{
var array = [];
for(var cnt = 0;cnt < 12;cnt ++){
array.push(((v & (1 << cnt)) != 0)?true:false);
}
if (!this.value || (JSON.stringify(array) != JSON.stringify(this.value))) {
this.set('value', array);
}
})
}
defaultInterval() {
return 1000;
}
}
window.customElements.define('grove-touch', GroveTouch);
共通化のポイントは以下のような感じです。
- 値のプロパティを
value
で共通化 - エレメントのプロパティをWebI2cSensorElementで定義
- ポートのオープンや、web-i2cエレメントとやりとりしてポートを設定するところなどをWebI2cSensorElementで定義
- 値読み込みのインターバル制御をWebI2cSensorElementに移譲
2つのI2Cセンサータグを作ってみて、このぐらいは共通化しても大丈夫そうだし、便利そうだなと思っています。
on-change 対応
現時点はアプリもPolymerで書いているので、値の変更はデータバインディングでできているのですが、最終的にはタグから change
イベントを飛ばすようにする予定です。
つまり利用者はPolymerを使わなくても、以下のようなHTMLコードを追加するだけで利用可能になることを想定しています。
<html lang="en">
<head>
<script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
<script src="node_modules/@chirimen/polyfill/polyfill.js"></script>
<script type="module" src="node_modules/@chirimen/web-i2c/web-i2c.js"></script>
<script type="module" src="node_modules/@chirimen/grove-touch/grove-touch.js"></script>
<script type="module" src="node_modules/@chirimen/grove-gesture/grove-gesture.js"></script>
</head>
<body>
何かしらのアプリ
<web-i2c>
<div slot="no-web-i2c">
このデバイスはCHIRIMENではありませんが、xxxxx。
</div>
<grove-touch slave-address="0x5a"></grove-touch>
<grove-gesture slave-address="0x73"></grove-gesture>
</web-i2c>
<script>
window.addEventListener('WebComponentsReady', e => {
document.querySelector('grove-touch').addEventListener('change', e => {
// 値が変わったときの処理
});
});
</script>
</body>
</html>
さいごに
WebComponentsを作るためのPolymerについては、 PolymerJapan コミュニティで活動しています。 毎月の集まりを Polymer.co-edoでも開催しているので、参加を待っています。
またCHIRIMENで、ブラウザからセンサーを動かしたいというような活動に興味があれば、コミュニティに参加ください。
どちらもユーザー主導で活動していますので、みなさまの参加をお待ちしております。
PHPカンファレンス関西2018に参加してGAEに継続的デプロイする方法について発表してきました
Friday, August 03, 2018 03:41:00 PM
2018/7/14 に行われたPHPカンファレンス関西2018に参加してきました。
今年も参加
昨年と同じくGRAND FRONT OSAKAで開催されました。
夜はスピーカーとスタッフの前夜祭から、コミュニティ前夜祭と合流しての2次会へと流れ、タクシーでホテルに戻りました。その後、3次会、4次会があったとかないとか…(これ毎年のコピペですwww)
PHPカンファレンス関西2018
PHPカンファレンス関西は3トラック+スポンサーブースです。朝一番の講演に参加者が多いのも特徴ですね。 今年はあまりセッションは聞かずに参加者と話したり、アンカンファレンスでPHPの非同期処理について話を聞いていたりしました。
私の発表はGAEへの継続的デプロイだったのですが、なんとタイムテーブルを見ると、私の前に
- Amazonの中の人が
PHPアプリケーションのコンテナ化入門
というタイトルで CI/CD の話をするらしい - Herokuの中の人が
HerokuでPHPアプリ開発速度を倍にする
というタイトルで 継続的デリバリー機能 の話をするらしい
ということでネタ丸かぶり?とか、私だけ中の人じゃないよ!とか心配になったので、この2つのセッションはしっかり前の席で聞きました。
GAEにPHPアプリを継続的デプロイする方法について発表しました
昨年に引き続きPHPネタですが、主にはDockerとGoogle Cloud Container Builderの話でした。
GAEを使っていて当然コードがPUSHされたらデプロイしたくなるのですが、何が良いのかよくわからない時期があって、調べて試した結果を発表するに至りました。 調べた過程で、まぁどんなツールを使っていても gcloud コマンドさえ動けば、あとはGAEと接続するための認証情報をそのCI/CDツールに最適な方法で管理するだけで、どんなものでも良いということがわかりました。 ただ、Cloud Container Builder使うとプライベートな空間を使えるわりには結構安いし、良いのではないかと思ったわけです。
デプロイのデモもギリギリ間に合って、ほっとしました。リポジトリの README に詳しい説明が書いてあるので、そちらを見ながらコードを動かしてみてください。
今回の発表をするのに30分でできる(当社比) Google Cloud Container Builderを利用した AppEngine SE環境への自動デプロイという記事が大変参考になったのですが、 GCPのコンソール(画面)から操作するのは、環境の再現性がなくて嫌だなーと思ったので、 gcloud コマンドを駆使して自動構築できるようにしました。 これは今回、かなり頑張ったところです。そしてデモ環境を何度も壊して作り直すことができたので、リハーサルも捗りました。
大阪を堪能
最終日は恒例の ねぎ焼き やまもと
へ。
今年はPHPerを4人(昨年は3人)引き連れ、梅田エスト店にやってきました。
そのあと有志で明石焼き/たこ焼きを食べに行って、聖地タイガースショップで買い物をして帰京しました。
さいごに
また来年も参加/発表したいので、1年の努力を惜しまずに…
Polymer.co-edo meetup #16 を開催しました
Sunday, July 29, 2018 11:31:00 AM
今年7回目となる Polymer.co-edo ミートアップ を開催しました。
今回の議題は
PWA Starter Kit でも使われていた lit-element を使って、カスタムエレメントを作る体験
ということで、codelabsにある、Polymer1系のエレメント作成では定番の Build your first Polymer element です。 当日は、上記チュートリアルの完成系のコード を見ながら lit-element で作ってみました。
このブログでは、当日やったことの履歴として、今後やってみたい人のために、手順を書いておきます。
Polymer CLI をインストールする
まず lit-element の README に書かれているように Polymer CLI をインストールします。 READMEではグローバルにインストールしていますが、今回はローカルに入れてみましょう。
icon-toggle
というディレクトリを作ってから、CLIをインストールします。
$ mkdir icon-toggle
$ cd icon-toggle
$ npm i polymer-cli@next
念のため、インストールできたか確認してみます。
help
コマンドが表示できていれば大丈夫です。
$ ./node_modules/.bin/polymer help
/\˜˜/ /\˜˜/\
/__\/ /__\/__\ Polymer-CLI
/\ / /\ /\ /\
/__\/ /__\/ \/__\ The multi-tool for Polymer projects
\ /\ /\ / /\ /
\/__\/__\/ /__\/ Usage: `polymer <command> [options ...]`
\ /\ / /\ /
\/__\/ /__\/
icon-toggle エレメントのスケルトンを作る
codelabs にあるコードは、すでにディレクトリ構造やファイルが準備されている状態から始まりますが、今回は CLI から作成します。
以下のコマンドを実行してみましょう。
$ ./node_modules/.bin/polymer init
何を作成するのか質問されるので、 polymer-3-element
を選択します。
? Which starter template would you like to use?
❯ polymer-3-element - A simple Polymer 3.0 element template
エレメント名はそのまま Enter
で進むと、 .gitignoreがないよ
というエラーになってしまいます。
info: [init] Running template polymer-3-element...
? Element name icon-toggle
? Brief description of the element
error: [cli.main] Uncaught exception: AssertionError [ERR_ASSERTION]: Trying to copy from a source that does not exist: xxx/icon-toggle/node_modules/polymer-cli/templates/element/polymer-3.x/.gitignore
e
これは、Polymer3のエレメントテンプレートがミスっているということで、ファイルを作ってからリトライします。
$ touch ./node_modules/polymer-cli/templates/element/polymer-3.x/.gitignore
$ ./node_modules/.bin/polymer init
質問には、上記と同じように回答してください。そうすると、以下のように表示されて完了します。
Setup Complete!
Check out your new project README for information about what to do next.
必要なパッケージをインストールする
まずインストールされている PolymerElement を削除します。
$ npm uninstall @polymer/polymer
つづいて、LitElement をインストールします。
$ npm i @polymer/lit-element
icon-toggle では iron-icon
と iron-icons
を利用する(codelabsでは最初からbower.jsonに入っている)ので、これらのCustomElementsもインストールします。
$ npm i @polymer/iron-icon
$ npm i @polymer/iron-icons
最後にもう一度 Polymer CLI をインストールしておきます。
$ npm i -D polymer-cli@next
LitElement で書き換えてみる
ソースコードを GitHub に置きました。 sizuhiko/lit-element-icon-toggle
Polymer CLIで作った Polymer3.0 element を LitElement に書き換える箇所は以下のとおりです。
import
をLitElement
に変更- 親クラスを
LitElement
に変更 static get template()
を_render({必要な引数})
に変更
codelabs は Polymer1 で書かれているので、Polymer3 形式に変更するときに気をつける箇所は以下のとおりです。
listeners
は使わずにaddEventListener
でクリックイベントを受け取る
あと、デモのコードのアップした内容を見て確認してください。 LitElementとは関係ないですが、Polyfillのインポートが以下のように変わっています。
<script src="../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
LitElement と PolymerElement の違い
PolymerElementはHtmlElementに以下のような機能が追加されて構成されています。
公式ドキュメントのAPI docの polymer-element.js
を参照してください。
Base class that provides the core API for Polymer’s meta-programming features including template stamping, data-binding, attribute deserialization, and property change observation.
また、このドキュメントに書いてある様々な機能を利用できます(たとえば tap イベントを処理するための gesture-event-listeners.js
とか)。
対して、LitElementではPolymerElementのつもりでいると、以下のようなポイントで躓きます。
- プロパティで
reflectToAttribute
が使えない- LitElement の issue Adding reflectToAttribute to the demo doesn’t work #10 に解決するサンプルコードが書いてあります。lit-element-icon-toggleではそのまま利用しています。
- プロパティで2ウェイデータバインディングが使えない
- LitElement の issue 2 way data binding not working #14 や Implement property change notification events (notify) #81 が参考になります。
- プロパティで
observer
が使えない
ということで、codelabs のPolymer1版ではあった、データバインディングの箇所は実装されていません。
現時点は上記 issue を参考に、値に変更があったときにイベント pressed-changed
イベントを投げるところまでは実装しています。
受け取り側の demo/index.html
で以下のようなJavaScriptを書くと変更イベントを受け取れます。
document.querySelector('icon-toggle[toggleicon="favorite"]'). addEventListener('pressed-changed', e => console.log(e));
プロパティの値が変化したときには、データバインディングでなく redux などを使おう、というのは PWA-Starter-Kit のコードからも伝わってくるので、まぁそうなのかなーと思います。 ただ、アプリでなく、エレメントを作って公開したい場合は、 redux なのか?という気もするので、change イベントなどを投げるのが良いのだろうな、とは思っています。
次回は
8/20(月) の予定です。Doorkeeperのコミュニティページに今年の予定も書いてあるので参考にしてください。
そろそろ、edoエレメントの開発をしないとなー、なんて思っています…
Recent Articles
- GAE gen1 で動いている PHP5.5 で作った個人開発サービスを gen2 PHP8.2 へ移行した1年記 〜 その 5 2024/05/01
- GAE gen1 で動いている PHP5.5 で作った個人開発サービスを gen2 PHP8.2 へ移行した1年記 〜 その 4 2024/04/30
- GAE gen1 で動いている PHP5.5 で作った個人開発サービスを gen2 PHP8.2 へ移行した1年記 〜 その 3 2024/04/30
- GAE gen1 で動いている PHP5.5 で作った個人開発サービスを gen2 PHP8.2 へ移行した1年記 〜 その 2 2024/03/20
- GAE gen1 で動いている PHP5.5 で作った個人開発サービスを gen2 PHP8.2 へ移行した1年記 〜 その 1 2024/03/20
- PHPカンファレンス関西2024に参加して、オフラインカンファレンスの盛り上がりを体験してきた 2024/02/18
- マルチプルレポをモノレポへコミットログを残しながら移行する 2023/09/27
- tsyringe を TypeScript 5 で使う方法 2023/05/02
- LocalStack を使って aws-sdk の Integration Test を実行する 2023/04/19
- AWS SDK v3 のモジュールと利用方法 2023/04/18
Tags
- PHP
- GAE
- toiletevolution
- phpkansai
- TypeScript
- aws-sdk
- aws-sdk@v3
- Jest
- JavaScript
- AWS
- import maps
- Dependencies Management
- dependabot
- GCP
- asucon
- Polymer
- Polymer.co-edo
- CHIRIMEN
- IoT
- WoT
- CakePHP
- CakeFest
- WebComponents
- ToiletEvolution
- Web Components
- PHPcon
- CakePHP3
- BDD
- Behat
- fixture
- Test
- phpmatsuri
- CoverFlow
- Flex