Warehouse Automation, iPad Pick List, Barcodes, Camera & Inventory Systems + St Tropez Jet Settin'

Last year

Hard to imagine, just a year ago, Oznium.com was in a cramped, dark, messy, and animal infested warehouse. Bats (yes, found multiple bats!), snakes, and black widows. And the metal roof was crazy. Just the tiniest drizzle sounded like a hail storm inside. At least it was cheap (for California standards).

Now, after a huge round of improvements

But now, we're in an amazing new Colorado warehouse (for the last 10 months). Radiant heat throughout, 3800 square feet, motorized roll up doors, and three bathrooms. In a beautiful little town, surrounded by mountains.

Been a whirlwind six weeks in Colorado with the latest round of improvements. Here's the details:

Mobile Pick Cart with iPad

Warehouse Pick Cart - With iPad Control

Old method, clumsy shipping process:

Pull up an order on the computer. Memorize the order's items. Walk around, picking the products. Bring them back to the packing table. Pack and ship. Go to next order / repeat process again.

NEW method, highly automated warehouse management system:

30 Barcoded Bins + Apple iPad
using ipad for warehouse inventory

On the iPad, tap a button to "create a new pick list". An algorithm assigns each customer order to a unique barcoded & numbered bin on the pick cart. We use three different bins sizes, and the algorithm uses dimensional product info to assign bins.

Since the computer knows the exact location of each product in our warehouse, it maps a pick route from start to finish. There's no back-tracking.

The iPad now displays the first pick "step". For example, it tells the user to pick a quantity of 3 from inventory location C-5-E and put a quantity of 1 into pick bin 17, and a quantity of 2 into pick bin 22.

The user taps the "next" button, and moves onto the next step.

(Our iPad app just runs in Safari. JavaScript caches the page-to-page pick steps, and AJAX handles the printing commands).

Automatic Label Printer

Whenever the user gets to a product that needs a barcode label (mostly items that are cut from a spool), there's a Zebra GX420d wireless printer on the pick cart that instantly spits out a barcode label. Along with our logo and phone number, the label shows the product name, quantity, and of course a scannable barcode. The label printer has an auto peeler mechanism to save time.

If for some reason the user wants to print a label manually, they can simply tap a button on the iPad.

Video demonstrating Apple iPad & Zebra GX420d wireless label printing
Note: In the video, we're tapping the "bin" box on the iPad which prints a label manually.
Normally, the label is automatically printed as soon as the user gets to a step which requires a label.

Technical details: setting up PHP, shell script, Mac printer server:

A print.php script running on your local MAMP stack gets ZPL code passed into it, and saves it to a local file.

print.php can call an exec() command to print.sh, passing in the printer name, and the path to the zpl file.

Its easiest to setup the Zebra printer on your local Mac directly in CUPS, by going to: http://localhost:631/
Here's a simple 4-step PDF graphical guide of how to setup the printer in CUPS:


// set random filename 
$file_path = "/temp/print/zpl_".rand(1,10000).".zpl";

// save the incoming zpl data to this file 
$fh = fopen($myFile, "w") or die("can't open file");
fwrite($fh, $_REQUEST["zpl"]);

// set printer name
$printer_name = "gx420d_hk1";

exec("/Applications/MAMP/htdocs/print.sh ".$printer_name." ".$file_path);

// Then delete the file once its printed.
exec("rm ".$file_path);



lpr -P $1 -r -E -l $2

Still need help building an awesome system?

Reach out to me by email: philbish at gmail dot com

Helped these guys, and others:
From: Bob Orchard
Date: October 10, 2020 4:30 PM
To: philbish at gmail
Subject: Regarding your wireless iPad-Zebra Warehouse Method


We've got a client that handles receiving and checking out packages on behalf of customers that come into their location to pick them up. We've been working on providing a solution that will allow them to easily, and wirelessly, print a label for each package received for easy check-out and delivery to clients that come in to receive their packages.

