LoginSignup
6
9

More than 5 years have passed since last update.

ESP8266 からAWSへMQTT を投げる

Last updated at Posted at 2018-04-30

こちらの記事の続きです。ESP8266 からAWSへMQTT を投げるプログラムです。このプログラムを参考にさせていただきました。ちゃんと解説するにはよくわかっていないところ多々なのですが、このままで動作することを確認しています。

ヘッダー

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>

//Wifi connection
ESP8266WiFiMulti WiFiMulti;
#define MAXTRY    100

//AWS
#include "sha256.h"
#include "Utils.h"

//WEBSockets
#include <Hash.h>
#include <WebSocketsClient.h>

//MQTT PAHO
#include <SPI.h>
#include <IPStack.h>
#include <Countdown.h>
#include <MQTTClient.h>

//AWS MQTT Websocket
#include "Client.h"
#include "AWSWebSocketClient.h"
#include "CircularByteBuffer.h"

//MQTT config
const int maxMQTTpackageSize = 512;
const int maxMQTTMessageHandlers = 1;

AWSWebSocketClient awsWSclient(1000);
IPStack ipstack(awsWSclient);
MQTT::Client<IPStack, Countdown, maxMQTTpackageSize, maxMQTTMessageHandlers> *client = NULL;

AWS IoT Configuration

AWS IoTのConfiguration を記載します。

//AWS IOT config, change these:
char aws_endpoint[]    = "abcdefghijklmg.iot.us-west-2.amazonaws.com";    //your-endpoint.iot.eu-west-1.amazonaws.com";
char aws_key[]         = "AXXXXXXXXXXXXXXXXXXQ";                          //"your-iam-key";
char aws_secret[]      = "9dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxTQ";      //"your-iam-secret-key";
char aws_region[]      = "us-west-2";                                     //eu-west-1";
const char* aws_topic  = "TOPIC/VALUE";                                  //"$aws/things/your-device/shadow/update";

setup()関数

setup()関数では、
1. Wifi を接続する。
2. websocket と mqtt レイヤーを接続する connect() 関数を呼ぶ
3. 接続がOKならば、subscribe() 関数でメッセージのサブスクライバー(購読者)であることを宣言します。

void setup() {
    Serial.begin(9600);
    Serial.println ("connecting to wifi");
    WiFiMulti.addAP("SSID", "PASSWORD");    // put your setup code here, to run once:
    int iwait=0;
    while(WiFiMulti.run() != WL_CONNECTED) {    //wait for connection
        delay(100);
        Serial.print (".");
        iwait++;
        if(iwait>=MAXTRY){ 
            Serial.println ("\wifi nconnect error");    //connect NG
            break;
        }
    }
    if(WiFiMulti.run() == WL_CONNECTED){            //connect OK
        Serial.println ("\nwifi connected");
        //Fill AWS parameters    
        awsWSclient.setAWSRegion(aws_region);
        awsWSclient.setAWSDomain(aws_endpoint);
        awsWSclient.setAWSKeyID(aws_key);
        awsWSclient.setAWSSecretKey(aws_secret);
        awsWSclient.setUseSSL(true);
        if (connect ()){
            subscribe ();
        }
    }
}

connect()関数

connect()関数では
1. MQTT Client をCreate する。
2. websocket layerを接続する。
3. mqtt layerを接続する。

//----------------------------------------------------------------
//# of connections
long connection = 0;
int port = 443;

