LoginSignup
6
0

More than 1 year has passed since last update.

東京から大阪にあるSpresenseを制御しよう! by MQTT via LTE

Posted at

初めに

MQTTの勉強とLTE使ってM2Mっぽいものを見せてくれよというリクエストから、Spresense のM2MをLTE経由でMQTTpub/subを使ってやってみようと作ってみました。このコードではM2Mって感じじゃないのですがベースのプログラムとして使えるかな~と思って言います。

具体的には、例えば、東京側にあるSpresenseKeypadで、1~4の数字を入力すると、それに合わせて大阪にあるSpresenseLED0~3が点灯するというものです。
※東京、大阪はイメージです。

Keypadも使うので、今回は、ArduinoIDEを使って実現しようとしました。
実は、これだと動きがもっさりしています。これを解消する記事は、別途書こうと思っていますが、それほど反応速度がいらないようなものには、非常に簡単にできるのでまずはここまでということで。

用意したもの

SPRESENSEメインボード[CXD5602PWBMAIN1]
https://www.switch-science.com/catalog/3900/

SPRESENSE LTE拡張ボード [CXD5602PWBLM1J]
https://www.switch-science.com/catalog/5999/

IIJmioプリペイドパック
https://s.iijmio.jp/prepaid/

と、Mainボード、LTE、SIMをすべて2セットづつ。

それに、Qwiicのコネクタとキーパッド。
SPRESENSE用Qwiic接続基板
https://www.switch-science.com/catalog/6318/

Qwiic - キーパッド(12ボタン)
https://www.switch-science.com/catalog/5535/

そうです。使いまわしです。苦笑い…。

ブログ(元ネタ)

この記事は、以下のブログに過去に投稿したもののまとめです。

LTEボードとMQTTを使ってM2Mを体感する その1
http://spresense.livedoor.blog/archives/28134913.html

LTEボードとMQTTを使ってM2Mを体感する その2
http://spresense.livedoor.blog/archives/28174660.html

サンプルプログラム

Spresense ArduinoIDELTE のサンプルの中に、MQTT で通信するサンプルがあります。

5.6. AWSサーバにGNSS位置情報をPublishする
https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_aws%E3%82%B5%E3%83%BC%E3%83%90%E3%81%ABgnss%E4%BD%8D%E7%BD%AE%E6%83%85%E5%A0%B1%E3%82%92publish%E3%81%99%E3%82%8B

これを見ることで、LTE を使った MQTT通信 のサンプルが作れます。

LTEを使う共通部分

LTEを使う上での共通定義部分は以下になります。

#include <LTE.h>
#include <ArduinoMqttClient.h>

// APN name
#define APP_LTE_APN "iijmio.jp" // replace your APN

/* APN authentication settings
 * Ignore these parameters when setting LTE_NET_AUTHTYPE_NONE.
 */
#define APP_LTE_USER_NAME "mio@iij"     // replace with your username
#define APP_LTE_PASSWORD  "iij" // replace with your password

// APN IP type
#define APP_LTE_IP_TYPE (LTE_NET_IPTYPE_V4V6) // IP : IPv4v6

// APN authentication type
#define APP_LTE_AUTH_TYPE (LTE_NET_AUTHTYPE_CHAP) // Authentication : CHAP

/* RAT to use
 * Refer to the cellular carriers information
 * to find out which RAT your SIM supports.
 * The RAT set on the modem can be checked with LTEModemVerification::getRAT().
 */

#define APP_LTE_RAT (LTE_NET_RAT_CATM) // RAT : LTE-M (LTE Cat-M1)

LTE lteAccess;
LTEClient client;

当然ですが、IIJ MIO 用のサンプルです。
異なる SIM を使う人は変更してください。

また、サンプルコードにある doAttach() は、そのまま使えるので使います。

void doAttach()
{
  while (true) {

    /* Power on the modem and Enable the radio function. */

    if (lteAccess.begin() != LTE_SEARCHING) {
      Serial.println("Could not transition to LTE_SEARCHING.");
      Serial.println("Please check the status of the LTE board.");
      for (;;) {
        sleep(1);
      }
    }

    /* The connection process to the APN will start.
     * If the synchronous parameter is false,
     * the return value will be returned when the connection process is started.
     */
    if (lteAccess.attach(APP_LTE_RAT,
                         APP_LTE_APN,
                         APP_LTE_USER_NAME,
                         APP_LTE_PASSWORD,
                         APP_LTE_AUTH_TYPE,
                         APP_LTE_IP_TYPE,
                         false) == LTE_CONNECTING) {
      Serial.println("Attempting to connect to network.");
      break;
    }

    /* If the following logs occur frequently, one of the following might be a cause:
     * - APN settings are incorrect
     * - SIM is not inserted correctly
     * - If you have specified LTE_NET_RAT_NBIOT for APP_LTE_RAT,
     *   your LTE board may not support it.
     */
    Serial.println("An error has occurred. Shutdown and retry the network attach preparation process after 1 second.");
    lteAccess.shutdown();
    sleep(1);
  }
}

MQTT通信を使う共通部分

MQTTで通信する上での共通定義部分は以下になります。
今回は、コードの単純化と応答速度を鑑みて、特に認証もセキュア通信もしませんでした。


// MQTT broker
#define BROKER_NAME "test.mosquitto.org"
#define BROKER_PORT 1883

// MQTT topic
#define MQTT_TOPIC "spresense/mqtt"

MqttClient mqttClient(client);

