LoginSignup
4
1

More than 3 years have passed since last update.

Wio(Arduino+GPSセンサ)からAlibabaCloud IoT Platformへ通信する

Last updated at Posted at 2019-12-13

はじめに

こんにちは。ひつじです。
すっかり寒い季節になってきましたね。

前回、AlibabaCloudPlatformの記事を書いたのですが今回は実際にIoTデバイスからセンシングデータを受信してみたいと思います。

本記事の目的としては「ArduinoとSoracomAir」を通じてAlibabaCloudへの接続が成功したことのシェア」となります。

<前回記事>AlibabaCloud IoT Platform設定方法

マイコンについて

マイコンって何だ!?とお思いの方もいらっしゃると思いますが、今回使うのは以下のマイコンモジュールです。

products_wio_lte.png

Wioと書いて「ワイオ」と読みます。
Seeed社が開発しているマイコンモジュールです。Grove コネクターと STM32F4 マイコン、LTE モジュールが搭載されています。

Wioについて

今、手元には2つのWioモジュールがあります。

wio2.png

Cat.1(カテゴリー1)
 NB-IoTと比較し帯域が多く利用でき、通話モードも備えている。
 SIM:Soracom Air
NB-IoT(NBは、Narrow Bandの略。)
 Cat.1より使用電流が少なく、モデムも低価格。帯域幅が狭いので低容量通信に長けている。
 SIM:SoftBank

このWioにはArduinoという開発環境が搭載されており、C#に似たArduino言語でプログラムを記述、実行することができます。
基板にはgroveコネクタが6個ほど付いているのがわかると思います。
ここに、センサーをアタッチするイメージです。
Groveコネクタを使えばセンサーをカチッとはめるだけで簡単に使えて便利です!

wio3.png

こんな感じ。

iOS の画像 (12).jpg

上記の画像はGPSセンサーをアタッチします。
なんかプラモデルみたいで楽しいですよね。

今回の最終構成ですが、このモジュールにてセンサーの情報を取得し、MQTTでAlibabaCloudのIoTプラットフォームへ転送を行います。その後、TableStoreと呼ばれるNoSQLにストアして、可視化ツール(DATAV)で可視化していきたいと思います。

[前置き]
記事が長くなっちゃったので、まずは、ArduinoとIoTPlatFormへの接続を投稿します

スクリーンショット 2019-12-13 16.09.17.png

Arduinoについて

Arduinoは使うマイコンモジュールによってボード、必要なライブラリが異なるので注意が必要です。
以下のリンクを参考すれば、ちゃんとWioの環境にあったArduinoが準備できるで安心してください。

Arduinoのインストール

Arduinoのインストールは以下のサイトから実施できます。

ボードの設定

今回はWioのボードをインストールする必要がありますが、手順は全て以下のリンクに記載されております。
https://seeedjp.github.io/Wiki/Wio_LTE_for_Arduino/Home-ja.html

今回使うマイコン

今回はSoracomスターターキットについてきているCat.1を利用していきたいとおもいます。こちらのスターターキットにはSoracomAirというSIMが付いています。今回はSoracomAirを用いた回線でAlibabaCloudに接続したいと思います。

以下、後々使う接続情報です。

項目 パラメータ
APN soracom.io
USERNAME sora
PASSWORD sora

IoTPlatformの設定

前回のブログに記述した内容を参考にIotPlatformの設定を行います。
設定後のパラメータは以下となります。

項目 パラメータ
ホスト名 a63V16tah0l.iot-as-mqtt.ap-northeast-1.aliyuncs.com
ポート 1883
クライアントID sheep29|securemode=3,signmethod=hmacsha1
トピック /a63V16tah0l/devsheep/user/topicsheep
ユーザ devsheep&a63V16tah0l
パスワード 217629783CFE62B50ECCB2B56CAAFC4C465E7D66

PubSubclient library注意点

PubSubClient.hはKeepAliveは15秒がデフォルトですが
AlibabaCloudではKeepAliveを30秒に設定する必要があります。

ご自身の端末にインストールしたライブラリを編集してください。

libraries\PubSubClient\src\PubSubClient.h
#ifndef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 30
#endif

Arduinoを操作してみる

では、実際にArduinoでのスケッチをしていきたいと思います。
WioデバイスのuptimeをAlibabaCloudに送ってみたいと思います。

尚、Arduinoのスケッチはスケッチ例から作成すると便利です。
ファイル -> スケッチ例 -> Wio LTE for Arduino -> mqtt -> mqttclient

#include <WioLTEforArduino.h>
#include <WioLTEClient.h>
#include <PubSubClient.h>
#include <stdio.h>

