Quantcast
Channel: MSDN Blogs
Viewing all articles
Browse latest Browse all 12366

IoT HubにWindows 10 IoT Coreでつなぐ

$
0
0

さてと…

※この投稿は、2015/10/22現在の公開情報を元に記載しています。最新の情報がないか確認してくださいね。

IoT Hubのプレビューが9/30に公開されました。タイミング的にちょっと遅い気もしますが、Raspberry Pi2で動作するWindows 10 IoT CoreデバイスをIoT Hubに接続する方法を説明します。とりあえず試す方法が、https://azure.microsoft.com/ja-jp/documentation/articles/iot-hub-csharp-csharp-getstarted/ に書かれています。この説明は、.NET Framework上でC#を使ったサンプルで、Windows 10 IoT Coreの場合はWindows RT上で動くUniversal Windows Applicationという違いがあって、そのままでは、動かすことができません。更に、プレビュー状態のため、説明通りにいかない部分もあるので、ここで解説しておきます。

※IoT Hubにつなぐ部分、送受信する部分は、通常のWindows 10のUWAでも利用できます。

折角なので、加速度センサー(ADXL345)、温度センサー(BME280)を使ってIoT Hubに送ってみましょう。基本の部分は、https://doc.co/4dEWrJを見てください。ハードウェアの構成は、このドキュメントに記載の

これに加えて、LEDも追加します。

 

 

 

 

次に、センサーやLEDをI2CやGPIOで制御するために、IoT Extensionを参照に加えます。

そして、https://doc.co/4dEWrJに記載に従って、MainPage.xaml.csのProgramクラスにdeviceId(Guid値)と、プロジェクトにSensorクラスを追加してください。

次は、IoT Hubへのアクセス用ライブラリの追加です。本来ならNuGetを使ってインストールできるのですが、本投稿を書いている時点でははうまくいかないので、ブラウザで、

https://github.com/Azure/azure-iot-sdks/

を開き、表示されたページの右横にある、”Download ZIP”をクリックし、どこかにZIPファイルを保存、ZIPファイルのプロパティでブロックを外し(必ずやってくだいね)、適当な場所に保存します。
csharp/Microsoft.Azure.Devices.Client.WinRTに入っているMicrosoft.Azure.Devices.Client.WinRT.csprojをプロジェクトに参照追加します。

ソリューションエクスプローラーで、ソリューションを右クリックし、”追加”→”既存のプロジェクト”を選択し、Microsoft.Azure.Devices.Client.WinRT.csproj を選択し、ソリューションに追加してください。
次に、追加したSDKのプロジェクトを、作成中のプロジェクト参照として追加します。これで、NuGetで組み込んだのと同じ状態になります。

 これで、IoT Hubにアクセスする準備は完了です。

後は、Modelsという名前でフォルダーをプロジェクトに作成し、そのフォルダーにSensorReadingという名前でクラスを作成し、

public class SensorReading
 {

     public string deviceId { get; set; }
   public double temp { get; set; }
  
public double accelx { get; set; }
  
public double accely { get; set; }
   
public double accelz { get; set; }
  
public DateTime time { get; set; }
  
public string msgId { get; set; }
}

と、コーディングしてください。このクラスを使ってセンサー計測値をJSONに変換します。

さて、MainPage.xaml.csのnamespaceの中身を以下の様に編集します。

namespace Win10IoTDevice
{
    using Windows.Devices.Gpio;
    using Microsoft.Azure.Devices.Client;
    using System.Threading.Tasks;
    using System.Diagnostics;
    using Newtonsoft.Json;
    using System.Text;

    /// <summary>
    /// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.Loaded += MainPage_Loaded;
        }

        Guid deviceId = new Guid(/* your device guid */);

        static string iotHubUri = "[your iot hub].azure-devices.net";
        static string deviceKey = "[your device key for your device guid]";

        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            InitLEDGPIO();
            InitializeSensor();
            InitializeUploadIoTHub();
        }

        DeviceClient deviceClient;
        DispatcherTimer uploadTimer;
