0

我创建了一个在 Arduino MKR 1010 上运行的 Arduino 应用程序。连接到 WiFi 后,设备最初订阅为自己指定的 MQTT 主题,并通过该主题通知它应该订阅的其他主题。这些后续 JSON 消息的负载大小约为 2kb,我测试的最后一个是 1.91kb。信息以彩色灯光的形式处理和表示。随着新主题上线或下线,它会收到此信息的通知并相应地调整其订阅。

预期行为

应用程序应该正确运行 - 在收到通知时订阅和取消订阅主题 - 并以彩色 LED 的形式处理主题的有效负载。这些 JSON 有效负载应在处理后清除,为任何后续工作负载释放内存。

实际行为

工作一段时间后(这可能会有所不同),应用程序要么停止完全处理有效负载,要么完全停止工作,并需要硬重置才能再次与设备通信。

下面是代码 - 我希望这能有所帮助 - 我已经对代码进行了注释,以便更清楚地说明它在哪里以及为什么执行给定的功能。我已经尝试将动态 Json 文档更改为各种大小 - 对于有效负载的大小来说,这似乎是最佳的 - 尽管我很乐意接受其他建议。

#include <SPI.h>
#include <WiFiNINA.h>
#include <ArduinoMqttClient.h>
#include <Adafruit_NeoPixel.h>
#include <ArduinoJson.h>
#include <MemoryFree.h>
#include <pgmStrToRAM.h>

// Networking Values
WiFiClient wlan;
int status = WL_IDLE_STATUS;
char ssid[] = "";        //  network SSID (name)
char pass[] = "";    // network password (use for WPA, or use as key for WEP)
int keyIndex = 0;  

// Subscription list for MQTT Subscriptions
MqttClient    mqttClient(wlan);
String subscriptions[10] ;

// Lighting Values
int dataPin = 5; 
#define NUMPIXELS          30
Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUMPIXELS, dataPin, NEO_GRB + NEO_KHZ800);
int lights[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29};

typedef struct {
  uint8_t red;
  uint8_t green;
  uint8_t blue;
} pixel_config_t;

pixel_config_t currentLights[NUMPIXELS];


// Setup - Initialises the light array to give non-sequential illumination
void setup() {
  Serial.begin(57600);

  pixel.begin();
  
  const size_t n = sizeof(lights) / sizeof(lights[0]);
  
  for (size_t i = 0; i < n - 1; i++) {
      size_t j = random(0, n - i);
      int t = lights[i];
      lights[i] = lights[j];
      lights[j] = t;
  }

  // Initialise lights with white light
  for(int counter = 0; counter < NUMPIXELS; counter++) {
    changePixelColor(lights[counter], 255, 255, 255);
  }
  
  mqttClient.onMessage(onMqttMessage);
}

// Loop - checks for the connectivity - and polls the MQTT server for new messages every 3 seconds
void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    connectWiFi();
  }

  if (!mqttClient.connected()) {
    // MQTT client is disconnected, connect
    connectMQTT();
  }

  mqttClient.poll();
  
  delay(3000);
}

// On receipt of MQTT message - process either a notification of a new Topic to subscribe to - or process a publication to a subscribed Topic
void onMqttMessage(int messageSize) {
  Serial.println(F("Received Mqtt Message"));
  
  DynamicJsonDocument doc(12000);
  deserializeJson(doc, mqttClient);

  String type = doc["type"];

  // if this is a message notifying of a new Topics that has come online - unsubscribe to those in our list that are no longer on this payload - and subscribe to the new ones
  if(type == "subscription_notification") {
    JsonArray query_uuids = doc["query_uuids"].as<JsonArray>();

    for(JsonVariant currentUuid: query_uuids) {
      String currentUuidAsStr = currentUuid.as<String>();
      if(!isInStringArray(currentUuidAsStr, subscriptions)) {
        subscribeToNewTopic(currentUuidAsStr);
      }
    }
    for(String existingSubscription: subscriptions) {
      if(existingSubscription && existingSubscription != "" && !isInJsonVariantArray(existingSubscription, query_uuids))  {
        unsubscribeToTopic(existingSubscription);
      }
    }
  }
  // Else this is a notification of new colourings of lights - iterate through the list of lights changing the LED to the corresponding number in the payload
  else {
    JsonArray spreadArray = doc["spreadProportions"].as<JsonArray>();
    int lightNumber = 0;
    
    for(JsonObject currentProportion : spreadArray) {
      uint8_t red = currentProportion["red"].as<int>();
      uint8_t green = currentProportion["green"].as<int>();
      uint8_t blue = currentProportion["blue"].as<int>();
      changePixelColor(lights[lightNumber], red, green, blue);
      lightNumber++;
    }

    Serial.println(F("Completed Update."));
  }

  // Clear JSON Document
  doc.clear();
}

