MachinechatのJEDIダッシュボードと仮想トグルスイッチでWiFi/MQTT対応リレーを制御

概要

このプロジェクトでは、MachinechatのJEDI Proダッシュボード上の仮想トグルスイッチコントロールによって制御されるワイヤレス電気機械式リレーを実例を挙げて説明します。ワイヤレスリレーのハードウェアは、ESP32マイクロコントローラボードとSeeedのGroveリレーで構成されています。ESP32は、Machinechat JEDI Pro上で動作するMQTTブローカのトピックをサブスクライブし、トピックの値に応じてGroveリレーの状態を変更します。サブスクライブされるMQTTトピックは、JEDI Proのダッシュボード上の仮想トグルスイッチコントロールの値です。ArduinoはESP32リレーアプリケーションの実装に使用され、JEDI ProはUbuntu Linuxが動作するSeeedのOdyssey Blue x86 Mini PCにインストールされ動作しています。

ハードウェア

  • Seeed Odyssey Blue x86 Mini PC
    クアッドコアCeleron J4105 Mini PC、128GB外付けSSD搭載

  • DFRobot Beetle ESP32C3
    Beetle ESP32-C ESP32-C3(バージョン2)トランシーバ;802.11 a/b/g/n(Wi-Fi、WiFi、 WLAN)2.4GHz評価ボード

  • Seeed Grove Relay
    電気機械式リレーGrobeプラットフォーム評価用拡張ボード

ソフトウェア

  • JEDI Pro
    IoTデータの収集、可視化、モニタリング、およびデータストレージのための適応型ソフトウェアで、IoTソリューションに組み込むことができます。
    • センサ、デバイス、およびマシンからのデータ収集
    • 直感的なリアルタイムおよび履歴データ、システムビューダッシュボードの構築
    • データ状態を自動的に監視し対応するためのルール作成
    • メールやSMSによるアラート通知の受信

         などの機能を備えています。

  • Arduino
    Arduinoは、使いやすいハードウェアとソフトウェアに基づいたオープンソースの電子機器プラットフォームです。

背景

MachinechatのJEDI Proは、HTTP、シリアル、LoRaWAN、MQTT、インターナルを含む複数のソースからデータを収集できるIoTアプリケーションソフトウェアです。収集されたデータは、JEDI上で動作するMQTTブローカを介して可視化、保存、操作、およびアクセスすることができます。JEDI MQTTトピックには、(MQTTだけでなく)あらゆるソースからJEDIに入るすべてのデータが含まれます。
バージョン3.1で、JEDIはデータダッシュボードにコントロールを追加する機能を導入しました。コントロールを使用することで、ユーザーはダッシュボードグラフィックを介して値を入力でき、その値は事前定義されたデータメトリックに保存されます。そのデータ メトリックには、JEDI で実行されているMQTTブローカ経由でアクセスできます(Machinechatの記事「Adding Controls to Data Dashboards」をご参照ください)。

実装

このプロジェクトでは、Beetle ESP32C3モジュールとGrove電気機械式リレーボードを使用してWiFi対応リレーを実装しています。ArduinoのPubSubライブラリを利用して、ESP32モジュール上にMQTTクライアントを実装しています。ESP32クライアントは、JEDI上の仮想トグルスイッチ値を取得し、スイッチ値に応じてリレーの状態(開/閉)を変更します。

image

以下の回路図と関連BOMは、Scheme-itプロジェクトのリンクBeetleESP32relayからアクセスできます。

ESP32ベースのWiFiリレーArduinoアプリケーションをセットアップ

1 - Beetle ESP32C3モジュールでArduinoをセットアップします。リンクBeetle ESP32C3 Wiki link をご参照ください。

2 - アプリケーションに必要なライブラリをインストールします。Arduinoのライブラリマネージャからこれらのライブラリを追加します。

3 - コードウォークスルー(ファイル名:BeetleESP32cMqttRelay1.ino)

