In a company where I work there is a kicker table. The company occupies many floors and for some of the employees it takes up to 3 minutes to get to the table and...to realize that the table is already occupied.
Therefore an idea arised to build a kind of simple status broadcasting and reservation system which operates in real time.
Company uses Slack communication tool where every employee has an account. We have even a #kicker channel just for discussions about...kicker. The channel could be used as a kind of "entry point" for reservation and to be informed about current table's status.
As usual, there are many concepts how to deal with such a system. But generally, one basic rule appeared in all of them: it has to be simple to use without any excessive steps to perform when dealing with the system.
The device and the service are not sticked to the kicker table and can be used for any "common resource" (like ping-pong table, console, etc...) which needs some kind of status broadcadting amd reservation solution.
So, let's get started...
Step 1: Proof of Concept and Prototyping
Raughly the idea was to build a device which will be laying next to the kicker table following these requirements:
- some indicators about the current table status - if You are standing next to it, You should be able to know that it is free or reserved and somebody will come to play in a 3 minutes. Traffic lights fits to the idea perfectly:
- green light - free to play,
- yellow light - reserved,
- red light - occupied.
- red button - occupy the table, start a game (after reservation or ad hoc).
- green button - release table.
By reservation I mean just the reservation for next 3 minutes. System is not designed so that user can reserve the table at exact time (e.g. 02:00PM). It does not work like reservation e.g. in restaurants but just for upcomming minutes.
Because of lack of LAN connection in place, the only option is to use WLAN - it is the best option anyway. The brain of the system must use Slack API to send and receive commands from Slack channel. First I tried to use NodeMCU. I was able to get and receive messages to and from Slack but because of HTTPS usage and also Slack's "welcome message" size (~300kB), NodeMCU was loosing connection and/or got some weird exception which I couldn't resolve digging through Internet.
So I decided to use something more powerful: Raspberry Pi 3 (Zero W with WiFi was not yet released on that time). By having RPi, I could switch the implementation language from C to Java as it is more convenient for me - so this was an advantage. Today You can use something more powerful than NodeMCU and less powerful than RPi. Raspberry Zero maybe?
After building first prototype on a breadboard with some crazy wiring, lot of sketching and prototyping, the system looked like it can work.
Having all of these ideas and working PoC, I started to plan different placement configurations of above items on a front panel so they will be the most informative and convenient to use. You can check some of the other proposals, maybe some fits better to You. The last one was the chosen one by me.
Step 2: Materials and Tools
Materials I used:
- Raspberry Pi, microSD card, micro USB power supply
- Green and red arcade buttons
- 16x2 LCD screen
- LEDs - I used RGB but You can use the proper color
- Male to Female and Female to Female breadboard jumper cables
- Micro USB interface
- Mini breadboard just to connect some wires
- Short micro USB cable working as a jumper inside the box to power the RPi
Tools I used:
- Sharp knife (e.g. utility knife for cutting carpet)
- Rotary tool
- Hot glue gun
- Soldering station
- Pliers, diagonal pliers/side cutters
Tools You probably need:
- All of the above but instead of "Me" it should be: "You" :)
Step 3: Front Panel - LCD Screen
Hole for LCD screen was straightforward. Just a rectangle which fits to my LCD screen. After trying to cut it with a sharp knife, I realized that plastic of the box is quite hard. So I used drilling tool to cut the window and to polish the edges.
Step 4: Front Panel - Status LEDs
LED holes are also straightforward. I just took a big drill for wood and then I polished the edges with drilling tool. The big LEDs fitted perfectly tight. I didn't solder any resistors to the LEDs yet - I left it for the assembling process.
Step 5: Front Panel - Buttons
The biggest problem with these 2 big buttons was to place them evenly with the proper spacing. I cut the holes just using my drilling tool as I could increase diameter step by step so the buttons fit tight.
Step 6: Power Connector
A small hole for micro USB power was a very delicate job to do. I wanted the hole to be as fit as possible so I spent here a lot of time for polishing. But I was satisfied with the final result.
Then I cut a short mini USB cable which was placed inside the box. One side it is plugged into RPi, and on the other side, all cables were soldered to the micro USB interface according to USB pinouts.
Then I hot-glued the small PCB directly to the box (it can be seen on a photo in the assembling step).
Step 7: Putting Everything Together
First I soldered appropriate resistors to the LEDs according to their color (voltage) for 3.3V volt. I used 100Ω for red, two resistors 82 and 100 for yellow (green and red node), and 100Ω for green. You can use the one of the online resistor for LED calculator. But please do some research by Yourself according to the brightness and exact color tone You want to achieve.
Legs of yellow LED were soldered together so the LED itself can be controlled just by one pin on RPi.
According to this pinout diagram:
LED nodes were connected:
- Green LED - GPIO1 on Rpi
- Yellow LED (both legs) to GPIO2 on RPi
- Red LED to GPIO0 on RPi
I connected LCD using I2C pins on RPi pins
- LCD SDA to GPIO8 on RPi
- LCD SCL to GPIO9 on RPi
- LCD PWR to 5V on RPi
- LCD GND to GND on RPi
The LCD was hot-glued to the box as an additional protection.
I connected 3.3V and GND to the small breadboard so I could use them for buttons.
Green button was connected to the 3.3V through mini breadboard and to GPIO5 on RPi.
Red button was connected to the 3.3V through mini breadboard and to GPIO4 on RPi.
So whenever You press the button, there is a high state on the RPi pin.
The mini bradboard works just fine so I skipped soldering all the wires into PCB. Instead I just covered the mini breadboard with hot glue so the cables will not fall off.
I also hot-glued RPi's cover to the box so it will not be wobbling inside.
I screwed the front panel with all the stuff inside.
Then I printed, cut and stick simple labels next to the traffic lights and buttons.
Step 8: Slack Configuration
Create Your team on Slack.com or use the one You have and You have at least admin rights.
In Slack, create a channel for service's Slack integration (or skip creating a channel if You want to use one You already have).
Add Incomming Webhooks integration to Your team. Select the channel and copy the webhook URL.
Add Bots integration to Your team. Choose some name for Your bot and copy the bot API token.
Your managing custom integrations's page should look like on the picture.
You have to invite the bot as a member of Your channel. You could do it already during creating a channel.
If You want to customize the service later on, please check the Slack API.
Step 9: Software Implementation
I used Raspbian as an operating system for my RPi by following this tutorial. Please forgive me I will skip explaining it as it is already documented in many places and the process is straightforward. I hope You are skilled and experienced enough to manage to setup RPi on Your own. Please don't forget to configure WiFi access on Your Raspberry Pi ;)
The Java libraries I used:
- pi4j - to use Raspberry Pi from Java
- Springboot as an application platrorm
- allbegray/slack-api as Slack integration
You need to edit configuration file in src/resources/config.properties. There are 3 entries You have to configure to use Slack API:
- channelName - name of the channel You want to post status changes and receive commands.
- slackBotToken - token of a bot configured in Your Slack team integrations which will be used to post messages to the channel mentioned above. Please note You have to add Slack Bot as a member of the channel.
- webhookUrl - the URL You can get from Slack Team's custom integrations.
mvn clean package
And in target tirectory You can find the Springbooted JAR file. To start a service:
sudo java -jar kicker-reservation-service-0.3.0.jar
I set this line to .sh script and added it as an autostart. So whenever the power is on, the service boots automatically.
One special explanation is needed to the LCD.
I tried different approaches/libraries to control LCD over I2C from RPi but I just failed. For some LCD was not working properly, for some it was showing some rubbish.
But one thing was working very nice just out of the box. It is the utility command line tool I found You can use to control LCD. So I decided to just use this tool directly from Java. It works like this that a normal Linux process (lcdi2c) is called (with prepared parameters) every time I want to display something on the LCD screen.
You need to download the tool and place it next to the JAR service.
Using this tool is a kind of hack and stupid solution But I follow the 1st rule of engineering:
If it is stupid, but it works...it is not stupid
Step 10: Usage Instruction
You can check kicker table current status on created Slack channel by typing "status" (or shortly "st") command or directly check the traffic lights on the device.
If You just want to play - press red button. Message will be send to Slack channel with info that kicker table is occupied. When You've finished playing - press green button. Message will be send to the Slack channel with info that kicker table is free to play.
Traffic lights will also change and LCD screen will show some detailed information.
Just in case You forget to release the table after You've finished playing, there is a timeout set to 20 minutes. If You are still playing and need more time, press red button again and the match will be extended by 5 minutes (only apply when there is less than 5 minutes left before timeout). Playing timeout will be presented on LCD screen.
To reserve kicker table, write a message „reserve” (or just: „res”) to the Slack channel.
The Yellow traffic light will switch on informing others near the kicker table that it is reserved and soon somebody will come to play.
Reservation timeout is set to 3 minutes. After that, kicker table switches its state to free to play.
If You need, You can cancel reservation by writing „cancel” on the Slack channel.
System has also some other minor features like:
- After reservation, buttons get freezed for 5 seconds. This is so to prevent situations, that just in the same time somebody reserve and a milisecond later somebody presses red button thinking that He/She is the one occupying the table but without a knowledge that somebody reserved the table just a milisecond before.
- Pressing any button freezes both of them for half of a second. This is so to prevent crazy button clickers so Slack channel will not be spammed that much.
- Free version of Slack allows to store 10000 messages by the whole team. To preserve some of the messages, service delete the old messages related to reservation/status system) and keep only last 6 of them. Why 6? Because most often there are 2 status scenarios: "Reserved-Occupied-Free" and "Occupied-Free". So the system can store at least 2 full occupied-free sessions. To clean all the system messsages, type "clean" (or "clear") command.
Step 11: Releasing
Till now (the moment of publishing this instructable), the system is running for 2.5+ month and is used by more than 30 people. Because of the kicker table status update, we always know when it is free or occupied so we don't loose time going back and forth anymore. The connection and the service are very stable so we can rely on it.
So far, so good...
Step 12: FAQ
Why reservation timeout is set to 3 minutes?
3 minutes is the max reservation time, adopt it as You like in the code. Generally it will rarely happen, that full 3 minutes will pass and reservation will be timed-out. In most cases somebody will come eventually and occupy the table.
Why playing timeout is set to 20 minutes?
Depending on a players, average playing time is ~10 minutes. If You need to play longer, press red button again when less than 5 minutes left and timeout will be extended back to 5 minutes. This timeout is set up just in case somebody forget to release the table.
Why there is no PIN pad on the device to confirm reservation; no logins and passwords?
Main idea was to keep-it-simple-stupid. Otherwise nobody will want to use it if reservation, starting and finishing the game need too much effort.
Why the device looks so industrial-ugly?
Because I didn't have laser cutter, CNC, 3D printer, fancy colored label maker etc. You are more than pleased to improve it and make it more beautiful.
Why not just implement some app and stick cheap tablet to the wall with the same functionality?
Apps, apps everywhere. People like to physically interact with things and not just tap on a flat screens.