Indoor Gardening Setup

I’ve always been a fan of gardening… it probably has something to do with spending all that time out in the sun with my great grandmother digging in the dirt as a kid and enjoying the great things that came from it when it was ultimately time for harvest. I lost touch with this joy for a bit in my 20’s but there was nothing like the mind-numbing contrast of the cubicled office to make me want to get back outside and get my hands dirty. After buying my first home with some property, doing some real gardening was high on my list.

One problem living in the part of Pennsylvania that I do is that the outdoor growing season doesn’t last all year long 😢 I started doing a bunch of container gardening just so I could bring things like peppers and herbs inside over the winter. This was mainly in order to get a jump on the next season… assuming they got enough sunlight, I didn’t forget to water them or it didn’t get too cold where I was keeping them. Some of my failures here made having a dedicated indoor space for gardening a high priority when looking for my current home.

Seed Starting

My indoor “gardening space” started out as just a small shelf in a closet in my laundry room. The early intention was to set it up as a staging area for starting seeds and growing transplants indoors so that they could be planted outside as soon as conditions allowed. My laundry room was perfect for this since it was by far the most humid room in the house and also the warmest due to it’s placement right next to my furnace. Both conditions being ideal for starting most seeds.

I started with a pretty simple germination station and a supplemental heating mat since many of the things I wanted to get a head start on require warm germination temperatures. I also use peat pellets as my growing medium. There are cheaper ways to do this, but these are very effective in my experience, not all that messy and they help with adding some much needed organic material on a regular basis to my shale and clay rich soil. They also help with transplanting the plants which I’ll get to later. You put the peat pellets in a few days before adding seeds and mist them down every day until they expand a bit. At this point, you can add your seeds and continue to mist them as needed, making sure that you don’t make conditions so wet that mold starts growing on the pellets. In a few days, you should have some sprouts which you can then transplant.

Most seeds don’t require light to germinate, so this basic setup works great as long as you are on the ball about getting germinated seeds out of the station before the sprouts start to require light. Since this requires transplanting, which can take some time, I eventually added a small LED setup. This helps in three distinct ways. It buys me more time before I NEED to transplant. It gives me the ability to work with seeds that do require light to germinate and it also allows the sprouts to become much hardier before transplanting since they can use the light to continue growing. I don’t have the best finesse when transplanting sprouts, so any help I can get in having seedlings that can take some abuse during transplanting is always helpful.

My current seed germination setup towards the end of germination round with only the ‘stragglers’ remaining.

Switches and Outlets

Some of you might be wondering about the tech involved at this point. There’s already one light and a heating pad involved, neither of which you’d really want to run 24/7. Suffice it to say that like everything, I started out small just using power strips and manually turning things on and off. Eventually, I moved to using timers and then automated, programmable outlets/switches since the manual management became annoying and unreliable. It’s really amazing how much you can do with these COTS products and things like IFTTT and the Google Assistant. I still use much of this basic hardware, but have supplemented with some custom hardware based on the raspberry pi and software that I wrote using Android Things and Actions on Google. If people are interested, I can document this in another post. It’s another thing that I hope to make available to others at some point after working out most of the kinks and documenting it more thoroughly, so let me know if you’re interested!


No matter how you start your seeds, eventually you’re going to need to transplant them. You could attempt to take them right from the seed starting area to the outdoors, but if you’re not doing this under the utmost growing conditions, you’re likely not going to have the best of luck. This means you need some capability to handle this phase indoors as well. Assuming your intention is to ultimately put these plants outside in a garden, this phase differs from the germination stage in a few notable areas:

  • You will need a space for growing plants.
  • You will need light; ideally adjustable to accommodate your growing plants.
  • You will need an effective strategy for watering around all of these electrical systems that prevents over/under watering.
  • You will need actual soil for the plants to put down a root system.
  • You need ways of strengthening your plants so that they don’t become too weak to survive outside.
Some recent transplants on an elevated platform getting them closer to the light

Space is the Place

