Backyard Automatic Watering using a Feather/Arduino

An Arduino project that automatically waters plants has been done many times.  This summer I finally decided to tackle on my own.  I’m writing up my first attempt at this project in two posts:

  • wirelessly connecting moisture readings from a spot in my garden. (This post)
  • automatically watering areas in the garden based on the moisture readings.
I say first attempt, because as I finish up this attempt I can see several areas where improvements can be made.  I mean, whoa.  I had no idea what the difference between measurements using two galvanized nails versus a sensor used by horticultural researchers….and if the idea is only for watering my backyard vegetables and not a cash crop – how much do I care?   So…what is the best my auto watering solution needs to be?

The Goal

The goals of this post are to:

  • build a moisture sensor gizmo that collects info on the moisture of the dirt it is stuck in and sends it to a receiver hooked up to my Mac.
  • build a receiver that reads the info sent by the moisture sensor gizmo and displays the info on my Mac.
  • identify improvements for the second prototype.

Thanks To Those That Went Before

  • Felix Rusu (lowpowerlab.com)  for his work on the Moteino.  The Moteino is an open hardware Arduino + RFM69HW radio  development board very similar in concept to Adafruit’s Feather series.  In fact, it is Felix’s RFM69xx library that Adafruit – and hence most of us – use within the Arduino IDE to talked with the radio. 
  • Thanks to Adafruit for great development board products like the Feather series.  Adafruit’s support is excellent.  I had a challenge with using a serial port with the feather (see below).  Thanks to Mike in Adafruit support, not only was my issue quickly fixed, but I learned stuff about the micro controller used by the Feather that I hadn’t realized.  THANK YOU MIKE.  I also want to thank Tony DiCola for removing any complexity in using the Watchdog timer by writing Adafruit’s Sleepy Dog library.  THANK YOU TONY.

Open Source

The Arduino and Fusion 360 files are available at this GitHub location.

The Stuff

The stuff I will build for this project include:

TX Box

This is what I’ll be calling the enclosure and the stuff inside that sends moisture readings.  The TX Box includes:

  • Moisture Sensor:  At the risk of stating the obvious, the role of the moisture sensor is to tell the electronics how moist the soil is.  So I ask myself, what probe should I use?  The more I learn about growing healthy plants aided with technology, the more respect I am gaining for the quality of the probes used.  At this point, it is not clear to me if two galvanized nails are good enough – or the accuracy/reliability obtained by using these sensors (particularly the EC5 and/or the 10HS) used by researchers  are required.  POSSIBLE SECOND PROTOTYPE IMPROVEMENT: explore the benefit of a more accurate/reliable sensor.  For this prototype, I am using these inexpensive moisture sensors being sold on eBay

The moisture sensor has three clearly marked pins, one for GND, VCC, and data.  The instructions consist of a sentence on the eBay page: Output voltage :0-2.3 V [2.3V is completely immersed in water] voltage, 5V power supply, humidity, the greater the output voltage increases.

  • A Lithium Ion Battery.  I don’t have active electrical plugs within reach of all areas of our backyard.  This leads me to choosing either solar or battery power.  I felt using a battery would be the simplest solution.  I wanted to recharge rather than replace the battery and I wanted the battery to power the remote measuring sensor for as long as possible.  For these reasons, I chose a lithium ion battery.  POSSIBLE SECOND PROTOTYPE IMPROVEMENT: Determine if solar power will work “better” if it does, replace battery power with solar power.

  • Adafruit’s Feather 32u4 with RFM69HCW:  YIPPEE! for this development board.  It dramatically speeds up how much time it takes to complete this prototype.  Besides having a small and light form factor, it is compatible with the Arduino IDE and Arduino’s pin outs.  It integrates in the terrific RFM69HCW radio that I have played with before – a great solution for home automation tasks that are not suitable for bluetooth or wifi.  A battery connector supports me plugging in a LiPo Battery and there is a micro usb port for communicating with the Arduino IDE.  If that wasn’t enough – like all the other Adafruit development boards – there are a wealth of libraries and documentation.  Add Adafruit’s excellent support, and the price is a bargain over what I’d have to do to bumble my way through putting the chips together.  Perhaps if I get serious about a final future build I might think it worthwhile to design my own PCB.  But for prototyping?  Like I said – YIPPEE!!!!!

 

  • Waterproof enclosure:  Designed in Fusion 360 and printed on my 3D printer. Here’s some images of the enclosure:

                          

I’m not going to detail the design or printing.  I will however point out some of the “best practices” I am evolving in my knowledge and practice of 3D printing design and print:

    • Have a realistic model for each component. By realistic, I mean not just the dimension of the object in the physical space, but also any room needed for placement on the side or cables, which is the case for the LiPo battery.  The simple models I made were based on measurements I made with my caliper.  When I relied on parameters I measured without a realistic model, I ended up having to reprint/adjust much more often. 

FeatherFusion360ModelMoistureSensorFusion360Model LiPoBatteryFusion360Model

 I found the Fusion 360 model for the Feather here.

    • Given the enclosure is going to be placed outdoors within an irrigation system, minimize any openings.  Now, this sounds obvious.  Yet my original design had an opening for the micro-USB port.  I ended up with two slits for the moisture sensor.  Hmmm… come to think of it, including the moisture probe inside the box is not the best idea.  Much better would be to have small holes for about 22 AWG wire that goes between the enclosure and the moisture probe.  POSSIBLE SECOND PROTOTYPE IMPROVEMENT:  Move the probe to outside the enclosure.  This way, the moisture sensor can be as close to where measuring takes place.  Whereas the box containing the feather and battery can be placed at a close by location.  Notice in the third picture on the right of the enclosure pictures that I ended up placing the enclosure into a ziplock bag and taped it up with waterproof tape.  I also put silicone around the area where the prongs went through the slits within the enclosure.

Receiving Station

When I evolve the prototype to include automatic watering, the receiving station will morph into something similar to the TX box only for receiving the packets from the TX box(es), deciding whether watering is needed, and turning the water hose on/off.  This stuff is reserved for the next stage of this prototype.  Until then, the receiving station is simply:

Arduino Code

A Gotcha – Using Serial Ports

I had no previous experience using a 32u4 based board with the Arduino IDE.  “Those that went before” know there is a hardware difference between the Arduino Uno and the Feather that “bit” me is in the handling of serial ports.  Buried a bit in Adafruit’s documentation is this info gem: “…UNO-type Arduinos have a seperate serial port chip (aka “FTDI chip” or “Prolific PL2303” etc etc) which handles all serial port capability seperately than the main chip. This way if the main chip fails, you can always use the COM port. M0 and 32u4-based Arduinos do not have a seperate chip, instead the main processor performs this task for you. It allows for a lower cost, higher power setup…but requires a little more effort since you will need to ‘kick’ into the bootloader manually once in a while.”

Manually restarting the boot loader is one of the behavioral differences discussed in Adafruit’s documentation .

The other is when the Serial port becomes available.  I wasn’t able to get Serial.print()’s in Setup() until Mike in Adafruit support pointed out:

———————————-

Are you using:

CODE: SELECT ALL | TOGGLE FULL SIZE
while ( ! Serial ) { delay( 10 ); }

before you call Serial.begin()?
That will make the code wait until the USB registration has finished before trying to print anything.

———————-

This race condition is noted in the if(Serial) Arduino documentation.  Looking back, I should have looked into why the examples that used the Serial functions started in setup() with while (!Serial);  instead of deleting because I didn’t have an understanding why it was there.  A D’OH moment on my part.

The Data Sent

The values to be passed from the TX box to the Receiving Station are stored within the valuesStruct_t structure.  A union data type is then used to map the value view to a string of bytes view.  The string of bytes is then sent to the Receiving Station where the bytes are picked up and then mapped back to values.  The values include:

//……………………..

