From 18ba7a39d7401a07cd39b30e90dbe637cc8122e7 Mon Sep 17 00:00:00 2001 From: Yuichiro Aoki <45054071+yuichiroaoki@users.noreply.github.com> Date: Tue, 31 Oct 2023 16:00:12 +0900 Subject: [PATCH] Mqtt (#8) * use mqtt instead of ws * update readme --- README.md | 55 +++++++++++++-- platformio.ini | 3 +- src/main.cpp | 182 +++++++++++++++++++++++++++---------------------- 3 files changed, 153 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index b0f66f6..a249e08 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,60 @@ Stream the sensor data ```mermaid sequenceDiagram participant ESP32 as ESP32 - participant Client as WebSocket Client + participant Client as MQTT Client participant TouchSensor as Touch Sensor - ESP32->>+Client: Start WebSocket server - Client->>ESP32: Send message to get sensor data - ESP32->>+ESP32: Start streaming data - Client->>ESP32: Send message to stop streaming - ESP32-->>-ESP32: Stop streaming + ESP32->>+Client: Start streaming data Client->>ESP32: Send message to sleep ESP32->>+ESP32: Enter deep sleep mode TouchSensor->>ESP32: Touch GPIO 4 ESP32-->>-ESP32: Wake up from deep sleep ESP32->>+ESP32: Start booting ``` + +## Set up WiFi +1. Connect to the ESP32's WiFi AP +2. Open http://192.168.1.1 +3. Select the SSID and enter the password of the WiFi network + +Then the ESP32 will connect to the WiFi network and start streaming data. +The WiFi configuration will be saved in the flash memory. + +Check if the ESP32 is connected to the WiFi network +```bash +ping opencmm.local +``` + +## Install Mosquitto MQTT Broker + +ref. https://www.vultr.com/docs/install-mosquitto-mqtt-broker-on-ubuntu-20-04-server/ + +/etc/mosquitto/conf.d/default.conf +``` +listener 1883 0.0.0.0 +allow_anonymous false +password_file /etc/mosquitto/passwd +``` + +### Receive data + +```bash +mosquitto_sub -t 'sensor/data' -v -h 192.168.10.104 -u opencmm -P opencmm +``` + +### Send command to ESP32 + +Update configuration +```bash +mosquitto_pub -t 'sensor/control' -h 192.168.10.104 -u opencmm -P opencmm -m '{"command": "config", "interval": 1000, "threshold": 100 }' +``` + +Go to sleep +```bash +mosquitto_pub -t 'sensor/control' -h 192.168.10.104 -u opencmm -P opencmm -m '{"command": "deepSleep" }' +``` + +Reset WiFi +```bash +mosquitto_pub -t 'sensor/control' -h 192.168.10.104 -u opencmm -P opencmm -m '{"command": "resetWifi" }' +``` \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 3ba9d9a..93d288f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,4 +16,5 @@ monitor_speed = 115200 lib_deps = links2004/WebSockets@^2.4.1 adafruit/Adafruit ADS1X15@^2.4.0 - bblanchon/ArduinoJson@^6.21.3 \ No newline at end of file + bblanchon/ArduinoJson@^6.21.3 + knolleary/PubSubClient@^2.8 diff --git a/src/main.cpp b/src/main.cpp index 9e27647..f849286 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,64 +5,100 @@ #include #include #include +#include void ledBlink(); +void callback(char* topic, byte* message, unsigned int length); +void reconnect(); +void publishSensorData(int sensorData); const int touchPin = 4; // GPIO4 as the touch-sensitive pin int sensorData = 0; int interval = 1000; // 1 second int threshold = 100; const char* hostname = "opencmm"; +const char* mqttServer = "192.168.10.104"; +const int mqttPort = 1883; +const char* mqttUser = "opencmm"; +const char* mqttPassword = "opencmm"; -WebSocketsServer webSocket(81); +const char* clientId = "ESP32Client"; +const char* sensorTopic = "sensor/data"; +const char* controlTopic = "sensor/control"; -bool streaming = false; -void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) +WiFiClient espClient; +PubSubClient client(espClient); + +void touchCallback() { - switch (type) - { - case WStype_DISCONNECTED: - // streaming = false; // Stop streaming data when a client disconnects - break; - case WStype_TEXT: - { - const uint8_t size = JSON_OBJECT_SIZE(3); - StaticJsonDocument json; - DeserializationError err = deserializeJson(json, payload); - if (err) - { - Serial.print(F("deserializeJson() failed with code ")); - Serial.println(err.c_str()); - } - const char *command = json["command"]; + // wake up from deep sleep + Serial.println("Touch detected"); + // turn on sensor + switchSensor(true); + ledBlink(); +} - if (strcmp(command, "start") == 0) - { - streaming = true; // Start streaming data when "startStreaming" message is received - const int _interval = json["interval"]; +void setup() +{ + Serial.begin(115200); + checkWifiInfo(); + MDNS.begin(hostname); + setupSensor(); + + client.setServer(mqttServer, mqttPort); + client.setCallback(callback); + + touchAttachInterrupt(touchPin, touchCallback, 40); // Attach touch interrupt + + // Configure Touchpad as wakeup source + esp_sleep_enable_touchpad_wakeup(); + + ledBlink(); +} + +void callback(char* topic, byte* payload, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.println(topic); + + char receivedJson[200]; + for (int i = 0; i < length; i++) { + receivedJson[i] = (char)payload[i]; + } + receivedJson[length] = '\0'; + // Deserialize the received JSON string + const uint8_t size = JSON_OBJECT_SIZE(3); + StaticJsonDocument jsonDoc; + DeserializationError error = deserializeJson(jsonDoc, receivedJson); + + if (error) { + Serial.print("Failed to parse JSON: "); + Serial.println(error.c_str()); + } else { + const char *command = jsonDoc["command"]; + if (strcmp(command, "config") == 0) { + const int _interval = jsonDoc["interval"]; if (isIntervalValid(_interval)) { interval = _interval; Serial.println("Interval: " + String(interval)); } - const int _threshold = json["threshold"]; + const int _threshold = jsonDoc["threshold"]; if (isThresholdValid(_threshold)) { threshold = _threshold; Serial.println("Threshold: " + String(threshold)); } - Serial.println("Streaming started"); - } - else if (strcmp(command, "stop") == 0) - { - streaming = false; // Stop streaming data when "stopStreaming" message is received - Serial.println("Streaming stopped"); - } - else if (strcmp(command, "deepSleep") == 0) + Serial.println("Configured"); + Serial.print("Received JSON - Threshold: "); + Serial.print(threshold); + Serial.print(", Interval: "); + Serial.print(interval); + Serial.print(", Command: "); + Serial.println(command); + } else if (strcmp(command, "deepSleep") == 0) { - streaming = false; Serial.println("Going to sleep now"); delay(1000); // turn off sensor @@ -74,61 +110,33 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) resetWifiCredentialsWithWs(); } } - - break; - default: - break; - } } -void touchCallback() -{ - // wake up from deep sleep - Serial.println("Touch detected"); - // turn on sensor - switchSensor(true); - ledBlink(); -} - -void setup() -{ - Serial.begin(115200); - checkWifiInfo(); - MDNS.begin(hostname); - setupSensor(); - - touchAttachInterrupt(touchPin, touchCallback, 40); // Attach touch interrupt - - // Configure Touchpad as wakeup source - esp_sleep_enable_touchpad_wakeup(); - - ledBlink(); - - webSocket.begin(); - webSocket.onEvent(webSocketEvent); +void publishSensorData(int sensorData) { + char message[20]; + snprintf(message, 20, "%d", sensorData); + client.publish(sensorTopic, message); } void loop() { if (WiFi.status() == WL_CONNECTED) { - webSocket.loop(); + if (!client.connected()) { + reconnect(); + } + client.loop(); - // If streaming is enabled, get sensor data and send it to the client - if (streaming) - { - int currentData = getSensorData(); - // if the difference is greater than threshold, send data - if (abs(currentData - sensorData) < threshold) - { - return; - } - sensorData = currentData; - String dataStr = String(currentData); - Serial.println(dataStr); - webSocket.broadcastTXT(dataStr.c_str(), dataStr.length()); - delay(interval); + int currentData = getSensorData(); + // if the difference is greater than threshold, send data + if (abs(currentData - sensorData) < threshold) { + return; } + sensorData = currentData; + Serial.println(currentData); + publishSensorData(currentData); + + delay(interval); } else { runServer(); delay(1000); @@ -138,9 +146,23 @@ void loop() } } +void reconnect() { + while (!client.connected()) { + Serial.println("Attempting MQTT connection..."); + if (client.connect(clientId, mqttUser, mqttPassword)) { + Serial.println("Connected to MQTT broker"); + client.subscribe(controlTopic); + } else { + Serial.print("Failed, rc="); + Serial.print(client.state()); + Serial.println(" Trying again in 5 seconds..."); + delay(5000); + } + } +} + // LED blink -void ledBlink() -{ +void ledBlink() { digitalWrite(LED_BUILTIN, HIGH); delay(500); digitalWrite(LED_BUILTIN, LOW);