## 參考文獻
[Node-Red Publish MQTT Server](https://hackmd.io/@HugoPeng/Sk6tsnp9A)
## 系統架構

## Wifi 環境確認
獲取Windows Wifi Slave IPv4位置

## Node-Red 架設

### broker server
設定 MQTT Server PC IPv4位置,PORT設為1883。

### mqtt in
* Humedity,Topic(主題)為ESP32發佈的識別名。

* Temperature,Topic(主題)為ESP32發佈的識別名。

### mqtt out
* LED Output,Topic(主題)為ESP32訂閱的識別名。

### dashboard group
* 如此專案未使用過,則新建新的group。Name 使用 Default。

### dashboard tab
* 如此專案未使用過,tab。Name 使用 Home。

### switch
On Payload 為 ESP32 接收的資料型態及資料。

### gauge
* Temperature,Range為UI要顯示的資料範圍。

* Humedity,Range為UI要顯示的資料範圍。

## ESP32程式說明
### Add PubSubClient Libary
```
[platformio]
src_dir = ./
[env:esp32-s3-devkitc-1]
platform = espressif32 @ 6.5.0
board = esp32-s3-devkitc-1
framework = arduino
board_build.filesystem = littlefs
build_flags =
-O0
-I board
-I lib
-I driver
-I sensor_module
-I canopen/CanFestival
-I canopen
-I app
-DCORE_DEBUG_LEVEL=3
-DARDUINO_USB_CDC_ON_BOOT=1
lib_deps =
pierremolinaro/ACAN_ESP32@^1.1.2
khoih-prog/ESP32TimerInterrupt@^2.3.0
ivanseidel/LinkedList@0.0.0-alpha+sha.dac3874d28
bakercp/CRC32@^2.0.0
tkjelectronics/Kalman Filter Library@^1.0.2
denyssene/SimpleKalmanFilter@^0.1.0
michalmonday/CSV Parser@^1.4.1
knolleary/PubSubClient@^2.8
monitor_speed = 921600
monitor_port = COM10
upload_speed = 10000000
upload_port = COM10
debug_tool = esp-builtin
debug_init_break = break setup
build_type = debug
board_build.mcu = esp32s3
board_build.f_cpu = 240000000L
```
### 範例程式
```
#include <Arduino.h>
#include <PubSubClient.h>
#include <LittleFS.h>
#include <esp_task_wdt.h>
#include "g_sensor.h"
#include "console.h"
#include "env_server.h"
#include "canopen.h"
#include "canopen_io.h"
#include "reg.h"
#include "usb_cdc.h"
#include "env_server.h"
#include "debug.h"
#include "private_protocal.h"
#include "hard_switching.h"
#include "hard_output.h"
#include "led.h"
const char *mqtt_server = "192.168.0.111";
WiFiClient espClient;
PubSubClient client(espClient);
void MonitorTask(void)
{
// TaskHandle_t task_hankle;
// TaskStatus_t task_status;
// task_hankle = xTaskGetHandle("GSEN_GetImuFifoTask");
// vTaskGetInfo()
}
#define SAMPLE_FREQ 1000
void callback(char *topic, byte *message, unsigned int length)
{
String messageTemp;
for (int i = 0; i < length; i++)
{
Serial.print((char)message[i]);
messageTemp += (char)message[i]; // 將接收訊息拷貝至messageTemp
}
DB_LOG(DLL_INFO, "message arrived, topic: %s, message = %s", topic, messageTemp);
// 若主題是esp32/output,則判斷訊息內容,若為”on”,則開啟LED燈,若為”on”,則關閉LED燈
if (String(topic) == "esp32/output")
{
if (messageTemp == "on")
{
DB_LOG(DLL_INFO, "on");
LED_SetLed(BL_RED, HIGH);
}
else if (messageTemp == "off")
{
DB_LOG(DLL_INFO, "off");
LED_SetLed(BL_RED, LOW);
}
}
}
// 重新連線MQTT伺服器函式
void reconnect()
{
// Loop until we're reconnected
while (!client.connected())
{
DB_LOG(DLL_INFO, "connecting…");
// 重新連接MQTT伺服器
if (client.connect("ESP32Client"))
{
DB_LOG(DLL_INFO, "connected");
// 訂閱esp32/output主題
client.subscribe("esp32/output");
}
else
{
DB_LOG(DLL_INFO, "connect failed, status code: %s", client.state());
DB_LOG(DLL_INFO, "connect again in 5 seconds...");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup()
{
esp_task_wdt_init(5000, TRUE);
delay(3000);
// xTaskCreateUniversal((TaskFunction_t)MonitorTask, "MonitorTask", 10240, NULL, osPriorityLow7, NULL, tskNO_AFFINITY);
HS_Init();
HO_Init();
LED_Init();
g_UsbCdcHandle.Init();
g_WiFiServerHandle.Init();
g_DebugHandle.Init();
g_PrivatePtotocalHandle.Init();
g_CanOpenHandle.Init();
g_ConsoleHandle.Init();
g_EnvRegHandle.Init();
g_G_Sensor.Init();
g_EnvIoHandle.Init();
// if (BIT_TEST(HS_GetHWId(), BF_CANOPEN_EN) == FALSE)
// {
// g_EnvRegHandle.WriteReg(REG_VAL(EFA_GSensor, EGA_DETECT_MODE), 1);
// g_EnvRegHandle.WriteReg(REG_VAL(EFA_GSensor, EGA_RUN), 1);
// }
DB_LOG(DLL_INFO, "InitFinish");
espClient.setTimeout(5000);
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop()
{
byte temperature = HS_GetRotarySW1Id();
byte humidity = HS_GetRotarySW2Id();
// 若MQTT斷線,則重新連接
if (!client.connected())
{
reconnect();
}
client.loop();
// 將溫度轉換成字串,並發佈溫度訊息
char tempString[8];
dtostrf((double)temperature, 1, 2, tempString);
DB_LOG(DLL_INFO, "Temperature: %s", tempString);
client.publish("esp32/temperature", tempString);
// 將濕度轉換成字串,並發佈濕度訊息
char humString[8];
dtostrf((double)humidity, 1, 2, humString);
DB_LOG(DLL_INFO, "Humidity: %s", humString);
client.publish("esp32/humidity", humString);
delay(10); // 每隔10ms重新執行loop函式
}
```
## Node-Red UI 測試
典籍進入Node-Red UI
http://127.0.0.1:1880/ui