#pragma warning disable 4014
        private void InitializeUploadIoTHub()
        {
            try
            {
                deviceClient = DeviceClient.Create(iotHubUri, AuthenticationMethodFactory.CreateAuthenticationWithRegistrySymmetricKey(deviceId.ToString(), deviceKey), TransportType.Http1);

                uploadTimer = new DispatcherTimer();
                uploadTimer.Interval = TimeSpan.FromMinutes(2);
                uploadTimer.Tick += UploadTimer_Tick;
                uploadTimer.Start();

                ReceiveCommands();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

        private async void UploadTimer_Tick(object sender, object e)
        {
            uploadTimer.Stop();
            await SendEvent();
            uploadTimer.Start();
        }

        async Task SendEvent()
        {
            List<SensorReadingBuffer> currentReadings = new List<SensorReadingBuffer>();
            lock (this)
            {
                foreach (var r in lastSensorReading)
                {
                    currentReadings.Add(new SensorReadingBuffer()
                    {
                        AccelX = r.AccelX,
                        AccelY = r.AccelY,
                        AccelZ = r.AccelZ,
                        Temperature = r.Temperature,
                        Timestamp = r.Timestamp
                    });
                }
                lastSensorReading.Clear();
            }
            Debug.WriteLine("Device sending {0} messages to IoTHub...\n", currentReadings.Count);

            try
            {
                List<Models.SensorReading> sendingBuffers = new List<Models.SensorReading>();
                for (int count = 0; count < currentReadings.Count; count++)
                {
                    var sensorReading = new Models.SensorReading()
                    {
                        msgId = deviceId.ToString() + currentReadings[count].Timestamp.ToString("yyyyMMddhhmmssfff"),
                        accelx = currentReadings[count].AccelX,
                        accely = currentReadings[count].AccelY,
                        accelz = currentReadings[count].AccelZ,
                        deviceId = deviceId.ToString(),
                        temp = currentReadings[count].Temperature,
                        time = currentReadings[count].Timestamp
                    };
                    sendingBuffers.Add(sensorReading);
                }
                var payload = JsonConvert.SerializeObject(sendingBuffers);
                Message eventMessage = new Message(Encoding.UTF8.GetBytes(payload));
                Debug.WriteLine("\t{0}> Sending message: {1}, Data: [{2}]", DateTime.Now.ToLocalTime(), currentReadings.Count, payload);

                await deviceClient.SendEventAsync(eventMessage);
            }
            catch (Exception ex)
            {
                Debug.Write(ex.Message);
            }
        }

        async Task ReceiveCommands()
        {
            Debug.WriteLine("\nDevice waiting for commands from IoTHub...\n");
            Message receivedMessage;
            string messageData;

            while (true)
            {
                receivedMessage = await deviceClient.ReceiveAsync();

                if (receivedMessage != null)
                {
                    messageData = Encoding.ASCII.GetString(receivedMessage.GetBytes());
                    Debug.WriteLine("\t{0}> Received message: {1}", DateTime.Now.ToLocalTime(), messageData);
                    var command = messageData.ToLower();
                    if (command.StartsWith("gpio:"))
                    {
                        var order = command.Split(new char[] { ':' });
                        switch (order[1])
                        {
                            case "0":
                                LedControl(0);
                                break;
                            case "1":
                                LedControl(1);
                                break;
                            case "2":
                                LedControl(2);
                                break;
                        }
                    }
                    await deviceClient.CompleteAsync(receivedMessage);
                }

                await Task.Delay(TimeSpan.FromSeconds(10));
            }

        }
#pragma warning restore 4014

        IoTDevice.IoTKitHoLSensor mySensor;
        DispatcherTimer measureTimer;
        private void InitializeSensor()
        {
            mySensor = IoTDevice.IoTKitHoLSensor.GetCurrent(IoTDevice.IoTKitHoLSensor.TemperatureSensor.BME280);
            lastSensorReading = new List<SensorReadingBuffer>();
            measureTimer = new DispatcherTimer();
            measureTimer.Interval = TimeSpan.FromMilliseconds(1000);
            measureTimer.Tick += MeasureTimer_Tick;
            measureTimer.Start();
        }

        private void MeasureTimer_Tick(object sender, object e)
        {
            var reading = mySensor.TakeMeasurement();
            lock (this)
            {
                lastSensorReading.Add(new SensorReadingBuffer()
                {
                    AccelX = reading.AccelX,
                    AccelY = reading.AccelY,
                    AccelZ = reading.AccelZ,
                    Temperature = reading.Temperature,
                    Timestamp = DateTime.Now
                });
            }
        }

        List<SensorReadingBuffer> lastSensorReading;

        void LedControl(int onLedId)
        {
            for (int i = 0; i < LED_PIN.Length; i++)
            {
                ledPin[i].Write(GpioPinValue.High);
            }
            ledPin[onLedId].Write(GpioPinValue.Low);
        }

        GpioPin[] ledPin = new GpioPin[3];
        int[] LED_PIN = { 5, 6, 13 };
        // GPIO5 - 29
        // GPIO6 - 31
        // GPIO13 - 33
        // 5V - 2
        private void InitLEDGPIO()
        {
            var gpio = GpioController.GetDefault();
            for (int i = 0; i < LED_PIN.Length; i++)
            {
                ledPin[i] = gpio.OpenPin(LED_PIN[i]);
                if (ledPin[i] != null)
                {
                    ledPin[i].Write(GpioPinValue.High);
                    ledPin[i].SetDriveMode(GpioPinDriveMode.Output);
                }
            }
        }

    }

    class SensorReadingBuffer
    {
        public double Temperature { get; set; }
        public double AccelX { get; set; }
        public double AccelY { get; set; }
        public double AccelZ { get; set; }
        public DateTime Timestamp { get; set; }
    }
}

