Build Log for May 12th – Pinch Valve Take 1




In my previous post, I discussed my latest project – automating reading and calibration of a pH and EC probe.  I completed my first go around of building the pinch valve.  The pinch valve will be used to start/stop the flow of solution into the container.

Thanks To Those That Went Before

Nick Johnson – THANK YOU.  Nick posted a YouTube video showing a pinch valve he made that used the HTX900 servo motor.  Nick also posted the CAD files he used on Thingiverse.  I used Nick’s work as the basis for this design and build.  The files from Thingiverse gave me many of the measurements I needed to build the enclosure.  THANK YOU.

James Youmatz – Fusion 360 support for bring up the spur gear addition (see below).  THANK YOU!

Adafruit – THANK YOU YET AGAIN.  For your detailed learning guides on servo motor stuff.

A Confession

Us Gals Learning About Servo Motors

While I am old enough to be a grandmother, sadly – this is the first time I have explored servo motors.  For you lucky young uns – oh the fun you must be having! :-).

Since I was a noob to servo motors, Adafruit’s explanation of servo motors was helpful, especially after I tried their simple sweep test.

Pinch Valve Design

Here’s the design I ended up with:


Here are the parts I 3D printed next to the HXT900:


Spur Gear

3D printing a spur gear to attach at the end of the rotor was a Fusion 360 challenge I had to overcome.  To make one, I started with a roller I quickly designed:


An image of the roller and spur gear:


  • The roller’s hole has a diameter of 3.2mm.
  • The diameter of the roller is 10.6mm.
  • The height is 8mm.
Now…how to put spurs on the roller?…In my Googling I stumbled across this post.  

James.Youmatz details the Spur Gear Generator…how cool is this?…:

“…there is a Spur Gear Generator that you can utilize in the Sample folder within Scripts and Add-Ins.”

These are the settings I used:


Arduino Code

I posted the test code I used at this GitHub location.  


Fail – Not Enough Torque 

Given the hose I am using – a piece of hose I snipped off from another project – the HTX900 did not supply enough torque to pinch the hose.  Perhaps I could find squishy enough hose.  However, the chances of leakage would be high given I am using a gravity set up for the solution flow.  Besides, now I know to look closer at torque requirements.

(side note: I had a disturbing flashback to being in school and having to “compete” on math problems that had a similar thought process to this explanation…i.e.: given this hose with these features and this motor with this torque – will the pinch work – umm…I dunno…can I try it? :-)…so here I try it.  The answer is .. no…).

The failure here is using a servo motor that does not have enough torque to pinch the hose (for now I will stay with the hose I am using).

The HTX900 servo motor has a torque of 22.20 oz-in (1.60 kg-cm) at 4.8V.  So I’m looking for something with “significantly” more oomph.  I just ordered this servo motor from  I figured I’d think of it like going to a store today and buying one. listed this servo as same day delivery and the specs are noted in the comments section as : This item will be worked angel in 90°-360° depend on your setting, not a circle. Speed: 4.8V@0.19sec/60°; 6.0V@0.18sec/60°. Torsion:4.8V@9kg-cm; 6.0V@11kg-cm. Working V:4.8V-7.2V .  Ah – the wonders of metal gears…

What’s Next

Once I get the servo motor, I’ll fit the enclosure and other parts and try pinching off the hose once again…hmm…I am sure I could just back of the envelope this but…well…watching stuff spin is more fun.

Auto pH/EC Reading and Calibration – Build Log 5/8

The goal of this project is to use hardware/software to automatically read the pH and EC values of a nutrient bath.  Periodically, the probes reading the values will be automatically calibrated.

Probes and Solutions


The probes include:

  • a pH probe.  I will use the Extech 601500 Standard pH Electrode.  While I’ve tried a few probes over the past couple of years, I don’t have a feel if one is “better” than the other.  I chose this probe because I have been happy with other Extech tools and it seemed reasonably priced at just south of $40.
  • an EC probe.  I will use the probe I have used in the past.  This post serves as a good reference to the probe I will be using.


The solutions needed include:

Pasted Image 5 5 17 12 53 PM

The container holding nutes will be used by both probes.  The container holding cleaner, pH 4, and pH 7 solution will be used by the pH probe.  The container holding the 1413µS/cm solution will be used to calibrate the EC probe.   The containers don’t have to be test tubes.  I’ll figure out what these are as the design becomes better known.

Probe Positioning

Probes need to move to a container and then insert themselves into the solution.  This requires back-and-forth movement along the x-axis along with up-and-down movement along the z-axis.

X-Axis Movement

X-Axis movement will be achieved using a similar method to the used by Adafruit for the sliding camera mount:



I’ll be using one stepper motor for X-axis movement.

Z-Axis Movement

The probes must move down into the solution with a container and then move up out of the container.  Since there is no Y-axis movement, the bottom of the probe must be high enough to avoid colliding with a container when it moves along the X-axis to align itself before moving down into a container.

Up to this point, I’ve decided on the L12-R Actuonix linear actuator.  My thought is the 50mm stroke should be enough.  The actual stroke required will become more clear when the containers are designed.

Filling and Emptying the Containers

Each of the five containers need to be filled before the probe is inserted and then emptied when the probe is removed.  


Except for the container holding the nutrient bath, containers will have a bottle filled with the appropriate solution positioned above with a feeder that puts the solution into the container.  Gravity will allow the flow of the solution into the container.  The flow of the solution is managed by a pinch valve similar to the one shown in this video:


The bottom of each container will be attached to a solenoid valve.  The solenoid valve for the container that has a probe inserted will open when the probe is removed.  The valve will remain open for enough time to empty the contents.

Tomorrow I plan to start prototyping.


It’s that time…when the Leaf Spa starts networking… 


(I can only imagine the conversations the plants might have…hmmm…did you hear what the basil said to the stevia…huh?  There are humans that don’t believe in climate change?….)

In deference to adding Internet and Bluetooth connectivity, I’ll be referring to this “improvement” to the Leaf Spa as iLeafSpa.

Thanks To Those That Went Before