WiFiネットワークに接続し、JEDI MQTTブローカに接続し、そしてJSON MQTTメッセージを解析します。

 /*
 WiFi/MQTT enabled relay example implemented on DFRobot Beetle ESP32C3
 filename: BeetleESP32cMqttRelay1.ino
 project hardware: DFRobot Beetle ESP32C3 board and Seeed Grove Relay board
 project function: ESP32 mqtt client connects to the Machinechat MQTT broker and subscribes to multiple topics (including a 
 virtual toggle switch on the JEDI data dashboard with two states "true" and "false").
 The virtual toggle switch value topic is monitored and used to control the state of the relay.


*/

#include "WiFi.h"
#include <WiFiClient.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "arduino_secrets.h" 

// Update these with values suitable for your network.
char ssid[] = SECRET_SSID;     // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)

// MQTT server info for JEDI Pro on Odyssey Ubuntu machine
const char* mqttServer = "192.168.1.23";
const int mqttPort = 1883;

StaticJsonDocument<256> doc;

int led = 10;

int data1 = 5;  //data1 of MQTT json message
int data2 = 5;  //data2 of MQTT json message
int data3 = 5;  //data3 of MQTT json message
int data4 = 5;  //data3 of MQTT json message
bool button = true;  //boolean variable of MQTT message
int msg = 0;
const char* timestamp = "dummy data";  //the is the MQTT message timestamp (this works)
String recv_payload;
const char* subtopic1 = "datacache/Button1boolean";                //test button control
const char* subtopic2 = "datacache/SeeedLoRaE5sensorTwo";  //LoRaE5 temp humidity sensor
const char* subtopic3 = "datacache/A84041F1B186136D"; //LHT65N garage temp humidity sensor

// wio terminal wifi 
// Beetle esp32c3 wifi
WiFiClient wclient;

PubSubClient client(wclient); // Setup MQTT client

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

// mqtt message callback
void callback(char* topic, byte* payload, unsigned int length) {

  //print out message topic and payload  
  Serial.print("New message from Subscribe topic: ");
  Serial.println(topic);
  Serial.print("MQTT payload length = ");
  Serial.println(length);
  Serial.print("Subscribe JSON payload: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);     // print mqtt payload
    //if payload[i] == "t"
  }
  Serial.println();

  msg = 1;  //set message flag = 1 when new subscribe message received

  
  //check subscribe topic for message received and decode    
  
  //********************************//
  //if message from topic subtopic1
  //********************************//
  if (strcmp(topic, subtopic1)== 0) {  

    Serial.print("decode payload from topic ");
    Serial.println(topic);
    deserializeJson(doc, (const byte*)payload, length);   //parse MQTT message
    button = doc["value"];    // boolean button value
    Serial.print("Button boolean value = ");
    Serial.println(button);

    //control state of relay    
    if (button == 1)
    {
      digitalWrite(led, HIGH);
      digitalWrite(6, HIGH);
      delay(100);  
    }
    else
    {
      digitalWrite(led, LOW);
      digitalWrite(6, LOW);
      delay(100);    
    }    
  }
  
  //********************************//
  //if message from topic subtopic2
  //********************************//
  if (strcmp(topic, subtopic2)== 0) { 
    Serial.print("decode payload from topic ");
    Serial.println(topic);
    deserializeJson(doc, (const byte*)payload, length);   //parse MQTT message
    data1 = doc["temperature"];    

    data2 = doc["humidity"];    // 
    
    Serial.print("data1 is LoRaE5 temperature = ");
    Serial.println(data1);
    Serial.print("data2 is LoRaE5 humidity = ");
    Serial.println(data2);     
  }
    
  //********************************//
  //if message from topic subtopic3
  //********************************//
  if (strcmp(topic, subtopic3)== 0) {   
 
    Serial.print("decode payload from topic ");
    Serial.println(topic);
    deserializeJson(doc, (const byte*)payload, length);   //parse MQTT message
    data3 = doc["TempF"];
    data4 = doc["Hum_SHT"];
    Serial.print("data3 = TempF = ");
    Serial.println(data3);
    Serial.print("data4 = Hum_SHT = ");
    Serial.println(data4);
  }
}