// Define a struct to hold the values
//……………………..
struct valuesStruct_t
{
uint8_t firmware_version;
unsigned int reading_number;
float battery_level;
int moisture_reading;
unsigned int sleepMS;
};
//……………………..
// Define a union type to map from the struct to a byte buffer
//……………………..
union txUnion_t
{
valuesStruct_t values;
uint8_t b[sizeof(valuesStruct_t)];
};

  • Firmware Version: This is currently set to 1.  The value of the Firmware Version is used by the Receiving Station to figure out if it understands the valueStruct_t structure.
  • Reading Number: The Reading Number increments each time the data is sent.  This way I can have an idea if data has been dropped as well as how many packets have been sent.  The data type is an unsigned int.  As noted in the Arduino Reference under Coding Tip: “When variables are made to exceed their maximum capacity they “roll over” back to their minimum capacity…”
  • Battery Level: The battery level lets me know how fast the battery is being used up and when I need to recharge it.  Adafruit provides the circuitry and code to easily report on the battery level.  From Adafruit’s documentation under Measuring Battery:  “Lipoly batteries are ‘maxed out’ at 4.2V and stick around 3.7V for much of the battery life, then slowly sink down to 3.2V or so before the protection circuitry cuts it off. By measuring the voltage you can quickly tell when you’re heading below 3.7V.
  • Moisture Reading: This is the reading from the moisture sensor read from one of the Feather’s ADC ports.
  • Sleep (in milliseconds): The amount of time between readings.

The Data Received

The data received is the same as the data sent.  Two additional pieces of info are used that come from the RFM69CHW firmware:

  • RSSI: To get an idea how how strong the signal is between the TX box and the Receiving Station.
  • The Node ID:  In order for a Receiver to know which RFM69* radio sent a packet, a Node ID is sent with the data packet.  In the Receiving Station’s Arduino sketch, the Node ID is set using #define NODEID 2.  In the evolved experience where there are three or more TX boxes, the Receiver will need to know which TX box sent the packet in order to identify where to irrigate.

Power Management

 The experience scatters one or more rechargeable batteries around my garden.  I want to minimize the time between having to recharge the battery (or batteries).  Stuff I want to optimize to meet this goal include:

  • Minimizing the amount of power used by the Feather.
  • Minimizing the power used by the RFM69CHW radio when sending data packets.
  • Minimizing the number of data packets that are sent.

Minimize Power Used By the Feather

Leave it to Adafruit’s document and SleepyDog library to make it easy for me to minimize the power the micro controller gobbles up. Instead of using delay(), the SleepyDog library uses the watchdog timer.  Adafruit’s Feather documentation under Radio Power Drawdoes a great job showing how power use is minimized using the watchdog timer.

int time_Between_Readings_in_ms;

void loop() {
// Since the watchdog timer maxes out at 8 seconds….
int number_of_sleeper_loops = 4; //time between taking a reading is 4 * 8 seconds = 32 seconds.
for (int i = 0; i < number_of_sleeper_loops; i++) {
time_Between_Readings_in_ms = Watchdog.sleep(8000);
}
transmitReadings(time_Between_Readings_in_ms*number_of_sleeper_loops);
}

The watchdog timer’s max amount of sleep time is 8 seconds. If you set the time between readings to be  >8000 and <= 32767 (the maximum positive value for an int), the watchdog timer is set to 8 seconds. If you set the time between readings to be >8000 and <= 32767 (the maximum positive value for an int), the watchdog timer is set to 8 seconds.  A negative signed int will set the watchdog timer to 15ms.

Minimize Power Used By the Radio

You Are Getting Sleepy….

When transmitting the packet within the transmitReadings() function, I make a call to radio.sleep().

if (radio.sendWithRetry(RECEIVER, txData.b, sizeof(txUnion_t))) {
radio.sleep();
}

As noted in Adafruit’s Feather documentation under Radio Power Draw :  “If you put the radio to sleep after transmitting, rather than just sitting in receive mode, you can save more current, after transmit is complete, the average current drops to ~10mA which is just for the micro controller.

The Power Level

This line in the sketch:

 radio.setPowerLevel(31);

where the number (in this case 31) sets the amount of power used for transmission between 5 and 20 dBm.  The value for the power level can be from 0 – 31.  The amount of power increments in steps of 1 dBM.  So for example radio.setPowerLevel(1) = 6 dBm.  If that is the case, I was wondering why values go from 0 – 31 instead of 0 – 15 since radio.setPowerLevel(15) = 20 dBm.

I’m assuming (note: I haven’t validated) the reason given in this post is correct: “…the rfm69hw puts increments power in one db steps from power settings 0 to 15, then starts over at 16 and increments up again from 16 to 31.”

I tried a variety of tests where the radio of the TX box was set at a variety of power levels and determined given the distance, I needed to leave the power level at the highest setting.

Minimize Number of Data Packets

For this prototype, the only thing I am doing to limit the number of data packets sent is to send at a period of 32 seconds (instead – for example – every time through the loop() ).  POSSIBLE SECOND PROTOTYPE IMPROVEMENT: Send a packet only upon request of the Receiving Station.  There is no point to sending packets unless the TX box is asked for an update since the intent is to take action and water (or not) depending on the moisture sensor reading(s). 

Running the Code

ßHere is an image of an example run:

 A moisture reading in the 500’s means the soil does not need watering.  But more on making a decision based on readings in the next post.

Second Prototype Improvements

I’ll collect all the improvements I noted above to be considered for an evolved prototype:

  • Explore the benefit of a more accurate/reliable sensor.
  • Determine if solar power will work “better” if it does, replace battery power with solar power.
  • Move the probe to outside the enclosure.
  • Send a packet only upon request of the Receiving Station.
 
 
 
 
 

Thanks for reading this far.  Please find many things to smile about.

Building an LED Grow Lamp – Let There Be Light

I recently finished building a one plant hydro planter (prototype) that includes a built-in air pump and an LED light.  My plan is to write some posts documenting what I learned about building an LED lamp in the process.  The posts I plan to write include:

  • Stuff about the quality of light I need to know in order to choose the LEDs. (This post)
  • Stuff about the quantity of light I need to know.
  • Design of the prototype LED grow lamp including LED chip choice and other implementation implications.
  • Testing the prototype planter by tracking the growth of a basil plant from seed to making pesto.

The Goal

The goal of this post is to get a strong feel for how what light quality means to plants and how that affects the choice of LEDs.  Specifically, gain a firm understanding of the two light enabled processes:  photosynthesis and photomorphogenesis.  Up until this point, I had a fair knowledge about how plants use light for photosynthesis.  However, I didn’t know much about photomorphogenesis.  Folks had kindly (and slowly) tried to explain photomorphogenesis to me…but…the explanations just didn’t stick.  I continued to attribute stuff that happened because of photomorphogenesis to photosynthesis.  Besides, there are a lot of syllables in the word photomorphogenesis.  All those syllables made me think photomorphogenesis was intimidating as a concept to grasp.  If it wasn’t, then wouldn’t it have a more approachable/friendly name?  Most likely many of you are wondering (perhaps in disbelief?) how I could be so challenged in grasping what you consider simple concepts.  If that is the case, this post is a waste of your time!

Thanks to Those That Went Before

I just finished the “Greenhouse and Horticultural Lighting Summer 2016” extension course offered by Michigan State University.  I will be used the knowledge about LED lighting for plants that I learned in the course to build the LED lamp.  THANK YOU to Heidi Wollaege – our teacher.  The content, Heidi’s delivery, and her exceptional answers to my questions made the course well worth the price.

Lighting for Plant Growth (for Dummies Like Me)

Without light, no plants.  Without basil, no pesto.  As I mentioned earlier, the two light processes I needed to have a firm grasp of where light quality is important are photosynthesis and photomorphogenesis.  

But what is light quality?

Light Quality

As noted in Dr. Erik Runkle’s article Light Quality Defined: “…light quality refers to the spectral distribution of light, or the number of photons of blue, green, red, far red and other portions of the light spectrum emitted from a light source.”

