読者です 読者をやめる 読者になる 読者になる

がりらぼ

WindowsRuntimeの応援ブログ

Arduinoで室温を計測してAzure上でAPIとして公開する

ASP.Net Arduino MicrosoftAzure

de:code2015SNR-003「Windows Phone/iOS/Android アプリ同時開発のススメ」のデータ計測とWebAPI作成をお手伝いさせて頂いてました。

この記事ではArduinoによるデータ計測からAzure上でWebAPIを公開するまでどのように作成できるかをご紹介します。

概要

全体的な構成図はこのようになります。 f:id:garicchi:20150522163930p:plain

コンポーネントとその役割はこのようになります。

テクノロジー名 役割
LM61biz 温度センサー
Arduino UNO & Ethernet Sield 温度計測&アップロード用マイコン
Azure Web Apps データ受信と送信のためのWeb API
Azure SQL Databse 計測データ蓄積のためのデータベース

流れとしてはこのようになります。

  1. 温度センサーで室温計測
  2. Arduino UNOでAzure WebAppsにアップロード
  3. Azure WebAppsからAzure SQL Databaseに蓄積
  4. Azure WebAppsにリクエストがあった場合はSQL Databaseからデータを取得しレスポンス

温度計測部

回路図はこのようになります。

LM61biz温度センサーで受け取った値をArduinoのA0ピンへと入力します。

f:id:garicchi:20150522155940p:plain

回路はブレッドボードとジャンパー線を使って作成し、ArduinoにはEthernet SieldをつけてインターネットにつながるLANに接続しておきます。

f:id:garicchi:20150301140659j:plain

Arduinoソースコードはこのようになります。

#include <SPI.h>
#include <Ethernet.h>

//your ethernet sield mac address
byte mac[] = { 0x**, 0x**, 0x**, 0x**, 0x**, 0x** };

//your server name
const char *server = "http://******.azurewebsites.net/api/temp";
//your server hostname
const char *host = "******.azurewebsites.net";

//your input pin
int tempPin=A0;

EthernetClient client;

unsigned long prevTime=0;
 
void send_request(float value)
{
  char buffer[256];
  char value_str[64];
  
  if (client.connect(host, 80)) {

    sprintf(buffer, "POST %s HTTP/1.1", "/api/temp");
    client.println(buffer);
    sprintf(buffer, "Host: %s", host);
    client.println(buffer);
 
    client.println("Content-Type: application/json");
 
    dtostrf(value,5,2,value_str);  //Arduinoではsprintfで小数をあつかうことができないのでこれ
    sprintf(buffer, "%s",value_str);
 
    client.print("Content-Length: ");
    client.println(strlen(buffer));
    
    client.println();
 
    client.println(buffer);
    Serial.println(buffer);
  }
  
}

void read_response()
{
  bool print = true;
  
  while (client.available()) {
    
    char c = client.read();
    // Print only until the first carriage return
    if (c == '\n')
      print = false;
    if (print)
      Serial.println(c);
  }
}
 
void setup()
{
  Serial.begin(9600);
  Ethernet.begin(mac);
  prevTime=0;
  delay(1000);
}

void loop()
{
  //send hourly <-- 100millisec * 60 seconds * 60minutes
  if((millis()-prevTime)>(unsigned long)(3600000)){
    int val = analogRead(tempPin);
    
    
    float temp=(float)val*500/1024-60;
    
    send_request(temp);
    read_response();
    client.stop();
    
   
    prevTime=millis();
    delay(1000);
    
  }
   
  
  
}

変更点としてはMacAddress、ServerName、ServerHostName、Pin番号の4つです。 f:id:garicchi:20150522162113p:plain

このコードではloop関数内で1時間ごとにデータを送信するようにしています。

millis()関数がミリセカンドの単位で時間を計測できるので、1時間=3600000ミリセカンド経過したらデータを送信するという形にしています。

アナログ入力を受け取ると電圧値から温度へとデータ変換をおこないます。データ変換に関してはこちらを参照してください。

f:id:garicchi:20150522164133p:plain

send_request関数ではPOSTリクエストを作成してデータを送信しています。

データ蓄積部

Arduinoから送信されたデータは、AzureWebApps上にホスティングされたASP.Net WebAPIを通し、Azure SQL Databaseへと送信されます。

