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.


pH/EC-983 Product Breakdown -First Post

I love watching Limor/Lady Ada take apart a Consumer Electronic device and explain to us what the chips are and what is going on.  I thought what a great learning opportunity to take something that I have some familiarity with – in this case pH and EC circuits – and find a product to take apart and figure out how the circuit works. 


The product I picked was the ph/EC-983.  I picked up a couple on eBay.


This handy tool integrates a pH and EC probe as well as gives a temperature reading.  It is inexpensive and if it is “good enough” I was thinking it would be super amazing to plunk the probe in the nutrient bath.  I would use firmware to take pH/EC measurements and use the measurements to adjust the pH and nutrients.

I was mostly interested in the bottom piece.  The bottom piece contains the pH and EC probes:

NewImage  NewImage

I was thinking if I could figure out the signals coming out of the probe:


So that I could put the probe in the nutrient bath and connect up a pH/EC circuit to be monitored through firmware.

 Hmmm…I couldn’t pry apart the device in the nice, clean way Lady Ada is able to…so…out came the Dremel!  


The Active Parts

To get started, I looked at the active parts.

These two images show the location of the parts:

Pasted Image 3 24 17 6 16 AM

Pasted Image 3 24 17 10 17 AM

HEF 4053BT

Two of the chips are the HEF 4053BT (data sheet):


From the data sheet: The HEF4053B is a triple single-pole double-throw (SPDT) analog switch, suitable for use as an analog or digital multiplexer/demultiplexer.   This page on Basic Electricity has a great discussion on switches including SPDT switches.

HEF 4011BT

Another is the HEF 4011BT (data sheet):


From the data sheet: The HEF4011B is a quad 2-input NAND gate.


Another chip is a variant on the 062C dual op amp (data sheet):

062C DualOpAmp


The internal ICL7106 (data sheet):


From the data sheet: TheICL7106 is designed to interface with a liquid crystal display(LCD)…


Unfortunately, I got a little too aggressive with the Dremel.  I’m still able to make out this chip is a HEF4030BT (data sheet):


From the data sheet: The HEF4030B is a quad 2-input EXCLUSIVE-OR gate. 

Maxim ?

Drat…the Dremel scratched the markings off this chip.  I can tell it is a Maxim and there looks to be A1601…or A1801…or…:



The SGM3005 XMS (data sheet): 


From the data sheet: The SGM3005 is a dual, low on-resistance, low voltage, bidirectional, single-pole/double-throw (SPDT) CMOS analog switch designed to operate from a single 1.8V to 5.5V power supply.

At this point, my eyes hurt.  Time to stop for now.


Adding a Flow Meter


, ,

Awhile back, the plants were not getting any water/nutrients because the pump relay stopped working.  It became clear to me after this incident that a flow meter monitoring whether the pump was working would be very beneficial to have as part of the Base section of the Leaf Spa.

This post is about incorporating the flow meter into the Leaf Spa.  

Thanks To Those That Went Before

Adafruit – Thank you for your awesome customer service.  Adafruit goes above and beyond any company I know providing sample code, tutorials, excellent forums, products I can trust to work.  Products cost a bit more…but I really want Adafruit and companies who respect their customers and employees.

The Flow Meter

I got a liquid flow meter in the mail from Adafruit yesterday.



How It Works

My goal is to detect whether water is flowing through the sensor.  I’ll do this in the firmware by figuring out if the flow rate is > 0 when the pump is supposed to be on.  I haven’t used a flow meter before so I figured I should know at least a little bit on how it works.

T.K. Hareendran’s blog post, “Working with Water Flow Sensors & Arduino”, gave me great info on the basics of how this type of flow meter works.  For example, I find out the type of sensor I bought is a YF-201 Hall-Effect Water Flow Sensor.  As pointed out in the article:  This sensor sits in line with the water line and contains a pinwheel sensor to measure how much water has moved through it. There is an integrated magnetic Hall-Effect sensor that outputs an electrical pulse with every revolution… By counting the pulses from the output of the sensor, we can easily calculate the water flow rate (in litre/hour – L/hr) using a suitable conversion formula.

I’ll be looking at the flow rate of water when the Leaf Spa firmware turns on the pump relay.  If there is no water flowing, something within the pump system (the pump itself, the relay) is not working.

As usual, Adafruit has provided superior support for the flow meter by making available a sample Arduino sketch at this GitHub location.  Getting this sketch working was easy and gave me a better feel for how the flow meter works with the Arduino.

I’ll blindly take the approach of “if you say so” based on Lady Ada’s comments in her Arduino Sketch:

  // if a plastic sensor use the following calculation
  // Sensor Frequency (Hz) = 7.5 * Q (Liters/min)
  // Liters = Q * time elapsed (seconds) / 60 (seconds/minute)
  // Liters = (Frequency (Pulses/second) / 7.5) * time elapsed (seconds) / 60
  // Liters = Pulses / (7.5 * 60)
  float liters = pulses;
  liters /= 7.5;
  liters /= 60.0;

I’m interested in the flow rate, not in how much water goes through the sensor.  Given what Lady Ada tells me about the flow rate (she’s using Q to represent the flow rate in liters/minute):

Pulses (Hz)) = 7.5 * Flow rate(liters/minute)

Flow rate (liters/minute) = Pulses (HZ)/7.5

Test Code