now onto two key light enabled processes that go on in a plant – photosynthesis and photomorphogenesis.

Photosynthesis

I thought this video – Williams Basics Plant Growth Development 4A  1 – does a great job in simply explaining photosynthesis.  Before I found this video, I wrote out my findings on what photosynthesis is.  Like I’ve said before, writing stuff out helps me know what I don’t know.

Since I appreciate stuff like Ohm’s law to simply explain important electronics concepts, I’m starting with the equation that simply explains photosynthesis:

I liked this description:  Chemically speaking, the inputs to photosynthesis are six carbon atoms, 12 hydrogen atoms and 18 oxygen atoms. Glucose uses six carbon, 12 hydrogen, and six oxygen molecules. Simple math shows 12 leftover oxygen atoms, or six oxygen molecules. Interestingly, and not coincidentally, the process of respiration breaks apart the glucose molecule. Respiration occurs in the cells of nearly all living things…” …respiration releases the energy the plant uses to grow.

Photons are absorbed by the plant leaves through the green pigment – chlorophyll.  

Carbon dioxide enters the plant through the stomata (which are on the “underbelly” side of a leaf). 

Water comes into the plant through a plant’s roots.

and there it is..easy schmeazy.

Most Efficient for Photosynthesis

Since chlorophyll is the molecule that absorbs photons,

 Microscopic Image of Chlorophyll

 the most efficient LED color wavelengths for photosynthesis are red and blue.  Dr. Runkle’s article, “Light Wavebands & Their Effects on Plants” provided a nice summary:

  • “…Blue light (400 to 500 nm)… Chlorophyll in plants highly absorbs blue light that is used for photosynthesis.  It also helps regulate the opening of stomata, which are tiny openings in the leaves that regulate the uptake of carbon dioxide…”
  • “…Green light (500 to 600 nm)…Plants appear green because they reflect and transmit slightly more green light than they do blue or red light…. generally, green light is less efficient at stimulating photosynthesis than blue or red light…
  • …Red light (600 to 700 nm)… Most LED arrays  [for plant growth] emit a high percentage (often 75-90 percent) of red light because it is absorbed well by chlorophyll, and the electrical efficiency of red LEDs is high.    

 Notice under the rationale for red light the mention of electrical efficiency.  Looking at a graph from Cree’s XP-E2 data sheet:

voltageDropAcrossRedLED

the voltage needed to power red LEDs is much less than the voltage needed to power blue or green LEDs.  Since P=IV, the cost of electricity (e.g.: in KW/hour) will be less if there is more red LEDs than blue (or green).

Besides photosynthesis, research has shown red and blue wavelengths of light have a big effect on photomorphogenesis.

Photomorphogenesis 

Now this just plain out amazes me…plants have light sensors.  Who knew?  Not me…So many times I have built some sort of prototype that uses a light sensor like this one:

PhotoResistorLightSensor

I use it to detect simple stuff.  Like how light or dark the light sensor thinks it is.  Here is link to an Instructable that gives an example of an Arduino project that uses this type of simple light sensor.

Plants use of their much more sophisticated light sensors to – as explained in this article to “…manipulate the shape and characteristics of a plant, such as leaf size, branching, and stem length.”  Saying the same thing in a slightly different way, plants use light sensors to detect the light conditions under which they are growing.  The plants use the readings they get from the light sensors to manipulate their size and shape. By manipulating size and shape, the plant can optimize for the light conditions it finds it self under.

Light Sensors Are Detecting Red and Blue Light

Phytochrome and cryptochrome are the pigments found in a plant acting as light sensors.  Phytochrome detects red (and far-red) light.  Cryptochrome detects blue light.  It makes sense there is a close relationship between optimizing the plant’s shape to the light source since light is providing a necessary ingredient to make food.  For more info on these pigments, I found this article interesting.

The Ratio of Blue to Red Light

Given a bunch of LEDs mounted on a PCB, what percentage should be red and what percentage should be blue? The stuff about photosynthesis and photomorphogenesis prepares me to make an informed (first) attempt at setting this percentage.  The factors I use in deciding the percentage include:

  • Red light is more efficient for both photosynthesis and photomorphogenesis
    • photomorphogenesis: from this abstract: “Plants with as little as 10 µmol·m−2·s−1 of B(blue) light were 23% to 50% shorter and had 17% to 50% smaller leaves than plants under only R(red) light.”
    • photosynthesis: Back to  Dr. Runkle’s article, “Light Wavebands & Their Effects on Plants”: “Most LED arrays emit ahigh percentage (often 75-90 percent) of red light because it is absorbed well by chlorophyll”
  • Red light takes less electricity than blue light.  
  • Blue light will help keep the plant stocky.
    • Heidi  Wollaeger – our teacher for Michigan State’s lighting course and co-author of the peer-reviewed article “Growth and acclimation of impatiens, salvia, petunia, and tomato seedlings to blue and red light.”  pointed out to me in an email exchange: “…in a sole-source environment (no sunlight), blue light activates cryptochrome (a photoreceptor in plants) which triggers a change in hormones in the plant which results in reduced stem extension and leaf expansion. You will see that 100% R light (without sunlight) leads to the most elongated plants with the largest leaves. A minimum of 10% B inhibits that excessive stem extension and leaf expansion. What is “ideal” is all a matter of perspective. If you (are) an ornamental plant plug producer and want small compact rooted plants – you will want some B or green in the spectrum. If you a basil grower indoors, you would want those large leaves and might want to have a 100% R.

Blue to Red Ratio for the Prototype

Given I will be growing basil, I will go with 100% Red LEDs

What I’ve Learned After Writing this Post

  • I have a much better feel for photosynthesis and photomorphogenesis.
  • I understand what light quality is.
  • I understand the importance of red and blue light to photosynthesis and photomorphogenesis.
  • I have made an informed choice on the Blue:Red ratio – 0:100 – for prototyping growing basil.

What’s Next

Now that I have a better feel for light quality (the Blue:Red ratio and what it means for photosynthesis and photomorphogenesis), I need a better understanding of light quantity.  Then onto design and implementation of the LED portion of the planter.

 

 

Thanks for reading this far.  Please find many things to smile about.

Black Spots on Basil

Tags

,

One of last week’s topic in the UF’s GreenHouse 101 was discovery and identification of plant diseases.  The teachers asked us to explore diseases in the plants we are growing.  I am growing basil.   I love basil.  I put it liberally on my salads, pizza, red sauces…. To meet my cravings, I try to grow as much basil as I can outside starting in early summer months.  

Sadly, one of my basil plants is sick.

The Goal

The goal of this post is to discuss a disease I am seeing on one of the basil plants.  I’ll start with observations and finish with a diagnosis.

Observation

Here is a picture of the sick basil plant:

basil in container

Here is the front of the leaf:

basil Front Leaf

the area around the dark spots has a wax-like “look and feel.”

…and the  back:

BasilBottomLeafwhen I first saw this picture of the back, I thought pests might be involved.  However, on closer inspection with a 10x magnifier, the areas that looked like there might be a webbing or small pest turned out to be dirt and/or dust.

Diagnosis

The black spots are most likely due to either a bacteria or fungi.  Within the section on Plant Health (week 4) of the Greenhouse 101 course, the teacher (Brian J. Pearson) noted fungi on plants is typically dry whereas bacteria is typically waxy.  In this case, the black spots and area around had a waxy feel.  This leads me to believe the black spots are do to a bacteria infecting the plant.  While there are many posts on the Internet that discuss black spots, I found this post to help me.  This diagnosis makes sense not just because observations appear similar to images provided for black spots on plants that are infected with a fungi or bacteria, but also because it most often occurs in late Spring/early Summer when the plant leaves stay wet longer than they should.  We live in the Pacific Northwest of the US where it rains quite a bit during this period.  

The class material on diseases pointed out those based on bacteria or fungi will find it’s way to other plants since wind, rain, insects… will transmit the bacteria/fungi to other plants.  At this point, this was the only affected plant.  

