こちらの記事の続きです。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()関数では、
- Wifi を接続する。
- websocket と mqtt レイヤーを接続する connect() 関数を呼ぶ
- 接続が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()関数では
- MQTT Client をCreate する。
- websocket layerを接続する。
- 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;
}
}