Building the Yale-NUS Smart Laundry System

TL;DR: We are in the midst of revamping a laundry checker website.

Update 27/12/2020: The project has been migrated over from a Flask based implementation to React

“See a problem, tackle the problem. Don’t sit on it.”


The purpose of this article is to explain what we did to get the Yale-NUS smart laundry prototype working. Credits to Shardul, Horatio, Prof. Ben Olsen, Prof. Chelsea Sharon, the Dean of Students over at Yale-NUS College (YNC), Niki & Ashley over at the Fabrication Laboratory, the YNC Infrastructure department, Prof. Chris Asplund for his feedback on the website’s user interface, Daniel Tan (my classmate back in ACSI) and the many people online who helped me understand how to code and work with electronics! I hope it will provide contextual information so that you as a reader or user of this service can gain a better appreciation of what went under the hood. If you’re up for it, you could even attempt to follow these steps and continue working on the project to upgrade its systems/internals.


Imagine this: You’re living in Cendana Tower B, and you’ve not done laundry in about a week and if you don’t do laundry soon you’re going end up not having clothes to wear or you’re going to puke from the stench emanating from your laundry stash. You lug the whole laundry basket over the link bridge and into the laundry room – only to find that ALL the washers are used up. How is it that for a residential college with a combined total of more than 30 floors of suites, there are only 6 washing machines to use?

You’re now faced with a dilemma. Wait till one of the washers clear up in the hot & humid laundry room so that you can stake your claim on the machine before someone else comes along to use it? Or leave your stuff around and come back later, hopefully with an available washer for you to use?


Read the washer door lock LED and send its status to a website for everyone to check on the go, at any time. This way, you can skip the emotional roller coaster and not have to lug all your laundry over just to know whether there’s an available washer!

Networking diagram

Diagram of how the Arduino Pro Mini, Raspberry Pi, and Google Cloud Platform (Website) interface with one another.

Key parts/components I used:

Setting up the Bluetooth Low Energy (BLE) AT-09 Module

Bluetooth Low Energy AT-09 (BLE Chip)

Typically, BLE modules function as either a “peripheral” or “central” mode. In my case, the AT-09 was acting as the peripheral which sends out signals asynchronously, whilst the Raspberry Pi’s Broadcom Bluetooth was the “central” device that was collecting data from all the BLE peripherals attached to the washers. One constraint I was faced with was the fact that the peripherals had to be battery powered and so asynchronous data transmission made the most sense so that the peripheral did not have to stay on or waste unnecessary power trying to sync with the client.

When I first got the AT-09 BLE chip from Aliexpress, it comes with a generic name but it has a unique identity as given by its mac address. I needed the mac address so that I could add it to the python program to establish a connection with the right BLE module.

Hence, the first thing I needed to do upon getting the AT-09 BLE module was to:

  • Download the Arduino IDE on my macbook.
  • Hook the CH340G USB to TTL converter to some dupont jumper cables, and attach those cables to the BLE module such that VCC -> VCC, GND -> GND, TXD -> RXD, RXD -> TXD.
  • Make sure that the Arduino is set to the right port, and the right processor (8 MHz, 3.3V, atmega 328)
  • Open up the IDE, and click on the serial monitor (top right hand corner with a + sign inside a magnifying glass symbol)
  • Make sure the BAUD is set to 9600
  • Type in the following commands:
    • AT+HELP (Lists out all the available commands)
    • AT+NAMECendana_1/2/3… (Changes the name of the BLE chip)
    • AT+LADDR (Prints out the all-important mac address of the chip which gives it its unique identity. Make sure to copy down this address, and when typing into the python code, add : between every 2 alphabets)
    • AT+POWE3 (Sets the transmission power of the BLE chip to its highest level)
  • To test that the above BLE chip is working fine, download the “LightBlue” app on your phone (iOS/Android), and do a scan for available Bluetooth devices. You should see the name of your BLE chip appearing on the app. Make sure that the reception level is about -50 to -60 dBs. I had a chip that was showing -93 dBs even at POWER 3, showing that it was probably defective to begin with. Swap these AT-09 BLE chips for new ones if you see that the signal is very weak.

