0

Hey all I have a sketch that takes up 99% of my storage space since I am using a Arduino Nano.

Although everything in my code fits as-is, there seems to be an issue with me sending a json string over Serial as its coming back saying "deserializeJson() failed: NoMemory". I've also already used the ArduinoJson Assistant.

My json string looks like this: {"hardd": {"warrDays": "1265","temp": "102","hddST": "18TB","hddSU": "4TB","hddPB": "70","fan": "4200","date": "Fri Mar 11TH 2024","time": "10:45pm"}}

Note that the iconImages.h has just code that has images to byte code like this (there are 12 total of these):

const unsigned char hdd [] PROGMEM = {
    // 'hdd (1), 24x24px
    0x00, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x5f, 0xff, 0xfa, 0x7f, 0xff, 0xfe, 0x7f, 0x00, 0xfe, 0x7e, 
    0x7e, 0x7e, 0x79, 0xcf, 0x9e, 0x7b, 0x0f, 0xde, 0x76, 0x7f, 0xee, 0x64, 0xff, 0xe6, 0x6d, 0xe7, 
    0xf6, 0x69, 0x99, 0xf6, 0x69, 0xbd, 0xf6, 0x6b, 0xbd, 0xf6, 0x6f, 0x99, 0xf6, 0x6f, 0xc3, 0xf6, 
    0x67, 0xff, 0xe6, 0x77, 0xff, 0xee, 0x73, 0xf3, 0xce, 0x79, 0xc7, 0x9e, 0x1c, 0x0e, 0x3e, 0x0f, 
    0x00, 0xfe, 0x66, 0x07, 0xfe, 0x70, 0x3f, 0xfe, 0x72, 0x7f, 0xfe, 0x76, 0x0d, 0x5e, 0x70, 0xed, 
    0x1e, 0x5f, 0xed, 0x5a, 0x3f, 0xef, 0xfc, 0x00, 0x00, 0x00
};

Here is my code - if anyone has any suggestions on how to go about shrinking the amount of storage space/memory so that it wont error out when I send the json string then that would be great!

My code:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_EMC2101.h>
#include <ArduinoJson.h>
#include "iconImages.h"

#include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeMono9pt7b.h>
#include <Fonts/FreeSerif9pt7b.h>

#define hdd_SCREEN_ADDRESS 0x3C
#define apple_SCREEN_ADDRESS 0x3C
#define dell_SCREEN_ADDRESS 0x3C
#define TCAADDR 0x70

//                           W    H
Adafruit_SSD1306 hdd_display(128, 32, &Wire, -1);
Adafruit_SSD1306 apple_display(128, 32, &Wire, -1);
Adafruit_SSD1306 dell_display(128, 32, &Wire, -1);

Adafruit_EMC2101 emc2101;
char character;

//For timer=========================================
const long Minutes = 1;
const long _Interval = (Minutes * 60 * 1000);
unsigned long previousMillis = 0;
//==================================================

//For HDD Stats=====================================
int i = 0;
const char* hdd_warrDays  = "";
const char* hdd_temp      = "";
const char* hdd_hddST     = "";
const char* hdd_hddSU     = "";
const char* hdd_hddPB     = "";
const char* hdd_fan       = "";
//==================================================

//For Apple Stats===================================
const char* apple_os      = "";
const char* apple_hddST   = "";
const char* apple_hddSU   = "";
const char* apple_hddPB   = "";
const char* apple_ip      = "";
const char* apple_uptime  = "";
//==================================================

//For Dell Stats====================================
const char* dell_os     = "";
const char* dell_hddST  = "";
const char* dell_hddSU  = "";
const char* dell_hddPB  = "";
const char* dell_ip     = "";
const char* dell_uptime = "";
//==================================================

//For Date & Time ==================================
const char* _date = "";
const char* _time = "";
//==================================================

