Making a Grow Light Stand

Last night was the quarterly hackathon at work, the day where we get to work on something fun and new until 4am and then demo to the team. Beers were drunk, Thai food was eaten and the sports tournaments were played out (darts and ping pong, or table tennis, if you prefer). It was a great time and although my work wasn't as brilliant as some of my colleagues, I felt accomplished by the time we crawled off for breakfast sometime around 7am.

That was 6 hours ago. I'm still awake. I've been awake since sometime between 7am and 9am yesterday.

I don't know why, really. I ran an errand for the wife this morning and one thing led to another. Before I knew it, I had not only completed the errand (returning some plants and a grow light stand to Growing Hope after Chrissy did some seed starting for them), I had also completed our own grow light stand (a project we purchased the pieces for back when I made the raised bed) and cleaned the cat litter boxes. Luckily for you, I didn't take pictures of the latter task; I'm keeping those precious memories of being watched by a cat while I dug around in his feces (mostly) to myself, but I digress.

Often, when you garden, you have to start some seeds. When the weather is inclement prior to the growing season, as it often is in these parts, you need to start those seeds indoors and, much like this winter in Michigan, there's no Sun indoors (I'm thankful for that, I like my stuff unsinged), so an artificial source of equivalent light is required. That's where the grow light stand comes in.

Unlike the one we had borrowed from Growing Hope, which was a simple wood construction with two A-frames at each end joined by two planks from which the 4' long fluorescent grow lamps were suspended, our grow light stand was to be made out of PVC. As mentioned earlier, we had purchased the pieces for it some time ago, which explains why some of the pieces were wrong. Thankfully, Home Depot awesomely gave me store credit for those incorrect pieces despite a lack of receipt. That's customer service for you.

The parts required for this little project were:

  • 120" of 2" PVC pipe
  • 4x end caps
  • 2x three-way connectors
  • 2x elbow connectors
  • 2x ¼" eye bolts with 4 nuts
  • 2x S hooks
  • 1x shop light
  • 2x fluorescent grow lamp tubes
Barry inspecting the parts and tools
Barry inspecting the parts and tools