The Arduino Pro Mini

  • It detects the LED status of the washer’s door lock light every minute
  • Goes into deep sleep whenever there is no light status change
  • Turns on the BLE module to send an on or off or blinking signal for 3 times at an interval of ~1 minute each.

Setting up the Arduino Pro Mini

What is it for?

  • Has an inbuilt analog input sensor to detect the change in resistance from the light-dependent resistor (LDR).
  • Performs a simple loop to check for the LDR’s threshold value, and limit the number of repeat BLE transmissions to 3 times.
  • Sensor checks can return: “on”, “off”, or “blinking”.
  • Puts the whole circuit (including the BLE Chip) into deep sleep for a minute.

To load the LDR logic onto the Arduino:

  • Fire up the Arduino IDE, open the code found on gitHub here:
  • Make sure that the Arduino is set to the right port, and the right processor (8 MHz, 3.3V, atmega 328)
  • “Compile” the code.
  • While holding onto the red colored Arduino Pro Mini’s reset button, plug in the USB to TTL converter.

Making sure that the Arduino is truly running on low power:

  • Make sure that the software loaded onto the IDE truly puts the chips into deep sleep. You can leave the LEDs on the Arduino/BLE on first just to see the transmission cycle of the Arduino is working as expected first. Once I was sure that it exhibits a deep sleep of ~1 minute each time, I went ahead and cut off the LEDs. There were cases where I uploaded more complex code and after about 5 cycles, the Arduino entered a bad state and just would not enter deep sleep!
  • Using the scalpel, pop off the red and yellow LED on the top side of the board. You can google the board’s schematics to figure out where the LEDs are.
    • While I was using the scalpel to pop the LED off, I recommend pulling upwards from under the LED so as to ensure that the fragile PCB does not get damaged. I had accidentally slipped and cut some other component before, and had to desolder the Arduino board from the stripboard using the braided copper wire (not fun!). (IMPORTANT! Make sure to wear eye protection for this in case the small LED shards fly into the eyes!)
    • Also, if I skipped this step of removing the LED, I observed that the AT-09 BLE was still drawing a relatively high current even though the Arduino was in deep sleep mode (where the BLE’s red LED shows a faint hue). I’m guessing that the 2N2222A transistor required a very low current difference between the base and collector for there to be no leakage between collector and emitter. In deep sleep, the base had a very low current but the collector has a relatively higher current of about 1.5mA (with LED on). Once the 2 LEDs were removed, the deep sleep current of the Arduino was only about 80 μA.
    • Also, when using the multimeter to read current loads in the mA scale, make sure that the + terminal of the battery connects to the load first, and not the multimeter’s + terminal directly. Doing so will blow the fuse of the multimeter, as I accidentally did on the Fluke 87 V RMS.

Circuit diagram for the Arduino

Putting things together: getting the circuit soldered onto the Stripboard

Key Materials Used (BLE and Arduino)

Equipment needed for soldering:

  1. Soldering iron ~280-400 degrees Celcius
  2. Multimeter to test current draw and for short circuits (especially between power terminals of the board)
  3. Lead-free solder
  4. Wire stripping tool
  5. Wire cutters
  6. Stripboard
  7. Scalpel to remove LED of Arduino and BLE, separate terminals on the stripboard, and cut up the stripboard.
  8. Crocodile clip clamps to hold your stuff
  9. Single-core cable
  10. Flux to remove oxide layer
  11. Braided cable to remove solder
  12. Fume exhaust
  13. Light + magnifying glass
  14. Solder Sucker tool to remove excess solder
  15. Electrical tape or Heat Shrink tubing to insulate wires on the power cord.

Solder up the breadboard according to the schematics below. The light green lines mean that I used the scalpel to break the copper strips to prevent a short circuit. purple meant single core cable. “Break” meant that I cut the board at those points.