Fix

Not every leaf had the black spots.  I removed those that did from the basil plant, leaving the healthy looking leaves alone.  For now I’ll keep an eye out for other plants that start showing black spots.  If the disease continues, I’ll consider a treatment such as a fungicide.  If that doesn’t work, I’ll assume the soil is contaminated with the disease and will remove the soil where the plants were growing that had leaves with black spots.  I also sterilized the scissors I used to clip off the infected leaves.

 

 

 

Ah yes.  Not a very exciting or technical post.  For me – fascinating and exciting to evolve my understanding of plant disease debugging as part of my seemingly endless effort to grow healthy vegetables and herbs.

 

Thanks for reading this far.  Please find many things to smile about.

Making a PAR and DLI Meter Using an Arduino

Tags

, , ,

I’ve been gratefully enjoying the online Greenhouse 101 course offered by the University of Florida.  This course inspired me to start measuring the Daily Light Integral (DLI) my plants receive.  To do this, I made a PAR (Photosynthetically Active Radiation) and DLI meter using an Arduino Uno, SD Shield, PAR sensor, and LCD.  I used a Fusion 360 to design and 3D printer to make an enclosure.

The Goal

The goal of this post is to describe the PAR and DLI meter that I made.

Thanks to Those That Went Before

Adafruit: I am a fan of Adafruit’s business model.  While their products typically list more than comparable products, Adafruit’s service to the maker community is worth the extra cost.  Often Adafruit’s learning site is the first place I go to when I want to figure out how a sensor or other hardware breakout board works.  The forums are active and include very knowledgable Adafruit employees who tirelessly answer questions from both the first timer to the expert.  Using Adafruit’s libraries and following along with the learning section makes it extremely easy to integrate logging.  Noe’s layer-by-layer series has been a great aid in learning how to make enclosures in Fusion 360.  In particular, I found this video very helpful for this project.  Thank you!

Apogee: I used the SQ-225 PAR sensor from Apogee.  Thank you for making this quality product.  My challenge was the cost at $205 for the PAR sensor.  I probably wouldn’t mind this as much if there was consulting or other service/support included.  

Autodesk: It took me about 6 weeks before I felt fluent enough to make the enclosure in Fusion 360.  Thank goodness for Autodesk’s excellent videos and forums!  I am incredibly grateful for how much more – and how easily – learning can be with good content and an enthusiastic community from the Internet.  Also, Kevin Schneider’s incredibly detailed Fusion 360 model of the Arduino Uno saved me a lot of time. 

MAKEiT: I bought the MAKEiT-PRO 3D printer.  They are located on the west coast of the US which I prefer since I am also located on the west coast of the US.  While on the expensive end, I am ecstatic  with the service/support I have gotten from Russell Singer (director of design and development).  Russell’s insights into 3D design and printer settings to optimize a 3D print more than make up for the extra $$ the printer cost.  Russell has been exceptionally responsive.  His advice constantly brings my 3D printing knowledge and ability leaps forward.  I also like the MAKEiT-PRO because it feels solid and I can dynamically change print settings as the print evolves.  There seem to be a gazillion different 3D printers to choose from.  I don’t have experience with any other printer to compare.  Russell – THANK YOU.  I am very grateful for the encouragement and insight you have shown.  You “know your stuff.”

University of Florida:  As I briefly noted in the intro to this post, I am taking the Greenhouse 101 course from UF.  It has been an incredibly enriching targeted knowledge us students are getting on the effect and control of factors (e.g.: temperature, light, CO2, PGR…) that shape the health of a plant.  Thank you for offering this course.  The instructors have been excellent.  The explanations are easy to follow.  I wish there was more discussion.  However, that has picked up recently.

Open Source

The Arduino sketch, Fusion 360 archive, and a PAR.CSV file with a test run logging data is located at this GitHub location. 

The PAR and DLI meter

I will make and use of this PAR and DLI meter I cobbled together:

                                   

Because…

I am practicing growing vegetables and herbs hydroponically indoors.  As is commonly known, plants need light for photosynthesis.  

Photosynthesis – light depended reaction

However, not all visible light waves are absorbed by a plant’s leaves.  The wavelengths of light used for photosynthesis is termed the Photosynthetically Active Radiation (PAR). Since I am growing inside with very little light coming from the sun, I need to figure out how much PAR to give a plant within each 24 hour period.  A sum of the total amount of PAR that a plant receives within a period of time is termed it’s Daily Light Integral (DLI).  

For this simple prototype, there are no buttons or other ways to input any settings.  Settings are within the Arduino sketch.  The PAR meter then merrily takes a PAR reading at the time interval I set in the Arduino sketch and then writes the reading as a CSV row into a PAR.CSV file on the SD card.

I’ll start with a brief discussion of the materials I used. 

Materials

I was happy to be able to reuse these that had been part of previous projects:

  • Arduino Uno
  • SD Data Shield
  • PAR sensor – I am using the SQ-225 from Apogee Instruments.  I got it in March, 2014 and hadn’t really used it.  I paid a whopping $205 + $6.67 = $211.67 for the SQ-225.  I say whopping because I bet the actual material is sub $50.  My thoughts on why the cost is so high is because there is a lot that goes into R&D, building the units (e.g.: each unit must be calibrated), service, and support.  Also, it seems most purchases of PAR meters are from institutions – academia and large greenhouses – where the cost is more easily absorbed than for hobbyists. There are challenges with the SQ-225 which include the sensor can only be used for indoor lighting and – I didn’t realize this until recently – as noted in this article, “...Apogee quantum sensors and meters for electric lighting are calibrated in a custom chamber filled with T5 cool white fluorescent lamps. LEDs have a very different spectral output than T5 lamps…

            (Image above) 

T5 cool white fluorescent spectrum (lamp used by Apogee for electric light calibration of quantum meters; black line) compared to broadband white LEDs (cool white fluorescent – blue line, neutral white fluorescent – green line, warm white fluorescent – red line) and defined quantum response (gray line).

        Unfortunately, this leads to less than accurate PAR readings:

LED

Electric Calibration Error [%]

Blue (448 nm peak, 10 nm FWHM)

-10.7

Green (524 nm peak, 15 nm FWHM)

5.8

Red (635 nm peak, 10 nm FWHM)

4.7

Cool White

-4.2

Neutral White

-6.1

Warm White

-9.9

Red, Blue Mixture

2.7

Red, Green, Blue Mixture

3.5

 

Here I am then…using the SQ-225 that cost me a significant amount of money.  If I were buying one today, I’d take a serious look at the NEW! IMPROVED!  SQ-520.  While this baby would set me back an even more whopping $345, it handles reading both LED and outside PAR values and includes the ability to data log PAR values and calculate the DLI.   Sadly, this sensor may not work since moving forward I would rather attach the PAR sensor to a PCB I designed that uses an inexpensive micro controller (like the FRDM-KL25Z).

I was going to include a battery however decided to simplify this initial build and provide power through the power sources supported by the Arduino Uno (i.e.: USB or wall wart).

Enclosure 

For some reason, a few months ago I got inspired to make 3D printed “stuff.”  Since then, I have been enthusiastically 3D printing on a MAKEiT-Pro printer I bought from MatterHackers.  I used Fusion 360 to make a 3D model and the MAKEiT-PRO printer to print out an enclosure for the PAR/DLI meter.

Assembling the Electronics

Assembling the Arduino, SD Data shield, PAR sensor, and LCD was easy since I had used each of these components within other projects.  The SD Shield sits on top of the Arduino:

 

Wiring

The wiring is hooked up to the power and analog pins that are exposed on the SD shield.

Pasted Image 6 17 16 5 15 AM

  • I used the info on this page to wire up the Funduino ICM1602 LCD.  There are 4 wires – Brown (GND), Red (Power), white(SDA, A5 pin) black (SCL, A4 pin).
  • As noted in the guide for the Apogee SQ-225there are three wires.  The power colors are not the standard red (positive), black (GND) I expected.  White is positive power, clear is GND, and green is hooked up to A3 to get the sensor readings.  The wires are very thin so I ended up soldering wires I usually use to hook up sensors to an Arduino.
  • I used Adafruit’s SD shield for logging PAR values.  