// Check if the UUID is in our current List of topics
bool isInStringArray(String uuidToQuery, String arrayToQuery[]) {
  for(int counter = 0; counter < sizeof(arrayToQuery) ; counter++) {
    if(arrayToQuery[counter] == uuidToQuery) {
      return true;
    }
  }
  return false;
}

// Check if a UUID is included in the incoming Json Array 
bool isInJsonVariantArray(String uuidToQuery, JsonArray arrayToQuery) {
   for(JsonVariant currentUuid: arrayToQuery) {
    String currentUuidAsStr = currentUuid.as<String>();
    if(currentUuidAsStr == uuidToQuery) {
      return true;
    }
  }
  return false;
}

// Subscribe to this new Topic and add it to our list
void subscribeToNewTopic(String topicname) {
  if((!topicname) || topicname == "null") {
    return;
  }
  Serial.println(F("Subscribing to new topic"));
  mqttClient.subscribe("query/" + topicname, 2);
  // add to the first element that has no value
  int counter = 0;
  for(String subscription : subscriptions) { 
    if(subscription == "") {
      break;
    }
    counter++;
  }
  subscriptions[counter] = topicname;
}

// Unsubscribe to a Topic
void unsubscribeToTopic(String topicname) {
  Serial.println(F("Unsubscribing to old topic"));
  mqttClient.unsubscribe("query/" + topicname);
  for(int counter = 0; counter < sizeof(subscriptions) ; counter++) {
    if(subscriptions[counter] == topicname) {
      subscriptions[counter] = "";
      break;
    }
  }
}

// Change the pixel color gradually from the current color
void changePixelColor(int pixelNum, uint8_t r, uint8_t g, uint8_t b ) {
  //int pixelNum = *(int*) pvParameters;

  uint8_t startR = currentLights[pixelNum].red;
  uint8_t startG = currentLights[pixelNum].green;
  uint8_t startB = currentLights[pixelNum].blue;

  while ((startR != r) || (startG != g) || (startB != b)){  // while the curr color is not yet the target color
    if (startR < r) startR++; else if (startR > r) startR--;  // increment or decrement the old color values
    if (startG < g) startG++; else if (startG > g) startG--;
    if (startB < b) startB++; else if (startB > b) startB--;
    uint32_t color = pixel.gamma32(pixel.Color(startR, startG, startB));
    pixel.setPixelColor(pixelNum, color);  
    pixel.show();
    currentLights[pixelNum].red = startR;
    currentLights[pixelNum].green = startG;
    currentLights[pixelNum].blue = startB;

    delay(3);  // add a delay if its too fast
  }
}

// Connect to the Wifi
void connectWiFi() {
  Serial.print("Attempting to connect to WiFi");
  while (WiFi.begin("", "") != WL_CONNECTED) {
    // failed, retry
    delay(5000);
  }
  Serial.println("Connected.");
}

// Connect to the MQTT Server - subscribing to the base Topic associated with this device
void connectMQTT() {
  mqttClient.setId("divnr-29715938");
  mqttClient.setUsernamePassword("", "");
  mqttClient.setKeepAliveInterval(5000);

  while (!mqttClient.connect("", 1883)) {
    // failed, retry
    Serial.print(".");
    delay(2000);
  }
  
  Serial.println(F("Reconnected"));
  // subscribe to a topic
  mqttClient.subscribe("device/7e887232-9cf1-453c-b352-647e9ccce11a", 2);
}
4

0 回答 0