.NET対応組み込みデバイス「Netduino」入門(7)

.NET対応組み込みデバイス「Netduino」入門(7)

Netduinoの計測結果をクラウド集計

2015年7月16日

Netduinoで計測した室温データをクラウドに送信してWebから見えるようにしてみよう。

Microsoft MVP for Windows Platform Development 初音 玲
  • このエントリーをはてなブックマークに追加

 前回作成したLCD付き室温測定回路から、httpプロトコルを使ってMicrosoft Azure(クラウド)上のサービスに室温データを送信する。

使用部品について

 前回のおさらいになるが使用部品とブレッドボード上の実装を再度紹介する。

図1 ブレッドボード上に配置

 Netduinoからの5Vラインは、赤いラインを通ってブレッドボードの一番下のプラス電源ラインを経由し、LCDのVDDRESETそして温度センサーのVDD、1組のプルアップ抵抗へと5Vを供給する。NetduinoのGNDからの線も同様に青いラインを通って下から2番目のGNDラインに接続し、LCDと温度センサーのGNDに接続する。

 SCLSDAの2つの信号線は、SCLがA23、SDAがA22でNetduinoに接続し、ここからB13C14に分岐してLCD側に接続する。また、プルアップ用の10KΩ抵抗でA13A14からプラス電源ラインの間を接続する。

Microsoft Azure Mobile Serviceの準備

 Netduino側のアプリを作成する前に、データを格納するMicrosoft Azure Mobile Service(=いわゆるmBaaS。最新Azureでは「Mobile Apps」と呼ばれている。詳しくはこちらを参照)を作成する。詳細は割愛するが、図2を参考に作成してほしい。

図2 モバイルサービスの作成

Azureには、プレビュー版の新ポータルと、従来からの旧ポータルがある。本稿では旧ポータルを利用した。

 モバイルサービスを作成したら、[データ]タブから「Item」という名前でテーブルを作成しておく。なお、作成時に指定できるアクセス許可レベルの設定は、デフォルトのままでOK。

 また、一番左の[クイックスタート]タブを開いて、先ほど作成したモバイルサービスのコードサンプルを参照して(具体的には図3のようにして閉じられている項目を開くと[アプリケーションへ接続する]ためのコードとして参照できる)、アクセスキー(=MobileServiceClientクラス・コンストラクターの第2引数。以下、AccessKey)とURL(=第1引数。以下、MobileServiceURL)をメモしておこう。ここでメモしたAccessKeyMobileServiceURLはコード作成時に使用する。注意点として、今回はhttpsではなくhttpを使うので、URLのhttpsの「s」を削除すること。

図3 接続情報の確認

Netduinoのネットワーク設定

 Netduino Plus 2にはLANインターフェースが実装されている。LAN接続をするためには、接続する有線LANに合わせて設定しなければならない。この設定は、Netduino Plus 2をUSB接続した後に.NET Micro Framework Deployment Tool(以下、MFDeploy)を起動して[Device]で[USB]を選択することでNetduino Plus 2デバイスを指定してから、上部の[Target]-[Configuration]-[Network]メニューでネットワーク設定ダイアログを表示して行う(図4)。また[MAC Address]欄には、Netduino Plus 2の裏のシールに記載された値を入力しておく。入力したMAC Addressは後でデバイスIDとして使用する。

図4 ネットワーク設定ダイアログ

 [Update]ボタンをクリックしてダイアログを閉じる。最後に、有線LANケーブルを接続し、[Ping]ボタンをクリックすると「IP Address」が表示される(表示されない場合は何度か[Ping]ボタンを押してみたり、有線LANケーブルを抜き差ししたりしてみてほしい)。