The Enclosure

(TBD: Mention PLA use) The Fusion 360 files I used are available at this GitHub location.  A valuable lesson I learned was to model the components first, then base the enclosure around the models.  Prior to doing this, I was spending A LOT of time printing the enclosure fixing measurements, then reprinting.  Paying more attention to detail on the measurements of the Arduino Uno, SD Shield, LCD significantly lessoned the number of prints I needed to do.  

Components in Fusion 360

  • Arduino Uno – Kevin Schneider has made a remarkably detailed Fusion 360 model of the Arduino Uno.
  • SD Shield – I copied the Arduino Uno files as another component and modified to the shape of the SD Card.
  • LCD – I carefully (well, as carefully as I could) the measurements with a digital caliper.
The steps I took are similar to those taken by Noe in his 3D enclosure printing video available from Adafruit.

Fittings

My goal was to stay away from using screws.  The biggest challenge was getting the Arduino to play nicely with the mount holes I had printed.

Pasted Image 6 18 16 6 02 AM

Bottom part of enclosure as viewed in Fusion 360

The tap posts broke off when putting the Arduino into the enclosure.  

Pasted Image 6 18 16 12 06 PM

 

As noted in the Arduino dimensions diagram:

 “All Arduino mounting holes are 3.2mm…”  3.2mm diameter posts are not thick enough for 3D printing.  I ended up adding a piece of plastic that acted as a wedge between the Arduino / SD shield and the inner edge of the bottom enclosure.

For my next enclosure, I’ll use these plastic spacers I ordered from eBay.

Fitting the LCD into the case proved to be easier than I thought it would be.  The rectangle measured for the LCD display was snug to the point the LCD stayed within the top of the enclosure.  Even though the LCD fit, when I do a future enclosure I’d like to have a stronger bind between the top of the enclosure and the LCD.  The LCD’s PCB does have mounting holes which I attempted to use.  However, the taps broke off (as they did for the taps on the bottom part of the enclosure).

The Arduino Sketch

The Arduino sketch is available from this GitHub location.  I’m assuming the sketch is self explanatory.  There are two times the PAR value is read: 1) every time through the loop in order to update the LCD 2) after logging_interval_in_ms milliseconds.  For testing, I set the interval to every 30 seconds.  In use, I set the the time interval to 15 minutes.  While the LCD updates every time through the loop, the date, time, PAR value is written in CSV format to the PAR.CSV file every time period.

Test

The test PAR.CSV is available from this GitHub location.  While I realize the SQ-225 par sensor that I have is for indoor lighting, I tested the light coming in from a sky window above my desk.

                

 I was interested to see the variability in PAR values – even if the readings were off because the SQ-225 is not calibrated for sunlight –  at given time of day.  After capturing the values into PAR.CSV on the SD card, I uploaded PAR.CSV to a Google doc file. 

 

 Initial readings in PAR.CSV  

The day was sunny with clouds.  I noted when the clouds covered the sun the PAR value would significantly decrease as it did at 1:47:14 PM.  As the sun went down, the PAR value dropped to 0.The PAR meter took samples from 1:43:40 June 15th until 5:21:32 AM June 16th, for a duration of 15 hours, 37 minutes and 52 seconds.  I used the info on this web page by Licor to calculate the DLI when readings occur every 30 seconds.

Total Time = 12 hours

∆t = 30 seconds 

∑PAR = 4646 µmol/m2 per 1/2 day (note: DLI is typically evaluated within a 24 hours (day) period.  I measured 12 hours)

DLI = 30seconds *4246µmol/m2/1,000,000 µmol/mol = .12738 mol/m2 per 1/2 day.  or ~ .255 mol per day.

I love basil.  The information in this source states: the rate of growth peaked at 500 μmol·m−2·s−1

A page on Apogee’s web site notes to calculate the DLI based on one PAR measurement, multiply the PAR value by 0.0864.

500µmol/m2s-1 = 500*0.0864mol/m2d = 43.2 mol/m2d

Even if the DLI was at the levels discussed within this paper from Purdue

 The DLI I measured was too low for the minimum acceptable quality.  I would have to augment the indoor lighting….which I plan to do with a DIY LED project.

Of course, as I noted earlier, the SQ-225 was not calibrated to measure daylight…so my measurements will carry a significant error to the point of most likely being meaningless.  With that said, I have a better feel for calculating the DLI.

So That’s That

I am very happy to improve my knowledge of growing plants while at the same time flex my maker skills.  It was extremely fun to pull out sensors and other pieces of electronics I had lying around.  I learned A LOT about 3D printing and will continue to evolve printing skills.

 

 

 

Thank you for reading this far.  Please find many things to smile about. 

 

   

 

From Kicad to Digikey -> MakeDigikeyBOM Code Review: The Python Scripts

Tags

, ,

I continue my quest to document the MakeDigikeyBOM Python package I built.

The Goal

The goal of this post is to familiarize us with the structure and purpose of the MakeDigikeyBom Python package and individual modules.

Thanks to Those That Went Before

As I noted in my previous post, I could not have gotten this far this quickly without the prior work of debvisme(xesscorp).  He is the author of Kicost – Python that “build(s) cost spreadsheet for a Kicad project.”  Kicost is well worth checking out.  The GitHub location is here.  

Open Source

The MakeDigikeyBom Python project is located at this GitHub location.

Flowchart

I am self-taught when it comes to making flowcharts.  I mention this because flowcharts I make don’t conform to a standard.  This may make them more difficult for you to read.  I apologize for that.  However, I find the method I use to work for me.

Here is the flow chart of MakeDigikeyBOM at the highest level:

NewImage

 

I have built two (well, actually three) Python files:

  • __main__.py : This is where the majority of the high level command/control happens.
  • makeDigikeyBOM.py: Takes the bom2csv and JellyBeanPartNumbers files and creates a MadeDigikeyBOM.csv file or a list of errors that must be fixed in either the bom2csv or JellyBeanPartNumbers files before the MadeDigikeyBOM.csv files can be generated.
  • __init__.py: I put this in because it identifies a bunch of Python files as a Package (at least in Eclipse).  I don’t know enough about Python to use it to an advantage.

The first thing is to gather user input.  The pieces of info include:

  • The full name of the bom2csv file.  The bom2csv file was discussed in a previous post.
  • The full name of the csv file that contains the jellybean parts.  As with the bom2csv file, the jellybean parts file was discussed in a previous post.
  • The directory path where MadeDigikeyBOM.csv will be written.
  • Currently the “num_processes” field is not used.  I got this field from the Kicost Python script and thought implementing is probably a good idea.  Having this input argument is a placeholder for a potential future feature.

 Since I run Python within the Eclipse environment, I enter arguments to MakeDigikeyBOM through the debug/run configurations.  Here are the files I used:

Pasted Image 3 14 16 5 32 AM

The code in __main__.py checks to see if the bom2csv and jelly bean parts files exist.  The script exists if either file does not exist.

If the files exist and the directory to contain MadeDigikeyBOM.csv exist, the __main__.py calls into makeDigikeyBOM() which is in the makeDigikeyBOM.py file.

That’s all there is to the high level part of the code.  

What’s Next

In the next post I’ll cover the makeDIgikeyBOM.py file.

 

 

 

 

 

From Kicad to Digikey – Start of MakeDigikeyBoM Code Review – Walk Through of Block Diagram

Tags

, ,