Even when I carved out that initial shelf in my laundry room closet to start my seeds, I knew that eventually I wanted to take over the entire closet. The first shelf started about 4 feet above the ground which gave me some serious growing space underneath. This height was also perfect for installing an adjustable fluorescent grow light system. In order to maximize the effect of the lights, I first covered all of the surfaces below this shelf with aluminum foil to reflect all light back at the plants. I chose a fluorescent system since I wanted it to be reasonably economical and didn’t need the added heat from the more energy consuming lights. At the time that I installed this, LEDs weren’t really viable due to their cost and questions regarding their effectiveness for growing plants. This latter concern has been addressed with newer models and I’ve since supplemented the base install with programmable LED arrays that allow me to tune the light wavelengths in order to optimize it for my plants and goals. Blue wavelengths encourage growth while reds encourage flowering/fruit production. You can see in many of the photos that the light is either skewed to red or blue or a mix depending on what I’m trying to accomplish.

Electricity and Water don’t mix

Obviously, after adding a few lights, heating elements and other controls, thinking about how to route power to everything becomes a concern… Especially when you factor in the need to water everything on a regular basis and deal with the inevitable situation where the water spills or goes someplace unintentional. It didn’t take me long to build catch basins beneath every spot where I place my plants in containers. There are a lot of benefits to this and I just found the largest plastic containers with lids available and use the lids. This depth is effective enough at keeping any over watering inside the lids. This has the added benefit of allowing you to water your plants ‘from the roots’ if you use containers that have holes in the bottom (which I would definitely recommend to prevent both under and over watering). These lids also allow you to route the power along the outskirts. No matter what, you definitely want to use GFCI outlets EVERYWHERE. I still do most of my watering by hand, mostly because I spend a bunch of time inspecting anything I’m growing on a regular basis anyway, but I’ve been experimenting with automating the watering in various ways.

Put roots down

The main goal of the ‘indoor transplant’ stage is to create plants that are hardy enough to put outside. One of the most fundamental things at this point is to provide everything the transplants need to create a healthy root system. This starts with using the peat pots mentioned earlier. They allow you to easily move the sprouts into a secondary container without disturbing any of the roots that have started at this point. Choice of container is the next step. I already mentioned that having a container with holes in the bottom and watering from the bottom of the container encourages healthy root growth but forcing roots to grow deeper in order to find water, but the size of the container also matters. Think about your timeline for moving the plants outdoors and the growth rate of your plants and adjust accordingly. If you’re moving them outdoors within a few days or a week, you can get by with a small container, but if it’s a plant that’s destined to stay in a container, or spend weeks inside first, you’ll want something much bigger. You can do multiple rounds of transplanting, but I like to think ahead about this and reduce the number of times I need to move the plants. No matter what container you decide on, you’ll need to fill it with good soil. Fill the container about 3/4 of the way and then take your sprout in its peat pod and tear the webbing on one side to make it easier for the roots to push through and place it in the center of the container. Add more soil around the plant and then water it deeply. Transplant complete!

Strong Plants

At this point, you’ve almost replicated a safe environment to reasonably approximate the conditions for preparing your plants for the outdoors. One thing you’re missing is stressors on the plant caused by weather conditions and inquisitive insects and animals. You can prep your plants for this by adding an adjustable, oscillating fan to the mix. I like to avoid directly blowing air on my plants and opt to have the fan face a wall and have the breeze ricochet back onto the plants.

Get Outside

What I’ve described here is a pretty effective way to get the jump on your growing season. Before putting your plants outside permanently, you’ll want to put them out during the day for a few days to ‘harden’ them. This is another area where having a system of trays makes things easier! I’ve been able to harvest weeks ahead of my neighbors when I get cooperative weather using this method for seed starting and I’ve been able to make that even better using techniques to create micro-climates outdoors (definitely another post).

Grow Inside

Pruned multi year pepper plants that are fruiting/flowering indoors!

If you have enough space, it’s also very easy to tweak this setup to create an all year round indoor growing environment. I do this mainly with peppers, greens and herbs. I’ll plant in permanent containers, move outside when the weather is right for the plants and then when it starts to get cold, prune the plants back and bring them indoors. I can then tweak the environment to either make the plants mostly dormant until the next growing season and put them back outside again, or to continue flowering and fruiting while inside. I have some pepper plants that are several years old at this point!