Adafruit – It seems I cannot THANK YOU ENOUGH.  This time, for the exceptional BLE Feather products and surrounding experience/support.  THANK YOU for showing me that when company leaders and their employees are as passionate about creating awesome experiences as the folks that are trying to make them, there is quality.  There is happiness.  There is inclusion.  THANK YOU.  Oh.  One more thing.  THANK YOU.

Apple – THANK YOU for Swift and Xcode as well as the iPhones to develop and play with.  Amazing.  These environments keep getting better and better.  THANK YOU for caring about security…although, I wish the latest MacBooks were something I wanted to upgrade to (sigh…).  Some things are perhaps small items to you….like removing the SD Card slot.  But for me…it just seems design is overwhelming customer needs…at least my needs :-).

The Goal of iLeafSpa

The goal of the iLeafSpa is to add Internet and Bluetooth so the Leaf Spa activities can be further automated past controlling relays into more of an expert system through it’s knowledge enhances the growth happiness of the Leaf Spa residence.

High Level Diagram

Here is a high level component diagram of the first iteration of iLeafSpa:

The Leaf Spa currently has Firmware and sensors interacting with the Grow Chamber to adjust the CO2 as well as turn on/off the water pump and LEDs.  Settings and sensor readings are written to an SD card.  An iPhone 4s takes time lapse movies.

iLeafSpa adds BLE and Internet connectivity by:

  • upgrading the Leaf Spa firmware/hardware to include BLE.
  • using the iPhone 4s (Smartphone in the image) as a BLE hub.
  • using the iPhone 4s to get to the Internet in order to upload log files, time lapse movies, and send alerts.
Another excitement is adding OTA-DFU.
I will eventually get around to adjusting pH (and perhaps EC) but that’s a bigger topic and not relevant to networking.  Later…

To The Internet!

I’ve been avoiding connecting to the Internet.  Perhaps as I get older my thought process is more like this:
…I’m seeing the Internet as a far less friendly place than I used to.  The faceless connectivity and lack of humanity behind much that I read disturbs me.  The residents of the Leaf Spa deserve a safe and happy neighborhood…and of course – full of light for photosynthesis.

More Uses for the iPhone 

Because of this, I’ve decided communication with the Internet will be through the iPhone 4S taking the time lapse movies instead of any micro controllers being used to collect data and adjust the Leaf Spa.  I’m relying on iOS to provide a robust security layer and access to services.  This will require me to write an iOS app.  I’m excited to be doing so because I find the Swift language to be delightful. I’m thrilled to be taking a staycation next week and focus on relearning the glories of Swift 3 + Xcode 8! 

Adding BLE to the Leaf Spa Firmware/Hardware

I’ll be changing the Arduino Uno out for an Adafruit BLE Feather.  E-X-C-I-T-I-N-G…I’m running out of SRAM space on the Arduino Uno I am currently using.  Also, adding BLE will require another shield piled on top of what is already there.  I have used and like Nordic’s BLE chips.  I did an in depth look at the nRF51822… when I built the Ladybug BLuE (starting around this blog post).

Oops!  I got so excited to try all this stuff out that I accidentally ordered Adafruit’s Feather 32u4 Bluefruit LE instead of the Feather nRF52832 BLE… MORE reason to resist hitting a purchase button before I’ve had enough coffee…With that said, this version is out of stock.  At least I can start with this Feather and move to the other when available.  

Testing the 32u4 BLE Feature

Whoa – nice.  I installed the Adafruit BLE iOS app after powering up the Feather.  The Adafruit App immediately found the Feather.  Upon connecting, the App let me know there was an update available and made it s-o-o simple by providing an OTA-DFU.  Like I said, nice.

Feather to iOS


I’ve written Arduino BLE code before.  I’ll start here by checking out how the Adafruit team has coded BLE support within an Arduino application.  I am interested in what I can pick up from the coding techniques that are used.

  • Download and add the Adafruit nRF51 library to the Arduino IDE. DONE.
  • Find an example that has the general structure I want to use moving forward.  DONE – using callbacks example.


  • Update Mac OS to Sierra to use Xcode 8.  Every time I go back to iOS programming, I watch the latest version of the excellent Stanford course on developing iOS apps written in Swift.  The latest uses Xcode 8.  I started with Xcode 7.  However, there were enough UI differences to make me want to upgrade to Xcode 8.  In order to upgrade, I needed to (finally?) upgrade to Sierra.  I avoid upgrading to a new OS if I am on an older machine until I have an application that requires me to do so.  Unfortunately, I was not delighted to upgrade my MacBook with the newer offering since I didn’t see any clear benefits, which means I have been on an older Mac OS version.  DONE…took long enough :-).
  • Write test code that is based on knowledge picked up getting to know Adafruit’s excellent Swift BLE iOS source code.

What’s Next

I plan to take a staycation this week.  The focus of fun will be reintroducing myself to Swift 3 and Xcode 8.  The outcome will be an iPhone 4s app that works with the Leaf Spa as a first test in evolving iLeafSpa.


I hope all is well with you.  Please find many things to smile about.




Another Time…Another Time Lapse


, ,

Time lapse snap shots of the Leaf Spa continue to be a work in progress (see a previous post).  I decided for my next exploration, I would add some type of wide angle to the iPhone 4s I’m using.  To explore this, I bought an inexpensive lens on eBay.  I’ll use the fisheye lens attachment.  Here is a short time lapse test at 2 fps:

ChallengesBringOpportunitesTada!  Not perfect.  But will work!

The New! Improved! Camera Mount

A challenge I have been having is coming up with a camera mount that:

  • Can be placed to get maximum image coverage of the Leaf Spa residents.
  • Doesn’t move around.  Previous efforts have ended up with the camera falling onto the shelf… 🙂
  • Can be adjusted / swiveled.
  • Doesn’t make it too difficult to remove the camera from the mount.  The O Snap! Software I am using on the iPhone 4s doesn’t directly upload photos or allow remote control of settings.

Challenge: Adjust/Swivel of Camera Mount

To address this challenge, I focused my attention on the iPhone mini-tripods.  I found one I had lying around which had this mount:


Two pieces of plastic held in place by a knob that grips on one end to a ball head and on the other end to legs.  The above image shows the piece I made with a 3D printer to hold the camera screw.  Here is a F360 rendering of the front of the mount:


Seeing the two pieces of plastic holding in the ball head gave me the idea to create a support that replaced the legs with something that could be mounted to the base of the LED shelf.  I came up with this design:


The holes are where the bolts coming through the LED shelf will go through.  It ended up being difficult for me to get the location of the bolts right on the model.  Next time:

Good better best This support did not need bolt holes since I ended up drilling holes through the plastic when I was drilling holes in the LED shelf.  Future print outs will need to adjust the holes to the LED shelf holes.

In an earlier attempt at the support, I made two pieces – the horizontal and vertical – then glued together.  Too much stress was on the junction point so I made the support one piece and added the fillet on the corner for additional strength.

Photo Op

Some images of the camera mount from inside the Leaf Spa:



Good better best The lens is on the right hand side.  Given the fisheye is a clip on, it is cumbersome/tricky to place the camera into the holder without moving the fisheye either off completely, or off the iPhone’s camera lens.


  • The cut out for the power cord is tight.  I edited the sketch within the F 360 model to increase the width.
  • Taking the camera out of the holder is a bit tricky because the mount is so close to the top of the shelf.  It is not that bad, since the mount can swivel.  However, if it does swivel, there should be a way to mark the optimum mount tilt.  Right now every time I remove the camera and put it back in, the view will be different not only because the fisheye could be moved as noted in the first “Good, Better, Best”, but the tilt will be different.
I am happy with this evolution of the camera mount.  It gives me something workable that I can test with.  As I noted, there are a few challenges.  However, this revision addresses major challenges I had in my previous efforts.  Now at least I can test time lapse!
Please find many things to smile about.  While you’re doing that, I will practice being kind.




Leaf Spa – Thank You Basil

The Basil in The Leaf Spa

Pasted Image 4 12 17 4 32 AM

It is time to reflect on what/how the basil is growing. What should I change to increase the plant’s quality given the Leaf Spa’s environment?  What should I change to the basil plants and/or environment to be more pleasing and better aligned to our family’s use?  Should I explore other varieties?

Based on explorations I did for this post:

  • I am happy with the current temperature.
  • I am changing the photoperiod to be 20 hours on and 4 hours off. This will achieve a higher DLI.  
  • I am evolving my use of basil.  
  • I will stay with the two varieties I am currently growing.


Two varieties are currently grown in the Leaf Spa, genovese and sweet basil.  While I am attempting to clone, I am also buying new seeds to begin at the beginning on a more focused approach to studying the basil growth, taste and use.

For now I’m going to stick to these two.  


I ran the script on several days worth of log data:

Seconds between readings: 60        
Target CO2 level: 1200        
Seconds for warmup: 180        
Seconds pump is on: 60        
Seconds between turning pump on: 1800        
Hour lights turn off: 12:00 AM        
Hour lights turn on: 8:00 AM        
–Average Values–          
LED ON     LED OFF    
Temp Humidity CO2 Temp Humidity CO2
23.9/75 72.9 1127 20/68 71.2 484

Measurements are grouped into whether the LEDs were on or OFF.  


  • The photoperiod is 16 hours, with lights off between 12AM and 8AM.
  • The pump circulates the nutrient bath every 30 minutes for 1 minute.
  • The target CO2 level when the lights are on is 1200ppm.
  • Readings are taken every minute.


I have been generalizing without much background that the “best” temperature for basil ranges between 70˚F and 85˚F.  This is based on information I got from the article titled Managing Air Temperatures For Basil Growth And Development.  Given the advice in this article, the Leaf Spa temperature readings are spot on.  I am thrilled these temperatures occur without the system having to control heat/air conditioning.  But is the pain/cost involved with adding an HVAC system at this point worth the gain in growing even better basil?  I’m happy with current results…but….but…

Could (should) they be better?  I googled to see if there has been research on the ideal temperature for growing basil (or herbs) within a controlled environment and came up with the article The Effect of Air Temperature on Growth of Eight Herb Species.  Author Leiv M. Mortensen comes from the perspective of how herbs are currently grown in Norway:  Relatively low temperatures of 13t o 18˚C have been recommended for herbs [1] [2], and temperatures below 20˚C are used in the greenhouse production of herbs in Norway

Based on Mr. Mortensen’s tests that are described within the article:


 He notes:  A substantial increase in the fresh weights of all eight herbs (ranging from 40 to 126%) was found to correspond to an increase in temperature from 18˚C to 24˚C or 27˚C.  Mr. Mortensen also posted a table on the plant’s height relative to the temperature.

Focusing on the basil results:

Basil     Temperature      
  18 21 24 27 27/15 24/18
weight (g) 52 63 85 107 82 68
% increase between   21.15% 34.92% 25.88%    
% increase from 18     63.46% 105.77%    
height (cm) 8 9 14 18 13 10
% increase between   12.50% 55.56% 28.57%    
% increase from 18     75.00% 125.00%    

I looked at the % increase in weight and height between the temperatures and between 18˚C and 27˚C.  Assuming these temperatures for 24 hours, the 27˚C temperature hows the 106% increase in weight and 125% increase in height.  Lowering the temperature for 12 hours to 15˚ or 18˚C acts more as an average.

I’d like to keep the plants shorter.  From the results, the higher the temperature has a significant affect on height.  Yet, the higher temperature as an equally significant affect on the size and number of leaves.

Given the temperatures I am currently seeing – 24˚C for 16 hours and 20˚C for 8 hours, I do not see a need for additional heating at this time.

However, I think of tweaking the Leaf Spa elements – like DLI – as the way I might adjust the amount of salt in a cooking recipe. In this case, I’m going to increase the LEDs being on by 2 hours.  So now the photoperiod will be 20 hours and 4 hours off. 

