Lチカ、リレチカ、カメパシャ、クラコネで、FEZ Spiderで画像キャプチャしてAzureのブロブに格納


今年のDevice 2 Cloud (D2C)コンテストの広島工業大学の学生さんの作品を見ていて、この作品の完成形が見たい…ということで、FEZ SpiderのCameraで撮った画像を、Web SiteのWeb APIで作ったHTTP RESTサービスに送って、Azure のBlob ストレージに格納するサンプルを紹介します。

で、その前に、FEZ Spider のDebug用 LEDでLチカするなら、

var timer = new GT.Timer(500);
bool ledOn = false;
timer.Tik += (t) => {
    ledOn = !ledOn;
    Mainboard.SetDebugLED(ledOn);
};
timer.Start();

ま、こんな感じ。リレーチカチカするなら、Relay X1あたりを使って、

relayX.TurnOn();
relayX.TurnOff();

 で、おしまい。

さて、本題。https://aka.ms/IoTKitHoL  と合わせて読むと理解度アップです。

構成を絵で描くと、

こんな感じ。Multicolor LEDはおまけ。

先ず、FEZ Spiderで、カメラでパシャ(カメパシャ)をするコードだが、タイマーを起動して、定期的にカメラで写真を撮って、クラウドに送信することとする。Program.csを以下のようにコーディング。

        void ProgramStarted()
        {
            /*******************************************************************************************
            Modules added in the Program.gadgeteer designer view are used by typing
            their name followed by a period, e.g.  button.  or  camera.
           
            Many modules generate useful events. Type +=<tab><tab> to add a handler to an event, e.g.:
                button.ButtonPressed +=<tab><tab>
           
            If you want to do something periodically, use a GT.Timer and handle its Tick event, e.g.:
                GT.Timer timer = new GT.Timer(1000); // every second (1000ms)
                timer.Tick +=<tab><tab>
                timer.Start();
            *******************************************************************************************/
            // ネットワーク初期化
            if (!ethernetJ11D.NetworkInterface.Opened)
            {
                ethernetJ11D.NetworkInterface.Open();
            }
            var ipAddr = ethernetJ11D.NetworkInterface.IPAddress;
            while (ipAddr == “0.0.0.0”)
            {
                if (ethernetJ11D.NetworkInterface.IsDhcpEnabled)
                {
                    ethernetJ11D.NetworkInterface.RenewDhcpLease();
                }
                else
                {
                    ethernetJ11D.NetworkInterface.EnableDhcp();
                }
                Thread.Sleep(500);
                ipAddr = ethernetJ11D.NetworkInterface.IPAddress;
            }
            Debug.Print(“IPAddress=” + ipAddr);

            // 時間合わせ
            SyncTimeService();

            // カメラ設定
            camera.PictureCaptured += camera_PictureCaptured;

            // タイマー起動 60000msecつまり1分毎
            timer = new GT.Timer(60000);
            timer.Tick += timer_Tick;
            timer.Start();

            // Use Debug.Print to show messages in Visual Studio’s “Output” window during debugging.
            Debug.Print(“Program Started”);
        }

        void camera_PictureCaptured(Camera sender, GT.Picture e)
        {
            timer.Stop();
            var now = DateTime.Now;
            string fileName = deviceId + now.Year + now.Month + now.Day + now.Hour + now.Minute + now.Second + now.Millisecond + “.bmp”;
            using (var request = HttpWebRequest.Create(url + “?fileName=” + fileName) as HttpWebRequest)
            {
                using (var reqStream = request.GetRequestStream())
                {
                    request.Method = “POST”;
                    request.ContentLength = e.PictureData.Length;
                    request.ContentType = “image/bitmap”;
                    reqStream.Write(e.PictureData, 0, e.PictureData.Length);
                }
                using (var response = request.GetResponse() as HttpWebResponse)
                {
                    if (response.StatusCode != HttpStatusCode.Created)
                    {
                        Debug.Print(“Web Response: ” + response.StatusCode);
                    }
                }
            }
            timer.Start();
        }

        string url = “http://[IoTWeb].azurewebsites.net/api/Bitmap“;
        string deviceId = “gadgeteer1”;

        void timer_Tick(GT.Timer timer)
        {
            timer.Stop();
            if (camera.CameraReady)
            {
                camera.TakePicture();
            }
            timer.Start();
        }

        GT.Timer timer;

        public static byte[] TimeServerIPAddress = new byte[] { 133, 243, 238, 243 };

        private void SyncTimeService()
        {
            if (ethernetJ11D.IsNetworkConnected)
            {
                TimeService.SystemTimeChanged += TimeService_SystemTimeChanged;
                TimeServiceStatus status = TimeService.UpdateNow(TimeServerIPAddress, 10);
                TimeService.SetTimeZoneOffset(540); // time origin
            }
        }
        void TimeService_SystemTimeChanged(object sender, SystemTimeChangedEventArgs e)
        {
            Debug.Print(“Time Synced”);
        }