Components to be soldered on:

  1. Arduino Pro Mini
  2. BLE
  3. Stripboard
  4. 24.9 kΩ metal film resistor (1% uncertainty)
  5. single-core cables
  6. 2 pin connectors for the battery
  7. 2N2222A NPN transistor
  8. 2 pieces of ~1.2m white-colored single-core cables with LDR attached in between the 2 wires.
  9. 4AA battery holder
  10. 4x AA Alkali batteries
  11. Jumper cables to female port (for the BLE)
Back of circuitboard – after soldering
Arduino, Bluetooth, LDR, Battery connector

Calibrating each sensor’s light-dependent resistor readout value to each machine:

  1. On the Arduino code, unmute the chunk of code that sends out the light values.
  2. On the Raspberry Pi, check the readout that the python code senses when the light is on/off. Once the light value has been determined, update the “threshold” portion of the code to that value found.
  3. Mute the whole chunk that sends out the light value as that will cause the Arduino to not enter deep sleep over a long period.

3D printing the box

Initially, I used donated Ferrero Rocher boxes sourced from some kind members of the Yale-NUS College community.

We intend to 3D print more boxes in due time. (Matas Vitkauskas is working on this at the moment)

Arduino Pro Mini Box dimensions:
Drawn using 2 and 1 point perspective techniques learned from my Historical Immersion class: Geometry and the emergence of perspectives

The Raspberry Pi

Photo: Raspberry Pi 3B+ on loan from the physics laboratory
(A Raspberry Pi 4 2GB was deployed)
  • Has a Raspberry Pi that is listening in on Bluetooth signals every 0.8 seconds, and uploads washer status via https POST to a server.
  • Sends out error messages on a Telegram Bot

Setting up the raspberry pi


  • NUS_STU and NUS_STU_2_4_GHz are on wpa enterprise wifi, which is buggy on Raspbian buster.
  • Eduroam doesn’t allow users to SSH

How to connect the Raspberry Pi to the National University of Singapore (NUS) Wifi

-I had initially tried using wpa_supplicant and editing the /etc/network/interface files manually to no avail. I found this really nifty 3rd party network interface called “wicd”.

My guess at what’s wrong with Raspberry Pi/Ubuntu systems not being able to connect to NUS Student Wifi is because in the latest Ubuntu 18.0.4 LTS and Raspbian Buster, the SSL somehow isn’t able to complete the authentication process with wpa enterprise networks correctly which generally uses a ca certificate. wicd is somehow able to authenticate wpa enterprise successfully for some unknown reason. If anyone figures this out, please explain it to me!

Also a problem specific to Raspbian Buster, the DHCP client (dhcpcd) is also not automatically refreshing itself with a new ipv4 with a valid internet connection. Hence, I had to use dhclient and disable dhcpcd.

Before I started, I had to connect the pi to some sort of personal hotspot or internet-connected LAN port first, just so that I could download all the necessary network interface packages.

For all the following commands below, $ denotes the start of the line to enter into terminal. Do not include the $ when typing in!

First, to enable SSH so that you can program the Pi remotely

  1. Open the terminal inside the Raspberry Pi and run the following commands
  2. $sudo raspi-config
  3. Turn on SSH by going to Interfacing Options>SSH
    1. Note that if you want to SSH, only NUS_STU and NUS_STU_2_4_GHz works. eduroam does not support SSH.