Frustrated Geez – I updated to Arduino IDE 1.8.2.  The problem with this is now the executable is Arduino  This executable has the version of the SD library that does not include end().  Perhaps “the right “ the to do is figure out a method to evolve to using the SD library so I’m not fumbling with the Arduino executable.  For now, I’m going to do what I did in this post.


I’d like to thank the basil plants for donating leaves so that I could make pesto for my family:

NewImage    NewImage


I have a fairly standard lunch routine in which I enjoy a magnificent salad.  Another big THANK YOU to the basil for donating daily leaves.  

Other Uses

I want to expand my use of a plant as I get to know it better.  I have seen basil ice cream and other culinary creations for basil.  Seems basil is quite the party pleaser, making almost any dish taste better.

Essential Oil

I’ve been thinking of ways to get the incredible smells I enjoy whenever I get a whiff of the basils.  It is time I DIY’d my own essential oil.  Here are the recipes I will be following that are on the Superbherbs archived site:

Cold Method
1. Let the herb you want to infuse sit overnight, so it will lose water. 
2. Fill a jar with as much herb as you want to infuse to 3″ from the top. 
3. Fill the jar with oil enough to cover the herb, plus 2″. Because herb exposed to air will mold, make sure all the herb is covered. 
4. Let sit in the sun or in a greenhouse for six to eight weeks. 
5. Strain into a clean, airtight, dark jar. Label, date, and store in a cool, dark place. Don’t be surprised if the oil doesn’t smell like the plant. It most often doesn’t. For a stronger oil, repeat the process. Double oleate oils are twice as strong, and triple oleate, three times as strong, etc.

Hot Method 
1. Let the herb you want to infuse sit overnight, so it will lose water. 
2. Fill a pot with as much herb as you want to infuse. Use a non-reactive pot. Glass is my first choice. You also can use stainless steel, enamel, or cast iron. Do not use aluminum or copper. 
3. Cover the herb with oil and add two more inches of oil. 
4. A double boiler is convenient, but if you don’t have one, put the pot in a bigger pot that has water in it. The oil should heat slowly over low heat for three hours. Do not overheat because too intense heat will destroy the volatile oils you are trying to collect. You can do this in a crockpot on the lowest setting also.
5. Strain into a clean, airtight jar, and store in a cool, dark place.

I’ll start by trying the hot method.    I saw this 16 ounce crock pot on  Since I had A LOT of orange peels around (my sister regularly sends me fruit from her garden 🙂 ), I’ll try the hot method first with orange peels.


I hope all is well with you.  Please find many things to smile about.

Using the Si7006 to get temperature and humidity readings


, , ,

I made a PCB with the Si7006 on it.  This post is my bumblings encountered as I successfully got temperature and humidity readings from a Si7006 using the PCB I designed.

In summary, the Si7006 is easy to work with.  It is relatively easy to solder and very easy to access via I2C.  I like the ease of use and “connect the chip” capability of chips that use the I2C interface.  It has become my interface of choice because of it’s simplicity and support on Arduino and micro python platforms.

The second aspect of this post that I found useful is evolving Arduino scripts for readability and reusability.  Implementing Tabs and an Si7006 within the Arduino scripts is a step up to how I have been programming examples and tests to interact with chips.  I also evolved handling error messages to work off error codes that are then resolved to strings that are stored in Flash.  It took me awhile to get this technique going.  I see it as a stepping stone to more robust/cleanable/readable code.

Thanks To Those That Went Before

OSH Park – THANK YOU for your exceptional PCB fabrication service at a fair price.  THANK YOU for the quality and cheerfulness of your employees.  THANK YOU for being kind and caring.  I am a very loyal customer.

Adafruit – THANK YOU as well for being kind and caring.  The knowledge folks like Tony D has shared has been a very valuable way to increase what I know how to do.

Open Source

The Arduino code that tests the Si7006 using tabs (Arduino IDE feature) and puts the getting the temperature and humidity within a class is located at this GitHub location.

The Kicad project I reference is located at this GitHub location.

Arduino IDE

I am currently using Arduino 1.6.11.  I keep getting these pesky WARNING messages…:

WARNING: Category ” in library EEPROM is not valid. Setting to ‘Uncategorized’
WARNING: Category ” in library SPI is not valid. Setting to ‘Uncategorized’
WARNING: Category ” in library SoftwareSerial is not valid. Setting to ‘Uncategorized’
WARNING: Category ” in library Wire is not valid. Setting to ‘Uncategorized’
Warning: platform.txt from core ‘Arduino AVR Boards’ contains deprecated”{compiler.path}{}” {} {} “{build.path}/{archive_file}” “{object_file}”, automatically converted to”{compiler.path}{}” {} {} “{archive_file_path}” “{object_file}”. Consider upgrading this core.


ChallengesBringOpportunitesYIPPEE!!! Looking at the Arduino downloads page – to my surprise the latest is 1.8.2…so I upgrade and the warnings go away. 

Code Readability

Tony D presented some great tips on Arduino coding with readability in mind. These techniques are based on Tony D’s Youtube video: CircuitPython: Converting Arduino Arc Reactor Sketch to CircuitPython with Tony D!   Tony posted the code he discussed at this GitHub location.

Multiple Tabs

The first technique is the use of multiple files.  Tony discusses this here.  I did this for this version of Si7006Test.ino.  It is a nice way to test how a library will work within an Arduino environment without having to create a library within a C/C++ IDE environment (I use XCode).  Unfortunately, the files within an Arduino project are specific to the project. In order to use the Si7006 within another .ino file, I’ll have to create an Arduino library. A bit of a pain but no big deal.

Si7006 Class

Tony discusses defining a class here.  It’s a nice way of arranging an interface to a chip or logical grouping of functions. 



Schematic, Layout, PCB

Github location

NewImage  NewImageNewImage

Simpson DOH Umm…C1…really?  There is a reason the capacitor symbol has a space between it…electrons don’t go across… This isn’t the first time I’ve made this fairly gross mistake.  I recall Mike at Adafruit support providing an excellent/detailed explanation.  Hopefully, the embarrassment I feel after making this basic mistake will train my brain to solidify a stronger conceptual/practical model into designing in bypass/decoupling capacitors. For now, I’ll remove the capacitor and bridge the pads.  





