Raspberry Pi meets SignalR!
Raspberry Pi電子工作で、C#のWeb技術を生かす!
Raspberry Piの概要と、そのGPIOの使い方を紹介。また、“Raspbian”OS上でC#プログラムをWebサーバーとして動かし、リアルタイムWeb機能を実現する方法を解説する。
いきなりだが、まずは筆者が撮影し公開している以下の動画をご覧いただきたい。
基板むき出しの電子装置に、LED(発光ダイオード)と押ボタン式のスイッチをつなぐところから動画は始まる。
動画の前半はWindows OS上で何かプログラムの表示やコマンドの実行などの作業をしている。その後、Webブラウザー(動画中ではIE)で何やらIPアドレスを指定して開くと、その電子装置の模式図が表示される。
そして、ブラウザーに表示されている模式図のLED横にある[On][Off]のボタンをクリックすると、これと連動して電子装置上のLEDの明かりがついたり消えたりするのだ。
さらに電子装置上の押ボタンを押すと、ブラウザー内の模式図の押ボタンも連動して押し込まれたり戻ったりする。
さらに今度はスマートフォン(動画中ではAndroid 4.3上のGoogle Chrome)で、同じ操作ができてしまう。よく見ると、スマートフォンまたはデスクトップOSでの操作や、電子装置上での操作が、おのおの、全てのブラウザー画面にほぼ即時に連動して反映されているのだ。
これはいったい何かというと、現実の電子装置とほぼリアルタイムで相互作用するWebアプリが作れますよ、という技術デモンストレーションなのだ。
そしてこのWebアプリは、デスクトップOS・スマートフォンいずれのデバイス上のWebブラウザーからでも使える。
ではWebアプリというからにはWebサーバーがあるはずなのだが、それはどこにあるかというと、動画冒頭で示した、名刺サイズの基板むき出しの電子装置自体がWebサーバーになっているのだ。
Raspberry Pi
この基板むき出しの装置は「Raspberry Pi」(ラズベリーパイ)だ。「BeagleBoard」などと同じで、いわゆるボードコンピューターと呼ばれるカテゴリに含まれる製品の1つである。
動画中で使っているRaspberry Piのモデル「Model B+」は*1、このサイズにして、512Mbytesのメモリと700MHzのARM CPUおよびGPUをシングルオンチップで搭載し、USBが4ポート、有線LANポート、HDMI出力、アナログオーディオ入出力ピンジャックを標準で備える*2。小さいながら立派なパーソナルコンピューター(PC)である。
- *1 Raspberry Piには、性能・サイズが異なるいくつかの“モデル”がある。
- *2 最近は、サイズはそのままに消費電力は微増に抑えつつ、メモリを増やし、CPUの世代を新しくして性能向上を果たした最新鋭モデルRaspberry Pi 2が販売開始され、さらに「マイクロソフトがRaspberry Pi 2用のWindowsをリリース予定」との発表があり、話題を呼んだ。
そしてこのデバイス上で動作する無償利用可能なOSイメージ各種も、公式サイトをはじめとしてインターネット上から入手可能だ。代表的なものとしては「Raspbian」というLinuxディストリビューションがある。
例えばRaspbianのOSイメージをダウンロードして別途購入のmicroSDカードに展開し、これをRaspberry PiのmicroSDカードスロットに挿入、USBポートにキーボードとマウス、HDMI出力に外部モニターを接続して、あとはmicroUSB形式コネクタに5V 1A~2Aの電源を供給すれば、普通にLinux OSのデスクトップPCそのものとして使える。
先の動画中でも、Raspberry PiのOSはRaspbianである。ただし、マウスやキーボード、外部モニターは接続しない“ヘッドレス”スタイルで起動し、USBポートに指したWi-Fiドングル経由で、Windows PCからSSHで接続して操作している。
GPIO(General Purpose Input/Output:汎用入出力)
そしてRaspberry Piの醍醐味(だいごみ)は、外部の電子装置とのやりとりで汎用的に使える「GPIO」というピンが装備されていることだ。Raspberry Pi上で動くプログラムから、GPIOのピンに電流が流れているかどうかを読み取ったり、ピンに電流を流したり止めたりできるのだ。
先の動画では、Raspberry PiのGPIOにLEDと押ボタンスイッチを接続しておき、プログラムからはGPIOとやりとりすることで、LEDの点灯・消灯を行ったり、押ボタンの状態を読み取ったりしていたのだ。
GPIOへのアクセスは“ファイルの読み書き”でもOK
プログラムからGPIOの信号状態を読み取ったり、電流のOn/Offを切り替えたりするには、用途に応じていくつか方法がある。その中でも簡単で汎用な方法としては「デバイスファイル」を経由する方法がある。
デバイスファイル方式は、標準入出力や通常のファイルへの読み書きと同じように、ある決められた特定のファイルに読み書きすると、それがすなわちGPIOの各ピンに対する信号読み取りと電流On/Offの設定となって伝わる仕組みだ。Raspbianでは/sys/class/gpio
フォルダー以下のファイルが、GPIOへのアクセスとなるようにできている。
デバイスファイル方式はファイルの読み書きと変わらないので、任意のプログラミング言語によるファイル操作はもちろん、シェルのecho
コマンドとcat
コマンド、およびリダイレクトだけでも操作できる*3。例えばGPIOの25番ピンにつないだLEDを点灯させるには、Raspberry Pi上のRaspbianのシェルから以下の3行を実行すればよい。
$ echo 25 > /sys/class/gpio/export
$ echo out > /sys/class/gpio/gpio/25/direction
$ echo 1 > /sys/class/gpio/gpio/25/value
|
value
ファイルに1
を書き込むと点灯し、0
を出力すると消灯する。
24番ピンにつないだ押ボタンスイッチの状態(つまり24番ピンに電流が流れているかどうか)は、以下のように/sys/class/gpio/gpio/25/value
ファイルの内容をcat
コマンドで表示させることで確認できる。
$ echo 24 > /sys/class/gpio/export
$ echo in > /sys/class/gpio/gpio/24/direction
$ cat /sys/class/gpio/gpio/24/value
|
Apache? nginx? lighttpd? いいえC#です!
さて冒頭では、このRaspberry Pi上で“Webサーバー”を動かしていることを書いた。
では、そのWebサーバーとはいったい何か?
実はApacheやnginx、lighttpdなどの一般的なWebサーバーではない。C#で書いたコンソールアプリなのだ。
Mono
昨年2014年11月に、.NET Framework(.NET Core 5)のオープンソース化と、その.NET Core 5がWindows OSのみならず、Mac OSとLinuxを公式サポート予定であることがアナウンスされた。
しかし、このマイクロソフト公式のLinuxサポートを待たずとも、.NET FrameworkをMac OSやLinux上で動かせるオープンソース実装「Mono」がすでに古くからある。つまり、C#製の実行ファイル(.exe)を、Raspbian上で実行可能なのだ。
Raspbian上でC#製の.exeファイルを実行できるようにするための準備は簡単。以下の、たった3つのコマンドをシェルから実行して、いちどMonoをインストールしておくだけである。
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install mono-complete
|
より正確に言えば、最初の2つのコマンドはRaspbianの既存パッケージの最新版への更新なので、Monoのインストールの本体は最後のコマンド1つだけである*4。
- *4 上記手順でインストールされるMonoのバージョンは古く、v.3.2.8である。最新モデルのRaspberry Pi 2におけるRaspbianへのMono最新版(v.3.12.0)のインストール手順については、下記のブログ記事が詳しい。
あとは、mono
コマンドを実行すれば、いつでもC#製の.exeファイルを実行できる。別途、Windows OS上のVisual Studioを使って作成したコンソールアプリ、例えば“hello.exe”をscp
コマンドなど経由でRaspberry Pi上にコピーしておき、Raspberry Piのコンソール上で以下のコマンドを実行すれば、この“hello.exe”が動作する。
$ mono ./hello.exe
world!
|
先の動画では、C#で書いたコンソールアプリをRaspbianにインストールしたMono上で実行していたのである。
C#のコンソールアプリがWebサーバーに
「C#のコンソールアプリなのにWebサーバーとはこれいかに」という話なのだが、.NETベースのアプリケーションでは「OWIN Self Hosting」という技法を用いることで、ASP.NETをホストするWebサーバー機能を簡単に搭載できる。
これにはまず、C#コンソールアプリのプロジェクトで、いくつかのライブラリ(具体的にはMicrosoft.Owin.StaticFilesとMicrosoft.Owin.SelfHost)をNuGetパッケージで追加した上で、下記のようにWebサーバーの構成・初期化を行うコードを記述する。
using System;
using Owin;
using Microsoft.Owin.FileSystems;
using Microsoft.Owin.StaticFiles;
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
appBuilder.UseFileServer(new FileServerOptions
{
EnableDirectoryBrowsing = true,
FileSystem = new PhysicalFileSystem(AppDomain.CurrentDomain.BaseDirectory)
});
}
}
|
次に、MainメソッドでWebサーバー機能を開始するコードを書けば、これだけで静的コンテンツを公開するWebサーバーが立ち上がってしまう。
using Microsoft.Owin.Hosting;
……省略……
class Program {
static void Main(){
var httpHost = WebApp.Start<Startup>(url: "http://*:80/");
Console.WriteLine("Server running on http://*:80/");
Console.ReadLine();
}
}
|
これをsudo mono AppName.exe
のようなコマンドで管理者として実行した状態で、Webブラウザーで「http://<Raspberry PiのIPアドレス>/」にアクセスすると、ファイルとディレクトリの一覧が表示される。
さらに先のStartup
クラスのConfiguration
メソッド内に機能の追加・構成を行うコードを足すことで、例えばASP.NET MVCなどのサーバー側Webアプリケーションフレームワークを稼働させることもできる。
このように、C#によるコンソールアプリ内にWebサーバー機能を実装すると、そのコンソールアプリをRaspberry Pi上にコピーしてきて実行するだけで冒頭の動画のようなWebアプリを動かすことができる。
コンテンツを所定のフォルダーに配置したり、httpd.confファイルを編集したりといった、面倒なWebサーバーの構成作業が一切不要なのだ。
ASP.NET SignalRで“リアルタイムWeb”
そして、.NETベースでのWebアプリ開発で「サーバー側コードから、ブラウザー上のJavaScriptコードへのプッシュ送信」(「リアルタイムWeb」と呼ばれる)を実現するライブラリとして「SignalR」というライブラリがある。
動画中でデモンストレーションしていたコンソールアプリでは、GPIOにつながれた押ボタンスイッチのOn/Offの状態を、200ミリ秒(msec)間隔でポーリング監視している。押ボタンスイッチの状態の変化を検知したら、SignalRによって、接続している全てのブラウザーに一斉通知を送ることで、ほぼ即時に表示を更新するようにできているのである。
同様にLEDの状態変化についても、SignalRによってサーバー側からブラウザーへ一斉通知を送っているので、あるデバイスによるLED点灯/消灯の操作の結果が、他のデバイスのブラウザー画面にもほぼ即時に反映される。
実装手順はこんな感じだ。
まず、SignalRのNuGetパッケージをプロジェクトに追加した後、先に紹介したStartup
クラスのConfiguration
メソッド内で、SignalRによる通信に使うURLをマップしておく。
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
appBuilder.MapSignalR();
……省略(上記のUseFileServerメソッド呼び出しなど)……
}
}
|
この例では、引数なしのMapSignalRメソッドを呼び出すことで、“/signalr”というURLにマップしている。
続けて、ブラウザーとの通信を賄うHub
クラスを実装(※実装方法はこちらを参考にしてほしい)。
using Microsoft.AspNet.SignalR;
……省略……
public class MyHub : Hub
{
……省略(ブラウザー側から呼び出されるメソッドを記述する)……
}
|
サーバー側からブラウザー側へ一斉呼び出しを行うには、下記の要領で、Hub
クラスのClients.All
プロパティに対して、好みのメソッド名での呼び出しを書く。
using Microsoft.AspNet.SignalR;
……省略……
var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
hubContext.Clients.All.MyCallBack(123);
|
この例では、全てのクライアントのMyCallBackメソッドを「123」という引数付きで呼び出している。
ブラウザー側のHTMLページでは、SignalRのJavaScriptライブラリを<script>
タグでインクルードしておき(上記のようにマップした場合は<script src="signalr/hubs"></script>
のようになる)、下記の要領でサーバー側からの呼び出しに対するコールバック関数を登録しておけばよい。
var conn = $.hubConnection();
var hub = conn.createHubProxy("MyHub");
hub.on("MyCallBack", function (num) {
// サーバー側でhubContext.Clients.All.MyCallBack(123)が実行されると、
// 引数numに123が渡されて、ここが呼び出される。
});
conn.start();
|
SignalRのおかげで、これだけのコードで“リアルタイムWeb”なアプリを実装可能だ。
- ※SignalRの説明と応用例について、動画付きのブログ記事を紹介しておく。
C#ならではの利点は?
今回紹介した技法は、もちろん、C#に限らず他の言語・処理系でも実装可能だ。
プログラミング言語それ自体で組み込みWebサーバーを実行するのは、PythonやNode.jsによる事例がよく知られていると思う。また、リアルタイムWebに関しては、Node.jsのSocket.IOライブラリの方が知られているかもしれない*4。
RaspbianにはPythonとRubyが初めからインストール済みであるし、Node.jsも追加できる。そしてこれら、Python、Ruby、Node.js、その他もろもろのRaspberry Pi上で動作する言語・処理系の多くで、リアルタイムWeb機能を実装できるだろう。それらの言語・処理系と同様に、C#によるプログラムを書ける人であれば、慣れたC#をそのまま使って、今回紹介したようなプログラム作成に取り組むことができるわけだ。
また、C#を採用する場合、Windows OS限定でよければVisual Studioという快適な開発環境を使って開発できるという利点もあるかと思う。Visual StudioはC#のコーディングのみならず、HTMLやCSS、JavaScriptのコーディングにおいても極めて秀逸な出来なので、サーバー側からクライアント側まで統合して快適に開発を進めることができる。Visual Studioには、利用資格に若干の制約があるものの、無償で使えるCommunity版(機能は有償のProfessional版と変わらない)*5もあるので、ぜいたくな開発環境を無償で入手できる人も多いと考えられる*6。
- *5 参考: Visual Studio Community版のダウンロード
- *6 Visual Studioを基盤とした無償で利用可能な開発環境として、Python用には「Python Tools for Visual Studio」というアドイン、Node.js用には「Node.js Tools for Visual Studio」というアドイン(ただしこちらはver.1.0の正式リリース前で、本稿執筆時点ではリリース候補第2版)がある。また、Mac OSおよびLinux OSで同様の統合開発環境を求めるならばJetBrains社の各種製品が選択肢になるだろう。Python用には「PyCharm」(有償、Community版は無償)、Ruby用には「RubyMine」(有償)が用意されている。
ソースコードと実践方法はGitHubに公開
以上、冒頭の動画で紹介したC#プログラムのソースコード一式は、GitHubで下記のリポジトリに公開している。
冒頭動画のデモンストレーションを実践するための、Raspberry Piのセットアップ方法、電子工作部分についての解説も、上記のリポジトリのREADMEに記載してある。ご自身でも実際に動かしてみたい方はぜひお試しいただき、プログラムと現実世界とのやりとりを楽しんでもらえればと思う。
おまけ: スマホでLEDを操作するクリスマスツリー
最後にもう1つ。
以上で紹介した技法を使って、小さなクリスマスツリーに仕込んだ赤・黄・緑のLEDを、スマホのブラウザーから点灯・消灯する仕掛けを作ったので、その動画を紹介しよう。
息子が幼稚園で作ってきた、逆さにした松ぼっくりに、色と飾り付けした小さなクリスマスツリー。それに、Raspberry PiのGPIOにつないだ3色のLEDを取り付けてある。これを本記事で紹介した技法で、C#製コンソールアプリがホストするASP.NET SignalR Webアプリによって、スマホのブラウザーから操作する仕組みだ。
使わなくなった古いスマートフォン数台を捨てずにあったので、それらとRaspberry PiをWi-Fiでつなぎ、子供たちにスマホを1人1台渡して遊ばせてみた。SignalRを使っているので、誰かのスマホで点滅・消灯を行えば、実際のクリスマスツリーのLEDに動作が反映されるだけでなく、他の子のスマホの表示も同期して更新されるのもポイントだ。
まとめ
- C#、ASP.NET SignalRの知識があるなら、あとはRaspberry Piを買ってくれば、GPIOを介して外界とリアルタイムに作用するプログラムを作って動かせる
- ユーザーインターフェースはWebブラウザーになるので、各種デスクトップOSのみならず、スマートフォンやタブレットなどデバイス問わず動く
- ユーザーインターフェースがネットワーク経由の各種デバイスのブラウザーになるので、Raspberry Pi本体にディスプレイや入力機器をつながない、ヘッドレス構成で稼働できる
- Apacheやlighttpd、nginxなどのHTTPサービスの構成が一切不要。ビルドしたバイナリを実行すればOKのゼロ・コンフィギュレーション
- 今回紹介した手法だとLAN内での動作に限られてしまうが、その代わりにレンタルサーバーサービスやクラウドサービスなど、インターネットに何かを設置するための契約・構成が一切不要
- Windows OSで開発するのであれば、強力な統合開発環境であるVisual Studioを使って、快適に開発できる
PCやスマホの画面の中だけで動いていたWebアプリが、Raspberry Piの上に載ることで、外界のスイッチやLED、その他いろいろなセンサーやデバイスと相互にやりとりができるWebアプリになれるのだ。いかがだろう、アイデア次第で「面白いこと」「役に立つデバイス」が作れそうな気がしてこないだろうか?
画面の中だけに閉じ込められていたWebアプリの世界から、その技術を生かして“リアルワールド”へ踏み出す一歩、この記事がその一助になれば幸いである。