I’m going to use an external interrupt (the attachInterrupt() API) to let the firmware know when water is flowing through the sensor.  The test sketch that seems to work – FlowMeterTest2.ino – is located at this GitHub location.

Adding Code

Simpson DOHBut first…an OOPS…I thought it would be a “good thing” to update the SD library since I was informed I didn’t have the latest…BUT I FORGOT about what I talked about in this post about SD.end().  Here is the error I got:

Multiple libraries were found for “SD.h”
Used: /Users/margaret/Documents/Arduino/libraries/SD
Not used: /Users/margaret/Documents/Arduino/libraries/SD-master
Not used: /Applications/

seems I’m not lacking SD libraries :-).

Turns out the one being used was the library that I updated yesterday…the SD library folder within my Arduino/libraries folder.  I deleted the SD folder.  Now the firmware is back to using the SD-master library…which includes the end() API.

Bummer – attachInterupt() is only available on pins 2 and 3 on the Arduino Uno.  The firmware is already using these pins (from TheLeafSpa.ino sketch located at this gitHub location (version 8767e1d):

   2 - DHT temp/humidity
   3 - SD card detect
   4 - pump relay
   5 - LED relay
   6 - CO2 relay
   7 - Software Serial
   8 - Software Serial
   10 - SDI chip select
   11 - SDI DI pin
   12 - SDI DO pin
   13 - SDI CLK pin

The firmware is using attachInterrupt() with pin 3.  This means I’m restricted with the current hardware configuration to using pin 2 for the flow meter.

It doesn’t help that Seeed’s Grove Base Shield limits the digital i/o pins further:

I’m changing the pin mappings:

   2 - Flow Meter
   3 - SD card detect
   4 - DHT temp/humidity
   5 - LED relay
   6 - CO2 relay
   7 - Software Serial
   8 - Software Serial
   9 - Pump relay
   10 - SDI chip select
   11 - SDI DI pin
   12 - SDI DO pin
   13 - SDI CLK pin
  • DHT is on pin 4 instead of pin 2.
  • pump relay is on pin 9 instead of pin 4.
  • Flow meter is on pin 2.

 Adding the Flow Meter

It took a bit of emotional effort to cut into the plumbing and insert the flow meter..but it’s done…before and after:

NewImage   NewImage 

Checking the Log File

 Below are two snippets of the log file after adding the flow meter:

1 3/22/2017 11:40:28          
0 3/22/2017 11:41:28 23.5 71.5 1097    
5 3/22/2017 11:41:28          
2 3/22/2017 11:41:28 167.33        


1 3/22/2017 11:55:28          
0 3/22/2017 11:55:29 24.3 70.2 1113    
5 3/22/2017 11:55:29          
6 3/22/2017 11:55:37          
2 3/22/2017 11:56:28 175.33        

1 in the first column means the pump has turned on. 2 means the pump turned off.  The row identifying the pump was turned off now includes a column with the flow rate in liters/minute.  Both are > 0 which means water has gone through the plumbing.  YIPPEE!  The first flow rate shows 167 liters/minute (~44 gallons/minute).  The second shows 175 liters/minute (~46 gallons/minute).

The pump’s data sheet (I am using the 160 GPH model) states the model I am using has a min GPH of 106 and a max of 175.

I measured a WAY HIGHER value…SO…hmmm…

The values for the flow rate ARE NOT ACCURATE however, the Leaf Spa is detecting whether the water is flowing.

So, for what I need it to do, the flow meter is doing ok.  At this point, I do not need the flow rate.  If I did, I would debug this further.

Good better best  Of course, measuring the flow rate as accurately as possible should be part of the Leaf Spa.  But since my goal at this point is to detect water flow, I will not debug now.  Future builds should accurately measure water flow.  Frankly, I am not surprised measurements are off.  I did not do any flow rate accuracy testing before putting the flow meter in.


ChallengesBringOpportunites Yippee!  The flow meter is in place.

Adding a Fan to the Left Side

Customer Check-In

The images show the improved (I hope!) left side with the second fan mounted as well as the plants/fan on the right side:



The right side of the Leaf Spa has a mounted fan blowing air down on the leaves:


None of the plants look stressed.  However, the left side of the Leaf Spa does not.  The Stevia Leaves curl up:


I’m exploring if this leaf stress is caused by the air temperature being too high.  I just turned down the light intensity.  Turning down the light intensity will lower the air temperature a bit.  

In this post I’m focusing on designing and 3D printing a fan  mount that will be attached on the left side of the Grow Chamber.  This way, the left side will be more balanced to the right in terms of air temperature and access to CO2.  I’ll be including a hole for a CO2 tube.  I plan to split the CO2 tubing so that both the left and right side will receive CO2 when the CO2 valve is turned on.  

The Fan Mount

I’ll start with the Fusion 360 model I made – and am using – for the right fan mount.  I will modify the model such that the bolt mounts go through the plastic and attach to the LED Shelf with a nut.  This way, the plastic doesn’t have to handle screw/bolt threading – a weakness on the right Fan mount.


Now that I have the fan mount 3D printed, it’s time to wire up power in a way that both fans share the 12V power supply.


 I put connectors on wires going between the Grow Chamber and the Base because I have this new idea to bling out the Leaf Spa so that I can wheel it outside during the summer.

One improvement down…many more to most likely come!