//----------------------------------------------------------------
//connects to websocket layer and mqtt layer
bool connect () {
    // create MQTT client
    if (client == NULL) {
        client = new MQTT::Client<IPStack, Countdown, maxMQTTpackageSize, maxMQTTMessageHandlers>(ipstack);
    } else {
        if (client->isConnected ()) {    
            client->disconnect ();
        }  
        delete client;
        client = new MQTT::Client<IPStack, Countdown, maxMQTTpackageSize, maxMQTTMessageHandlers>(ipstack);
    }

    // delay is not necessary... it just help us to get a "trustful" heap space value
    delay (1000);
    // debug print
    Serial.print (millis ());
    Serial.print (" - conn: ");
    Serial.print (++connection);
    Serial.print (" - (");
    Serial.print (ESP.getFreeHeap ());
    Serial.println (")");

    // connects to websocket layer
    int rc = ipstack.connect(aws_endpoint, port);
    if (rc != 1)
    {
        Serial.println("error connection to the websocket server");
        return false;
    } else {
        Serial.println("websocket layer connected");
    }

    //connects to mqtt layer
    Serial.println("MQTT connecting");
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.MQTTVersion = 3;
    char* clientID = generateClientID ();
    data.clientID.cstring = clientID;
    rc = client->connect(data);
    delete[] clientID;

    if (rc != 0)
    {
        Serial.print("error connection to MQTT server");
        Serial.println(rc);
        return false;
    }
    // sucsess connection to mqtt
    Serial.println("MQTT connected");
    return true;
}

subscribe ()関数

ひとつのTOPIC の購読者であることを宣言します。

//----------------------------------------------------------------
// subscribe to a mqtt topic
void subscribe () {
   // subscript to a topic
   // messageArrived is a callback function when MQTT message received
    int rc = client->subscribe(aws_topic, MQTT::QOS0, messageArrived);
    if (rc != 0) {
        Serial.print("rc from MQTT subscribe is ");
        Serial.println(rc);
        return;
    }
    Serial.println("MQTT subscribed");
}

generateClientID()関数

Client ID をランダム関数から作成します。

//----------------------------------------------------------------
// generate random mqtt clientID
char* generateClientID () {
    char* cID = new char[23]();
    for (int i=0; i<22; i+=1)
        cID[i]=(char)random(1, 256);
    return cID;
}

メッセージ受信

メッセージを受け取るコールバック関数です。受け取ったメッセージをプリントしています。

//----------------------------------------------------------------
// count messages arrived
int arrivedcount = 0;

//----------------------------------------------------------------
//callback to handle mqtt messages
void messageArrived(MQTT::MessageData& md)
{
    MQTT::Message &message = md.message;

    Serial.print("Message ");
    Serial.print(++arrivedcount);
    Serial.print(" arrived: qos ");
    Serial.print(message.qos);
    Serial.print(", retained ");
    Serial.print(message.retained);
    Serial.print(", dup ");
    Serial.print(message.dup);
    Serial.print(", packetid ");
    Serial.println(message.id);
    Serial.print("Payload ");
    char* msg = new char[message.payloadlen+1]();
    memcpy (msg,message.payload,message.payloadlen);
    Serial.println(msg);
    delete msg;
}

メッセージ送信

メッセージの送信を行います。この送信方法ではJSON形式ではありません。

//----------------------------------------------------------------
//send a message to a mqtt topic
void sendmessageNumber (int num) {
    //send a message
    MQTT::Message message;
    String strbun;
    String snum = String(num);
    const char *buf;

    strbun="{\"Temporather\":\"";
    strbun+=snum;
    strbun+="\"}";
    buf = strbun.c_str();   
    Serial.println (buf);   // kakitest

    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf)+1;
    int rc = client->publish(aws_topic, message); 
}

ループ関数

awsWSclient.connected ()をチェックしてclient->yield()を呼ぶ、この行が無いとメッセージを受け取れません。sendmessageNumber(int num)で値を送信します。

//----------------------------------------------------------------
int msend_count=16;
void loop()
{
  //keep the mqtt up and running
    if (awsWSclient.connected ()) {    
        client->yield();
    } else {
    //handle reconnection
        if (connect ()){
            subscribe ();      
        }
    }
    if(!(msend_count--)){
        sendmessageNumber(1234);
        msend_count=16;
    }
}
6
9
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
9