Good better best 

  • Fix the bypass capacitor schematic/layout to actually be correct :-).  Whoa…seriously embarrassed on what I did based on my learnings from Contextual Electronics.  But perhaps the way I should look at it was my mistake became obvious when I started testing.  Yes, I should have picked this up during design.
  • The 0805 footprint I used is larger than I would like (although usable).  I picked the one for easy soldering.  I’d like one that better fits the pins.
  • Add an LED that lights up when the BoB is powered.

Si7006 Firmware

I2C Arduino Pins

I used pins A4 and A5 on the Arduino Uno to handle the I2C conversation with the Si7006:


Logic Analyzer

Isn’t it just like chips not to talk the first time they are put together over an I2C bus?  This is what happened to me the first time I ran the Arduino code.  The first time the Arduino couldn’t even find the Si7006.  Who knew this chip was so shy?  This link gives us the error codes -> 0 = Success, 1 = data too long to fit in transmit buffer, 2 = received NACK on transmit of address, 3 = received NACK on transmit of data, 4 = other error.  I was getting error code = 2…couldn’t find the darn chip.

And looking at the traffic on the ever trusty Saleae logic analyzer:


I noticed wire traffic shows an address of 0X80.  The I2C address of the Si7006 ix 0x40.  This reference by robot-electronics (see I2C device addressing) helped me understand this stuff about bitshifting the I2C address by 1 bit.  Here is a bit shift calculator to use.  

As the error code let me know, the NAK means the I2C chip with address 0x40 couldn’t be found. Hmm…

Looking closer at the chip:


There doesn’t appear to be enough solder on the SDA pin.  Putting on more solder, I now get:

0X84 + ACK

0X88 + ACK

Setup Read to [0x81] + ACK

0x20 + NAK


ChallengesBringOpportunitesOutput from the Arduino sketch:

********Si7006 example sketch**********

Humidity: 41.86
Temperature: 19.71


I am thrilled to have evolved Arduino Firmware testing to include:

  • tabs
  • use of a class instead of calls to function to represent access to the S7006.
  • error messaging.
Instead of copy/pasting code, the code is available at this GitHub location.  For Leaf Spa purposes, Si7006.
  float humidity, temperature;
  si7006.getHumidityAndTemperature(humidity, temperature);

is the only function needed to be used.

Error Messages

To save on SRAM, I wanted to put error messages into Flash. The Arrays of strings example on Arduino’s PROGMEM web site was just what I needed to understand in order to get this to happen.  VERY useful.


…all this took awhile.  Meanwhile, I need to fix a few leaks.  I’m learning A LOT from maintaining the Leaf Spa….while I will continue to evolve, at some point I am excited to start on version 2 which will take into design consideration all I have learned.





Leaf Spa Residents Getting Apartment Numbers


, ,

Welcome to the Leaf Spa Luxury Plant Apartments

I’ve started to think of the plants that grow in the Leaf Spa as residents within dah (ever so) swanky Leaf Spa apartment building…the challenge of course is affordable rent (just ask my kids whose current salaries can’t afford an apartment…grrr…but I diverge).

I decided to make the apartment numbers be the nutrients as they appear within the periodic chart.  


Apartment K

Here is an image from Fusion 360:


This way, not only will I be reminded of the important macro and micro nutrients, but be constantly reminded of the gleeful combination of chemistry and (plant) life.  

ChallengesBringOpportunitesNow I can refer to a plant not only as “the basil plant”  but the basil plant in apartment K…for some reason I find that fantastic.  It makes me happy/smile, so I must do it.  Happiness, pain, sadness…back to delight…don’t you just love it?

I’ll use two colors – white for the box and black for the lettering.

Thanks To Those That Went Before

Russell Singer – Russell works for MAKEiT (here is a podcast that features Russell and his work)- the company behind the Pro-M 3D printer I bought about a year ago.  Russell’s knowledge on how to successfully print based on the particulars of a design is excellent.  Besides that, Russell has ALWAYS answered my email questions in a timely, detailed, and courteous fashion.  As I get older, I become so much more grateful for the excellence and difference one person can make. THANK YOU RUSSELL.

Fusion 360

The wonderful concept of complete parametric design of a component continues to elude me.  Fresh off watching Adafruit’s excellent Layer by Layer – Adaptive Parametric Features youtube video, I was ready to embrace designing everything using parameters and constraints.  Alas, things got WAY too complicated quickly when applying parameters and constraints to text within the component.  I tried to follow an Autodesk help tutorial posted in the help forum…but…really?  I have to stand on my head, twirl, and do…what?  …seriously?  Back to rolling in the dirt and just doing whatever it takes with Fusion 360.

3D Printer


For this I want to use PLA.  So I go on Amazon to get white and black filament.

Simpson DOHI ordered TPU instead of PLA.  I didn’t know about TPU…I like the elasticity/flexibility…hmmm….this time I’m returning and getting PLA.  Too much stuff lying around.  And so I wait.  Oh…I accidentally touched the hot end of the extruder when it was HOT…..OUCH…don’t do this …..D’OH…. 🙂


I like to check for firmware updates every once and awhile.  The current version on my Pro-M is 2.13.  The version on the MAKEiT is 2.17.   Luckily, the update went smoothly.  Perhaps mostly due to the fact I had done an update before and knew to use Cura and the USB port.  Would be nice if I could just OTA (Over The Air) update the printer and not use Cura….but alas….the good news is MAKEiT would rather focus on customer’s successful printing.  A good tradeoff.

Print Settings for Dual Extrusion

Getting the settings right  takes more skill and practice than I have.  Lucky for me, MAKEiT has amazing support mostly in the form of Russell Singer.   A big challenge I have with two color printing is the nozzle leaking when changing colors.  There are others, so I asked Russell for advice.

Advice From Russell on Two Color Printing

Dual extrusion on our printers requires a little bit of attention first to Z-height leveling of the nozzles. For two materials or two colors printing together in one part, it’s important that the nozzles are as close to evenly level as possible. If printing with a second material like PVA only for support, the secondary nozzle should be very slightly higher than the nozzle printing the main part.