Interested in indoor gardening? Have you built something similar? What’s holding you back? I’d like to hear more from you!

Shopify Webhooks driving AWeber

This post is a solution to a problem I had with the AWeber Shopify integration. To get the most out of this post, check out the original problem here.

…the continuation…

Being that I was spending 30+ minutes every day manually solving this problem, it was important that I had a MVP solution quickly. I took a step back to think about my immediate needs and the future direction that I would like to take this solution and came up with the following constraints:

  • Need to get something basic up and running quickly that can be easily iterated upon
  • Everything needs to be deployable to the Google Cloud Platform (and not cost a fortune to run)
  • The solution should be something that I can eventually monetize. This means a clean, UI based integration in the Shopify ecosystem (i.e. support for Node, React, Next) and the need to be able to handle many Shopify stores and scale appropriately.
  • Anything built must be easy to fit into the multichannel lead generation vision of Threddies. Eventually this would need to become the way that all leads get added to my email service provider without using any direct integrations.

Shopify Webhooks

I did a little digging and realized that I could solve just about every variant of the core problem if I were notified any time a customer was created or updated in Shopify. Conveniently enough, Shopify provides webhooks for both of these cases (in addition to many more). Webhooks are great for creating quick integrations and very easy to handle using Google Cloud Functions.

I prototyped the ‘create customer’ webhook and had something up and running in no time for my test store. I also started to think more about how I can quickly iterate on webhook based integrations in the future. The most simplistic integration using webhooks doesn’t require authentication, but it does require verifying the data sent is actually from the expected Shopify store and not just anyone on the internet. This is done using the X-Shopify-Hmac-Sha256 header. When you receive the webhook data, you need to verify the data in the body by generating this value (using a private key) and comparing it with what Shopify sends. There are two different ways to do this and it depends on how you integrate with Shopify. The preferred approach is to develop a Shopify app which has it’s own key that you can use to verify every authorized store that is using your app. The drawback of this approach is that you need a full blown Shopify app that implements the store authorization flow and requires some UI work. Since I’m not a React expert, I opted to take the second approach and avoid the UI by having each Shopify store owner that was going to be using this integration provide their store’s key to me. You can get this key by going to your store’s settings page and registering a webhook in the ‘Notifications’ area. This key is used to verify the integrity of all webhook data sent. Things I learned from this step:

  • Cloud Functions would likely not be the final way of deploying this since it did not provide a way to surface a UI in a customer’s Shopify store.
  • The Cloud Function for each webhook is going to have a lot of repeated boilerplate for verifying the integrity of the data sent and handling responses/errors. I would also need a more centralized storage location for keeping Shopify Store specific data so that it wouldn’t need to be duplicated in every Cloud Endpoint
  • Shopify webhooks require a timely response, so putting any heavy lifting in the cloud function is not going to happen. Take too long to respond, and Shopify will deregister your interest in the webhook data. This started to get me thinking about how to recover from this scenario.

Hookup to AWeber

I was getting data from Shopify and verifying the integrity of the data, but at this point nothing was happening with it. In order to get the data into AWeber, I had to again obtain some information from each admin of the Shopify stores that I was integrating with. At the bare minimum, I needed an AWeber account id and a list id to add all subscribers to. I also needed my customer to authorize my app to interact with their AWeber account. More requirements for UI, but I still wanted to put that off and focus on solving the original problem. I also didn’t want to force my users to go into AWeber in order to add my integration. I found this great NodeJs wrapper library around AWeber’s API that did everything I wanted it to do. Using this, you can enter your AWeber integration information and use it to generate an auth URL that you can send to your customer. They can then use that URL to provide your integration with the necessary permissions to their account. They send back a verifier code after authorization that you can use to get all of the necessary tokens needed for your integration to access that account. This information doesn’t change unless the user removes your integration, so it works perfectly until I actually setup the full blown authorization path in my Shopify App.