NetduinoでのREST/JSONプログラミング

 回路が完成したら、Visual Studioで[Netduino Plus 2 Application]テンプレートを選択して、新規にプロジェクトを作成して(本稿の例では、プロジェクト名はVB.NET用は「IoTRestVB」、C#用は「IoTRestCS」とした)、アプリのプログラミングを始める。

前回のクラス構成

 まずは前回と同じクラスをプロジェクトに取り込む。

図5 前回のクラス構成

 I2C用クラスであるI2CLibクラスを基本クラスとして、LCD用AQM0802Libクラス、温度センサー用ADT7410Libクラスに派生させてから呼び出している。

Json.NETクラスライブラリの追加

 Azure Mobile Serviceにデータを送信するためには、JSON形式のデータとして送信しなければならない。簡単なものであればJSON形式になるように送信文字列を組み立ててもいいが、今回はNuGetパッケージとして配布されている.NET Micro Framework用クラスライブラリを使用する。NuGetから必要なクラスライブラリを取得するには次の手順で行う。

 ソリューションエクスプローラーでプロジェクト項目の右クリックメニューから[NuGet パッケージの管理]を選択する。これによりダイアログが表示されるので、図6の説明手順を実施する。

図6 Json.NETクラスライブラリの追加
  • 1[オンライン]を選択。
  • 1検索欄に「Json.NET」と入力して検索。
  • 1検索結果の一覧から「Json.NetMF」を選択して[インストール]ボタンをクリック。

 NuGetパッケージとしてインストールすれば自動的に参照設定なども行われるし、更新がかかれば[NuGet パッケージの管理]ダイアログで[更新プログラム]として表示されるので、クラスライブラリが管理しやすくなる。

.NETコンポーネントの追加

 今回はネットワーク通信が必要なので、標準提供の[.NET]コンポーネントから「System.Http」と「System.IO」についても参照設定を行う。その手順は、図7を参考にされたい。

図7 参照の追加

C#の場合は、ソリューションエクスプローラーでプロジェクト項目を右クリックしてコンテキストメニューを表示し、そこから[参照の追加]メニューを選択(VBの場合は、プロジェクトプロパティの[参照]タブを開いて[追加]ボタンをクリック)。これにより、このダイアログが表示される。
[Add Reference]ダイアログの[.NET]タブの一覧から「System.Http」と「System.IO」を選択して[OK]ボタンをクリック。

データ送信クラスの追加

 クラスライブラリの追加が完了したら、室温を送信するためのRESTLibクラスを作成する。

Visual Basic
Imports System
Imports Microsoft.SPOT
Imports System.Net
Imports System.Text
Imports System.IO

Friend Class RESTLib
  Implements IDisposable

  Private Const DeviceId As String = "00-04-a3-00-00-00"
  Private Const AccessKey As String = "[AccessKey]"
  Private Const UrlString As String = "[MobileServiceURL]"

  Public Sub Setup()
  End Sub

  Public Sub Upload(temperature As Single)
    Try
      Dim request = CType(HttpWebRequest.Create(UrlString + "tables/Item"), HttpWebRequest)
      Dim serializer = New Json.NETMF.JsonSerializer()
      Dim json As New TItem

      request.Headers.Add("X-ZUMO-APPLICATION", AccessKey)  ' ……1
      request.Accept = "application/json"                   ' ……1
      request.ContentType = "application/json"              ' ……1
      request.Method = "POST"                               ' ……1
      json.DeviceId = DeviceId.ToString()
      SyncLock (Me)
        json.Temperature = temperature
      End SyncLock

      Dim jsonString = serializer.Serialize(json)                       ' ……2
      Dim postDataBytes As Byte() = Encoding.UTF8.GetBytes(jsonString)  ' ……3
      request.ContentLength = postDataBytes.Length
      Using reqStream = request.GetRequestStream()
        reqStream.Write(postDataBytes, 0, postDataBytes.Length)         ' ……4
      End Using
      Using res = CType(request.GetResponse, HttpWebResponse)
        Debug.Print(res.StatusCode.ToString())
      End Using
    Catch ex As Exception
      Debug.Print(ex.Message)
    End Try
  End Sub
 
  Public Class TItem
    Public Property id As String
    Public Property DeviceId As String
    Public Property Temperature As Single
  End Class
 
#Region "IDisposable Support"
  ' ……省略……
#End Region
End Class
C#
using System;
using Microsoft.SPOT;
using System.Net;
using System.Text;
using System.IO;
 
namespace IoTRestCS
{
  internal class RESTLib : IDisposable
  {
    private const string DeviceId = "00-04-a3-00-00-00";
    private const string AccessKey = "[AccessKey]";
    private const string UrlString = "[MobileServiceURL]";
 
    public void Setup()
    {
    }
 
    public void Upload(Single temperature)
    {
      try
      {
        var request = (HttpWebRequest)(HttpWebRequest.Create(UrlString + "tables/Item"));
        var serializer = new Json.NETMF.JsonSerializer();
        var json = new TItem();
 
        request.Headers.Add("X-ZUMO-APPLICATION", AccessKey);      // ……1
        request.Accept = "application/json";                       // ……1
        request.ContentType = "application/json";                  // ……1
        request.Method = "POST";                                   // ……1
        json.DeviceId = DeviceId.ToString();
        lock (this)
        {
          json.Temperature = temperature;
        }
 
        var jsonString = serializer.Serialize(json);               // ……2
        var postDataBytes = Encoding.UTF8.GetBytes(jsonString);    // ……3
        request.ContentLength = postDataBytes.Length;
        using (var reqStream = request.GetRequestStream())
        {
          reqStream.Write(postDataBytes, 0, postDataBytes.Length); // ……4
        }
        using (var res = (HttpWebResponse)request.GetResponse())
        {
          Debug.Print(res.StatusCode.ToString());
        }
      }
      catch (Exception ex)
      {
        Debug.Print(ex.Message);
      }
    }
 
    public class TItem
    {
      public string id { get; set; }
      public string DeviceId { get; set; }
      public float Temperature { get; set; }
    }
 
    public void Dispose()
    {
    }
  }
}
リスト1 通信部分(上:RESTLib.vb、下:RESTLib.cs)より抜粋

00-04-a3-00-00-00にはデバイスID(図4参照)を指定する。また、[AccessKey][MobileServiceURL]「https」を「http」に変更しないと正常に動作しないことに注意)を先ほど取得した値(図3参照)に書き換える。

  • 1REST/JSONデータ送信用ヘッダーの設定。
  • 2クラスからJSON文字列への変換。
  • 3JSON文字列からUTF8データへの変換。
  • 4データ送信。