void setup() {
  Serial.begin(9600);

  if (!hdd_display.begin(SSD1306_SWITCHCAPVCC, hdd_SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ;
  }

  hdd_display.clearDisplay();
  hdd_display.display();
  hdd_display.setTextColor(WHITE);
  /*
    if(!apple_display.begin(SSD1306_SWITCHCAPVCC, apple_SCREEN_ADDRESS)) {
      Serial.println(F("SSD1306 allocation failed"));
      for(;;);
    }

    apple_display.clearDisplay();
    apple_display.display();
    apple_display.setTextColor(WHITE);

    if(!dell_display.begin(SSD1306_SWITCHCAPVCC, dell_SCREEN_ADDRESS)) {
      Serial.println(F("SSD1306 allocation failed"));
      for(;;);
    }

    dell_display.clearDisplay();
    dell_display.display();
    dell_display.setTextColor(WHITE);
  */
}

void loop() {
  unsigned long currentMillis = millis();

  while (Serial.available()) {
    String input_content = Serial.readString();

    if (input_content.length() > 2) {
      Serial.println(input_content);
      readAndParseJson(input_content);
      input_content = "";
    }
  }

  if (currentMillis - previousMillis >= _Interval) {
    previousMillis = currentMillis;

    Serial.println("previousMillis");

    if (i == 0 || i == 1 || i == 2 || i == 3) {
      i++;
    } else if (i == 4) {
      i = 0;
    }
  }

  doHDD(i);
  //doApple(i);
  //doDell(i);

  delay(100);
}

String getSplitValues(String data, char separator, int index) {
  int found = 0;
  int strIndex[] = { 0, -1 };
  int maxIndex = data.length() - 1;

  for (int i = 0; i <= maxIndex && found <= index; i++) {
    if (data.charAt(i) == separator || i == maxIndex) {
      found++;
      strIndex[0] = strIndex[1] + 1;
      strIndex[1] = (i == maxIndex) ? i + 1 : i;
    }
  }

  return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}

void scanI2C() {
  for (uint8_t t = 0; t < 8; t++) {
    Wire.beginTransmission(TCAADDR);
    Wire.write(1 << t);
    Wire.endTransmission();
    Serial.print("TCA Port #");
    Serial.println(t);

    for (uint8_t addr = 0; addr <= 127; addr++) {
      if (addr == TCAADDR) continue;

      Wire.beginTransmission(addr);

      if (!Wire.endTransmission()) {
        Serial.print("Found I2C 0x");
        Serial.println(addr, HEX);
      }
    }
  }
}

void readAndParseJson(String json) {
  //https://arduinojson.org/v7/assistant
  StaticJsonDocument<512> doc;
  DeserializationError error = deserializeJson(doc, json);
  json = "";

  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());

    return;
  }

  if (doc.containsKey("hardd")) {
    Serial.println("hdd");
    JsonObject hdd = doc[F("hardd")];
    hdd_warrDays = hdd[F("warrDays")];
    hdd_temp = hdd[F("temp")];
    hdd_hddST = hdd[F("hddST")];
    hdd_hddSU = hdd[F("hddSU")];
    hdd_hddPB = hdd[F("hddPB")];
    hdd_fan = hdd[F("fan")];
    _date = hdd[F("date")];
    _time = hdd[F("time")];
  } else if (doc.containsKey("apple")) {
    Serial.println("apple");
    JsonObject apple = doc[F("apple")];
    apple_os = apple[F("OS")];
    apple_hddST = apple[F("hddST")];
    apple_hddSU = apple[F("hddSU")];
    apple_hddPB = apple[F("hddPB")];
    apple_ip = apple[F("ip")];
    apple_uptime = apple[F("uptime")];
  } else if (doc.containsKey("dell")) {
    Serial.println("dell");
    JsonObject dell = doc[F("dell")];
    dell_os = dell[F("OS")];
    dell_hddST = dell[F("hddST")];
    dell_hddSU = dell[F("hddSU")];
    dell_hddPB = dell[F("hddPB")];
    dell_ip = dell[F("ip")];
    dell_uptime = dell[F("uptime")];
  }
}