There were two AWeber issues that I discovered at this point: there is no way to add the subscriber’s location without using an originating ip address for geolocation. This means the ability to send using the subscribers local time window is not something that will work with subscribers added this way. Also, AWeber integrations are confirmed opt-in by default; AWeber would not turn this off for everyone using my integration, so I had to turn it off for each account/list I wanted to use it with and tell my customers to do the same. This was necessary since my integration already leverages Shopify’s confirmed opt in and I didn’t want to confuse my subscribers by making them do it again. The Shopify webhook payload already includes a flag for ‘accepts_marketing’ and I verify that this flag is true before attempting to add any information to AWeber. Things learned at this point:

  • I really need that UI!
  • The create customer/update customer flows look very similar from a Cloud Function perspective, so there needs to be some consolidation.
  • The AWeber deauth path needs to be handled. This can’t be done in a cloud function since it’s so far removed from the user capable of fixing this problem. For now, just alert on the error when it occurs and add it to the list of issues to handle later. This is another item that indicates the need for a systems health check in the customer’s Shopify store (and a way to recover all subscribers added between the time when a failure occurs and the Shopify store owner resolves the problem)

Ready for Production

At this point, things were working well enough that I felt confident allowing this integration to start doing my job for me. Before moving everything to production, I refactored everything to eliminate the obvious problems that I saw at this point.

Instead of Cloud Functions being the primary entry point, I created a NodeJs app to do this instead. This allowed me to setup all of the webhook routing inside this app and put all of the webhook verification and ‘health check’ code into this app. If there was a problem, I could fail fast without fear of Shopify deregistering the webhook.

This also provided a place where I could add all of the UI code for the integration and the intelligence for recovering from failures. This app can also morph into a frontend that is capable of handling and routing any future webhook integration that I want to create.

I then deployed the NodeJS app to Google App Engine. At first it wasn’t working and the errors indicated that the Next.js build step wasn’t occurring on deployment. I solved this by adding a custom build step that is automatically run on deployment by Google Cloud Build. You can do this by adding the script ‘gcp-build’ to your package.json. All of this gets deployed to an App Engine standard environment using automatic scaling. So far with 4 Shopify stores using this integration, the entire platform stays under GCP’s daily usage quotas and costs nothing to run!

Next Steps

Obviously, if anyone else shows interest in this solution, the most immediate need is to make the UX better by rolling out a nice Shopify Admin UI, but there are a few other next steps that I’m currently working on.

  • There is still too much heavy lifting in the webhook handler. I’m working on just pulling enough out of the payload to know what ultimately needs to be done and then publishing this as a Shopify-agnostic event to Google Pub/Sub where it will ultimately be processed by a Google Cloud Function. This will allow me to let Shopify know that the webhook has been processed much more quickly and sets up the necessary infrastructure to start removing my other AWeber integrations in favor of directly publishing the necessary information as an event into this platform.
  • The event driven architecture opens up many additional possibilities… it allows me to do more analysis on the data before it gets into my email service provider. This allows me to better tag and identify the sources of this data. The AWeber Etsy integration for instance doesn’t provide any capability for tagging or otherwise identifying these subscribers. Eventually, this will be the place where I can plugin my ML project that I have been working on that correlates behavior and surfaces insights across sales channels
  • Turn this into a full blown marketing channel app for Shopify. I’ve always dreamt about a day where I can do my email marketing from Shopify the same way that I run Google Shopping or Facebook Ads campaigns. This platform provides the foundation for doing that. I’m really excited about the possibilities!
  • If enough interest exists, turn this into an actual product. Reach out if you’re a Shopify and AWeber customer that is already experiencing the original problem I solved, or have ideas for how this can become perfect for something that you’re trying to do.

Annoying Time Sink of the Month…

Every day there is an annoying thing that I MUST do.  It annoys me that I need to, but as part of running a professional business it must be done.  I discovered the issue about a month ago and have been doing this job manually every day since… all the while thinking about a solution to automating this task out of my life for good.

The Background