//connect to mqtt broker on JEDI One and subscribe to topics
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a unique client ID using the Wio Terminal MAC address
    String MACadd = WiFi.macAddress();
    MACadd = "WioTerminal" + MACadd;  
    String clientID = MACadd;

    // Attempt to connect
    if (client.connect(clientID.c_str())) {
      Serial.println("connected");
      // set up MQTT topic subscription     note: topic needs to be "datacache/" + Device on JEDI One 
      Serial.println("subscribing to topics:");
      Serial.println(subtopic1);        
      client.subscribe(subtopic1);        
      Serial.println(subtopic2);
      client.subscribe(subtopic2); 
      Serial.println(subtopic3);
      client.subscribe(subtopic3); 
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  pinMode(led,OUTPUT);
  //pinMode(7, INPUT);   //switch input
  pinMode(6, OUTPUT);   //relay control input 
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqttServer, 1883);  //set mqtt server
  client.setCallback(callback);
}

メインループは、接続されているかどうかをチェックし、MQTTメッセージをチェックし、そしてGrove Relayボードの状態を更新します。

void loop() {
  
   // try reconnecting to WiFi if not connected   
  if (WiFi.status() != WL_CONNECTED) {
        Serial.println("not connected to WiFi, try reconnecting");
        WiFi.disconnect();
        delay(5000);
        setup_wifi();
      }
 
  // check if connected to mqtt broker
  if (!client.connected()) {
    reconnect();
  }
  if (msg == 1) {                         // check if new callback message
    
    msg = 0;      // reset message flag
  }
  Serial.println("debug - in main loop");

  delay(1000);

  client.loop();

}

4 - MQTTトピックをサブスクライブした場合のArduinoコードからのシリアルモニタ出力例

デバッグ時やコード変更時に役立つように、サンプルArduinoコードにはいくつかのPrintステートメントが挿入されています。サブスクライブされているトピックを受信したときのシリアルモニタ出力の例を以下に示します。

5 - BeetleESP32cMqttRelay1.inoアプリケーションの最新のソースコードは、以下のリンクのgithubにあります。

JEDI Proのインストール

Machinechat JEDIがまだインストールされていない場合は、以下を参照してください。

Getting Started with machinechat’s JEDI One IoT Platform

JEDI MQTTブローカ - トピックのサブスクライブ

JEDIトピックには、あらゆるソースからJEDI Oneに送られてくるすべてのデータが含まれます。MQTTクライアントコードまたはアプリケーション内から、以下のようにトピックをサブスクライブします。

特定のデータストリームの場合:

datacache/TargetID

ここで、datacacheはJEDI Oneの固定の最上位トピックであり、 TargetIDは対象のデータ ストリームのTargetIDまたはIPアドレスです。

このプロジェクトの例では、
datastreamはdatacache/Button1booleanになります。
mqttServerは192.168.1.23です。
mqttポートは1883です。

(注:詳細については、Machinechatの記事「Adding Controls to Data Dashboards 」をご参照ください。)

JEDI Proのセットアップ

1 - Controlを作成する際、Controlからの値を保持するデータメトリックを作成する必要があります。JEDIの左側にあるナビゲーションパネルからDevice Dashboardを選択します。

2 - Data Sourceを追加します。

3 - JEDIダッシュボードにControlを追加します。

4 - JEDIダッシュボードに仮想トグルスイッチを追加します。

5 - JEDIバーチャルトグルスイッチのControl例です。

まとめ

柔軟で高性能なWiFi対応電気機械式リレーは、DFRobotのBeetleESP32モジュールとGrove Relayボードの2つの小型開発ボードで簡単に実装できます。WiFiリレーの仮想トグルスイッチコントロールは、JEDIデータダッシュボードのコントロール機能とJEDIのMQTTブローカを使用して実装されています。ESP32上で動作するMQTTクライアントは、JEDIデータダッシュボード上の仮想トグルスイッチコントロールによってWiFiリレーのMQTT制御を提供します。MachinechatのJEDI IoTデータ管理は、収集中のあらゆるデータへのMQTTアクセスを提供するだけでなく、必要に応じて追加処理、アラート、その他のアクションも提供します。

参考資料




オリジナル・ソース(English)