void doHDD(int num) {
  hdd_display.clearDisplay();
  hdd_display.drawBitmap(0, 0, hdd, 24, 30, WHITE);

  if (num == 0) {
    //Show tempature
    hdd_display.drawBitmap(25, 0, thermometer, 24, 30, WHITE);
    hdd_display.setFont(&FreeSans9pt7b);
    hdd_display.setCursor(45, 15);
    hdd_display.print(hdd_temp);
    //hdd_display.print("100");
    hdd_display.setTextSize(1);
    hdd_display.setCursor(45, 29);
    hdd_display.print("tempature");
    hdd_display.drawBitmap(75, 0, degreesf, 24, 30, WHITE);
  } else if (num == 1) {
    //Show warranty
    hdd_display.setFont();
    hdd_display.drawBitmap(30, 1, warranty, 24, 30, WHITE);
    hdd_display.setTextSize(1);
    hdd_display.setCursor(60, 3);
    //hdd_display.print(341);
    hdd_display.print(hdd_warrDays);
    hdd_display.print(" day's");
    hdd_display.setCursor(60, 13);
    hdd_display.print("left of");
    hdd_display.setCursor(60, 23);
    hdd_display.print("warranty");
  } else if (num == 2) {
    //Show Hdd stats
    hdd_display.setFont();
    hdd_display.drawBitmap(30, 1, hddSpace, 24, 30, WHITE);
    hdd_display.setTextSize(1);
    hdd_display.setCursor(60, 3);
    //hdd_display.print("5.6TB free");
    hdd_display.print(hdd_hddST);
    hdd_display.print(" free");
    hdd_display.setCursor(60, 13);
    //hdd_display.print("of 18TB");
    hdd_display.print("of ");
    hdd_display.print(hdd_hddSU);

    //drawProgressbar(60, 25, 60, 7, atoi(hdd_hddPB));
    int progress = atoi(hdd_hddPB) > 100 ? 100 : atoi(hdd_hddPB);
    progress = progress < 0 ? 0 : progress;
    float bar = ((float)(60 - 1) / 100) * progress;
    hdd_display.drawRect(60, 25, 60, 7, WHITE);
    hdd_display.fillRect(60 + 2, 25 + 2, bar, 7 - 4, WHITE);
  } else if (num == 3) {
    //Show fan rpms
    hdd_display.setFont();
    hdd_display.drawBitmap(30, 1, fanSpeed, 24, 30, WHITE);
    hdd_display.setTextSize(1);
    hdd_display.setCursor(60, 3);
    hdd_display.print("Fan running");
    hdd_display.setCursor(60, 13);
    hdd_display.print("@ ");
    //hdd_display.print("4,102");
    hdd_display.print(hdd_fan);
    hdd_display.print(" rpm");
  } else if (num == 4) {
    //Show date/time
    hdd_display.setFont();
    hdd_display.drawBitmap(30, 1, timeAndDate, 24, 30, WHITE);
    hdd_display.setTextSize(1);
    hdd_display.setCursor(60, 3);
    //hdd_display.print("10:34pm on");
    hdd_display.print(_time);
    hdd_display.print(" on ");
    hdd_display.setCursor(60, 13);
    //hdd_display.print("Fri Sep");
    hdd_display.print(getSplitValues(_date, ' ', 0));
    hdd_display.print(" ");
    hdd_display.print(getSplitValues(_date, ' ', 1));
    hdd_display.setCursor(60, 23);
    //hdd_display.print("22nd 2024");
    hdd_display.print(getSplitValues(_date, ' ', 2));
    hdd_display.print(" ");
    hdd_display.print(getSplitValues(_date, ' ', 3));
  }

  hdd_display.display();
}

void doApple(int num) {
  String _apple_tmp[3];
  apple_display.clearDisplay();
  apple_display.drawBitmap(0, 0, apple, 24, 30, WHITE);

  if (num == 0) {
    //Show OS
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, runningOS, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("macOS 12.9");
    apple_display.print(getSplitValues(apple_os, ' ', 0));
    apple_display.setCursor(60, 13);
    //apple_display.print("Monterey");
    apple_display.print(getSplitValues(apple_os, ' ', 1));
    apple_display.setCursor(60, 23);
    apple_display.print(getSplitValues(apple_os, ' ', 2));
  } else if (num == 1) {
    //Show Hdd stats
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, hddSpace, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("5.6TB free");
    apple_display.print(apple_hddST);
    apple_display.print(" free");
    apple_display.setCursor(60, 13);
    apple_display.print("of ");
    //apple_display.print("of 18TB");
    apple_display.print(apple_hddSU);

    //drawProgressbar(60, 25, 60, 7, atoi(apple_hddPB));
    int progress = atoi(apple_hddPB) > 100 ? 100 : atoi(apple_hddPB);
    progress = progress < 0 ? 0 : progress;
    float bar = ((float)(60 - 1) / 100) * progress;
    apple_display.drawRect(60, 25, 60, 7, WHITE);
    apple_display.fillRect(60 + 2, 25 + 2, bar, 7 - 4, WHITE);
  } else if (num == 2) {
    //Show IP address
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, ethernet, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("192.168.1.123");
    apple_display.print("IP Address");
    apple_display.setCursor(60, 13);
    apple_display.print("...");
    apple_display.print(getSplitValues(apple_ip, '.', 2));
    apple_display.print(".");
    apple_display.print(getSplitValues(apple_ip, '.', 3));
  } else if (num == 3) {
    //Show uptime
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, uptime, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("35 days 17:14");
    apple_display.print("Uptime");
    apple_display.setCursor(60, 13);
    apple_display.print(getSplitValues(apple_uptime, ' ', 0));
    apple_display.print(" ");
    apple_display.print(getSplitValues(apple_uptime, ' ', 1));
    apple_display.setCursor(60, 23);
    apple_display.print(getSplitValues(apple_uptime, ' ', 2));
  } else if (num == 4) {
    //Show date/time
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, timeAndDate, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("10:34pm on");
    apple_display.print(_time);
    apple_display.print(" on ");
    apple_display.setCursor(60, 13);
    //apple_display.print("Fri Sep");
    apple_display.print(getSplitValues(_date, ' ', 0));
    apple_display.print(" ");
    apple_display.print(getSplitValues(_date, ' ', 1));
    apple_display.setCursor(60, 23);
    //apple_display.print("22nd 2024");
    apple_display.print(getSplitValues(_date, ' ', 2));
    apple_display.print(" ");
    apple_display.print(getSplitValues(_date, ' ', 3));
  }

  apple_display.display();
}