In terms of settings here is what comes to mind:

  • Using significantly higher retraction z-lift setting can help quite a bit by preventing travel motions from one nozzle from impacting areas already printed by the other nozzle. For two-color printing I use a z-lift value of 0.8, for soluble support printing slightly higher of 1.2
  • Soluble support benefits significantly from printing with a raft.
  • Tool change retraction distance should be far enough to take the material out of the heat zone, 35mm works well
  • Extra restart distance after tool change can be useful if you notice gaps in extrusion, but depending what materials and how often it’s switching nozzles it may be unnecessary
  • On parts where there is significant lag between when one nozzle stops and restarts printing, using a prime tower may be necessary. Prime towers can be finicky and and like to fall over if the part is very tall, using a raft can help avoid this
  • Adding in a tool change gcode script (below) to adjust temperatures based on which nozzle is active can reduce stringing, color contamination, potential for clogs, and a few other improvements


and typed out:
G1 X100 Y170 F4000; Move out of the way while it stabilises active tool temp.

{IF NEWTOOL=0}; LEFT Extruder is active (T0)

{IF NEWTOOL=0}M104 S180 T1; Cool inactive extruder to 180c (T1)

{IF NEWTOOL=0}M109 S210 T0; Heat active extruder to 210c (T0).

{IF NEWTOOL=1}; RIGHT Extruder is active (T1)

{IF NEWTOOL=1}M104 S180 T0; Cool inactive extruder to 180c (T0)

{IF NEWTOOL=1}M109 S210 T1; Heat active extruder to 210c (T1). 

Things to be aware of when using this script: the numbers for temperature must be changed within the script if you use different materials (this is for PLA now). If you use this script with ABS you’ll have to manually adjust the temperatures within the script’s tab to appropriate ones for that material. Also there are sometimes other things that trigger S3D to think a tool change has happened, even when printing single nozzle, so if you leave this script in place when it’s not needed it might unexpectedly adjust your temperatures. For this reason it’s probably best to save a different profile for two-material printing that’s separate. When it moves out of the way to allow time for temperature adjustment the head will move to a fixed point, specified by the first line of the script. Where it says “X100 Y170” you can adjust those numbers to place the head at a point in the XY plane that ideally isn’t very far away from the main part or prime tower, but also isn’t directly over it. Last thing to be aware of with this script is that Simplify3D requires you to have two separate processes setup for two material prints; both processes must have this script otherwise it will only go through the temperature changes half the time, and the temps will be wrong the other half.


I imported the FFF file Russell attached, made sure the tool chain script was added to both processes, and also:

  • Increased the Extrusion Multiplier from .93 to .97.  I still believe at least the filament I use requires a higher Extrusion Multiplier than what Russell recommends.  I am not completely confident of this.  However, for now I will go with a .97 extrusion multiplier.
  • Changed the parameters Russell noted:
    • Retraction Z-lift
Pasted Image 4 6 17 9 11 AM
    • Tool change retraction distance and extra restart distance:
Pasted Image 4 6 17 2 55 PM

.  I’ll start my settings with an updated Pro-M FFF file which I downloaded from this site.

I go to using the Configuration

The FFF file’s GCODE section has these settings:


First Print

The first print ended up using white for the text.  In the future, I now know to check out what will be printed by changing the coloring to Active Toolhead.  In this print’s case, it was showing that only one color would be printed:

Pasted Image 4 6 17 5 24 AM

Not what I wanted.  What did I do wrong in the setup?

Pasted Image 4 6 17 5 30 AM

of Course! I did not set the tool for the layers to be the extruder with the black filament.


Printing the text was also a challenge as the text got smaller because of the melting of the filament – the text is a bit small with the settings.  Instead of spending time improving text printing, I’m going to change the Fusion 360 model to only have the chemical symbol instead of other text.



Right now I’m printing out more apartment numbers – CA, N, etc…. sometimes the print works…and other times…well…it’s truly a process….

Updates to the Python Code That Reads the Logfile


, ,

Farming in a Shipping Container

I’ll state up front I am naive to the complexities and why the idea below won’t work.  I’m just starting to think about this.  If I’m still thinking about it months later, perhaps the idea isn’t so bad.  If I start talking to folks (in the idea below this would be folks running shelters for example) and they agree it is a good idea, perhaps I’ll move ahead.  Please let me know if you have thoughts/criticisms that I can learn from.

I’m thinking this youtube video on shipping container farming is a great way to get fresh produce into our cities.  I’d like to evolve a container to take advantage of sun as well as external CO2 to supplement (LED) lighting.  I do like the way the shipping container farm minimizes water use…and then figure out a way to gather up the food waste into compost to reuse as fertilizer (nutrients)….hmmm…. where seeds check in and cities are fed…. …partner with a local shelter to train folks to work on it (and by working on it they get not just a “minimum wage” but a livable environment -> housing + food + healthcare + education + love) ….provide produce to the shelter…hmm.  

What’s Up Today?

I want to evolve the Python script(s) I wrote that will help me analyze the Leaf Spa’s log files.  This will be an ongoing effort.  One thing I am doing is changing the code such that summary results is written out to a separate CSV file.  The filename will be <input CSV filename>_summary.csv.

I can now run the script from a terminal window by typing Python within the folder that contains the python files.

Open Source

The Python scripts I’ll be referring to are located at this GitHub location (version ae9b9db).

This Python Experience

My Python code update experience feels like this:

Happy to be learning.  Snug in a save Python IDE environment…but so…so…so…so much to learn! 🙂 …ummm…I should probably point out the obvious – and of course, I am so…so…so…NOT AS CUTE…

Changing to the Atom Editor

Ugh…Eclipse with PyDev just made me sad.  The Eclipse Neon environment lost my Python environment.  I can’t shake the feeling that at least for Python development Eclipse has gotten bloated.


Once I get a food visual associated with something I find it hard to shake (such is the power of food on my ability to think!)…the visualization I get is one in which I see when I leave something in the refrigerator too long and it takes on a green/gray color as it seems to bloat in a very unpleasant way.  