As of right now, it appears you're the only one that's been able to successfully send a print request from an iPad to a zebra printer and I was wondering if you had any recommendations or any way to point us in the right direction so that we could provide our client with a similar solution.

I spoke with Suzan at Oznium.com and she recommended me emailing you directly. If you could provide any help at all it would be greatly appreciated.

Thank you!
Bob Orchard

TinyPint Design & Consulting
"Website Design & Online Marketing for Small Businesses"
web: www.tinypint.com
From: Paul Matthews
Date: September 8, 2020 1:29 PM
To: philbish at gmail
Subject: Your warehouse setup

Dear Phil

I am writing to you regarding your amazing post about your warehouse setup. My wife and I own a web business in Australia (www.larkmade.com.au) that sells gift and homeware products (to women) and, from what I can see on the web, there are a lot of parallels between our two businesses – four years ago we were packing parcels in our spare bedroom; then we moved to the garage; then to a warehouse. You however are further on than we are – What really struck home with me is that you mentioned that you'd been overseas when you received a phone call from your warehouse guy who was threatening to quit; I'm actually writing this from a hotel in Paris and my warehouse guy HAS just quit.

I was aware that this was likely to happen as we've recently been unable to keep up with the timely shipping of parcels due to the number of orders we'd been receiving and he's really been feeling the pressure. Our warehouse guy, who has worked for us for nearly 3 years, has proven very resistant to change and has been unwilling to modify the systems he employs to get the parcels out the door and he has taken my understandable concern personally. On an average day we receive around 40-50 orders and in the past he has been able to cope with this, but he's now burnt out. I think this is because of the system we use to facilitate the processing of orders:

We use a Magento website on the front end and are about to implement a SAAS warehouse management system called Unleashed in the backend. Historically we have received an order on the site, printed it out, walked around the warehouse to pick the goods, packed it and then shipped it – you know this story, I think! – but on my return I intend to implement something similar to your picking cart to free up time. It seems there are two elements at play in the warehouse, space and time, and while I can't do much immediately about the former given our current warehouse I definitely believe I can improve the latter by employing a more systematic approach. Fundamentally, I have come to the conclusion that we have moved from being a gift business to a logistics business with a gift business on the front end.

So, anyway, just wanted to say, awesome post, very inspiring, wish I had your back end in our company. And where did you get those brilliant stackable blue boxes that are in your photos?

Paul Matthews
Lark Australia Pty Ltd
4a Duke Street
Daylesford Vic 3460

Our South Africa warehouse is also automated with printers, barcode scanners, and cameras.

Oznium.com provides LED Strips and Prewired LEDs.

Fish-eye Network Camera

An Axis 212 network camera with fish-eye lens is mounted to a custom welded aluminum arm which positions the camera directly over the pick cart. It gives us a perfect view of the picker, the pick bins and either side of aisle / inventory bins. We archive video of the pick process. This helps us analyze each motion to figure out ways to optimize even further. It also provides an audit trail if there's a problem with an order.

Time-lapse video from the fish eye camera. Sample pick list of me filling just five orders. Trippy huh!?

Portable Battery Power

We obviously need to power the label printer and camera, so we use a $100 battery backup / power supply that gives us about an hour of run-time. We just plug it in to a wall outlet whenever we're not picking orders.

We use this one from Amazon: CyberPower CP850AVRLCD Intelligent LCD UPS System, 850VA/510W

Its technically not the most efficient or elegant method, but its a quick and dirty way thats worked well for 10+ years.

We have three things plugged into it:
- Zebra thermal printer
- iPad charger
- Axis wifi camera

All of these things ultimately run on low voltage DC, so it would be more efficient to use a 12V 7AH rechargeable battery But the UPS battery backup is easier.

Packing & Shipping Process

Once the pick list is complete, the user brings the cart to the packing and shipping table.