コードの中で、deviceId、iotHubUri、deviceKeyという変数がありますが、まずはGuid生成ツールで新規にGuidを作成して設定し、

https://azure.microsoft.com/ja-jp/documentation/articles/iot-hub-csharp-csharp-getstarted/

に記載のCreateDeviceEntryアプリでDevice Keyを作成して、deviceKeyの値とし、作成したIoT HubのURLにあわせてiotHubUri変数を編集すれば動きます。チュートリアルと上のコードを見比べてみてください。IoT Hubとの送受信の部分は基本同一です。

1秒ごとにセンサー計測値を貯めて、2分ごとにIoT Hubに貯めたデータを一括送信します。チュートリアルのReadDeviceToCloudMessagesを起動しておくと送信したデータを確認できます。また、

https://azure.microsoft.com/ja-jp/documentation/articles/iot-hub-csharp-csharp-c2d/

に記載の、SendCloudToDeviceSendCloudToDeviceMessageAsyncメソッド

private async static Task SendCloudToDeviceMessageAsync(string command)
{
   
var commandMessage =new Message(Encoding.ASCII.GetBytes(command));
    await serviceClient
.SendAsync("device id guid", commandMessage);
}
と変更し、7のMainメソッドを
Console.WriteLine("Send Cloud-to-Device message\n");
serviceClient
=ServiceClient.CreateFromConnectionString(connectionString);
Console.WriteLine("Press any key to send a C2D message.");
var string command = Console.ReadLine();
SendCloudToDeviceMessageAsync(command).Wait();
Console.ReadLine();
と変更して、実行して、コンソールで、gpio:0、とか、gpio:1とか、gpio:2とか入力すると、Raspberry Pi2側でデータを受信し、対応するLED(0の場合はGPIO5、1の場合はGPIO6、2の場合はGPIO13に、つながっているLEDが光ります。
以上、かなりはしょって説明しましたが、機材が手元にある人はやってみてくださいね。まだ、プレビューなので、結構落ちたりしますが、フィードバックもよろしくお願いします。
安定したころを見計らって、https://doc.co/M7uGBDにIoT Hubシナリオを追加予定です。
新しい技術を獲得する唯一の早道は、実際にやってみることです。是非チャレンジしてみてくださいね

Viewing all articles
Browse latest Browse all 12366

Trending Articles