休日の小ネタ。デバッグ用の基盤作りました。スイッチはプルアップしています。LEDは4つ付いていますが、スリーステートの状態が把握できるように以下の様な回路にしてみました。ハイとローで点灯するLEDが変わります。VFが1.8VあるLEDを使ったので、ハイインピーダンスだと点灯しないと思いましたが、うっすらと点灯しています。実際のVFは1.65V以下なのかもしれません。“””
Angular2でSPAなシステム開発:serviceのデータを同期するならPromiseよりもEmitter、EmitterよりもObservable
Ionic2がAngular2を前提している関係上、作法に則った形でアプリケーションを作ろうとすると、どうしてもAngular2の知識が必要になります。今回やりたかったのは、websocketの接続やデータを一括してserviceで行い、serviceがwebsocketでデータを受信したら、関係しているPageでデータのアップデートを行うという作業。各Pageでwebsocketの接続を作るのであれば考えることは少ないのですが、一つのアプリケーションで複数の接続を張るというのは合理的では無いですし、同じデータを複数のPageで使うこともあるので、ばらばらに接続すると整合性に問題も出そうです。Angular2で各Pageで同じデータを共有するにはInjecterを付けたserviceを使うのが基本のお作法の様です。Services – ts でここで困ったのが、service側で情報を取得して管理する情報が変化したときに、これをPage側に働きかけてPageを更新する方法。Page側からserviceのメソッドを実行するのは簡単なのですが、Service側がきっかけとなって更新をする方法がすぐには分かりませんでした。本当はserviceとPageの各変数を直接バインドしてしまう方法があればいいなと思ったのですが、今日かなり検索した限りでは見つかりませんでした。最初に気づいたのが、先ほどのページで解説されているPromiseを使う方法。JavaScript Promiseの本このサイトは素晴らしいですね。無茶苦茶わかりやすい。みんな買いましょう。
getAfterFalse() { console.log(""getAfterFalse""); return new Promise(resolve =>{ setInterval(()=>{ if(this.flag == false){ this.flag = true; console.log(""flag change""); resolve(HEROES); } },1000); }); }
service内で目的の条件が達成されるかどうかをウォッチしておいて、条件達成時にresolveをして、呼出元に処理を戻します。
this._heroService.getAfterFalse().then(heroes => this.heroes = heroes);
Pageに戻ってきたらPageの変数を更新します。が、ポーリングをしているというのがいかにもださく、処理に即時性も無いですし、負荷も大きいはずです。そこで次に発見したのがEventEmitterを使う方法。Angular2 detect change in service – Stack Overflow
import {EventEmitter} from 'angular2/core';@Injectable()export class HeroService { public flagUpdated = new EventEmitter();
service側でEventEmitterを定義しておいて、発火させたいところでemitします。
this.flagUpdated.emit(this.flag);
Page側はsubscribeしておくと、emitされて時点でイベントを検知して処理が実行できます。
this._heroService.flagUpdated.subscribe( (flag) => { this.getHeroes(); console.log(flag); }
が、EventEmiterをカスタムイベント以外のために使うのは誤用のようでできるだけ避けるべきとの事。EventEmitter is really an Angular abstraction, and should be used pretty much only for emitting custom Events in components.でここで解説されている通りObservableを使うことに。一番ややこしそうなので敬遠していたのですが、HTTPモジュールを使うためには結局は慣れていないといけないと諦めました。リンク先のサンプルは何故か長いですが、やってみるとコンパクトな記述もできそうです。
import {Observable} from 'rxjs/Observable';import 'rxjs/add/operator/share';@Injectable()export class HeroService { flagChange$: Observable; private _observer; constructor() { this.flagChange$ = new Observable(observer => this._observer = observer).share(); // share() allows multiple subscribers }
それでも下準備は一番長いです。2つのimportと2つの変数、そしてインスタンスの定義が必要です。定義した_observerのnextを呼ぶと発火します。
this._observer.next(this.flag);
Page側の処理はEventEmitterの場合と同じで、インスタンスのsubscribeを呼びます。
this._heroService.flagChange$.subscribe( flag => { this.getHeroes(); console.log(flag); }
公式のTour of HerosのServicesのサンプルコードに手を加えて実験してみました。何をやっているかわかりにくいのですが、見出しのTour of Herosの文字列にクリックイベントが設定してあり、ここでID13の名前を押した時点でのDateのmilisecondに変更しています。同時にObservableのnextを実行して、Page側のsubscribeを実行しています。Page側はgetHeroesを実行しているので変数をservicesから取得してきて表示を更新しています。実際にはObservableでデータの取得・受渡までやらないと意味が無いのだと思いますが、とりあえず非同期をトリガーできるところまで。日本語の情報が少なくて一つのことをやるのにも大分と時間がかかりますが、やってみると殊の外簡単。シンプルにアプリのロジックを書けそうでよいですね。”””
node.jsでサーバサイドのJavaScrpt開発:socket.ioはwscatではなくiocatでデバッグ
久しぶりにsocket.ioを使うので、簡単なプログラムを作ってテストをしてみることにしました。サーバサイドはこれ。
///var fs = require(""fs"");var server = require(""http"").createServer(function(req, res) { res.writeHead(200, {""Content-Type"":""text/html""}); var output = fs.readFileSync(""./index.html"", ""utf-8""); res.end(output);}).listen(8080);var io = require(""socket.io"").listen(server);var reply:string;io.sockets.on(""connection"", (socket) => { io.sockets.emit(""message"", ""thank you for connecting""); console.log(""connection from socket.io client""); socket.on(""message"", (message) => { console.log(""key:message %s"", message); reply= ""I got message from you:"" + message; io.sockets.emit(""message"", reply); }); socket.on(""disconnect"", () => { console.log(""disconnected""); }); socket.on(""CS_REQ_registerdRiders"", () => { io.sockets.emit(""SC_RES_registeredRiders"", JSON.stringify(registeredRiders)); console.log(""CS_REQ_registerdRiders:response send""); });});
クライアント側はこんな感じ。
socket.io test
ただブラウザでテストするのはどうにもまどろっこしいので、コマンドラインから実行できるよう、ネット上で多く紹介されているwscatを使うことにしました。最初にハマったのは、wscatがwsに同梱されているのでは無く、wscatとして配布されていること。今のwsのレポジトリではwscatは実行できないようです。パスの問題でしょうか。で次にハマったのが、wscatでいくらnodeに接続しても接続が確立されずにhang upとなったり、無言となったりするという現象。いろいろ試してみた挙げ句、wscatではなくiocatを使うと接続に成功しました。iocatsocket.ioはメッセージ送信時にキーを付ける機能があったりしますので、そのあたりが通常のwebsocketとは互換性が無いのかもしれません。(2016/03/14追記)私が誤解していたようです。socket.ioはwebsocketの一実装だと思っていたのですが、そもそも違うプロトコルなんですね。リアルタイム双方向通信について“””
ionic2でハイブリッドなアプリ開発:ionic2/Angular2でsocket.ioを使う
Creating a Real Time Chat Application with Ionic 2 and Socket.io ionic2でsocket.ioを使うにはどうしたら良いかと思い最初に見つけたのがこの記事。ですが、index.htmlでインポートするというのはionic2/angular2の作法に沿っていない様に思われ、もしindex.htmlがアップデートされたときに記述が消失してしまうリスクもあるように思いました。そこでもう少し検索して発見したのがこちら。How to include socket.io-client · Issue #221 · AngularClass/angular2-webpack-starter npmでsocket.io-clientというモジュールを入れて、これを呼ぶとのこと。npmからローカルインストールされたものがクライアントのビルドの中に入るのかちょっと不安でしたがやってみたらできました。
npm install socket.io-client --savetypings install socket.io-client --save --ambient
このとおりインストールしてコードを書いてみます。書き方は公式より。socketio/socket.io-client: Realtime application framework (client)
import {Page, NavController, NavParams} from 'ionic-angular';import {ItemDetailsPage} from '../item-details/item-details';import * as io from 'socket.io-client';@Page({ templateUrl: 'build/pages/registered-riders-list/registered-riders-list.html'})export class registerdRidersList { selectedItem: any; icons: string[]; items: Array<{title: string, note: string, icon: string}>; constructor(private nav: NavController, navParams: NavParams) { var socketio = io('http://localhost:8080'); socketio.emit('CS_REQ_registerdRiders',''); socketio.on(""SC_RES_registeredRiders"", function (data) { console.log(data); });
ちゃんとサーバー側への送信(emit)、サーバー側からの受信(on)、両方が作動しました。”””
Angular2でSPAなシステム開発:Serviceのデータを同期する方法/Eventをsubscriveする方法
Angular2でSPAなシステム開発:serviceのデータを同期するならPromiseよりもEmitter、EmitterよりもObservable誤用ということなのですが、Ionic2(というかAngular2)のserviceのデータを同期させるのは、EventEmitterを使うのがわかりやすいです。コードを読む人もObservableよりわかりやすいのでは無いでしょうか。Lifecycle Hooks – ts 最初はこの中のngAfterContentCheckedとかngAfterViewCheckedを使って、serviceのget系メソッドを実行してみたのですが、初期ページを表示させてその後ページが1回遷移するだけで30回以上このイベントが呼ばれていました。そのたびにメソッドを呼んでいるのは余りにも無駄でパフォーマンスの無駄が大きいと思われました。
import {Injectable, EventEmitter} from 'angular2/core';@Injectable()export class SettingsService { public hello:string = 'hello'; helloChange: EventEmitter= new EventEmitter(); constructor() {} getHello(){ return this.hello; } setHello(str:string){ this.hello = str; this.helloChange.emit(this.hello); }}
これがemitする側のサービス。
this._helloSubscription = _settingsService.helloChange.subscribe((value) => { this.myhello = value; });
受ける側のページコンポーネント。これだけで同期できます。参考にしたのはこのディスカッション。最初の方のドットルールでは値を反映させることはできませんでした。javascript – updating variable changes in components from a service with angular2 – Stack Overflow “””
Ionic2でハイブリッドなシステム開発:IoniconはIoniconのページの名前では指定しない
Ionicには最初からフラットなデザインのアイコンが多数装備されています。Ionicons: The premium icon font for Ionic Framework Fontawesomeが定番だと思いますが、Ioniconsでも充分でしょう。700個もありますから普通に使う分には該当するものが見つかると思います。がこれを使おうとしてちょっとハマりました。上記のサイトでアイコンにマウスオーバーするとアイコンのコードのようなものが現れるのですが、これをタグの中で指定してもアイコンが表示されません。 いろいろ試行錯誤したところ、下記のページの名称で指定すれば表示されることが確認できました。Ionic 2 | Ionicons – Ionic 2 Developer Preview – Ionic Framework つまり
ではなく、
です。 “””
Ionic2でハイブリッドなアプリ開発:スタイルシートをスクリプトから操作したいときはngStyleを使うと簡単
Ionic2のアプリケーションでスクリプトからスタイルシートの要素を変更したいと思い色々試行錯誤していたのですが、普通のウェブサイト構築の時に使うdocumentオブジェクトからたどる方法では上手くいきませんでした。オブジェクト自体は取得できるのですが、その先の要素指定が上手くいきません。で、Angular2のサイトに戻ってみたらそのまんまなディレクティブがありました。NgStyle – js
ngStyleにJSのオブジェクト形式でスタイルシートの要素を渡します。シングルクォーテーションを付けずに渡すとクラスのプロパティにバインディングされます。シングルクォーテーションをつけて文字列にするとそのままの内容でスタイルシートの要素として解釈してくれます。ちなみに何をやりたかったかというと、画面上にボタンを配置して動的にボタンのサイズを変更したかったんです。これができるとユーザーやシチュエーションに応じてインターフェースを変更できるのでよいですね。ただ上手くやらないとHTMLにデザイン要素が混入して混乱しそうです。sizeとかを変数で渡すのでは無く、オブジェクトごとスクリプト側で指定して、ngStyleはidやclassを指定するようなスタイルで使用するのがよいかもしれません。”””
Raspberry PiでIoTなシステム開発:光電センサをマイコンやRaspberry Piに接続する際の回路と定数
かわっちタイマー(バイクジムカーナ用自作タイム計測機の名前です)2号機で現在実装している光電センサとの接続回路のメモです。ノイズによる誤動作を防止するため、光電センサの出力を直接マイコンにつなぐのでは無く、光電センサの出力で一旦フォトカプラのLEDを明滅させ、オン時にフォトトランジスタ側のコレクタをグランドに落としています。直接接続だと、光電センサからマイコンまでの配線が10mを超えてくるとアンテナ効果が大きく、入力が不安定になっていました。2m程度でも室内で蛍光灯の電源を入れただけで誤動作する状態です。これがフォトカプラを介すると入力が安定し、誤動作しなくなりました。電圧変換も一挙に行えるので、電圧変換のために実装していた分圧抵抗が減らせる分、実装もシンプルだと思います。実験に使用したオムロンのE3JK-RN12は回帰反射型で、反射板との間を遮断したときに遮光でダーク、遮断しないときに入光でライトになります。今のところダークオンに設定していますので、遮断時にNPNトランジスタがオンでLEDもオン、遮断しないときにNPN がオフでLEDもオフです。手で光を遮ったときに、オレンジ色の動作確認燈が点灯します。手を離すと確認燈が消灯します。今回の回路では動作の確実性を優先させるため、LEDへの電流量を確保すべく、電流制限抵抗を1KΩにしました。定常状態でオフになる使用法であればこれでもよいですが、オンが多いのであれば消費電流量が多いので、抵抗を増やした方がいいかもしれません。回路図中のA点で実測してみると、入光時が11.3V、遮光時が0.7Vでした。出力はマイコンの入力容量が小さいので、大きなプルアップでも十分と考え、10KΩでプルアップしています。本当はマイコンとフォトトランジスタのコレクタの間に100Ωぐらいの抵抗を入れて、マイコンの入力にある電荷を抜くときの電流を制限すべきだと思います。ただ今回の使用方法ではオンオフの頻度が少ないのでフォトトランジスタの内部抵抗と熱容量でも十分と判断したので、抵抗は入れませんでした。回路図中のB点で実測すると、オン時(遮光・光電センサとフォトトランジスタ共にオン)で0.1V、オフ時で(遮光・光電センサとフォトトランジスタ共にオフ)で3.3Vでした。スレショールド電圧からすると十分すぎますので、もっとLED側の電流が少なくてもよいかもしれません。マイコン側はダウンエッジを割り込みで検出し、ソフトウェアのロジックでチャタリングを除去しています。”””
Ionic2でハイブリッドなアプリ開発:imgタグを使う方法
HTMLアプリなので画像を表示するにはimgタグを使うわけですが、パスの指定が特殊です。appフォルダ以下のhtmlテンプレートがあるフォルダに画像を配置しても、ビルド時にwwwにはコピーされません。そのため最初からwwwのimgに画像を記録しておく必要があります。こうしておくと./img/~でアクセスできます。
“””
Ionic2でハイブリッドなアプリ開発:socket.ioのemitはコネクションを確認してから
socket.ioを使うアプリを開発していたのですが、デスクトップでシミュレートしている分にはいいのですが、実機(Android)に入れると途端にレスポンスが遅くなります。そんなに古い奴じゃ無いのに。色々試した結果、connectする前にsocket.emitをすると遅くなることが分かりました。そこでemitをラップしてconnectの状態を確認してから実行させると、アプリのもっさりが無くなりました。
export var createIO = (address:string) => { manager = socketio(address); manager.on(""connect"", () =>{ isConnected = true; console.log('io connected'); }); manager.on(""disconnect"", () =>{ isConnected = false; console.log('io connected'); });}export var emit = (name:string,data:any) => { if(isConnected){ manager.emit(name, data); }}
“””