Each bin is labeled on all sides with a barcode, and a number (1 to 30). We simply scan a bin, and the order pops up on the computer screen. We empty the contents of the bin, scan them with our wireless barcode scanner (to verify everything is correct), and then pack them. We place the package on the scale, and scan the barcode on the package which tells the computer exactly what type of package it is (for example, large priority mail box, flat rate priority envelope, padded mailed, etc.)

Some packages don't have barcodes. We automatically snap photos from three angles, and feed these photos to proprietary image recognition software. It figures out exactly which package is on the scale with almost perfect accuracy. This process is still in beta, but I've gotten it down to about six-tenths of second.

We record which package was used to ship the order for a variety of reasons. The main reason is to automate re-ordering of packaging supplies. We keep inventory levels of all packaging supplies.

Label Printing

Custom Bright Green Shipping Labels

Our standard shipping labels are 4" x 6". We re-arrange the label layout a bit so we can fit a 3/4" bright green color bleed on the top of the label with our logo and phone number pre-printed. Its an inexpensive and easy way to add a little more branding to our packages. 95% of our labels print with this, while certain international labels print on a larger format laser printer. We've got an auto-peeler, so the label pops out pre-peeled, all ready to be applied.

Automatic Pick List Labels

Small barcode labels automatically come out whenever the picker gets to a product that needs a label. Or they can be generated manually by tapping a button on the iPad.

Raw ZPL II Printer Code

To optimize print spool speed, and print quality, we send raw ZPL code to the printer. An image file (PDF, PNG, etc) could be 60k, whereas the ZPL text is just 1k. We don't have to worry about resolution.

Direct Label API Integration with USPS & UPS

We used to run a convoluted method to send XML files to Endicia/Dazzle on our shipping PC. And we used to have a messy ODBC link with UPS Worldship. Now we generate shipping labels using Endicia's Label Server API, and UPS Shipping API. This gives us a deeper level of control, and makes things faster / more reliable.

Pre-generated & Cached Labels

It can take anywhere from one second, to sometimes 15 seconds to get the label back from Endicia's Label Server API. One second isn't too bad, but every bit of time savings helps. We try to pre-generate as many labels as possible (where we are pretty sure of the weight and shipping method). We run this process in the background, and cache the labels. If a cached label exists when the order is shipped, the label is instantly fed to the printer. If we mis-calculated the weight or method, and the cached label isn't used, we'll just automatically refund/cancel it.

UPS Paperless Invoices (EDI)

We ship worldwide, and most countries already support paperless invoices, so its just one less thing we have to worry about printing and affixing to the package. We can just put a single 4x6 label on the box.

Warehouse Layout & Organization

Many people ask where we get these cool stackable blue bins. They are available from Uline: Giant Stackable Bins

Inventory Location Method

We've got a handful of aisles, each named with a letter (A, B, C…)

Each aisle has columns, named with a number (1, 2, 3…) Just like street numbers, one side is even, and the other side is odd.

Each column has six rows, named again with a letter (A through F)

So location C-3-D would be on aisle C, column 3, and the 4th bin up.

Location C-2-D would be across from C-3-D.

If we have excess inventory that doesn't all fit in a bin, we have back-stock locations too.

Randomized Inventory Locations

Logically, you'd group ducks with ducks, and trees with trees. It works OK to group similar products together, but once you give every part number its own unique inventory location, it doesn't really matter where they are placed. We find that, by having similar products physically separated, and placed in seemingly random places, it greatly improves picking accuracy. The pickers now don't even think about what product they are picking, they just go to a certain location and pick from that bin.

If you have yellow ducks and orange ducks right next to each other, eventually a yellow duck will find its way into the orange duck bin by mistake. Perhaps a friend comes into your warehouse and wants to look at a duck. They grab the yellow duck, look at it, and then carelessly put it back into the orange duck bin.

