Introduction: Hacking a Vending Machine to Release Cans With SMS

This HowTo is to show how we hacked a RedBull Vending Machine and help you reproduce it.

Our first idea is to release cans when people send an SMS with a valid token displayed in the machine (or in totens nearby) and log the time and amount of releases.

The vending machine won't have any internet connection (except local carrier network) and that was the reason we choosed SMS.

Step 1: Understanding the Machine

The vending machine have a main controller which takes care of the refrigerator (read the temperature's sensor and control the cooler motor) as well the vending process (control the payment and records the sales).

Basically almost all vending machines uses 24V DC motors, but each one have a different mode to push the products. For this one we have 4 columns, where the cans is piled up each other and the mechanism rotates in on direction where each time only one can fall.

To detect if the can fall from the column, the machine have some kind of "shute sensor" (works like a piezo) who senses the vibration. If the sensor detects a big raise of the value it means the can hit the bottom of the machine and it is available for the user. That means you need the keep the motor ON until the sensor detects the can. If the motor is turned on for more than 5~10 seconds it means the column is empty.

The machine we used already have the payment hardware striped and we keep the temperature control from the main board active, using only the motors and a sensor.

For our case we don't have any difference between the columns. So our project will active one column each time (randomly) and, if the can don't fall from it, turn on the next column and try again N times.

When the system receive a SMS (with a valid token) the machine releases one can and record in the SD card the user phone number, the message with the token and if the can was released or not.

Step 2: Preparing the Equipment

Here is the part list:

SD Card Shield

This shield was really easy to use. Since it use SPI, the Digital Pin 4 is used the select the shield. We are using a FAT16 formatted card. The manual, code and everything you need to know about this card is here. For our project, the idea is to create a data logger with all machine interactions.

EFCom SIM900 board

You can find the AT Command manual here. This board uses the Digital Pin 6 to power up/down the board. So, when you turn on your equipment, the first think you need to do is to turn on the shield, setting D6 to HIGH for 3 seconds. To control this shield you need to use the Serial connection, with Arduino UNO the SoftwareSerial library will work well and for the MEGA we put a jump direct to the Serial1 pins.

Shute sensor circuit

It's homemade, but it is the same circuit you need to connect any piezo sensor. It came with something like a resistor and we just attached the resistor in parallel with the Ground and the A7 pin.

Relays

We didn't have the 4 channel relays, so we used 2 two-channel relays. This relays use LOW to close the circuit. Make sure your are the same or change in the code this logic.

To connect the relays we used the digital pins 22, 24, 26 and 28 and the 5V and GND pins from MEGA.

Step 3: Receiving SMS

We try to find some library, but all of them are related to Arduino GSM Shield and didn't works well. So we decided the use the serial command directly to the board and active a function that shows all received messages in the serial port.

To enable this notification, use the following commands:

ATE0<br>AT+CMGF=1<br>AT+CNMI=1,2,0,0,0

The first command disable the ECHO MODE, so the chip will not echo any command you send after that.

The second will be responsible to activate the TEXT MODE when you receives SMS. The other mode forces the chip to show your messages with the HEXA mode. If you need to receive special characters it is the only way. Since we will use only the first 5 numbers in the message it is not a problem. Otherwise, we in Brazil we use some special chars and accentuation who makes this really annoying.

The last command activates the SMS notification. But it only work with your SIM card is enabled and activated. The Status LED should be on before you send this command.

After configure your board, all SMS messages received will begin with "+CMT", followed by the sender phone number and the date/time. And the next line will be the message:

+CMT: "01198***0955","","16/04/08,19:19:03-12"
123456

You can test this just connecting an Arduino board, without the chipset and talked directly the the SIM900. The board speed is 2400bps.

Step 4: Activating the Motors and Reading the Shute Sensor

First, our goal here is to activate one motor each time randomly and go to the next motor if the sensor doesn't detect any can. It will try for 8 times (two times for each column).

To do that, first you need to select one column and to make that easy we stored the pin for each column in an array. To make the random command works well you need to read some noise and generate the seed. So we get the analogRead from A0 (which is not connected to anything). Since our relays use the LOW to activate, we set all in HIGH.

int relays[4] { 22, 24, 26, 28 };

void setup() { 
   randomSeed(analogRead(0)); 
   for (int i=0; i<4; i++) {
      pinMode(relays[i], OUTPUT); 
      digitalWrite(relays[i], HIGH); 
   }
}

Now you have your relays set and ready to be activated. Let's check how to activate one and check the sensor.

Shuffle the motor and reading the sensor

#define THRESHOULD_SENSOR 100
#define ROLLING_TIME 3000
#define NUMBER_OF_TRIES 8

(...)

boolean bateu() {
  int in = analogRead(A7);
  Serial.print("an "); Serial.println(in);
  delay(10);
  return in >= THRESHOULD_SENSOR;
}

boolean activateRelays() { 
  int tentativas = 0;
  boolean released = false;
  int current_release_millis;
  int relay_idx = random(0, 3);

  while (!released && tentativas < NUMBER_OF_TRIES) {
    tentativas++;
    digitalWrite(relays[relay_idx], LOW);
    current_release_millis = millis();
    int delay_time = millis() - current_release_millis;

    while (delay_time <= ROLLING_TIME) {
      delay_time = millis() - current_relase_millis;
      if (bateu()) {
         released = true;
         break;
      }
   }
   digitalWrite(relays[relay_idx], HIGH);

  if (relay_idx == 3) {
      relay_idx = 0;
    } else {
      relay_idx++;
    }
  }
  return released;
}

Ready to go! If you call the activateRelays() function it should return if the can was released or not. And try to do that for 8 times.

We put a constant THRESHOULD_SENSOR to be our parameter to check if the can hit the bottom of the machine, If you are using a simple piezo, the value should be more than 400. But our tests the value after 100 works fine.

The ROLLING_TIME constant defines the time the motor should be kept on before change to other ou stop the trying.

Step 5: The Code and Wiring

Step 6: It's Alive!

Last final piece is to gather all hardware and put a AC plug to the power supply.

Put some cans inside the machine and close it.