Hmmmm….I shall move on…

I’m feeling positive about using Atom as my Python IDE now that I have had a few days using Atom.  While not as rich as Eclipse, it is good enough and much lighter to set up and work in.   Also – Once I finish coding/debugging…it is a snap for me to run the script from the command line.  YIPPEE!


The first bumbling I ran into was installing the terminal-plus package in order to get a command line so that I could run Python from within Atom…I had forgotten I already had a way to run Python within Atom based on what I documented in this post (i.e.: installing and using the Script package).  So I deleted the terminal-plus package based on AbeEstrada’s advice:


You can list your packages from terminal with this command

apm list

And then you can uninstall with

apm uninstall PACKAGENAME


 I found I could drag-n-drop the tab of an open file to the desktop. This creates a text file which contains the full pathname to the file.

Pasted Image 3 31 17 3 47 AM

This technique was very useful when inputing the full filename.

Test How Stuff Works in Python

Since I am still at the floaty stage with Python, I constantly need to try out Python commands.  To do this, I installed the script package.  I then added a file to the project.  I add / delete lines and then run just this script (command – i ).  Note: I tried running just by line number but got back an error message letting me know line level execution is not supported in Python.  Not a big deal.


I am not ready to take off my Python floats yet.  Besides, I just love the crutch of a source line debugger. This led me to install the Python debugger package.  It could be my error, but at times I think I’m using the debugger correctly and I don’t get expected results..The challenge appears to be getting enough practice with this debugger in Atom to efficiently using it.  Once I gained practice, the debugger became very useful.


The link above documents the few commands. The ones I rely on include:

  • alt-r -> brings up the debugger
  • shift-alt-r -> set/remove a breakpoint.  I use this only when starting the debugger.  I then step into the function that is in another file to switch the debugger to that file.  Then I can use the b command (see below) to set breakpoints within the current file.
  • input is put on the input line.  For example, I input the log file with something like: -i /Users/…/03312017a.csv
Commands I stumbled upon that worked / I found useful:
  • p <variable name> on the debugger command line displays the value of the variable.
  • b  -> show which breakpoints are active
Enter these on the line that says “Enter debugger commands here (hit return after command).

Python Learnings

As I learn to swim in the Python pool with my floaties on, I discover stuff that perhaps will let me swim in this python pool with more elegance.  Understanding and using Python better is one of the reasons I am enthusiastic to evolve this script.

Logging Library

Python’s Logging library is AWESOME (see the documentation).  Here’s an example of how I’m using it:

Setting Up

import logging
FORMAT = ‘In: %(filename)s Line: %(lineno)d %(message)s’
logger = logging.getLogger(__name__)

In Code

SDfilepath = “/Volumes/LeafSpa/”
SDfilename = SDfilepath + “DATALOG.TXT”
theLogFile = open(SDfilename)
logger.error(‘ERROR! ‘+SDfilename+ ‘ (on the SD CARD) could not be opened.’)

Results from Running Code

In: Line: 39  ERROR! /Volumes/LeafSpa/DATALOG.TXT (on the SD CARD) could not be opened.

A Better Way To Handle a Switch Statement