Now imagine, if you had yellow ducks next to green shrubberies, and on the complete opposite side of the warehouse, had orange ducks next to green trees. Your friend is much less likely to put that yellow duck back into the bin of trees. And if he did, it would be pretty obvious.

We generate a list of all our part numbers, sorted by the most commonly picked items. Using this list, we generate inventory locations for each product. We put the most popular items on the first aisle, and the least popular items furthest away on the last aisle.

Warehouse Camera System = peace of mind!

15 Network High Resolution Cameras

We are using 10 x 2MP Vivotek cameras, 2 x 10MP Arecont cameras, 1 Axis 215 PTZ dome camera, and 1 Axis 212 fish-eye camera.

I'm hardly ever in the warehouse (so far only 6 weeks this year), so its really good to have piece of mind while I'm away. I can check in to make sure things are staying clean and organized. We can use the recorded video as an audit trail if there's a problem with an order to pinpoint exactly what went wrong. And hopefully prevent it in the future.

Photos Available to Customer (yes, of their actual order!)

This one's really cool. We've got five cameras pointed at our shipping table from various angles. Our system automatically snaps a handful of photos while the customer's order is being packed. We make these instantly available to the customer, so they can see how their exact order was packed (on the My Account page).

Here's what we show on the My Account page:

Actual photos of Oznium packing your order
Why Photos?
At the precise moment your order is weighed, photos are automatically snapped by three fixed-position cameras. These photos are labeled with your order ID and instantly fed into our proprietary software. We then measure the package in 3-D and analyze color composition in order to categorize the delivery medium. Once the order's information is processed, a shipping label is automatically printed and placed on your package.

In addition to the photos, we record shipping sequence videos for every order. If any problems should arise, this documentation becomes part of the audit trail used in researching your order. And we regularly review video footage of our shipping center, to continually look for ways to improve our operations.

We provide these photos to you, because we think that such transparency makes for good customer service, and hey--we think the technology is somewhat cool.

Warehouse Packing Station & Shipping Table

Doran 7000XL Wireless Ethernet Network Scale

We've made a custom ship table that conveniently holds the most popular packaging supplies. The packing table also houses:

Cheap PC

24" LCD Screen

12" x 12" Stainless Steel Doran Scale, with wifi adapter

2 x Direct Thermal Label Printers

2 x Wireless Laser Printers

1 x Symbol Barcode Scanner

1 x Wireless Honeywell 2D Barcode Scanner

Handful of routers and power backups

12" Doran 7000XL Network Scale

Really complicated to set up. Their tech support didn't even know what Linux was… So I was pretty much on my own. Using a DIGI Connect RS232 Serial to Wifi adapter, I gave the adapter/scale its own IP address. Played with a bunch of configuration settings, and finally figured out a way to communicate with the scale from a custom perl script.

The scale averages weights 12 times a second, and sends current weight to my perl script 3 times a second. The perl script maintains a constant connection with the scale, and re-connects automatically if needed.

I save the last stable weight reading to a file, which can then be used from my backend systems. I've made some triggers available too, for example, I can have the perl script "ping" a certain URL if the weight changes (and motion stops). This will be useful for further automating the auto image recognition system. The user could place a package on the scale. As soon as the scale has a stable weight, the perl script would ping a URL to begin the image snaps / recognition process. And about 1 second later, an appropriate shipping label would automatically print.

Inventory Cycle Count System

Rather than be overwhelmed with a massive inventory count at year end, we try to count a few items per day, each day of the year. This way we can count each product at least twice a year, and it doesn't take more than 15 or 20 minutes a day. A system keeps track of who counted what, and when. It then queues up the most urgent part numbers that need to be counted next.

Barcode System

Linear vs. 2D

Its a brand new implementation, and so far working really well. Before, we didn't have barcodes on anything, and stupid mistakes were common. For example, we'd accidentally send the customer a blue duck instead of a red duck.