void doDell(int num) {
  dell_display.clearDisplay();
  dell_display.drawBitmap(0, 0, dell, 24, 30, WHITE);

  if (num == 0) {
    //Show OS
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, runningOS, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //apple_display.print("Windows 11");
    dell_display.print(getSplitValues(dell_os, ' ', 0));
    dell_display.setCursor(60, 13);
    //apple_display.print("Monterey");
    dell_display.print("V. ");
    dell_display.print(getSplitValues(dell_os, ' ', 1));
    dell_display.print(dell_os);
  } else if (num == 1) {
    //Show Hdd stats
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, hddSpace, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //dell_display.print("5.6TB free");
    dell_display.print(dell_hddST);
    dell_display.print(" free");
    dell_display.setCursor(60, 13);
    //dell_display.print("of 18TB");
    dell_display.print("of ");
    dell_display.print(dell_hddSU);

    //drawProgressbar(60, 25, 60, 7, atoi(dell_hddPB));
    int progress = atoi(dell_hddPB) > 100 ? 100 : atoi(dell_hddPB);
    progress = progress < 0 ? 0 : progress;
    float bar = ((float)(60 - 1) / 100) * progress;
    dell_display.drawRect(60, 25, 60, 7, WHITE);
    dell_display.fillRect(60 + 2, 25 + 2, bar, 7 - 4, WHITE);
  } else if (num == 2) {
    //Show IP address
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, ethernet, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //dell_display.print("192.168.1.123");
    dell_display.print("IP Address");
    dell_display.setCursor(60, 13);
    dell_display.print("...");
    dell_display.print(getSplitValues(apple_ip, '.', 2));
    dell_display.print(".");
    dell_display.print(getSplitValues(apple_ip, '.', 3));
  } else if (num == 3) {
    //Show uptime
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, uptime, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //dell_display.print("35 days 17:14");
    dell_display.print("Uptime");
    dell_display.setCursor(60, 13);
    dell_display.print(getSplitValues(apple_uptime, ' ', 0));
    dell_display.print(" ");
    dell_display.print(getSplitValues(apple_uptime, ' ', 1));
    dell_display.setCursor(60, 23);
    dell_display.print(getSplitValues(apple_uptime, ' ', 2));
  } else if (num == 4) {
    //Show date/time
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, timeAndDate, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //dell_display.print("10:34pm on");
    dell_display.print(_time);
    dell_display.print(" on ");
    dell_display.setCursor(60, 13);
    //dell_display.print("Fri Sep");
    dell_display.print(getSplitValues(_date, ' ', 0));
    dell_display.print(" ");
    dell_display.print(getSplitValues(_date, ' ', 1));
    dell_display.setCursor(60, 23);
    //dell_display.print("22nd 2024");
    dell_display.print(getSplitValues(_date, ' ', 2));
    dell_display.print(" ");
    dell_display.print(getSplitValues(_date, ' ', 3));
  }

  dell_display.display();
}

Would be great if someone could look over the code and suggest areas where I could save some memory so the json works.

1
  • This line must be wrong: 'Serial.println("previousMillis");' Taking the quotes away will save a few bytes. Also I woud use the F() macro on more of your strings. There is even a case for replacing your use of Strings by char arrays. But that is a lot of work. And one more point: I have found that whenever I run close to memory limits with the Arduino IDE, code begins to behave unpredictably. I have seen this way before reaching 99% of availability.
    – Lee-xp
    Commented May 5 at 14:13

1 Answer 1

3

I'm pretty sure you're using ArduinoJson 7 because ArduinoJson 6 would not return NoMemory in such conditions.

On 8-bit microcontrollers (such as the Arduino Nano), I recommend using version 6 because its fixed memory allocation strategy allows the code to be much smaller and can run without heap allocations, thanks to StaticJsonDocument.

Use the ArduinoJson Assistant to compute the right size for your StaticJsonDocument. In your case, it suggests a size of 192 bytes.

You can save a lot of RAM by passing the stream directly to deserializeJson() instead of loading it to a String.

Avoiding containsKey() can reduce the size of your program (and speed it up slightly). Instead, extract a JsonObject and check if it's null.

Beware that the F() macro doesn't duplicate strings. For this reason, you should probably use regular RAM strings when extracting from the JsonDocument.

You can find other memory-saving tricks in How to reduce memory usage?.

Finally, you can significantly reduce the program space by removing logging and replacing the repetitive patterns with loops.

1
  • Thanks for the suggestions there Benoit. I'll look into doing some of those and see if I have any success.
    – StealthRT
    Commented May 6 at 17:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.