Besides adding in the Flow Meter code, I’ve been checking the log files and decided to add additional information such as what were the settings being used for LED, pump, CO2 on/off, etc.

As I added this to the code, I started getting messages that the amount of memory left could lead to unpredictable results.

Drat. The days of “getting this working as quickly as possible” coding on the Arduino Uno platform are over.  Besides, I’ve switched from poking at the code to relying on keeping the plants healthy and happy.  I am getting a lot of use from the log file information…so most likely I will be wanting to add more rows.

While I don’t see myself as an EFFICIENT and AWESOME coder – we all know the type…the person who would be the star of an X-Games Coder Edition…whoa…that is so not me!  But in the spirit of IT MUST WORK SO FIX IT…

I will buckle down on fixing up how strings are handled within theLeafSpa.ino.

Thanks To Those That Went Before

The folks behind the Arduino Uno and the Arduino IDEI am EXTREMELY grateful for the Arduino Uno environment.  The IDE is simple and easy to get started in.  There is a library for every sensor and peripheral.  This environment has saved me massive amounts of prototyping time.

Open Source

This blog post will discuss changes made to TheLeafSpa.ino.  The specific version discussed is found at this GitHub location.

The Arduino Uno Environment

The Arduino Uno environment has enabled so many of us to realize our DIY projects.  There are many pros to working in this environment:

  • Simple.
  • Libraries available for practically every sensor or device a DIYer wants to interact with.
  • A VERY supportive and helpful community.  It is easy to Google and discover how to do exactly what you wish to do.
Like everything that does many things very well, there are a few things that are traded off, including:
  • Lack of source line debugging.
  • Compiled language – compared with Python where you can try something and get immediate results.
  • Limited memory which you will most likely run out as your prototype grows.  This is the case with the Leaf Spa.
  • A programming language that is more C like than a simple language like Python or the extremely well done Swift language.
  • Lack of a “native” Internet support similar to what we’re seeing in the WiPy area.
The trade off I am addressing in this blog post is the limited memory.  I started getting compiles with running out of memory warnings…

Steps To Increase Available Memory

Unfortunately, I didn’t record the benefit of each change I made as I tore through theLeafSpa.ino…but here is a list of the stuff I did.

Removing the Debug Library

The debug library – even when turned off – affected the amount of memory.  The debug library proved extremely useful when initially developing the prototype code.  However, the library became less useful as the code became stable and I started relying on the log file instead of printlns to a serial monitor.

Removing the Use of the String() Object

Environments like Swift and Python make handling strings exceptionally easy.  The Arduino IDE provides a similar simplistic experience through the String() object.  The challenge I ran into is this abstraction took away too much control over how much memory was left.  In an environment in which each additional byte of memory starts to matter, control of the memory outweighed the simplicity of coding (unfortunately).

Sprintf() – a Brief Detour

When I first removed the String() object, I replaced creating a string with ints and floats with sprintf().  However, the code using sprintf() was still too big.

What I ended Up Coding for Strings

The code I am documenting here is located at this GitHub location.  I ended up (perhaps not surprisingly) relies on:

  • character arrays and char pointers.
  • itoa(), dtostrf(), strcpy() for int, float, and string conversions.
  • Using two global char arrays – stringBuffer and additionalInfo to store info that will be written to the log file.
Here is an example of the change I made when I replaced a usage of String():
  itoa(globalSettings.secsBtwnReadings, additionalInfo, 10);
  char *idx = additionalInfo + strlen(additionalInfo);
  *idx++ = ',';
  itoa(globalSettings.targetCO2Level, idx, 10);
  idx = additionalInfo + strlen(additionalInfo);

I use a pointer to position where to copy in the data.  The amount of memory I ended up with:

Sketch uses 24,970 bytes (77%) of program storage space. Maximum is 32,256 bytes.
Global variables use 1,416 bytes (69%) of dynamic memory, leaving 632 bytes for local variables. Maximum is 2,048 bytes.

This is good enough for now.  If I need to reduce program storage space, the next thing I probably will look into is not using dtostrf().    Here is the difference when no dtostrf() is used compared to when it is.

Not used:

void setup() {

void loop() {

Sketch uses 450 bytes (1%) of program storage space. Maximum is 32,256 bytes. Global variables use 9 bytes (0%) of dynamic memory, leaving 2,039 bytes for local variables. Maximum is 2,048 bytes.


void setup() {
  // put your setup code here, to run once:
  float f = 99.9;
  char fStr[6];

void loop() {

Sketch uses 2,022 bytes (6%) of program storage space. Maximum is 32,256 bytes. Global variables use 9 bytes (0%) of dynamic memory, leaving 2,039 bytes for local variables. Maximum is 2,048 bytes.

The code is more windy, but it does do what I want – give back enough RAM to stabilize the code.