I've experimented with a handful of symbologies and originally liked the 2D datamatrix style because it didn't take up too much space on a label. But it seems the linear Code 128 is overall the best choice. Readability with our scanners is quick. We aren't encoding much data, and can fit the barcode into about 1/4" x 1 1/2"

Data Format & Barcode Tracking

We have full control over the design process, manufacture 95-something percent of our products, and are only one selling them. We don't have to worry about UPC codes. We've made up our own simple data format:


x = quantity in pack

y = unique part number (auto increment database field, so far from 1 to 1500 or so)

z = unique purchase order id

An example could be: 10-556-345

Which would mean there's 10 red duck beaks in the package and they are from purchase order 345.

We use the purchase order to track supplier defects. For example, we can see if defects are coming from a certain purchase order / manufacturing batch.

I've thought about using a unique serial number for each label, where no two barcode labels would be the same. This would allow us to track a few more things, but I don't think its really necessary now. From what I understand, Zappos does this, and they call it a "license plate".

Scanning User Interface

The entire backend system runs through a browser (rather than a desktop app). Of course, a barcode scanner just plugs in to a USB port and simulates a keyboard. If you scan a barcode, the data is "typed" into the computer.

To handle barcode scanning in our web interface, I programmed our scanners to send an open bracket "[" + the actual barcode data + a closing bracket "]".

There's a couple hidden form fields and a javascript event watcher that looks for an open bracket keystroke, and then starts writing the barcode data to another hidden field. Once it sees a close bracket, it knows it just got a barcode, and then handles it.

The system automatically displays a confirmation indicator next to each line item on the order as it is scanned. If partial quantity is scanned, it shows up orange. If the exact amount is scanned, it shows up green, and if too much is scanned, it shows up red.

It obviously won't let the user proceed if there's an error. If a completely wrong product is scanned, we do an AJAX call with the part number scanned, and get the name back.

There's more to do, but I'll save it for next year.

For example...

Voice Picking

I whipped up a super beta version of this just to test the concept. It works fine.

Basically, the picker can wear a headset, and receive voice directed commands.

Something like: "Go to location E-40-D and pick 2 quantity. Put them in bin 12."

Then with voice recognition, they can say, "OK", and it'd move on to the next step. Or they could say "repeat"…

Pick to Light / Put to Light

Each inventory bin will have an LED light that will be individually controllable from our web server. When the picker is on a certain step, the bin will light up.

And the bin on the pick cart that they are supposed to put the product into will light up.

And when they are back at the shipping table, we will use a dimensioning algorithm to suggest a box/envelope size to be used for the order. A light next to those boxes/envelopes will turn on, thus visually directing them to the appropriate package.

With some training and optimization, the algorithm will be able to make better decisions than the shippers. So we won't waste oversized boxes.

Infrared Beam Trip Sensors

Think of the sensors on the bottom of your garage door. One is an infrared emitter, the other is an infrared receiver. Same thing your TV remote uses.

In the same device that holds the LED to light up the bin, there will be infrared emitters/receivers.

As soon as someone sticks their hand into a bin, the infrared beam will be broken. We'll be able to tie this in with the pick system. If for example, they accidentally grabbed something from the wrong bin, or put something into the wrong bin, a buzzer would go off, and the bin could flash. When they grab from the correct bin, and place into the correct bin, the lights would turn off, and the next step would appear.


I was halfway across the world, in Kyoto, Japan for a month or so. I got a nasty email from my main/only shipping guy at 2 am. He "went off the deep end" and was about to quit half-way through a busy Monday. I begged him to stay on and ship orders at least until I could find and train a replacement.

I hadn't been back to the US in eight months, and things were starting to slip. Someone who is angry and quitting isn't the best person to train a new employee. Plus, I hadn't even met this person yet! I was on a plane the next day.

On the way back from Japan, I stopped in Beverly Hills, and just when I thought it couldn't get any worse, a bad lightning storm took out most of our electrical equipment. We had battery backups / surges, but pretty much everything was fried: computers, printers, routers.