メインプログラムの作成

 クラスの用意ができたらMainメソッドからADT7410LibクラスとAQM0802Libクラスの呼び出しを作成する。

Visual Basic
Module Module1
  Sub Main()
  Using rest As New RESTLib
      Using lcd As New AQM0802Lib
        lcd.Init()                            ' ……1
      End Using
      While (True)
        Dim value As Single
 
        Using adt7410 As New ADT7410Lib
          value = adt7410.ReadTemperatre      ' ……2
        End Using
        Using lcd As New AQM0802Lib
          lcd.Locate(0, 0)
          lcd.WriteMessage(value.ToString())  ' ……3
          rest.Upload(value)                  ' ……4
        End Using
        Thread.Sleep(1000)
      End While
    End Using
  End Sub
End Module
C#
……省略……
public class Program
{
  public static void Main()
  {
    using (var rest = new RESTLib())
    {
      using (AQM0802Lib lcd = new AQM0802Lib())
      {
        lcd.Init();                            // ……1
      }
      while (true)
      {
        Single value;

        using (ADT7410Lib adt7410 = new ADT7410Lib())
        {
          value = adt7410.ReadTemperature();   // ……2
        }
        using (AQM0802Lib lcd = new AQM0802Lib())
        {
          lcd.Locate(0, 0);
          lcd.WriteMessage(value.ToString());  // ……3
          rest.Upload(value);                  // ……4
        }
        Thread.Sleep(1000);
      }
    }
  }
}
リスト2 メインルーチン(上:Module.vb、下:Program.cs)
  • 1LCD初期化(usingブロックの間だけ接続)。
  • 2温度センサーからの値取得(usingブロックの間だけ接続)。
  • 3LCDに温度表示(usingブロックの間だけ接続)。
  • 4温度データ送信。

アプリ実行

 アプリを実行すると1秒ごとに気温を送信する。

 送信したデータは、Azureのポータルサイトにおける該当のモバイルサービスの[データ]タブで確認できる。

図8 送信結果

まとめ

 Netduino Plus 2では残念ながらリソースの関係でOpenSSLが利用できない。そのため、SSL通信が不要なhttpを使ってAzureに測定結果を送信した。しかし、センサー測定値の送信にはもっと軽量なAMQP(Advanced Message Queuing Protocol)というプロトコルを使用することが主流になりつつある。

 AMQPは2003年のJohn O'Hara氏により提唱されたセキュリティも考慮されたメッセージ交換方式だ。AzureのIoT連携機能であるEvent Hubsでも採用され、.NET Micro Framework用のライブラリもオープンソースとして公開されている。

 今回も当初はEvent Hubsを使用することを想定してサンプルアプリも作成したが、残念なことにEvent Hubsとの接続にはセキュリティを意識したAMQPSプロトコルが必須であり、その接続にはSSLによる暗号化が必要なため、Netduino Plus 2で実行することはできなかった。

 Arduinoとピン互換で.NET Micro Frameworkが動作するハードウェアがないか探したところ、Netduino Plus 2の後継機種であるNetduino 3 WiFiや、ルネサスエレクトロニクスがこの夏に発売予定のGR-Peach ならばSSL通信が可能であると分かった。早期評価版のGR-Peachが入手できたので、次回はSSL対応の.NET Micro Frameworkの設定や、GR-Peachに今回の回路をそのまま使ってEvent Hubsへ測定結果を送信する方法などについて紹介したい。

※以下では、本稿の前後を合わせて5回分(第5回~第9回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

5. Netduinoシリアル通信(I2C)でLCD表示

シリアル通信(I2C)をさらに学ぼう。I2C通信で液晶ディスプレイ(LCD)に文字を出力するサンプルを作成する。

6. Netduinoシリアル通信(I2C)で複数機器接続

シリアル通信(I2C)で2つ以上の機器を同時に使用するサンプルを作成する。温度センサーから室温を取得して液晶ディスプレイ(LCD)にリアルタイム表示してみよう。

7. 【現在、表示中】≫ Netduinoの計測結果をクラウド集計

Netduinoで計測した室温データをクラウドに送信してWebから見えるようにしてみよう。

8. GR-PEACHボードとAzure Event Hubでクラウド集計

ついに発売開始されたGR-PEACHを利用。Microsoft Azure Event Hubを使って室温データをクラウドに送信してWebから見えるようにしてみよう。

9. サーボモーターをコントロールしよう

Netduinoはセンサー入力系だけでなく豊富な出力系も活用できる。今回は、ラジコン経験者にはなじみがあるサーボモーターをNetduinoから制御してみよう。

イベント情報(メディアスポンサーです)

サイトからのお知らせ

Twitterでつぶやこう!