#define APN               "soracom.io"
#define USERNAME          "sora"
#define PASSWORD          "sora"
#define MQTT_SERVER_HOST  "a63V16tah0l.iot-as-mqtt.ap-northeast-1.aliyuncs.com"
#define MQTT_SERVER_PORT  (1883)
#define ID                "sheep29|securemode=3,signmethod=hmacsha1|"
#define OUT_TOPIC         "/a63V16tah0l/devsheep/user/topicsheep"
#define MQUSER            "devsheep&a63V16tah0l"
#define MQPASS            "217629783CFE62B50ECCB2B56CAAFC4C465E7D66"
#define INTERVAL          (60000)

WioLTE Wio;
WioLTEClient WioClient(&Wio);
PubSubClient MqttClient;

void callback(char* topic, byte* payload, unsigned int length) {
 SerialUSB.print("Subscribe:");
 for (int i = 0; i < length; i++) SerialUSB.print((char)payload[i]);
 SerialUSB.println("");
}

void setup() {
 delay(200);
 SerialUSB.println("");
 SerialUSB.println("--- START ---------------------------------------------------");
 SerialUSB.println("### I/O Initialize.");
 Wio.Init();
 SerialUSB.println("### Power supply ON.");
 Wio.PowerSupplyLTE(true);
 delay(500);
 SerialUSB.println("### Turn on or reset.");
 if (!Wio.TurnOnOrReset()) {
   SerialUSB.println("### ERROR! ###");
   return;
 }
 SerialUSB.println("### Connecting to \""APN"\".");
 if (!Wio.Activate(APN, USERNAME, PASSWORD)) {
   SerialUSB.println("### ERROR! ###");
   return;
 }
 SerialUSB.println("### Connecting to MQTT server \""MQTT_SERVER_HOST"\"");
 MqttClient.setServer(MQTT_SERVER_HOST, MQTT_SERVER_PORT);
 MqttClient.setCallback(callback);
 MqttClient.setClient(WioClient);
 if (!MqttClient.connect(ID,MQUSER,MQPASS)) {
   SerialUSB.println("### ERROR! ###");
   return;
 }
 MqttClient.subscribe(IN_TOPIC);
 SerialUSB.println("### Setup completed.");
}

//INTERVALでUPTIME送信
void loop() {
 char data[100];
 sprintf(data, "{\"uptime\":%lu}", millis() / 1000);
 SerialUSB.print("Publish:");
 SerialUSB.print(data);
 SerialUSB.println("");
 MqttClient.publish(OUT_TOPIC, data);
err:
 unsigned long next = millis();
 while (millis() < next + INTERVAL)
 {
   MqttClient.loop();
 }
}

スケッチと確認

IoTPlatformの設定とスケッチの作成が完了したら
マイコンボード(Wio)への書き込みを実施しましょう。

ardui.JPG

実行後はArduino上のコンソールから出力結果を確認できるので、出力結果を確認してみましょう。

ツール -> シリアルモニタ

ardui2.JPG

上記の例では「soracom.io」と「AlibabaCloud」への接続がうまくできたことを表しています。

AlibabaCloudコンソールでPublishデータの確認

次にAlibabaCloudのIoT Platformの画面にて出力結果を確認してみましょう。
AlibabaCloudコンソールにログインして、IoT Platformのアイコンをクリックします。

監視と運用 -> デバイスログ -> デバイス動作分析

ステータス200で返ってきていることが確認できますね。

ar1.png

では、WioからPublishしたテキストデータも確認しましょう。
監視と運用 -> デバイスログ -> アップストリーム分析 -> MessageID

ardui4.JPG

これでWioデバイスからSoracomAirを使ってAlibabaCloudのIotPlatformとの接続を確認できました。

GPSセンサーからデータを送る

GPSセンサーで緯度経度の情報を送付してみたいと思います。

先ほどと同じ要領で下記のようなコードをスケッチします。
尚、GPSのサンプルコードもWioのボードにあるので参考にすると簡単にかけます。

#include <WioLTEforArduino.h>
#include <WioLTEClient.h>
#include <PubSubClient.h>    // https://github.com/SeeedJP/pubsubclient
#include <stdio.h>
#define APN               "soracom.io"
#define USERNAME          "sora"
#define PASSWORD          "sora"
#define MQTT_SERVER_HOST  "a63V16tah0l.iot-as-mqtt.ap-northeast-1.aliyuncs.com"
#define MQTT_SERVER_PORT  (1883)
#define ID                "sheep29|securemode=3,signmethod=hmacsha1|"
#define OUT_TOPIC         "/a63V16tah0l/devsheep/user/topicsheep"
#define MQUSER            "devsheep&a63V16tah0l"
#define MQPASS            "217629783CFE62B50ECCB2B56CAAFC4C465E7D66"
#define INTERVAL          (60000)
WioLTE Wio;
WioLTEClient WioClient(&Wio);
PubSubClient MqttClient;