Second, installing all the necessary packages

  1. $sudo apt-get upgrade
  2. $sudo apt-get wicd wicd-curses wicd-gtk
  3. Add the user to netdev group $sudo gpasswd -a pi netdev
  4. $sudo wicd-curses
  5. Change wicd preferences (click “preferences” on the bottom right).
    1. General Settings:
      1. Network Interfaces: wlan0
      2. Wired Interface: eth0
      3. [x] Always switch to wired connection when available
      4. [x] User default profile on wired autoconnect
      5. [x] Automatically reconnect on connection loss
    2. External Programs
      1. (x) dhclient
      2. Wired Link Detection (x) Automatic
      3. Route Table Flushing (Automatic)
    3. Advanced Settings
      1. Driver: Wext
      2. Backend: external
  6. Set wicd configuration for both NUS_STU and NUS_STU_2_4_GHz by going to the config page of wicd-curses
    1. [x] Use Static DNS
    2. DNS domain:
    3. DNS server 1:
    4. DNS server 2:
    5. [x] Use these settings for all networks sharing this essid
    6. [x] Automatically connect to this network
    7. [x] [Use Encryption]
    8. WPA2-PEAP with CCMP/MSCHAPV2 (without domain)
      1. Username: nusstu\Exxxxxxx
      2. password:
  7. $sudo systemctl disable dhcpcd.service
  8. Go to /etc/dhcp/dhcpclient.conf to Remove the comment $supersede send-lease-time 900;. Set to maybe about 600-900?
  9. Restart the raspberry pi now: $sudo reboot now
  10. To check that you are connected to the internet, turn off your hotspot, go to
  11. To check for your ipv4 address: $ifconfig
  12. If the above doesn’t work, try:
    1. $sudo nano /etc/network/interfaces
      1. Refer to the image below
    2. $sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
      1. Refer to the image below

If you need to debug why the wifi isn’t connecting

  1. go to $cd /var/logs/wicd
  2. You can read the wicd.log file using $sudo nano wicd.log
  3. You can transfer the wicd.log file to local machine using $sudo scp /var/logs/wicd/wicd.log [name_of_laptop]@172.XX.XXX.XXX:wicd.log

Thirdly, getting the scripts to run automatically if the pi is shutdown and restarted accidentally:

  1. $sudo crontab -e
    1. On the first time you do this, set nano as the default editor
  2. Type in the following at the end of the file: 0,10,20,30,40,50 * * * * sudo python3 /home/pi/YNC_Laundry/Deployed/ & sudo python3 /home/pi/YNC_Laundry/Deployed/ &
  3. ctrl x to save and exit.
Bluetooth python script to receive BLE data from the peripherals
  1. Clone the YNC_Laundry git repository.
  2. Occasionally, do a git pull to update any new code.
  3. Do a git push to get everything from the pi up to the repo
    1. $git add .
    2. $git commit -m “logs”
    3. $git push

The Yale-NUS Laundry Webpage

(Credits to Shardul, Horatio, Rinat, Ivan, Neel, and other members of YNC Hacks for chipping into the design of the webpage and writing the code for the flask app)

Code accessible:

Old repo:

What the Google Cloud Platform web app can do:

  • Web app runs in the cloud to provide the web page for users
  • Handles the incoming POST message and stores them in a JSON dictionary.

Setting up Google Cloud Platform to host the webpage

To get the site up, I primarily followed the steps found here:

Of course, there has to be some tweaking and an allocation of swap memory to ensure that GCP’s Compute Engine’s Ubuntu Instance doesn’t freeze up due to the measly 0.6GB RAM it has.

Well, can’t ask for more, the processor is already being given as “always free”.

Flask app and how to host it on a production server on the web

To get the python code (running off flask), on a production server (gunicorn), being hosted by nginx’s server block:

Features to be added:
(Send me an email at [email protected] or message if you’re interested to help out!)

  • Build 14 more Arduino sensors
  • Configure 2 more Raspberry Pis
  • 3D print 2 more Raspberry Pi cases and 14 more Arduino Pro Mini Boxes
  • Upload logs data to Google Sheets so that logs can be analyzed into a weekly schedule heatmap. This report can be shared with the College community so that our folks can schedule their laundry ahead of time.


  • I forgot to tape up the exposed power cables from the batteries at the start, which led to a short circuit that melted the chip and the battery holder. All the hard work soldering the Arduino and components together went down the drain in less than 5 seconds. :'(
    • Heat shrink tubing will be a good investment in the future!
    • I’m currently using electrical tape to hold them together.
  • Not knowing which chips were compatible with Arduino LowPower library by RocketScream.
    • I had initially tried to use KeyWish BLE nano but the BLE and Arduino Nano were designed and developed together so I could not use the SoftwareSerial Library to turn off the BLE chip using software when the arduino was in deep sleep. The lowest power consumption I could achieve with that setup was about 8mA.

Leave a Reply