In my previous post, I discussed my reason for creating yet another Python script to convert Kicad schematics into a BoM spreadsheet with pricing info from Digikey.  This post is a continuation.  Since the first post I am happy to say I have gotten all the goo to work and was able to use the MadeDigikeyBOM.csv to order parts from Digikey.  So far I am excited with the results.  I find them a terrific time saver (of course, learning python and getting all this to work takes A LOT more time than doing one schematic -> BoM by hand…but YIPPEE! What a learning opportunity…and I plan for plenty more schematics.

The Goal

The goal of this post is to start a code review MakeDigikeyBoM python project.  I’ll cover the block diagram I created to represent the “big picture”.

Thanks to Those That Went Before

I could not have gotten this far this quickly without the prior work of debvisme(xesscorp).  He is the author of Kicost – Python that “build(s) cost spreadsheet for a Kicad project.”  Kicost is well worth checking out.  The GitHub location is here.  The code I used the most was the script that scrapes the Digikey pages.  I learned a lot about the Kicad XML and various Python techniques from other sections of the code.

The folks who created the Beautiful Soup library for Python.  Beautiful Soup is incredibly useful/well done to parse XML files.

Open Source

The MakeDigikeyBom Python project is located at this GitHub location.

Updated Block Diagram

I like to start by doing a fly by of a block diagram.  I had done an initial block diagram in the previous post.  The block diagram evolved as the design and implementation evolved.  Here is the updated block diagram

NewImage

A

Input from a Kicad schematic.  The important component Value and PN properties are important to this process.

For example, here is an image of Ladybug Blue’s Schematic with it’s hierarchical sheets:

NewImage

Each schematic component has a PN field and Value field.  The PN field must contain one of the following:

A1

The schematic component D1 (RED_LED) with a manufacturer part number PN = XPEBRD-L1-R250-0061.  When the PN is a manufacturer or Digikey part number, the value field is not used:

NewImage

A2

The component C1 has a Jelly Bean PN = C and Value of .1u:

NewImage

When MakeDigikeyBoM modifies the <outputFrom_bom2csv>.xml file, the created <modified_outputFrom_bom2csv>.xml file replaces the PN field value to the digikey part number CS21F104XZBCNNNC.  This is the part I chose for all .1u capacitors.

 

NewImage

A3

The P5 component has None in it’s PN field value:

NewImage

A component with None in the PN field tells MakeDigikeyBom that this component is not purchased through Digikey.  The Value field is ignored.

B

Use the bom2csv plug-in to create the “BoM” XML.  The bom2csv plug-in was discussed in my previous post. The XML branch that is the most important to the DIgikey BoM creation process is the <comps> branch.  As the tag suggests, this is where the component info is found.

Here are the <comp> properties for the three types of PN discussed above.

A None <comp>

NewImage

Here, the PN = None.  The Value=BNC, but that isn’t used by the Digikey BoM process.

A Jelly Bean <comp>

NewImage

In the above, component C1 is a .1u of part type C.  The Value = .1u is used by the process.

A Manufacturer or Digikey Part Number

NewImage

As when the PN=None, the Value field is not used.  In this case, the PN number is passed directly into the screen scraping section of the Digikey process.

C

The first part of the MakeDigikeyBoM Python script takes in the output from bom2csv discussed under “B” above and creates an intermediate file that is then used by another part of the Python script.  The intermediate file is in the same XML format as the file created by bom2csv.  The properties for <comp> components that use a Jelly Bean PN have been replaced by looking up the PN / Value field in the JellyBeanPartNumbers.csv file with the part number that must be should be either the Digikey or manufacturer part.

D

For the C1 Jelly Bean <comp> listed above, the PN = C and the Value = .1u.  The Python script looks for the row in the JellyBeanPartNumbers.csv file:

NewImage

in this case, the manufacturer part number = CL21F104ZBCNNNC.  The modified bom2csv file replaces the <comp> tag for C1 with this part number:

NewImage

E

The Python script creates a URL with the PN as keyword to the Digikey web site.  The URL is pretty much what we might use when searching for this part:

url = ‘http://www.digikey.com/scripts/DkSearch/dksus.dll?WT.z_header=search_go&lang=en&keywords=CL21F104ZBCNNNC” 

The html is parsed by BeautifulSoup into a fairly easy to access html tree.

There is a whole bunch of Goo in the Python script to scrape through the html and parse it out into the MadeDigikeyBoM.csv file.  If all goes well, the MadeDigikeyBoM.csv file is created.  For example:

NewImage

I realize the image is rather small…here is the row for .1u capacitors:

C13,C11,C17,C16,C3,C2,C1,C7,C6,C5,C4,C18

.1u

12

CL21F104ZBCNNNC

1276-1007-1-ND

0.1

0.031

0.0144

0.00783

792969

http://www.digikey.com/product-detail/en/samsung-electro-mechanics-america-inc/CL21F104ZBCNNNC/1276-1007-1-ND/3889093

There are 12 .1u capacitors.  The price per 1 = $.10, 10 = $.031, 100 = $.0144, and 1000 = $0.0144.  Digikey has 79,269 of these capacitors in stock.  The link to the Digikey page is included.

Challenge

The challenge is this part of the script will need to be updated when Digikey updates the web page.  This – of course – is true of any web page scraping process.

What’s Next

I’ll start going over the Python modules in the next post.  I’ve posted the Python scripts at this GitHub location.

 

 

Thanks for reading this far.  Please find many things to smile about.

From Kicad to Digikey -> Generating a BoM based on eeSchema – Overview

Tags

,

This is my latest ‘sacrificial draft’ to generate a BoM csv file with Digikey prices based on schematic files I create in Kicad.  Once I’m done with layout, creating a BoM from the components in the schematic is tedious and time consuming.  So I jump on the already heavily populated bus of folks using Python to automating the workflow going from eeSchema to ordering parts.

I will refer to this effort as MakeDigikeyBOM.py to reflect I pretty much only shop for chips on Digikey and the tool is written in Python.  Since I am fumbling about with Python for my own use and I stick to Digikey for my chip supplier, I have “hard coded” Digikey into the process.  All of this could be expanded and be made more robust.  Right now “it works good enough for me” and really is a sacrificial draft.  

Thanks to Those That Went Before

I wanted to start with saying how very grateful I am to devbisme (xesscorp) for Kicost – Python that “build(s) cost spreadsheet for a Kicad project.”  The GitHub location is here.  There is a very good chance Kicost is all you need.  It is certainly worth checking out if you use Kicad and want to automate BoM creation!  I chose to evolve Kicost to MakeDigikeyBOM.py to enhance with two features I feel are important:

  • The ability to not have to enter the part number within the schematic for jelly bean parts (capacitors, resistors,…)
  • Viewing the 1, 10, 100, 1000 unit pricing of parts.  This way I might order more parts even though I need less to lower the price per part.

The Goal

The goal of this post is to provide an overview of my MakeDigikeyBOM.py effort.  To do this, I will take a simple schematic created in Kicad:

I call this Kicad project myTestDigikeyBOMCreation.

 … i.e.: a schematic that is just a bunch of components…

and run it through MakeDigikeyBOM.py to create  a csv file that provides Digikey pricing info built by scraping the Digikey pages associated with the manufacturer part number:

Block Diagram

The Block diagram gives us a picture of the workflow I have defined to go from components within eeSchema to a csv file with the pricing info from Digikey – as shown in the image above:

BlockDiagramGoogle

Block Diagram

Components

You create your schematic by adding components – these are within the left blue circle of the block diagram.  Each component has a very important field, the PN field.  This is a custom field added to the components.  Kicad lets us add custom fields.  The Kicad documentation at this point gives direction on how to add a custom field like PN.

There are two types of components:

  • Manufacturer
  • Jelly Bean
The RED_LED component is an example of a manufacturer component:

 

The capacitor is an example of a jelly bean component:

The Value field becomes important when using a jelly bean component.  A Jelly Bean component is reconciled to a manufacturer part number using a Python script that matches the PN value (in this case ‘C”) and the Value in the value field (in this case .1u) to a row in a csv file that maps these two properties to a manufacturer’s part number. 

Jelly Bean Part Numbers

I created a Google spreadsheet that I named JellyBeanPartNumbers.  Here is an image of a few of it’s rows:

JellyBeanPartNumbers

I export the rows (which includes the header row) to a file named JellyBeanPartNumbers.csv.  This is the second blue circled area on the Block Diagram.  This csv file is used as input into the MakeDigikeyBOM.py script. 

bom2csv

The first step in the process of going from eeSchema to a BoM spreadsheet is running bom2csv.  bom2csv is a plugin for eeSchema that (at least for me!) is included with the Kicad install.  For more info on bom2csv, see the Kicad documentation on eeSchema (see this link, go to section 3.1 “Using eeSchema” then scroll down to #58 – where creating a BoM is discussed).  

bom2csv creates an XML and a csv file.  We’ll be using the XML file as input into MakeDigikeyBOM.py.  This is the file named <outputFrom_bom2csv>.csv in the above Block Diagram.  I use < filename > to represent a name that will change based on the name of the Kicad project.  In this example, the Kicad project is named myTestDigikeyBOMCreation.  The XML file that is created is named myTestDigikeyBOMCreation.xml.

We’re now ready to run MakeDigikeyBOM.py.

MakeDigikeyBOM.py

MakeDigikeyBOM.py is a bunch of Python Goo that takes in:

  • the XML file created after running bom2csv.
  • JellyBeenPartsNumber.csv.
I’ll discuss MakeDigikeyBOM.py in more detail in my next post.
 
 
Thanks for reading this far.  Please find many things to smile about. 

Using Python and a PLIST to Get pH and EC Values for a Plant into an iOS Swift App

Tags

, , , ,

The EC and pH level of a nutrient bath will be different depending on the plant type.  The Ladybug client software – at least initially an iOS app – gets the plant type from the user and then uses this info to determine the best pH level and nutrient level for the nutrient bath.  This way, the user doesn’t have to constantly look up what the pH and EC values should be.  For example, according to this table, a basil plant does best when the pH is between 5.5 and 6.5 and the EC is between 1.0-1.6mS.  This table says a tomato plant does best when the pH is between 5.5-6.5 and the EC is between 2.0-5.0.  I want to have a table/data base of plant types with the pH and EC values I need to set the nutrient bath.

The Goal

The goal of this post is to build a workflow that scrapes pH and EC values for herbs and vegetables from web sites and create a plist that can be used within an iOS app as an easy to use dictionary.  

Open Source

The files I used include:

Design Choices

  • plists or Core Data:  iOS has many ways an app can read/write a table of data.  I narrowed the choice to using either Core Data or plists.  I chose plists because the table of pH and EC values will most likely be less than 100 (although I assume I’ll be adding other plants over time) and the lookup is very simple – given a plant type, what should the pH and EC values of the nutrient bath be at?
  • Tool to scrape web pages and create plist: I chose to use the Python that is installed on my Mac’s OS X – Python 2.7 – and PyDev – the Python Eclipse plug-in.  The BeautifulSoup package makes it extremely easy to scrape web pages.

Code

Python

Scrape_pH_and_EC_into_plist.py (located at this GitHub location) scrapes:

for the pH and EC values of vegetable and herbs.  There are many sources for pH and EC values.  I am not sure which has the “best” values so I am starting with the values on these pages.  I use these because they come up near the top of Google searches for vegetable/herb pH/EC values.
 
The pH and EC values are text ranges like 5.5-6.5.  Python made it easy for me to parse these into the two numbers: 5.5 and 6.5, take the average and use that value as the “best” value for (in this case) the pH value of 6.0.
 
The plant name as well as the pH and EC values are written out into the file named pH_and_EC_values.plist .

Swift

I’m writing the Ladybug client in Swift.  I used a Playground to figure out the structure I wanted for the plist file as well as the Swift code I will use to access the pH and EC values.  I ended up deciding on a structure for entries within the plist to be:

<key>Basil</key>
     <dict>
          <key>pH</key>
          <string>6.0</string>
         <key>EC</key>
        <string>1.3</string>
     </dict>

I put a copy of the plist that is created from Scrape_pH_and_EC_into_plist.py at this GitHub location.

Here is the code I wrote in the playground to test accessing the entries in the plist:

//: Playground – noun: a place where people can play

 

import Foundation

if let path = NSBundle.mainBundle().pathForResource(“pH_and_EC_values”, ofType: “plist”) {

    print (“Path to plist: \(path)”)

    let fileManager = (NSFileManager .defaultManager())

    if fileManager.fileExistsAtPath(path) {

        if let plants = NSDictionary(contentsOfFile: path) {

            for key in plants.allKeys as! [String] {

                let plant = plants[key]

                print(“plant: \(key) pH: \(plant![“pH”]) | EC: \(plant![“EC”])”)

            }

        }

    }

}

In order to use a plist within a Playground, the plist file must be added to the Playground’s Resources folder. For example, I added a Resources folder within the Playground file I used (located at this GitHub location):

 

 

Debugging in a Playground with XCode 7

There seems to be some tweaks to displaying results in XCode 7. The tweaks confused me so I thought I’d document them here.  This will probably change in an upcoming release.

I ran across some settings that needed tweaking before the debugging experience was adequate.  Prior to changing settings, I would get very little info on what was going on.  For example: 

 

In the above example which I pulled from a Stackoverflow posting, notice how debugging just shows there are 4 items.  Viewing details just shows the last item.  To fix this, I had to hover over the popup that shows results and right click to change the view from “Latest Value” to “Value History”.

 

The other thing to do is to show the debug area by clicking the button on the far left:

 

 That’s it for now.  Thank you for reading this far.   Please find many things to smile about. 

Code Review and Error Handling: Ladybug Lite Blue

Tags

, , ,

Update (1/2-/2-16) Nordic just posted a useful article on nRF51 SDK error codes here.

I just finished a code review with Ron.  I wanted to capture a few of the recommendations Ron made.

The Goal

The goal of this post is to capture what I consider the biggest changes I will make to the existing Ladybug Lite Blue firmware as well as future coding based on Ron’s feedback.

Thanks To Those That Went Before

I was thrilled to have 1:1 time with Ron for a code review as an outcome of the Contextual Electronics course.  What a terrific opportunity to evolve my firmware programming abilities.  Ron did not disappoint. 

Open Source

The Ladybug firmware I am writing about in this blog post can be found at this github location.  Doxygen documentation is included within the Eclipse project’s Documentation/html/Search folder (see index.html).

I’d be grateful for feedback on how to improve the code. 

#define versus static const

My “NEW! IMPROVED! …Rule of Thumb:”

  • Use #define for magic numbers that are global in scope.  Use static const for variables that span functions within a .c file because:
    • #define is global in scope – which means there is a greater chance for conflicting use.  I might use a #define to name a time out period to 10 (#define TIMEOUT 10) and then use the same name within another .c file with a time out period of 20 (#define TIMEOUT 20).  Using the “static” keyword keeps the variable within the scope of the .c file.
    • static const variables are strongly typed.  I’m telling the compiler the exact data type to use for the variable.
    • the code is more readable.
Example of a magic number that is global in scope from the nRF51 SDK (ble_gap.h):

/**@brief GAP device name maximum length. */

#define BLE_GAP_DEVNAME_MAX_LEN           31

 Example where I should have used static const.  In the Ladybug_Hydro.c file I had:

/**

 * \brief mapping the FET pins to the schematic

 */

#define EC_VIN_FET0

#define EC_VOUT_FET7

I changed these to:

/**

 * \brief mapping the FET pins to the schematic

 */

static uint32_t m_EC_VIN_FET=0;

static uint32_t m_EC_VOUT_FET=7;

  • avoid making any changes to any bit of the code of an external SDK (like Nordic’s).  For example, I started changing stuff like:

#define APP_ADV_TIMEOUT_IN_SECONDS      0

to:

static uint32_t const      m_app_adv_timeout_in_seconds = 0;

I would have preferred to use a static const instead of #define however the SDK requires a precompiled value since it is used within another #define.
Note: I name variables m_<variable name> to identify variables that are scoped to a .c file (versus local to a function).  

Error Handling

I like the way the Nordic SDK supports error handling.  My code as well as SDK code are peppered with:

APP_ERROR_HANDLER(err_code);

and

APP_ERROR_CHECK(err_code);

both are #define’d in the app_error.h file of the nRF51 SDK.  These resolve into calling error routines I defined within main.c:

/**@brief Callback function for asserts in the SoftDevice.

 *

 * @details This function will be called in case of an assert in the SoftDevice.

 *

 * @warning This handler is an example only and does not fit a final product. You need to analyze

 *          how your product is supposed to react in case of Assert.

 * @warning On assert from the SoftDevice, the system can only recover on reset.

 *

 * @param[in] line_num   Line number of the failing ASSERT call.

 * @param[in] file_name  File name of the failing ASSERT call.

 */

void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)

{

  app_error_handler(DEAD_BEEF, line_num, p_file_name);

}

/**@brief Function for error handling, which is called when an error has occurred.

 *

 * @warning This handler is an example only and does not fit a final product. You need to analyze

 *          how your product is supposed to react in case of error.

 * \note I decided to use the SEGGER_RTT printing functionality.  My understanding is the SEGGER_RTT calls can be left in code with no effect

 * when there is no terminal to output.  The con of this approach is I can’t hook up a UART enabled terminal session and see what is going on without the debugger present.

 *

 * @param[in] error_code  Error code supplied to the handler.

 * @param[in] line_num    Line number where the handler is called.

 * @param[in] p_file_name Pointer to the file name.

 */

void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name)