char broker[] = BROKER_NAME;
int port = BROKER_PORT;
char topic[]  = MQTT_TOPIC;

で、ここにMQTTの クライアントID が必要です。
これは、punlisher/subscriberごとに代わるので、publisher側は、

m2m_pub.ino

// MQTT ID
#define MQTT_ID "spresense_pub"

と定義し、subscriber側は、

m2m_sub.ino

// MQTT ID
#define MQTT_ID "spresense_sub"

と定義します。

また、今回は Broker には、mosquitoの公開サーバ を使いました。

mosquitoはこちら。

今回は、この辺の説明は飛ばします。

これで、LTE経由でのMQTT通信の準備ができました。

Publisher側のコード

Publisher側は、Keypadをつかうので、includeとインスタンス定義に以下を追加します。

m2m_pub.ino
#include <Wire.h>
#include "SparkFun_Qwiic_Keypad_Arduino_Library.h"

KEYPAD keypad1; //Create instance of this object

setup() は以下になります。

m2m_pub.ino
void setup()
{
  // Open serial communications and wait for port to open
  Serial.begin(115200);
  while (!Serial) {
      ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("Starting .");

  if (keypad1.begin() == false)  {
    Serial.println("Keypad does not appear to be connected. Please check wiring. Freezing...");
    while (1);
  }
  Serial.println(keypad1.getVersion());

  /* Connect LTE network */
  doAttach();

  // Wait for the modem to connect to the LTE network.
  Serial.println("Waiting for successful attach.");
  LTEModemStatus modemStatus = lteAccess.getStatus();

  while(LTE_READY != modemStatus) {
    if (LTE_ERROR == modemStatus) {

      Serial.println("An error has occurred. Shutdown and retry the network attach process after 1 second.");
      lteAccess.shutdown();
      sleep(1);
      doAttach();
    }
    sleep(1);
    modemStatus = lteAccess.getStatus();
  }

  Serial.println("attach succeeded.");

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  mqttClient.setId(MQTT_ID);

  while (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());
    sleep(1);
  }

  Serial.println("You're connected to the MQTT broker!");

  ledOn(LED0);
  ledOn(LED1);
  ledOn(LED2);
  ledOn(LED3);
}

データを送りユーティリティー関数として、sendData を用意します。

m2m_pub.ino

void sendData(String testString)
{
    mqttClient.beginMessage(topic);
    mqttClient.print(testString);
    mqttClient.endMessage();
}

これで、MQTTpublish ができるようになったので、loop() の中で、keypad の1から4の入力を検出して、それに合わせた 数字MQTT で送るようにします。

m2m_pub.ino
void loop()
{
  keypad1.updateFIFO();  // necessary for keypad to pull button from stack to readable register
  char button = keypad1.getButton();

  if (button > 0) {
     switch (button) {
        case '1':
          sendData(String(1));
          break;
        case '2':
          sendData(String(2));
          break;
        case '3':
          sendData(String(3));
          break;
        case '4':
          sendData(String(4));
          break;

        default:
          break;
      }
    }
}

これで、keypad の入力の数字に合わせて数字を送ることができました。

Subscriber側のコード

Publisher側は、受け取った文字に合わせてLEDをつけるだけなので、特に追加のincludeとインスタンス定義はありません。

setup() は以下になります。

m2m_sub.ino
void setup()
{ // Open serial communications and wait for port to open
  Serial.begin(115200);
  while (!Serial) {
      ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("Starting .");

  /* Connect LTE network */
  doAttach();

  // Wait for the modem to connect to the LTE network.
  Serial.println("Waiting for successful attach.");
  LTEModemStatus modemStatus = lteAccess.getStatus();

  while(LTE_READY != modemStatus) {
    if (LTE_ERROR == modemStatus) {

      Serial.println("An error has occurred. Shutdown and retry the network attach process after 1 second.");
      lteAccess.shutdown();
      sleep(1);
      doAttach();
    }

  Serial.println("attach succeeded.");

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  mqttClient.setId(MQTT_ID);

  while (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());
    sleep(1);
  }

  mqttClient.subscribe(topic);

  Serial.println("You're connected to the MQTT broker!");
}

これで、MQTTsubscribe ができるようになったので、loop() の中で、受け取った文字に合わせて LED を点灯するようにします。

m2m_sub.ino
void loop()
{
  int messageSize = mqttClient.parseMessage();
  if (messageSize) {
    while (mqttClient.available()) {
     switch (mqttClient.read()) {
        case '1':
          ledOn(LED0);
          ledOff(LED1);
          ledOff(LED2);
          ledOff(LED3);
          break;
        case '2':
          ledOff(LED0);
          ledOn(LED1);
          ledOff(LED2);
          ledOff(LED3);
          break;
        case '3':
          ledOff(LED0);
          ledOff(LED1);
          ledOn(LED2);
          ledOff(LED3);
          break;
        case '4':
          ledOff(LED0);
          ledOff(LED1);
          ledOff(LED2);
          ledOn(LED3);
          break;

        default:
          break;
      }
    }
    Serial.println();
  }
}

これで リモート にある Spresenseキーパッド 入力に合わせて LEDを点灯させることができました。

動作結果

動かすとこんな感じになります。

冒頭にも書いたとおり、かなり動きがもっさりしますが、これは、Arduino の MQTTライブラリでsubscribe することが原因のようです。SDKで動かせば早くなります。

機会 があればこちらも書きま~す。

6
0
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
6
0