Too many orders were piled up, with a brand-new person running around with no clue what to do. A bit of a mess! We're known for shipping orders within hours. Customers were upset when it took two to three days.

Anyways, I hit the ground running, and have been working crazy hours, 6 to 7 days a week. Rewarding to see all this progress. And now able to hang out in far-away places again without worrying!

Now for work-life balance awesomeness

Off to hang out in Europe for a bit. Literally threw a few t-shirts in a bag and hopped on the next flight to Frankfurt :) Not sure where I'll end up, but thinking somewhere warm, like driving the coast of France / Spain / Italy.

Update: So far, spent a night in Frankfurt, then drove down to Zürich for a few nights to enjoy my all-time favourite spa, at the Dolder Grand (one of my top five hotels).

Then hit the tiny car-free town of Zermatt, high in the Swiss alps, right below the Matterhorn. Went paragliding off the mountain and caught some sweet thermal updrafts. Spent like 25 minutes flying around, and got cool video from the iPhone (a bit worried I'd drop it though!).

Note, best place to stay in Zermatt: Hotel Omnia, perched on a giant rock. Feeling like James Bond, you enter through a narrow cave down below, through a set of air-lock doors, and up a 5-story elevator in the granite.

Then drove through France, straight to Barcelona, for jamón ibérico de bellota. Its the best ham in the world. From Spanish pigs who are fed a strict acorn diet, and then cured for two years. Lots of awesome architecture and fun culture. Picasso & Gaudi.

Spent a night in Andorra. Its a tiny country in the Pyrenee mountain range, wedged between France and Spain. Quite a strange place. Infamous as an inexpensive shopping mecca. The main town, Andorra la Vella, reminds me a bit more of Singapore than a European town (because of the shopping, modern buildings, and lights). Yet tons of natural beauty. Takes 30 minutes to drive across the country. Enjoyed some peaceful hiking around high-mountain lakes.

St Tropez is really fun. Yachts, celebrities, and fashionable people. Yet despite the glitz, it feels quite relaxed, almost stuck in a place in time. Awesome clubs (26 euro drinks are not uncommon), and awesome dining.

Alain Ducasse's, "Spoon", serves a unique bubble gum flavoured ice cream for desert.

An hour's drive into the countryside, through curvy vineyard backroads, is Chez Bruno, famous for its truffle creations. Foie gras stuffed pidgeon with truffles. Mmmm.

A trendy Morrocan restaurant tucked down a narrow cobblestone alley, serves heaping portions of couscous and lamb. Washing it down with Morrocan mint tea, I felt as if I were actually in Marrakesh.

Gotta love a place that serves pool-side breakfast until noon. And restaurants that don't even start dinner until 9:30.

I could definitely see renting a villa and hanging in St Tropez for a few months.

But… au revoir France! Decided to hit Bali. Saw a picture of a beach there and almost died, it was so beautiful. Booked a flight at 10 am, and was on the plane less than six hours later. Gotta love last-minute travel decisions. And its always good to leave a place before you're tired of it - so you still have good memories. 20 hours of flights: Nice - Dubai - Kuala Lumpur - Denpassar.

Iranian caviar, and '00 Dom on Emirates - Not a bad way to travel :)

Will probably stay in Bali for at least a month, maybe two or three. Not sure where to after Bali. Cape Town and Hawaii are on my radar though.

Matterhorn - about to paraglide off this mountain

Playing on an inactive ski lift in Andorra

Cruising French country side with the top down

Cool Thai / Viet restaurant tucked down this alley in St Tropez

Poolside breakfast at Hotel Byblos - St Tropez

Another rough day at "the office"

Truffles at Chez Bruno

Neon green poodle?

Jamón ibérico de bellota - best in the world

Selamat Datang!

email: philbish at gmail dot com