Since Python didn’t support a switch statement, I didn’t search to see if there is something more elegant than:

            if rowType == 3: #LED is turned on
                inLEDonState = True
            if rowType == 4: # LED is turned off
                inLEDonState = False
            if rowType == 0: # A reading
                temp = float(row['info1'])
                humidity = float(r... 

My goal in the evolution of my coding skills is to write code that helps in readability.  Most folks seem to focus on efficiency…again – that code shredder that we all marvel at who can solve the answer to any question with one line of highly unreadable code…The challenge I have is what happens the next time I need to pick up the code…or you want to figure out what is going on?  Given that microprocessors are powerful and heck – this code is in an abstract language like Python – what is Pythonic (an approved way to write something in Python) while at the same time more readable?  And this is where using a dictionary to handle options that I’m currently handling with if this option:….if that option:…..

Using a Dictionary

Digging deeper into using a “switch dictionary” in an effort to have more maintainable code, I found these two articles useful:

and came up with the code found in this version of  (version ae9b9db).

Good better bestDetermining Light On

I am figuring out whether a sensor reading (record type 0) happened when the light was on or off based on whether a Light on record (record type 3) or Light Of (record type 4) happened.  This isn’t robust since the log file might not have Light on/off records in the case the SD card has been removed, the file deleted, then reinserted prior to a light on/light off event.  Taking a step back, determining if the lights are on can be made if:
  • As noted – a record in the log file is a light on/off record.
  • There is a settings record that has noted when the light is to be turned on and off.  Using this info, if the sensor record’s time stamp is between the lights on hours, the sensor reading happened when the light was on.
  • If there are CO2 on/off (record type 5 and 6) interspersed with the sensor readings since CO2 is released only when the light is on.  Note: there will still be chances to miscategorize a sensor reading. 
Bumbling around the log file and Python coding took a few days.  I took longer than others might.  However, I appreciate the additional knowledge I gained using Python and the Atom editor.  It was also a chance for me to evolve the usefulness of the log file for future analysis.  Most likely this is just one of many evolutions that I’ll make to the post-process and evaluation of the log file.


Not Writing Records to the Logfile.

Customer Check-In

Despite all the fiddling and stuff like running out of CO2, fixing the pumps…I’m pleased with how my customers are doing in the leaf spa.  Here are pictures from yesterday:

IMG 5401

IMG 5403


IMG 5405 

I’ve been using the Kale and A LOT of basil.

Today’s Post

I thought I had fixed the challenge I was having writing records out to the log file.  Well…I haven’t.  I just looked at the most recent log file and see that it only has 28 rows.  Hmmm….In this post I find and fix a memory leak but first I take a step back to understand how memory is used by the Arduino.  I am glad I did.  I now have a much better conceptual model with where my code is going versus my variables…even though I “sort of” knew this, I did not have a strong enough conceptual model in my head…I guess I lost my memory about (Arduino) memory.

The memory leak turned out to be repeated calls to openFile() in writeSensorDataToLogFile() that created and left hanging around instances of File objects:

void  writeSensorDataToLogFile() {
    File logFile = openFile();  
  if (!logFile) {  
  dtostrf(sensorData.temperatureValue, 4, 1, additionalInfo);
  char *idx = additionalInfo + strlen(additionalInfo);
  *idx++ = ',';
  dtostrf(sensorData.humidityValue, 5, 1, idx);
  idx = additionalInfo + strlen(additionalInfo);
  *idx++ = ',';
  itoa(sensorData.CO2Value, idx, 10);
  writeEventHappened(SensorData, additionalInfo);

Thanks to Those That Went Before

Adafruit: Thank you for your excellent tutorial on “Memories of an Arduino.” I am an extremely happy customer of Adafruit.  I feel great about buying from Adafruit because I feel that a lot of the margins made are given back to us through these great tutorials, youtube videos, friendliness, etc.  Adafruit is NOT a company in which a few (usually white men) are making a ton of money while they lack the compassion shown by Adafruit.  Again THANK YOU.

Open Source

The version of TheLeafSpa.ino that evolved from this post is located at this GitHub location.

Debugging Memory Use

How Memory is Used by the Arduino

I decided to take a step back and appreciate the memory architect used by the Arduino.  It’s like going into a place that does wine sampling.  A moment to reflect on why something is the way it is, and appreciate it for what it is…OK..enough with the analogies.

Adafruit’s excellent section on memory architecture, notes on the Arduino, Flash = Program Memory and SRAM = Data Memory.

The Arduino UNO has only 32K bytes of Flash memory and 2K bytes of SRAM.” Note: for completeness there is also EEPROM.  However, theLeafSpa.ino challenge would be on how much Flash and/or SRAM the code is using. 

Looking at this table, 

I might consider using a Mega instead of the Uno. Or perhaps the Adafruit Feather M0 WiFi – ATSAMD21 + ATWINC1500.  If I switch to the Feather (which is tempting…), I lose the Grove Connector base shield..of course, I could have a Frankenstein way of tying altogether for now…

How Memory is Used by TheLeafSpa.ino

From my previous post, I noted the current amount of program storage (flash) and SRAM (dynamic memory) the compiler and boot loader let me know about:

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.

Hmm…these numbers made me think I don’t have this type of issue:

 but…I underemphasized the term “dynamic” in my thinking.  The amount of SRAM changes.  

Using free_ram()

I had been calling free_ram() at the beginning of the code (see the debug library)…but I wasn’t doing what Bill recommended in the Adafruit article: “SRAM utilization is dynamic and will change over time. So It is important to call free_ram() at various times and from various places in your sketch to see how it changes over time.”

I added a function to add an amount SRAM record to the log file:

  Write the amount of SRAM available after the record has been written.  If there is a change, it's of interest
  to know the length of stringBuffer and additionalInfo.  Are they what I expect them to be?
void writeFreeRamtoStringBuffer() {
  int sram = freeRam();
  itoa(AmtSRAM, stringBuffer, 10);
  char *idx = stringBuffer + strlen(stringBuffer);
  *idx++ = ',';
  itoa(sram, idx, 10);
  idx = stringBuffer + strlen(stringBuffer);
  *idx++ = ',';
  itoa(strlen(stringBuffer), idx, 10);
  idx = stringBuffer + strlen(stringBuffer);
  *idx++ = ',';
  itoa(strlen(additionalInfo), idx, 10);
int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);

The added AmtSRAM records are added within the writeEventHappened function:

void writeEventHappened(logRow_t event, char * additionalInfo) {
  if (event == CardInserted || event == CardRemoved) {
  File logFile = openFile();
  if (!logFile) {
  // an event has a log row type followed by date/time followed by additonal info.
  itoa(event, stringBuffer, 10);
  char *idx = stringBuffer + strlen(stringBuffer);
  *idx++ = ',';
  idx = stringBuffer + strlen(stringBuffer);
  *idx++ = ',';
  strcpy(idx, additionalInfo);

Looking at the log file:


13,459   (67 bytes)
0,3/29/2017,10:4:18,22.1, 84.0,764

13,428   (67 bytes)
0,3/29/2017,10:6:18,22.0, 82.7,1343

13,397   (31 bytes)
0,3/29/2017,10:8:18,21.9, 83.0,967

13,366    (67 bytes)
0,3/29/2017,10:10:18,21.9, 83.5,1168

13,335    (67 bytes)
0,3/29/2017,10:12:18,21.9, 83.7,1301

13,304    (31 bytes)
0,3/29/2017,10:14:18,21.8, 84.0,973

0,3/29/2017,10:16:18,21.8, 84.2,1191


The most glaring thing I notice is SRAM is lost after writing a row that has a record type that is not a sensor reading (i.e.: record type is not 0 and before writing a sensor reading.  I highlighted these occurrences above.

This is how I tracked down the overzealous / needless creation of File Instances:

void  writeSensorDataToLogFile() {
  File logFile = openFile();  
  if (!logFile) {  

The log file now looks like:

0,3/30/2017,1:2:27,18.8, 79.5,523
0,3/30/2017,1:4:27,18.8, 79.6,514
0,3/30/2017,1:6:27,18.8, 79.7,515
0,3/30/2017,1:8:28,18.7, 79.9,514
0,3/30/2017,1:10:28,18.7, 79.7,515
0,3/30/2017,1:12:28,18.7, 79.8,522

I changed the log file row types for the amount of SRAM.  AmtSRAM = record type 11.  The amount of SRAM starts out as 545 bytes prior to writing out the first record (53).  It goes down to 523 before writing out record type 10 (warmup is over).  This is a loss of 22 bytes which remains consistent.  So at this point, I’m not researching deeper.  When a relay gets switched there are some bytes that get lost.  However, these return.  The SRAM stays around 523 bytes.  This will work.  

I enjoyed working on this.  It is always fun to learn and seeing positive changes based on applying what I have learned.

The Leaf Spa Code Got Too Big for the Arduino – When Code Stops Working

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.