以上で、FEZ Spider側は完了。コード読めば、分るよね。プロジェクトの参照に、アセンブリを3個追加することを忘れずに。

  • Microsoft.SPOT.Time.dll
  • System.Http.dll
  • System.IO.dll

次はクラウド側。ここから先は、Azureのサブスクリプション契約が必要。申し込みは、http://azure.microsoft.com/ja-jp/ から。

まずは、画像を保存するストレージを作ろう。http://manage.windowsazure.com  を開いて、左下の”+新規”をクリック。”データサービス”→”ストレージ”→”簡易作成”と選択し、

URLには、適当な名前を入力。仮に、”photostorage“としておこう。ストレージが出来上がったら、ポータルの左側のタブの”ストレージ”を選択、出来上がったストレージを選択して、下の黒帯の”アクセスキーの管理”をクリック。表示された、プライマリーアクセスキーを記録しておく。仮に、”storageaccesskey“としておくね。

では次に、Visual Studio で、ASP.NETアプリプロジェクトを作ります。

そして、次のダイアログで、Web APIを選択、

右下のMicrosoft Azureの”クラウド内のホスト”にチェックを入れて”OK”クリックし、Azure上にWebサイトをさくっと作ります。出来上がったプロジェクトのControllerフォルダーを右クリックして、”追加”→”コントローラ”を選択して、BitmapControllerという名前でコントローラを作ります。出来上がった、BitmapController.csファイルのBitmapControllerクラスの中に、以下のメソッドを追加する。

        public HttpResponseMessage Post([FromUri] string fileName)
        {
            var task = this.Request.Content.ReadAsStreamAsync();
            task.Wait();
            var reqStream = task.Result;

            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting(“StorageConnectionString”));
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference(“iotstorage”);
            container.CreateIfNotExists();
            CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
            blockBlob.UploadFromStream(reqStream);

            var response = new HttpResponseMessage();
            response.StatusCode = HttpStatusCode.Created;
            return response;
        }

このメソッドが、作成したWebサイトに、http://[IoTWeb].azurewebsites.net/api/Bitmap?fileName=gadgeteer1201412071000001.bmp といった形式でPOSTすると、このメソッドにルーティングされる、と、そんな仕組みにASP.NETアプリはなっている。あ、そうそう、”StorageConnectionString”の設定をしておかないと、このコードはちゃんと動かない。Web.config を開いて、

    <appSettings>
       
<addkey=“StorageConnectionString”value=“DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key/>
   
</appSettings>

と、<appSettings>…</appSettings>に上のボールドで示した一行を入れ、account-nameを、さっき作ったストレージアカウント名、ダイアログに表示されていたプライマリーアクセスキーでaccount-keyを置き換えて、おしまい。

後は、プロジェクトを右クリックして発行する。このサービス、PCのローカルのエミュレータでも実行はできるけど、外のデバイスからそのサービスにつなぐには、PCのセキュリティに色々と穴をあけないとつなげられないので、お勧めしない。色々手間かけてPCの脆弱度を高めるより、Azureを使った方が手っ取り早いし、結果的に安くつく。

あ、FEZ Spider側のプログラムのurlの[IoTWeb]を作成したウェブサイトに合わせて修正することを忘れずに。

ちゃんと格納されているかは、Visual Studioのサーバーエクスプローラで、AzureのStorageを覗いてみれば確認できる。

ブロブに画像を格納してしまえば、後は、IT側で何でもできる。Webサービス側で、ブロブから画像を取り出す方法は、格納する道具立てを使えばできる。インテリセンスを駆使して試してみてほしい。デバイスローカル(SDカードとか)に格納したい場合は、http://yseosoft.wordpress.com/2012/07/14/net-gadgeteer-%e3%83%87%e3%82%b8%e3%82%ab%e3%83%a1%e3%82%92%e4%bd%9c%e3%81%a3%e3%81%a6%e3%81%bf%e3%81%9f-%e4%bd%8e%e6%a9%9f%e8%83%bd%e3%81%a0%e3%81%91%e3%81%a9%e4%b8%80%e5%bf%9c%e5%ae%8c%e6%88%90/ も参考になるはず。

たいしたコード量でもないので、是非、試してみてほしい。このシステム構成、写真をアップロードするデバイスが増えても対応できるので、いろいろトライしてみてね。

 D2Cにエントリーしたほかの学生さんたち、結構、スマホ連携的なシナリオもあったので、http://blogs.msdn.com/b/hirosho/archive/2014/07/25/gadgeteer-azure-part-1.aspx も参考になると思うので、是非。

Comments (3)

  1. trunghieu9xt より:

    too many errors , I am overcome it

    http://www.thammyhoc.com/

  2. Hiroshi Ota MS より:

    ?

    All code has worked well in my environment.

    But I cut several detail settings and config and so on.

    It is verry helpful for me so that please tell me bad part.

    Thanks!

  3. Vo Tu より:

    Thanks for share but i hope it perfect because i error about fill database and i fixing it and i hope it work.

Skip to main content