Ver código fonte

Basic MQTT framework

Scott Bezek 3 anos atrás
pai
commit
157ac009b1

+ 1 - 0
firmware/src/.gitignore

@@ -0,0 +1 @@
+secrets.h

+ 6 - 0
firmware/src/main.cpp

@@ -3,6 +3,7 @@
 #include "display_task.h"
 #include "interface_task.h"
 #include "motor_task.h"
+#include "mqtt_task.h"
 
 #if SK_DISPLAY
 static DisplayTask display_task(0);
@@ -15,6 +16,10 @@ static MotorTask motor_task(1);
 
 InterfaceTask interface_task(0, motor_task, display_task_p);
 
+#if SK_MQTT
+static MQTTTask mqtt_task(0, motor_task, interface_task);
+#endif
+
 void setup() {
   #if SK_DISPLAY
   display_task.setLogger(&interface_task);
@@ -27,6 +32,7 @@ void setup() {
   motor_task.setLogger(&interface_task);
   motor_task.begin();
   interface_task.begin();
+  mqtt_task.begin();
 
   // Free up the Arduino loop task
   vTaskDelete(NULL);

+ 65 - 0
firmware/src/mqtt_task.cpp

@@ -0,0 +1,65 @@
+#if SK_MQTT
+#include "mqtt_task.h"
+
+#include "motor_task.h"
+#include "secrets.h"
+
+
+MQTTTask::MQTTTask(const uint8_t task_core, MotorTask& motor_task, Logger& logger) :
+        Task("MQTT", 4096, 1, task_core),
+        motor_task_(motor_task),
+        logger_(logger),
+        wifi_client_(),
+        mqtt_client_(wifi_client_) {
+    auto callback = [this](char *topic, byte *payload, unsigned int length) { mqttCallback(topic, payload, length); };
+    mqtt_client_.setCallback(callback);
+}
+
+void MQTTTask::connectWifi() {
+    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
+
+    while (WiFi.status() != WL_CONNECTED) {
+        delay(1000);
+        logger_.log("Establishing connection to WiFi..");
+    }
+
+    char buf[256];
+    snprintf(buf, sizeof(buf), "Connected to network %s", WIFI_SSID);
+    logger_.log(buf);
+}
+
+void MQTTTask::mqttCallback(char *topic, byte *payload, unsigned int length) {
+    char buf[256];
+    snprintf(buf, sizeof(buf), "Received mqtt callback for topic %s, length %u", topic, length);
+    logger_.log(buf);
+}
+
+void MQTTTask::connectMQTT() {
+    char buf[256];
+    mqtt_client_.setServer(MQTT_SERVER, 1883);
+    logger_.log("Attempting MQTT connection...");
+    if (mqtt_client_.connect(HOSTNAME "-" MQTT_USER, MQTT_USER, MQTT_PASSWORD)) {
+        logger_.log("MQTT connected");
+        mqtt_client_.subscribe(MQTT_COMMAND_TOPIC);
+    } else {
+        snprintf(buf, sizeof(buf), "MQTT failed rc=%d will try again in 5 seconds", mqtt_client_.state());
+        logger_.log(buf);
+    }
+}
+
+void MQTTTask::run() {
+    connectWifi();
+    connectMQTT();
+
+    while(1) {
+        long now = millis();
+        if (!mqtt_client_.connected() && (now - mqtt_last_connect_time_) > 5000) {
+            logger_.log("Reconnecting MQTT");
+            mqtt_last_connect_time_ = now;
+            connectMQTT();
+        }
+        mqtt_client_.loop();
+        delay(1);
+    }
+}
+#endif

+ 35 - 0
firmware/src/mqtt_task.h

@@ -0,0 +1,35 @@
+#pragma once
+
+#if SK_MQTT
+
+#include <Arduino.h>
+#include <PubSubClient.h>
+#include <WiFi.h>
+
+#include "logger.h"
+#include "motor_task.h"
+#include "task.h"
+
+
+class MQTTTask : public Task<MQTTTask> {
+    friend class Task<MQTTTask>; // Allow base Task to invoke protected run()
+
+    public:
+        MQTTTask(const uint8_t task_core, MotorTask& motor_task, Logger& logger);
+
+    protected:
+        void run();
+
+    private:
+        MotorTask& motor_task_;
+        Logger& logger_;
+        WiFiClient wifi_client_;
+        PubSubClient mqtt_client_;
+        int mqtt_last_connect_time_ = 0;
+
+        void connectWifi();
+        void connectMQTT();
+        void mqttCallback(char *topic, byte *payload, unsigned int length);
+};
+
+#endif

+ 12 - 0
firmware/src/secrets.h.example

@@ -0,0 +1,12 @@
+// Rename this file to secrets.h and add your secret details.
+
+// Network setup
+#define WIFI_SSID "myssid"
+#define WIFI_PASSWORD "supersecretpassword"
+
+#define HOSTNAME "smartknob" // e.g. smartknob.local
+
+#define MQTT_SERVER "10.0.0.2"
+#define MQTT_USER "mqttuser"
+#define MQTT_PASSWORD "megasecretpassword"
+#define MQTT_COMMAND_TOPIC "smartknob"

+ 5 - 1
platformio.ini

@@ -42,11 +42,12 @@ lib_deps =
   bogde/HX711 @ 0.7.5
   adafruit/Adafruit VEML7700 Library @ 1.1.1
   bakercp/PacketSerial @ 1.4.0
-  nanopb/Nanopb @ 0.4.6   ; Ideally this would reference the nanopb submodule, but that would require
+  nanopb/Nanopb @ 0.4.7   ; Ideally this would reference the nanopb submodule, but that would require
                           ; everyone to check out submodules to just compile, so we use the library
                           ; registry for the runtime. The submodule is available for manually updating
                           ; the pre-compiled (checked in) .pb.h/c files when proto files change, but is
                           ; otherwise not used during application firmware compilation.
+  knolleary/PubSubClient @ 2.8
 
 build_flags =
   ${base_config.build_flags}
@@ -66,6 +67,9 @@ build_flags =
   ; Ambient light sensor (VEML7700) enabled: 1=enable (display/LEDs match ambient brightness), 0=disable (100% brightness all the time)
   -DSK_ALS=1
 
+  ; Enable MQTT (wifi must be configured in secrets.h first)
+  -DSK_MQTT=1
+
   ; Pin configurations
   -DPIN_UH=26
   -DPIN_UL=25