Threddies, being both an E-Commerce and Brick and Mortar business, has two distinct buyer’s journeys that start out in very different ways.  In one case, a prospective lead finds us online and is ultimately driven to our website (this journey becomes much more complicated when you consider that a user’s journey could start from Google, Amazon, Etsy, eBay, etc.).  In the other, someone stops by our shop in person… talks to us about the local happenings… and if we’re lucky, makes a purchase. Our end goal is to turn visitors into customers, and even better REPEAT customers. Most of the time, people do not become a customer on the first visit, so our goal is to make them a potential customer, by getting them to sign up for our email list, or at the very least, joining us on their preferred social media platform.  A lot has been written about this Omnichannel retail problem and it was something that we felt we had a fairly good handle on.

We recently have been consolidating our technology stack and introducing processes to make things consistent across all of the sales/leads ‘channels’ that we support.  One area of integration that occured (and ultimately became the root of my current problem) was our choice to move the brick and mortar store to use Shopify POS instead of Square’s offering.  This had many benefits: reduction in payment processing fees, combined CRM and inventory systems, a common user interface for our employees to use across all channels, etc.

The Vexing Problem

The problem that I didn’t see coming involves the collection of emails in our email marketing platform.  We use AWeber and AWeber has both a Square and Shopify integration. We were actively using the Shopify integration to collect emails from our website and the Square integration to collect emails from B&M purchases (We also use the Etsy integration, but the issues with that is a subject for another blog post).  In both cases, we use separate web based sign up forms or the AWeber Atom mobile app (appropriately tagged) to collect email addresses from those that don’t ultimately make a purchase. If you are a Shopify and AWeber user, you should be aware that AWeber’s integration does not support collecting emails that are entered using Shopify’s Newsletter functionality, this was something that I discovered early last year and have built an acceptable workaround for that (I can document this for anyone interested).

After removing Square from the store, I quickly noticed that no emails were being collected from B&M purchases.  Initially, I thought it was a sync issue and that they would eventually show up, but they never did. I did some digging and testing and it seems that the AWeber/Shopify integration was only collecting emails from customers who made a purchase from the website, no emails would ever be added from Shopify POS.  My daily chore of adding emails had begun… even worse, since I was constantly watching what was going on with email adds, I started to notice other issues.

We don’t require users to provide an email address in order to make a purchase, providing a valid phone number will allow you to make a purchase as well.  We do require an email address, however, in order to create a Threddies account which gives the customer access to some additional features that they wouldn’t get otherwise.  I noticed over time that there were many customers that made a purchase without an email and then ended up creating an account with an email at a later date. NONE OF THESE EMAILS WERE BEING CAPTURED!  This was a fairly large problem that required some explaining to our customers when I finally added them all manually to our email list. I did some additional testing and discovered that this same use case occurs when a customer updates their email address from their account.  AWeber never gets the updated email address. This was a particular issue since many of our customers originate from channels that obfuscate their real email addresses (Amazon, eBay, etc.), but then they ultimately warm to us and provide their real email address after making repeat purchases.


I immediately started looking for solutions since manually doing this  every day was a nightmare. The AWeber provided integration is free with an AWeber account, but there are several paid solutions in the Shopify app store.  All of the third party integrations suffered from various issues… either they used polling on a regular interval to collect email addresses rather than being reactive to events occurring in the Shopify ecosystem, or they came with heavy handed tag syncing.  None of them specifically guaranteed the Shopify POS or Newsletter functionality that I desired. Since this problem was/is on my mind every day, I started thinking about the ideal state that I would like to have… tailored email marketing automation that is triggered by the channel that the user originated from.  This is important because the Amazon/eBay/Etsy’s of the world tend to be very restrictive regarding the content of the email that you can send to their users. Due to this, many of the emails sent to customers originating from these channels tends to be manually sent (often through systems that don’t have guaranteed high deliverability like AWeber), rather than automated which takes a crazy amount of time.  I also want intelligence behind tag syncing between Shopify and AWeber. It was clear that none of the existing integrations could meet these needs. This is the problem without an automated solution… for now… Stay tuned!

If you made it this far, and are interested in the thrilling conclusion… I wrote about my solution here.