ESP32: MQTT を使った Lチカ

Ubuntu 24.04 上の Arduino IDE 2.3.2 を使いました。
ボードは、 ESP32 Dev Module です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/8bed17fc-9062-cb25-75bc-85a90eacaa9c.png)


## 必要なライブラリー

```text
Arduinojson
PubSubClient
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/5eaa67c1-6646-4289-3b3d-2f69c84d338d.png)


## プログラム

```text:config.h
// ---------------------------------------------------------------------
//	common/config.h
//
//					Feb/08/2023
// ---------------------------------------------------------------------
#define MQTT_SERVER_HOST  "broker.emqx.io"
#define MQTT_SERVER_PORT  1883

const char *ssid = "*****";
const char *password = "*****";

#define LED1 32
#define LED2 33
#define LED3 25
#define LED4 26
#define LED5 27
#define LED6 14
#define LED7 12
#define LED8 13

int leds[8] = {LED1,LED2,LED3,LED4,LED5,LED6,LED7,LED8};
// ---------------------------------------------------------------------
```

```text:mqtt_led.ino
// ---------------------------------------------------------------
//	mqtt_led.ino
//
//						Feb/08/2023
// ---------------------------------------------------------------
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

#include "config.h"

#define	PROGRAM	"mqtt_led.ino"
#define	VERSION	"2023-2-8 PM 14:22"

WiFiClient espClient;
PubSubClient client(espClient);

#define TOPIC "M5Stack"

int icount = 0;
// ---------------------------------------------------------------
void setupWifi()
{
	delay(10);
	Serial.printf("Connecting to %s", ssid);
	WiFi.mode( WIFI_STA);
	WiFi.begin(ssid, password);

	while (WiFi.status() != WL_CONNECTED) {
		delay(500);
		Serial.print(".");
	}
	Serial.printf("\r\nSuccess\r\n");
}

// ---------------------------------------------------------------
void msg_proc(String msg)
{
	DynamicJsonDocument doc(1024);

	deserializeJson(doc, msg);

	if ((doc.containsKey("ledno")) && (doc.containsKey("status")))
		{
		const int ledno = doc["ledno"];
		Serial.println(ledno);
		const bool status = doc["status"];
		Serial.println(status);

		if (status)
			{
			digitalWrite(leds[ledno], HIGH);
			}
		else
			{
			digitalWrite(leds[ledno], LOW);
			}
		}
	else
		{
		Serial.println("*** error *** lendo ***");
		Serial.println("*** error *** status ***");
		}
}

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

	Serial.print("Message arrived [");
	Serial.print(topic);
	Serial.print("] ");

	payload[length] = '\0';

	String msg = String((char*) payload);
	Serial.println(msg);

	msg_proc(msg);

}

// ---------------------------------------------------------------
void reConnect()
{
	while (!client.connected()) {
		Serial.print("Attempting MQTT connection...");
		String clientId = "M5Stack-";
		clientId += String(random(0xffff), HEX);
		if (client.connect(clientId.c_str())) {
			Serial.printf("\r\nSuccess\r\n");
			client.subscribe(TOPIC);
		} else {
			Serial.print("failed, rc=");
			Serial.print(client.state());
			Serial.println("try again in 5 seconds");
			delay(5000);
		}
	}
}

// ---------------------------------------------------------------
void setup()
{
	Serial.begin(115200);
	delay(3000);
	Serial.println(PROGRAM);
	Serial.println(VERSION);
	Serial.println();

	setupWifi();
	client.setServer(MQTT_SERVER_HOST, 1883);
	client.setCallback( callback);

	for (int it=0; it<8; it++)
		{
		pinMode(leds[it], OUTPUT);
		}

}

// ---------------------------------------------------------------
void loop()
{
	if (!client.connected())
		{
		reConnect();
		}

	client.loop();

	if ((icount % 100) == 0)
		{
		Serial.printf("*** loop *** %d ***\r\n",icount);
		}

//	delay(2000);	
	delay(100);

	icount++;
}

// ---------------------------------------------------------------
```

## テスト用スクリプト

```bash:go_publish.sh
#
HOST="broker.emqx.io"
TOPIC="M5Stack"
ARGS="-d -t orz  -h ${HOST} --topic ${TOPIC}"
#
mosquitto_pub $ARGS -m '{"ledno": 0,"status": true}'
sleep 2
mosquitto_pub $ARGS -m '{"ledno": 0,"status": false}'
#
mosquitto_pub $ARGS -m '{"ledno": 1,"status": true}'
sleep 2
mosquitto_pub $ARGS -m '{"ledno": 1,"status": false}'
#
mosquitto_pub $ARGS -m '{"ledno": 2,"status": true}'
sleep 2
mosquitto_pub $ARGS -m '{"ledno": 2,"status": false}'
#
mosquitto_pub $ARGS -m '{"ledno": 3,"status": true}'
sleep 2
mosquitto_pub $ARGS -m '{"ledno": 3,"status": false}'
#
mosquitto_pub $ARGS -m '{"ledno": 4,"status": true}'
sleep 2
mosquitto_pub $ARGS -m '{"ledno": 4,"status": false}'
#
mosquitto_pub $ARGS -m '{"ledno": 5,"status": true}'
sleep 2
mosquitto_pub $ARGS -m '{"ledno": 5,"status": false}'
#
mosquitto_pub $ARGS -m '{"ledno": 6,"status": true}'
sleep 2
mosquitto_pub $ARGS -m '{"ledno": 6,"status": false}'
#
mosquitto_pub $ARGS -m '{"ledno": 7,"status": true}'
sleep 2
mosquitto_pub $ARGS -m '{"ledno": 7,"status": false}'
#
```

## Python のテストプログラム

```py:publish.py
#! /usr/bin/python
#
#	publish.py
#
#						 Feb/08/2023
#
# ------------------------------------------------------------------
import sys
import json
from time import sleep
import paho.mqtt.client as mqtt

# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")

host = 'example.com'
port = 1883
topic = 'M5Stack'

client = mqtt.Client(protocol=mqtt.MQTTv311)

client.connect(host, port=port, keepalive=60)

for it in range(8):
	unit_aa = {}
	unit_aa["ledno"] = it
	unit_aa["status"] = True
#
	str_json = json.dumps(unit_aa)
	client.publish(topic, str_json)
	sleep(2.0)
#
	unit_aa["status"] = False
	str_json = json.dumps(unit_aa)
	client.publish(topic, str_json)
#
client.disconnect()

sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```

## Node.js のテストプログラム

```js:publish.js
#! /usr/local/bin/node
// ---------------------------------------------------------------
//	publish.js
//
//					Feb/08/2023
// ---------------------------------------------------------------
'use strict'

require('date-utils')

var mqtt = require('mqtt')
var count = 0


// ---------------------------------------------------------------
function publish_proc(msg)
{
	console.error("*** publish_proc ***")

	var client  = mqtt.connect('mqtt://example.com')
	const topic = 'M5Stack'
	client.on('connect', function () {
		client.publish(topic, msg)
		client.end()
		})
}

// ---------------------------------------------------------------
function counter_proc () {
	var dt = new Date()
	var formatted = dt.toFormat("HH24:MI:SS")
	console.log(count, "只今の時刻：",formatted)
	var timeoutId
	if ((count % 2) == 0)
		{
		timeoutId = setTimeout(counter_proc, 2000)
		}
	else
		{
		timeoutId = setTimeout(counter_proc, 0)
		}

	var unit_aa = {}
	unit_aa["ledno"] = Math.trunc(count / 2)
	unit_aa["status"] = (count + 1) % 2

	const json_str = JSON.stringify(unit_aa)
	publish_proc(json_str)

	count++

	if (count == 16)
		{
		clearTimeout(timeoutId)
		console.error ("*** 終了 ***")
		}
}

// ---------------------------------------------------------------
console.error ("*** 開始 ***")
counter_proc()
// ---------------------------------------------------------------
```

実行スクリプト

```bash:start.sh
export NODE_PATH=/usr/local/lib/node_modules
./publish.js
```

## Go のテストプログラム

```go:publish.go
// ---------------------------------------------------------------
//
//	publish.go
//
//					Feb/09/2023
// ---------------------------------------------------------------
package main

import (
	"os"
	"encoding/json"
	"fmt"
	"log"
	"time"

	mqtt "github.com/eclipse/paho.mqtt.golang"
)

// ---------------------------------------------------------------
func main() {
	fmt.Fprintf (os.Stderr,"*** 開始 ***\n")
	opts := mqtt.NewClientOptions()
	opts.AddBroker("tcp://example.com:1883")
	cc := mqtt.NewClient(opts)

	if token := cc.Connect(); token.Wait() && token.Error() != nil {
		log.Fatalf("Mqtt error: %s", token.Error())
	}

	for it := 0; it < 16; it++ {
		unit_aa := make (map[string]interface{})
		unit_aa["ledno"] = it / 2
		if ((it % 2) == 0) {
			unit_aa["status"] = true
		} else {
			unit_aa["status"] = false
		}
		output, _ := json.Marshal(unit_aa)

		token := cc.Publish("M5Stack", 0, false, output)
		token.Wait()
		if ((it % 2) == 0) {
			time.Sleep(time.Second * 2)
		}
	}

	cc.Disconnect(250)

	fmt.Println("Complete publish")
	fmt.Fprintf (os.Stderr,"*** 終了 ***\n")
}


// ---------------------------------------------------------------
```

実行の準備

```bash
go mod init publish
go mod tidy
```

実行コマンド

```bash
go run publish.go
```

## Ruby のテストプログラム

```rb:publish.rb
#!/usr/bin/env ruby
# --------------------------------------------------------------------- 
#	publish.rb
#
#						Feb/09/2023
# --------------------------------------------------------------------- 
require 'mqtt'
require 'json'
 
host = 'example.com'
port = 1883
topic = 'M5Stack'

STDERR.puts	"*** 開始 ***"
 
client = MQTT::Client.connect(:remote_host => host, :remote_port => port)
for it in 0..7 do
	unit_aa = {}
	unit_aa["ledno"] = it
	unit_aa["status"] = true
	json_str = JSON.generate(unit_aa)	
	client.publish(topic, json_str, retain=false)
	sleep(2)
	unit_aa["status"] = false
	json_str = JSON.generate(unit_aa)	
	client.publish(topic, json_str, retain=false)
end
#
STDERR.puts	"*** 終了 ***"
# --------------------------------------------------------------------- 
```

ライブラリーのインストール

```bash
gem install mqtt
```

実行結果

```text
$ ./publish.rb 
*** 開始 ***
*** 終了 ***
```

確認したバージョン

```text
$ ruby -v
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
```

## 参考ページ
[Go: MQTT の pub/sub](https://qiita.com/ekzemplaro/items/3016d0b8fc3f68280ae4)
[Julia: MQTT の Publish](https://qiita.com/ekzemplaro/items/b41a379ee002b34e83c8)