{

  // This call can be used for debug purposes during application development.

  // The SEGGER_RTT APIs will not cause a problem in production so I’m leaving them in.

  SEGGER_RTT_WriteString(0,“—>>>BUMMER!! In app_error_handler\n”);

  SEGGER_RTT_printf(0,“error code: %d (or 0X%X if assert..base for BLE = 0x3000) Line number: %d file name: “,error_code,error_code,line_num);

  SEGGER_RTT_WriteString(0,p_file_name);

  SEGGER_RTT_WriteString(0,“\n”);

  //  ble_debug_assert_handler(error_code, line_num, p_file_name);

}

For now, error checking ends up printing out information about what/where the error occurred.  This has led to quickly figuring out where the error is and an idea of why it is happening.  In the future I could see mapping these error routines to LED indicators.  I use the SEGGER_RTT APIs because they are robust and work when the code is running in both run time and debug mode. Contrast this version of printf to the serial port to what I discussed in this post.

Checking for NULL Pointers

The basic point here is to check input values of called functions.  This is simple stuff that I should just do. For example, I was not checking for NULL pointer input to functions.  For example, I would pass in  a pointer to an int16_t array:

static void get_EC_reading(int16_t *p_EC) {

and assume p_EC pointed to a valid address.  I added in a simple check:

  if (p_EC == NULL){  //Shouldn’t be passing in a null pointer given the EC Vin and Vout values are planned to be stored at this memory location.

      APP_ERROR_HANDLER(LADYBUG_ERROR_NULL_POINTER);

  }

I also added error codes unique to the Ladybug to the Ladybug_Error.h file. 

Implement Time Outs

When using the pstorage APIs to access the nRF51822’s flash, the Nordic examples use code that has the potential to hang the system if feedback from the pstorage is not given to the pstorage handler in my code.  The pstorage APIs manage access to flash when the BLE stack is running.  This allows the BLE stack to figure out when it is safe to read from and (more difficult!) write to flash.  The function ladybug_Flash_Init() in the Ladybug_Flash.c file registers the ladybug_Flash_handler() function to be called back when a flash activity has completed.  The ladybug_flash_read() and ladybug_flash_write() functions rely on the static variable m_mypstorage_wait_flag to let them know when the flash action has been completed.  These functions wait until completion.  If the ladybug_Flash_Handler() is never called, the program will hang without having an app timer set up to fire after an amount of time.  I discuss using the nRF51 SDK’s app timers in this post.  Here is the code I use to surround a flash action.  In this case within ladybug_flash_write():

 // Start the timer up again to timeout if writing to flash doesn’t happen

  start_timer();

  m_mypstorage_wait_flag = 1;

  err_code = pstorage_store(p_handle, p_bytes_to_write, num_bytes_to_write, 0);

  while(m_mypstorage_wait_flag) {  }

  APP_ERROR_CHECK(err_code);

  stop_timer();

If the timer fires, the caller’s call back function is invoked.  This returns an error code to the caller.  It is then up to the caller to act on the error code.  Here is the definition of ladybug_flash_write() showing how the call back function did_flash_action() is included within the call to ladybug_flash_write():

void ladybug_flash_write(flash_rw_t what_data_to_write, uint8_t *p_bytes_to_write,pstorage_size_t num_bytes_to_write,void(*did_flash_action)(uint32_t err_code));

I call ladybug_flash_write() in main.c.  Thus main.c also include the call back function:

/**

 * \callgraph

 * \brief call back from Ladybug_Flash.c to let us know if the flash write was successful (or not)

 * @param err_code          0 if successful

 */

void did_flash_write(uint32_t err_code) {

  if (err_code == 0) {

      SEGGER_RTT_WriteString(0,“…Flash write SUCCESS!”);

  }

  else {

      APP_ERROR_HANDLER(err_code);

  }

}

That’s it for now.   Thank you for reading this far.  Please find many things to smile about.

Ladybug Lite Blue – A Tale of Two Power Sources

After using the Ladybug Lite Blue in my nutrient baths, I’ve decided to change the hardware design from just using a coin cell battery to using a DC power source when available and switching to a coin cell battery when not available.  At some point I envision designing an outdoor version that switches between solar power and battery so I am excited to explore using multiple power sources.

The Goal

The goal of this post is to add switching between a DC and battery power source to the Ladybug Lite Blue Schematic and board layout.

Note: I will be using the acronym LBL to refer to the Ladybug Lite Blue hardware.

Thanks to Those that went Before

Thank you (as always) to  Chris Gammell of Contextual Electronics!  I came up with a design to switch between the two power sources using an op amp and a p-channel mosfet.  I showed my design to Chris who without hesitation – and I might add a lot of respect/kindness! – steered me to a much better design using Schottky diodes – which I discuss below.  In fact, Chris pointed out he had covered this a month or so ago in our Contextual Electronics course!  Shame on me for needing Chris’s nudge when he had already provided the “better” solution.  There is so much Chris is teaching us that I need to go back and figure out what else I have missed.

Thank you Afrotechmods for your excellent video on the Schottky diode.

Open Source

Kicad v4.01 files and LTSpice simulation that is discussed below can be downloaded from this github location.

The Solution

  • use a commonly available power source for DC power: USB and CR2032 3V coin cell battery.
  • use Schottky diodes along with DC power being at a higher voltage than battery to use DC power when plugged in.  

LTSpice

The LTSpice simulation is simple.  I defined a DC and battery power source.  The DC power source pulses 3.3 volts on and off.  This allows the voltage graph to show the voltage at the load when DC power is on as well as off.

Features of the Design

  • When both power sources are available, current flows through D1 (i2) and through D2 (i1).
  • The voltage rises to 3.3V – the maximum DC voltage, which is .3V more than the maximum battery voltage of 3V.
  • Diode D1 is getting a reverse current.  At this point, power is being driven by the DC source.

Benefits of Schottky Diodes

Features of a Schottky diode that makes it a good fit for this scenario include:
  • A diode’s forward voltage drop is ~ .7V.  The Schottky diode has ~ .2V forward voltage drop (this depends on variables like the amount of current).
  • Switching from allowing current to flow to not allowing current to flow happens instantly.

Schematic and Board Layout

The Kicad v4.01 schematic and board layout are available at this github location.

 

 

 

A short one.   Thank you for reading this far.  Please find many things to smile about.