/*
note: need add library Adafruit_BMP280 from library manage
Github: https://github.com/adafruit/Adafruit_BMP280_Library
*/
#include <M5StickC.h>
#include "DHT12.h"
#include <Wire.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include <ArduinoJson.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
// PubSubClient.h 実ファイルのMQTT_MAX_PACKET_SIZEを1024等に設定する必要があります
// https://github.com/knolleary/pubsubclient
// Wifi Settings
const char* ssid = "[ご自身の環境のWifiSSID]";
const char* password = "[ご自身の環境のWifiPassowrd]";
// AWS IoT Settings
const char* endpoint = "[ご自身のAWSアカウントのIoTエンドポイント]"; // 東京リージョンなら右記のような形 xxxx-ats.iot.ap-northeast-1.amazonaws.com
const int port = 8883;
const char* pubTopic = "[適当なTopic名 - 記事中では envTopic としていました]";
const char* clientId = "[適当なデバイス名 - 記事中では M5Stick01 としていました]"; //
char pubTopicShadow[128];
char subTopicShadow[128];
#define QOS_SUB 0
const char* rootCA = \
"-----BEGIN CERTIFICATE-----\n" \
"...\n" \ // [ご自身で取得したRootCA]
"-----END CERTIFICATE-----\n";
const char* clientCert = \
"-----BEGIN CERTIFICATE-----\n" \
"...\n" \ // [上記CLIコマンドで生成したデバイス用証明書]
"-----END CERTIFICATE-----\n";
const char* clientPrivateKey = \
"-----BEGIN RSA PRIVATE KEY-----\n" \
"...\n" \ // [上記CLIコマンドで生成したデバイス用秘密鍵]
"-----END RSA PRIVATE KEY-----\n";
// Wifi/Network
WiFiClientSecure httpsClient;
PubSubClient mqttClient(httpsClient);
char buffer[1024];
// Timer interrupts
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
volatile int interruptCounter;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
// LED_PIN
#define M5_STICK_PIN_LED 10
boolean ledState = true; // HIGH: LED Off/Low: LED On
// ENV HAT
DHT12 dht12;
Adafruit_BMP280 bme;
void checkWiring() {
while (!bme.begin(0x76)) {
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(0, 0, 2);
M5.Lcd.println("Could not find a valid BMP280 sensor, check wiring!");
delay(1000);
}
}
void reconnect() {
while (!mqttClient.connected()) {
if (mqttClient.connect(clientId)) {
M5.Lcd.setCursor(0, 40, 2);
M5.Lcd.println("AWSIoTConnected");
mqttClient.subscribe(subTopicShadow, QOS_SUB);
} else {
M5.Lcd.setCursor(0, 40, 2);
M5.Lcd.printf("AWSIoTConnect Failed. state=%d", mqttClient.state());
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
// JSON Parse
payload[length] = '\0';
String json = String((char*) payload);
// Debug JSON in SerialConsole
Serial.println(json);
StaticJsonDocument<1024> docShadowDesired;
DeserializationError error = deserializeJson(docShadowDesired, json);
M5.Lcd.setCursor(0, 60, 2);
if (error) {
M5.Lcd.printf("deserializeJson Failed");
} else {
if (sizeof(docShadowDesired["state"]["led_status"]) > 0) {
M5.Lcd.printf("Desired: %d", int(docShadowDesired["state"]["led_status"]));
ledState = !boolean(docShadowDesired["state"]["led_status"]);
digitalWrite(M5_STICK_PIN_LED, ledState);
} else {
M5.Lcd.printf("Desired: corrupted value");
}
}
}
void setup() {
// put your setup code here, to run once:
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
// Timer
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 5000000, true);
timerAlarmEnable(timer);
// I2C
Wire.begin(0,26);
// GPIOSetup
pinMode(M5_STICK_PIN_LED, OUTPUT);
digitalWrite(M5_STICK_PIN_LED, ledState);
// check ENVHat
checkWiring();
// WifiSetup
//// Avoid Connect Error (JIC)
WiFi.disconnect(true);
delay(1000);
//// Connect
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
M5.Lcd.setCursor(0, 40, 2);
M5.Lcd.printf("Wifi Connected");
// Configure MQTT Client
httpsClient.setCACert(rootCA);
httpsClient.setCertificate(clientCert);
httpsClient.setPrivateKey(clientPrivateKey);
mqttClient.setServer(endpoint, port);
mqttClient.setCallback(mqttCallback);
// pubTopic/subTopic
sprintf(pubTopicShadow, "$aws/things/%s/shadow/update", clientId);
sprintf(subTopicShadow, "$aws/things/%s/shadow/update/delta", clientId);
// Debug topic name in SerialConsole
Serial.printf("pubTopicShadow=%s\n", pubTopicShadow);
Serial.printf("subTopicShadow=%s\n", subTopicShadow);
}
void loop() {
// update button state
M5.update();
// Button Pressed
if (M5.BtnA.wasReleased()) {
// turnOn/Off LED
ledState = !ledState;
digitalWrite(M5_STICK_PIN_LED, ledState);
}
// check ENVHat
checkWiring();
// reconnect
if (!mqttClient.connected()) {
reconnect();
}
mqttClient.loop();
// Timer Interrupt execute Every 5sec
if (interruptCounter > 0) {
Serial.println("Timer interrupted");
// CounterReset
portENTER_CRITICAL(&timerMux);
interruptCounter--;
portEXIT_CRITICAL(&timerMux);
// display Temp/Humidity/Pressure
float tmp = dht12.readTemperature();
float hum = dht12.readHumidity();
M5.Lcd.setCursor(0, 0, 2);
M5.Lcd.printf("Temp: %2.1f Humi: %2.0f%%", tmp, hum);
float pressure = bme.readPressure();
M5.Lcd.setCursor(0, 20, 2);
M5.Lcd.printf("pressure: %2.1f", pressure);
// create JSON
DynamicJsonDocument docEnv(1024);
JsonObject data = docEnv.createNestedObject("env");
data["temperture"] = tmp;
data["humidity"] = hum;
data["pressure"] = pressure;
serializeJson(docEnv, buffer, sizeof(buffer));
// Debug JSON in SerialConsole
Serial.println(buffer);
// Publish - The client only supports publishing at QoS 0
mqttClient.publish(pubTopic, buffer);
// report current LED status to ShadowTopic
// create JSON
DynamicJsonDocument docShadowReport(1024);
JsonObject state = docShadowReport.createNestedObject("state");
JsonObject reported = state.createNestedObject("reported");
reported["led_status"] = int(!ledState);
serializeJson(docShadowReport, buffer, sizeof(buffer));
// Debug JSON in SerialConsole
Serial.println(buffer);
// Publish - The client only supports publishing at QoS 0
mqttClient.publish(pubTopicShadow, buffer);
}
// wait
delay(500);
}