Vending machines are extremely common in Hong Kong. You can find one pretty much anywhere, selling not just refreshments, but also small items like face masks and umbrellas etc. FreshUp is the leading vending machine operator in Hong Kong, their smart vending machine is one of the early IoT projects I've worked on.
Unlike traditional vending machines, the smart vending machine utilises a heavily customised Android system with an app to enable unique features such as on-screen product information, advertisement placement, time-based product pricing, and remote data update & stock level monitoring, which none of these can be done by a conventional vending machine.
Killer Feature - Scheduled Discounts
Benefiting from the Android system underneath, the smart vending machine is able to perform time-based events and has so much more information stored for the products compared to the traditional vending machines. These extra abilities allow us to implement a killer feature for the smart vending machine - Scheduled Discounts.
I call the Scheduled Discounts a killer feature because this is the feature that helped FreshUp wins the contract from the banks. The first batch of the vending machines was deployed in some banks' back offices, with the refreshments the machines selling set to have discounted prices outside office hours as some sort of compensation for employees doing overtime work (it's actually a thing because OT work is so so common in Hong Kong 🤦🏼♂️).
Moving on, let's talk about how I managed the schedule of this project. It is one big aspect that I'd like to highlight here. The original schedule I was given was unbelievably tight, to a point that there were only 20-ish days left to the launch date FreshUp promised their clients when I received their call. A feature list and system spec were all I got at that time, and the machines were not yet arrived in their warehouse cause of a delay from the manufacturer.
With tough conditions like this, the first thing that came to mind is, of course, to fight the schedule. By fighting the schedule, it doesn't mean simply asking for more time or a delay. My client wasn't the only party involved there, plus it's not what they want.
Instead, I started by identifying what we need to have the machine able to serve its' core function - selling things, then prioritising the most important features to ship in the first few releases. This way I can then provide a solid timeline showing my client that the machines can start doing business out in the field by the day they promised their customers, and when'll the rest of the features be delivered.
Given a clear timeline in sight, my client is confident that we can pull off the project following my plan.
With the schedule settled, I then sketched out some UI/UX drafts so the UI designer has something to start with. From this point onwards, I just work hard to get things ready for delivering the first production release on the date set.
Difficulties, of course, we have to talk about them. The biggest difficulty is indeed the extremely tight schedule. Even though my client went with my plan to split the project into phases, it was still a real challenge to get the production release ready in 20-ish days (although I've made an entire web platform for a facial recognition solution in a month 2 years later, that's another story 🥸).
Dealing with constantly changing requirements and specifications was another challenge. As the APIs for controlling the mechanical parts of the vending machine were being developed in parallel by the client, a lot of things were that clear back then. After all, my client isn't a software firm and the documents from the vending machines' manufacturer from China have quite some information missing, so can't fault my client for that, just that's the norm. Anyway, to minimise the impact of things not under my control on my progress, I had the system designed in modules, and use abstraction for most parts to isolate different functions. I also went with NoSQL for the schemaless JSON-style documents so that it's less painful to modify the data structure to accommodate the new requirements.
Then comes the tricky parts. For whatever reason, like many other unbranded Android devices I've seen, the manufacturer of the vending machines wasn't keen to load newer Android versions onto the boards. The smart vending machines were running KitKat (Android 4.4) and that brings the problem - for a vending machine, the users are expected to be limited to interact with the designed pages and functions only, hence you'd want to run the machines in kiosk mode, but that's a feature only exists from Lollipop (Android 5) onwards. Because the vending machines were running an old-ish Android version, I had to use tricks to hide the system navigation bar, have the app runs on start up, and override the back function so the users won't be able to exit the app.
The second tricky part is having the UI work on different screen sizes with non-standard DPIs. While the layout fits the 22 & 55-inch models, it wasn't the case with the 7-inch model, even though everything looks just fine on the emulator. It took us a relatively long time to figure out the cause. Turns out that although the 7-inch model is using an 800p screen, it's not the resolution that caused the issue but the weird DPI which can't be emulated on the emulator. Fortunately, we don't have more small screen size variants to deal with, so in the end, simply making a separate set of layouts dedicated to that 7-inch screen was enough to have that settled.
At the end of the day, I'm happy that I've pulled off the project. Had the machines launched on schedule, and with everything done in around 9 weeks. Most satisfying thing? Must be the fact that the machines are widely available in Hong Kong, which means my work is being used day after day (it looks a lot more refined nowadays tho, but still can see my work being the backbone there 😼)
Also, looking back on my code 5 years later, I still have no problem understanding what I wrote. It makes me pound that I've left my client a clean and good-quality code base as a foundation to further expand their business.