まずAzure WebAppsとAzure SQL Databaseのインスタンスを作りましょう。

Azureでのインスタンスの作り方は以下を参考にしてください。

Azure アプリ サービスでの ASP.NET Web アプリの作成

Get started with SQL Database

次にSQL Databaseにテーブルを作りましょう。今回は以下のようにしました。

テーブル名 Temperature

カラム

カラム名 内容
Id 一意なID int
RegisterDate 日付 datetime
Temp 気温 float

続いてASP.Net WebAPIでGetとPostメソッドを作ります。

ASP.Net Web APIについてはこちらを参考にしてください。

Insider.NET > 連載:ASP.NET Web API 入門 - @IT

PostメソッドArduinoからのデータ受信用、Getメソッドはモバイルアプリへのデータ返却用に使用します。

public class TempController : ApiController
{
    //モバイルアプリからGetリクエストをうけたとき
    public IEnumerable<Temperature> Get([FromUri]DateTime from,DateTime to)
    {
        var tempList = new List<Temperature>();
        //SQL接続
        var connectionStr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
        using (var connection = new SqlConnection(connectionStr))
        {
            connection.Open();
            //クエリ引数にある指定の日付を条件にSQLクエリを作る
            var sql = string.Format("select * from dbo.Temperature where RegisterDate >= '{0}' and RegisterDate < '{1}' order by RegisterDate",
                from,to);

            //SQL発行
            using (var command = new SqlCommand(sql, connection))
            {
                using(var reader = command.ExecuteReader())
                {
                    //取得した結果をコレクションに入れる
                    while (reader.Read())
                    {
                        var date = reader.GetDateTime(1);
                        var val = reader.GetDouble(2);

                        tempList.Add(new Temperature
                        {
                            RegisterDate = date,
                            Value = (float)val
                        });
                        
                    }
                }
                
            }
            connection.Close();
        }

        //結果返却
        return tempList;
    }

    //ArduinoからデータがPostされたとき
    public HttpResponseMessage Post()
    {
        //stringとしてPostの内容を読む
        var content = this.Request.Content.ReadAsStringAsync().Result;
        //float変換
        var t = float.Parse(content);
        //データを挿入するSQLクエリの作成
        //時間に関しては世界標準時を取得できるので+9
        var sql = string.Format("insert into dbo.Temperature values('{0}','{1}')",
        DateTime.Now.AddHours(9), t);

        //SQL接続
        var connectionStr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
        using (var connection = new SqlConnection(connectionStr))
        {
            connection.Open();

            using (var command = new SqlCommand(sql, connection))
            {
                //SQL発行
                command.ExecuteNonQuery();
            }
            
            connection.Close();
        }
        //レスポンスを返す
        var result = new HttpResponseMessage();
        result.Content = new StringContent("OK");
        result.StatusCode = HttpStatusCode.OK;
        return result;
    }


}

作成したASP.net APIのWeb.configファイルのSQLDatabase接続文字列を編集します。

今回はDefaultConnectionという名前を使うのでconnectionStringタグを編集します。

<connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=tcp:{server hostname},1433;Initial Catalog={databasename};User Id={user id};Password={pass};" providerName="System.Data.SqlClient" />
    
</connectionStrings>

接続文字列は管理ポータルからも見ることができます。 f:id:garicchi:20150526131655p:plain

WebAPIができたらAzure Web Appsへとデプロイします。

Azure Web Appsへのデプロイには発行プロファイルを利用すると便利です。

MSDN Blogs

あとはデプロイしたサイトに向かってHttpアクセスをすると、溜まった気温データを取得することができます。

クエリ引数にはfromとtoにDateTimeに変換できる文字列を入れると、fromとto間の気温データを取得することができます。 f:id:garicchi:20150526132248p:plain

VisualStudioでも入っているデータを閲覧することができます。

f:id:garicchi:20150526132725p:plain

以上でArduinoで計測したデータをAzureにアップロードし、WebAPIとして公開することができました。

decode2015ではさらにWebAPIをXamarin Formから利用してグラフ化するのでぜひ、いろんなプラットフォームでこのようなAzureを利用したIoTシステムを構築してみるといいと思います。 *