String cmds[14] = {"\0"}; // for SplitFunction
String latlong; // 分割された文字列を格納する配列
void callback(char* topic, byte* payload, unsigned int length) {
  SerialUSB.print("Subscribe:");
  for (int i = 0; i < length; i++) SerialUSB.print((char)payload[i]);
  SerialUSB.println("");
}
void setup(){
  delay(5000);
  SerialUSB.println("");
  SerialUSB.println("--- START ---------------------------------------------------");
  SerialUSB.println("### I/O Initialize.");
  GpsBegin(&Serial);
  Wio.Init();
  SerialUSB.println("### Power supply ON.");
  Wio.PowerSupplyGrove(true);
  delay(500);
  SerialUSB.println("### Power supply ON.");
  Wio.PowerSupplyLTE(true);
  delay(500);
  SerialUSB.println("### Turn on or reset.");
  if (!Wio.TurnOnOrReset()) {
    SerialUSB.println("### ERROR0! ###");
    return;
  }
  SerialUSB.println("### Connecting to \""APN"\".");
  if (!Wio.Activate(APN, USERNAME, PASSWORD)) {
    SerialUSB.println("### ERROR1! ###");
    return;
  }
  SerialUSB.println("### Connecting to MQTT server \""MQTT_SERVER_HOST"\"");
  MqttClient.setServer(MQTT_SERVER_HOST, MQTT_SERVER_PORT);
  MqttClient.setCallback(callback);
  MqttClient.setClient(WioClient);
  if (!MqttClient.connect(ID,MQUSER,MQPASS)) {
    SerialUSB.println("### ERROR2! ###");
    return;
  }
  SerialUSB.println("### Setup completed.");
}
int split(String data, char delimiter, String *dst){
    //SerialUSB.println("### Step-S1");
    int index = 0;
    int arraySize = 15; //GPGGAのフィールド数指定
    int datalength = data.length();
    dst[index] = "\0";
    for (int i = 0; i < datalength; i++) {
        char tmp = data.charAt(i);
        if ( tmp == delimiter ) {
            index++;
            dst[index] = "\0";
            if ( index > (arraySize - 1)) return -1;
        }
        else dst[index] += tmp;
    }
    return (index + 1);
}
void loop()
{
  delay(5000);
  //SerialUSB.println("### Start");
  char sLat[64]="";
  char sLong[64]="";
  char sLatLong[64]=""  ;
  const char* data = GpsRead();
  //SerialUSB.println("### Step2");
  if (data != NULL && strncmp(data, "$GPGGA,", 7) == 0) {
      //for debug
      //data="$GPGGA,010841.000,3539.9084,N,13945.6998,E,1,4,1.99,165.8,M,3";
      SerialUSB.println(data);
      int index = split(data, ',', cmds);
      for(int i = 0; i < index; i++){
          if(i == 2){
               //string型のままではsprintfできないのでchar型に変換
               char x[50]="\0";
               (cmds[i].substring(0,2)+'.'+cmds[i].substring(2,4)+cmds[i].substring(6,9)).toCharArray(x, 50);
               sprintf(sLat,"\"lat\": %s",x);
          }
          if(i == 4){
               char y[50]="\0";
               (cmds[i].substring(0,3)+'.'+cmds[i].substring(3,5)+cmds[i].substring(6,10)).toCharArray(y, 50);
               sprintf(sLong,"\"long\": %s",y);
          }
      }
    sprintf(sLatLong,"{%s,%s}",sLat,sLong);
    SerialUSB.println(sLatLong);
    MqttClient.publish(OUT_TOPIC, sLatLong);
  }
}

#define GPS_OVERFLOW_STRING "OVERFLOW"
HardwareSerial* GpsSerial;
char GpsData[300];
char GpsDataLength;
void GpsBegin(HardwareSerial* serial)
{
  GpsSerial = serial;
  GpsSerial->begin(9600);
  GpsDataLength = 0;
}
const char* GpsRead()
{
  while (GpsSerial->available()) {
    char data = GpsSerial->read();
    if (data == '\r') continue;
    if (data == '\n') {
      GpsData[GpsDataLength] = '\0';
      GpsDataLength = 0;
      return GpsData;
    }
    if (GpsDataLength > sizeof (GpsData) - 1) { // Overflow
      GpsDataLength = 0;
      return GPS_OVERFLOW_STRING;
    }
    GpsData[GpsDataLength++] = data;
  }
  return NULL;
}

では、実行してみます。

i10.JPG

IoTPlatformでPublishデータの確認をしてみましょう。

スクリーンショット 2019-12-13 15.40.52.png

GPS情報が取得できましたね。
latは"latitude"の略で緯度を意味します。
longは"longitude"の略で経度を意味します。

最後に

本来であれば、このあとルールエンジンを用いてTableStoreと連携し、
DataVで可視化までしたかったのですが別記事として投稿致します!

それではご査収ください〜

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1