In addition, the following tools were used:

  • Safety Gloves and Glasses
  • Drill
  • ¼" drill bit
  • Permanent marker (I used the one Chrissy got from John Mayer's fan club)
  • Hacksaw
  • Pliers
  • Wrench/Spanner (for tightening the nuts)

The assembly was really quite easy and probably would have taken about an hour at most if I hadn't needed to go to Home Depot twice (once for the shop light and again to get the correct size elbows).

First, the PVC pipe was marked (with the John Mayer fan club marker) and cut (with the hacksaw) to the following lengths:

  • 4x 5"
  • 2x 24"
  • 1x 52"

Then, using the connectors and end caps, join them all together to create the stand.

All the pipe fittings and lengths ready for assembly
All the pipe fittings and lengths ready for assembly
End caps fitted to 5" pipe (QA manager, Barry checking craftsmanship on the left)
End caps fitted to 5" pipe (QA manager, Barry checking craftsmanship on the left)End caps fitted to 5" pipe
End caps, 5" lengths and three way connector combined
End caps, 5" lengths and three way connector combined
Light stand legs and cross bar assembled
Light stand legs and cross bar assembled
Completely assembled stand without light fixture
Completely assembled stand without light fixture

See, that was easy, right? No glue, just push it all together. It's a little disappointing that it did not include power tools, but don't worry, because this is where I whipped out my trusty drill after marking where I wanted the eye bolts to go. The shop light fixture hangs from these, so I measured where the chains would go in the shop light and chose eye bolt locations accordingly.

Chains, S hooks, etc. for attaching the light fixture
Chains, S hooks, etc. for attaching the light fixture
Position of eye bolt for one side of light fixture mounting
Position of eye bolt for one side of light fixture mounting

If you attempt this, be sure to wear your safety gear as I did; PVC pipe can be slippy and drills can make easily eye bolt holes in your hand if you're not careful (I recommend having some sleep too).

Safety gear on and ready to go
Safety gear on and ready to go

Once the holes were drilled in the pipe (though a little skewed), I fitted the eye bolts. In order to get a sturdy fixture, I first screwed a nut onto the eye bolt, then pushed the remainder through the pipe and applied a lock nut to the other side (though a regular nut would have done, I think). I then tightened the nuts on each side of the pipe so that the eye bolt was secure.

Eye bolt installed (note the two nuts on either side of the pipe)
Eye bolt installed (note the two nuts on either side of the pipe)
Chains showing S hook before being attached and after
Chains showing S hook before being attached and after

The shop light fixture came with its own chains for suspending it, however, only one end of these chains had a hook, so I carefully crimped S hooks onto the other ends of the chains. I then hooked one end into the corresponding eye bolt and the other into the light fixture and that was job done.

The assembled and working light stand (with QA manager doing final inspection)
The assembled and working light stand (with QA manager doing final inspection)

The height is even adjustable by threading the hook through the eye and hooking back into the chain.

With the assembly complete, I placed the new stand over Chrissy's seedlings and plugged it into our timer ready for her to be surprised when she gets home or reads this (whichever is first).

Chrissy's seedlings enjoying their new light stand
Chrissy's seedlings enjoying their new light stand

Now, I've been awake for far too long so I'm off to play video games and eat snacks before a well-earned nap.

KalamazooX 2013

I struggle to put into words the Kalamazoo X Conference, more commonly known as KalamazooX, a single day, single track non-tech conference for techies. The difficulty is not in describing the talks, the speakers, the venue or the overall experience, describing the conference in such terms is easy; the talks were insightful and inspirational, the speakers were passionate and informative, the venue was accessible and appropriate, and the overall experience was emotionally demanding and entirely worthwhile. To describe what KalamazooX was to me, specifically, to reach deep inside and expose the raw emotions, to be open and honest about me, that is difficult.

It was the simple mantras:

It's not about you.
– Jim Holmes (@aJimHolmes)

Move the elephant. Direct the rider. Shape the path.
– Todd Kaufman (@toddkaufman)

It was the inspirational stories behind Todd Kaufman's talk on enacting change or Mike Wood's (@mikewo) talk on choices of doing the right thing, saving and changing lives, and becoming a better person.

It was the tears that welled in my eyes during Layla Driscoll's (@layladriscoll) talk on being happy, after she encouraged us to sit with our eyes closed and think about who we are. I wrote, "I am sensitive, funny, creative."

It was the encouragement from Leon Gersing (@rubybuddha) and Alan Stevens (@alanstevens) to take time out from time and reality, to meditate, and to find our inner voice.

It was the relief I felt in hearing Alan Stevens say, "you do not require approval from any external source," or Elizabeth Naramore (@ElizabethN) say, "It's okay for it not to be okay."

It was the moment I wrote in my notebook, "I feel less special than others. Is that true? Am I? Or do I need to redress my self image?" I think we both know the answer to that (though some have known a lot longer than others).

It was connecting with others in unexpected, overwhelming and assuring ways.

I do not believe for an instant that I was the only one in attendance that was deeply moved and I suspect that those who were returning attendees already knew about the impact this event can have. What a secret they have kept, hiding the true value of this event behind such dismissive phrases as "My favourite conference of the year!" and "It's a non-tech conference for techies. It's all about soft skills." Such pedestrian phrases pay no due to the experience at all. A more accurate and yet still inadequate phrase was tweeted to me by Michael Letterle (@mletterle) during this years event:

Now, you may think I'm being overly dramatic or reverent and you might be right. I have a tendency toward such things, but rather than assume that be the case, I encourage you to attend next year's KalamazooX and experience it for yourself (or at least look through the #kalx13 tweets). If, having done so, you still feel I have been exaggerating, I will concede and leave you and your cold, black heart to //Build, PyCon or whatever it is that floats your ghost ship (just playing, I'll still love you really).

To close, I thank Michael Eaton (@mjeaton), his team and all the speakers1 for putting on an event so cathartic that even writing about it overwhelms me a little. To uncover a part of oneself is enlightenment, to see that reflected in others is KalamazooX.

  1. Besides those mentioned above Suzan Bond (@suzanbond), Jen Myers (@antiheroine), Brian H Prince (@brianhprince), Jeff Blankenburg (@jeffblankenburg) and Justin Searls (@searls) all gave amazing talks. []

jQuery validation of select elements where multiple="multiple"

I was recently working on a simple feature in our web client at work. Part of the feature required that the user be able to select one to many items from a multiple select list. My first stab at this worked great; I added the required class to the select element and voila, the user was limited to at least one item. However, I thought it would be nice to give a custom error message with a little more context than just "this field is required" and perhaps provide the ability to limit the selection to a variable minimum and maximum length.

I quickly discovered that I don't understand the jQuery Validation plug-in and the documentation seems to be written by someone who thinks I might know way more than I actually do1. My next step was to find examples but they were all related to comparing element values on more standard input elements, which just served to confuse me further, so I embarked on a quest to find out how to solve my problem and write a blog about it.

Now, I'm sure that what I am about to document will seem like child's play to the jQuery ninjas out there, but for every ninja equipped with the skills to silently dispatch every henchman in the room, there's someone like me who just wants to get out of the room alive. So, please bear that in mind as you read on and whether a ninja or just a survivor, please comment.

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>My jQuery real good fun time yeah page</title>
    <script src="http://code.jquery.com/jquery-1.9.1.js" type="text/javascript"></script>
    <script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.js" type="text/javascript"></script>
    <script type="text/javascript">
        /* Placeholder for my amazing coding skills. */
    </script>
</head>
<body>
    <form id="mySuperCoolForm">
        <fieldset>
            <legend>Select some stuff</legend>
            <select name="things" multiple="multiple">
                <option>thing 1</option>
                <option>thing 2</option>
                <option>thing 3</option>
                <option>thing 4</option>
                <option>thing 5</option>
            </select>
            <input type="submit" />
        </fieldset>
    </form>
</body>
</html>

This is the simple HTML page that I'm going to work with. There's nothing complex here, just a form with a select and a submit input. I have also added some script imports for jQuery and the jQuery validate plug-in and an empty script element for our validation definitions to live.

To this, we want to add some validation to make sure that at least one element in the list is selected when the form is submitted. First, just to check things are wired up correctly, we will just specify the select named "things" as being required. Rather than do this by just adding the required class, let's use some scripting, that way we can manipulate the script as we go.

$(function () {
    $('#mySuperCoolForm').validate({
        rules:{
            things:{
                required:true
            }
        }
    });
});

This code is not doing much. It is telling the jQuery validate plug-in to attach its validation to our form, mySuperCoolForm with the rule that our field, things is required. If you try this out and click the submit button without selecting anything, you'll get a message stating, "This field is required." Not a very descriptive message, so let's fix that by adding a message for our "things are required" rule.

$(function () {
    $('#mySuperCoolForm').validate({
        rules: {
            things: {
                required: true
            }
        },
        messages: {
            things: {
                required: 'Please select at least one thing.'
            }
        }
    });
});

Again, not a very complex change. I have added a messages field to the JSON object being passed to the validate method. This field provides messages that should be displayed when validation rules fail. In this case, we are stating we want at least one thing to be selected whenever our required rule fails. You should note the correlation here between the name of our field, things and the rules and messages that are attached to it. This is important to understanding how to manipulate the jQuery validation. When a rule fails to validate for a named field, the message under the same named field with the matching name to that failed rule will be displayed.

That works nicely so it's job done, right? Not quite. You see, while this works for the cases where one to many items need selecting, it feels a little hacky. I'd rather say explicitly "I want x items selected" rather than rely on the required rule working the way it does for multiple select scenarios. I like being explicit. So, let's get explicit2.

Validating with minlength

It just so happens that the jQuery validation plug-in has another rule, minlength that appears to be exactly what we want. Thinking this, I naively wrote some code to require at least two items. I also included some string formatting for the error message so that the number of things in the message matched the number required by the rule.

$(function () {
    $('#mySuperCoolForm').validate({
        rules: {
            things: {
                minlength: 2
            }
        },
        messages: {
            things: {
                minlength: $.format('Please select at least {0} things.')
            }
        }
    });
});

Now, if we select two things, we can submit just fine, but if we select just one thing, we get told we need at least two. So far so good. However, if we select nothing, the form passes validation and submits fine! What? We stated a minimum of two and yet zero passes. That makes no sense. It made even less sense when I set my minlength to 1 and it didn't appear to do any validation at all. Everything was feeling so intuitive, what happened? By looking at the code, it becomes clearer.

The minlength rule looks like this:

minlength: function( value, element, param ) {
			var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
			return this.optional(element) || length >= param;
		}

If you put a breakpoint here, you'll discover that when nothing is selected, value is null, but that's okay because length becomes `0` in that circumstance anyway. The problem is on the second line of the function, which I have highlighted. It checks to see if the element is optional or not and if it is optional, the element passes validation regardless. A quick look at the optional function shows that it calls the required rule and returns the inverse of its result. When we have no items selected, required returns false which optional turns to true which incorrectly says our data is valid. However, when only one item is selected, required returns true which means the `length >= param` check occurs and our validation fails as we would like. While this behaviour is probably intuitive for say, string input fields where no value and values of a certain minimum length make sense, this is confusing when using minlength with select fields.

To get our validation working as we would like, we have to apply both the required and minlength rules as follows:

$(function () {
    $('#mySuperCoolForm').validate({
        rules: {
            things: {
                required: true,
                minlength: 2
            }
        },
        messages: {
            things: {
                required: 'Please select at least 2 things.'
                minlength: $.format('Please select at least {0} things.')
            }
        }
    });
});

Unfortunately, now we've lost the nice dynamic nature of our error messages. If we change the minlength rule to 3, we have to remember to edit the message for required. It seems we have gone from "feels hacky" to "feels hackier".

What I really want is for required to behave differently when I have the minlength rule applied to a select element. When using minlength on a select element, I want required to default to true but my error message to come from the minlength message format. This would feel far more intuitive for this use case than the current behaviour does. So, given that the plug-in does not do this, what can we do to fix it?

Implementing an intuitive minlength

The jQuery Validation plug-in provides the ability to add custom validation methods. Not only does this allow the addition of new methods, but it also allows for the replacement of existing methods. This gives us two options:

  1. Create a new minlengthofselection or similar that follows the rules we want.
  2. Override the existing minlength that does things the way we want.

While the first option is probably safest for those already familiar with the behaviour as it stands, option two is more fun. Guess which one I did3.

$(function () {
    $.validator.addMethod('minlength', function (value, element, param) {
        var length = $.isArray(value) ? value.length : this.getLength($.trim(value), element);

        if (element.nodeName.toLowerCase() === 'select' && this.settings.rules[$(element).attr('name')].required !== false) {
            // could be an array for select-multiple or a string, both are fine this way
            return length >= param;
        }

        return this.optional(element) || length >= param;
    }, $.format('Please select at least {0} things.'));

    $('#mySuperCoolForm').validate({
        rules: {
            things: {
                minlength: 2
            }
        },
        messages: {
            things: {
                minlength: $.format('Please select at least {0} things.')
            }
        }
    });
});

In this final update to the code, I provided a new implementation to the validator for minlength. This new version is almost identical to the default except that when checking a select element, it looks to see if the field is explicitly not required, thereby assuming that we want something to be selected. Finally, we have a minlength validation check that works intuitively for our scenario as well as the more common scenarios surround string lengths and we don't have to hard code numbers into the error message.

Conclusion

In conclusion, I ran into what is probably a corner case when it comes to using jQuery Validation where things were not as intuitive as I had hoped. In doing so, I was able to learn more about the plug-in and eventually, resolve my specific issue.

  • Have you had a similar problem?
  • Do you have improvements to suggest?
  • Should I submit this minor change for inclusion in the jQuery Validation plug-in?

Please, comment and let me know.

Acknowledgements

I would like to thank, alen, the author of this tutorial which gave me a foundation to work from when investigating and resolving this issue.

  1. Turns out the real reason was my expectations of what should work and the reality of what did work did not match, making the documentation hard to interpret. []
  2. Not in that way! []
  3. Hint: It's not the first one. []