Skip to content

User Manual

Product description including introduction

I’ve created a digital dice that can be used during a drinking game. The dice roll decides the direction of the dice. If you roll 2, you have to take a shot. Roll 1 and give the dice to the person on your right and roll 6 to give the dice to the person on your left.

When predrinking on a night out, the game ‘Bussen’ is a popular game. Later on in that game, you have to choose someone to take a shot. People often pick the same person for that and some people might feel left out. My digital dice solves this problem my randomly selecting a person to take a shot: the person who rolls number 2.

The target audience for my product is 18+ adults who like to play drinking games.

The dice features the following things: - The dice shows the players what to do by using a led matrix. - To roll the dice, the players have to push a button. - When you roll 2, the red LED will go on. Any other number will light up the green LED. - The brightness of the green and red LED is affected by the LDR sensor. When it’s dark, the LED’s brightness will increase. - The rolled number and 5 last rolled numbers are displayed on a website.

Design of my digital dice

Step-by-step guide

Installation instructions Arduino IDE and libraries

Instructions Arduino IDE

  1. Download the latest version of the Arduino Desktop IDE.
  2. Start the app.
  3. Open the ‘Preferences’-window.
  4. Add this URL to ‘Additional Boards Manager URLs: https://arduino.esp8266.com/stable/package_esp8266com_index.json. Press save.
  5. Go to ‘Tools’ in the menu now, find ‘Board: ‘. Select ‘Boards manager …’
  6. Search for ‘esp8266’. Select the latest version and install this.

Build instructions embedded device

You have to solder your WeMos. For this, you can use this tutorial.

After that, you have to build the prototype embedded device. You can use the wiring diagram to see how you should connect all the wires and sensors. The last version of my wiring diagram, with power supply

NoteMake sure that you use red wires for the power source (vcc). This is the + on the breadboard. Use black wires for the GND, which is - on the breadboard.

Installation instructions embedded code

To install the full arduino code, follow these steps: 1. Go to my gitlab by using this URL. 2. Open the dice_shot.ino file. 3. Download the file. Download ino file on gitlab 4. Open the downloaded ino file in your Arduino IDE app 5. Make sure you’ve selected the right board: Select board Arduino IDE and the right port: Select port Arduino IDE 6. Upload the code to your WeMos Save file Arduino IDE 7. Congrats! Your code works with your embedded device :)

Installation instructions docker desktop

Instructions docker

  1. Install the Docker Desktop app and follow the instructions.
  2. My course prepared the docker files that can be downloadedhere. Download (and unzip) the project on your computer.
  3. Open your command line.
  4. On Windows: Start > search and open: ‘cmd.exe’.
  5. Mac: CMD + Space > search and open ‘terminal’.
  6. Enter this command:

    docker -v

    The terminal shows something like this:

    Docker version 20.10.17, build 100c701 5. Use the command line to navigate to the place where you saved your docker files by using the command below. is the location of the docker files on your computer:

cd “” 6. Start the Docker Containers with this command: docker-compose up

  1. Go to the Docker Desktop-application. You should see 5 docker containers running.
  2. Open your webbrowser and visit the following URL to test your environment:

    http://localhost/

Installation instructions application code and libraries/frameworks

Network configuration of embedded device (using WiFi)

The WEMOS is able to connect to the internet by using WiFi. To connect your WEMOS to the internet, use this sketch:

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>


void setup() {
    Serial.begin(115200); //Initialize serial communication
    WiFi.begin("SSID", "password"); //SSID and password

    // Keep in while-loop while the device is not connected to your accesspoint.
    while (WiFi.status() != WL_CONNECTED) {
    delay(1000); // Waiting on connection...
  }
}

void loop() {
    digitalWrite(LED_BUILTIN, LOW); // LED on
    delay(500);
    digitalWrite(LED_BUILTIN, HIGH); // LED off
    delay(500);
}

Notes: - WiFi.begin(…,…): Use the name and password of your own wifi-network. - Open the ‘Serial Monitor’ in the Arduino IDE and set the baud rate to 115200

With the WiFi connected, you can make requests on your computer to receive or post data. To do this, change the void loop() function of the code above to this:

void loop() {
    WiFiClient client;
    HTTPClient httpClient;

    //
    String url = String("http://localhost/insert.php?dice=") + x;
    Serial.println(url);
    if (httpClient.begin(client, url)) {

    //start connection and send HTTP header
    int httpCode = httpClient.GET();

    if(httpCode == HTTP_CODE_OK) { // HTTP_CODE_OK == 200
        String payload = httpClient.getString();
        Serial.println(payload);
    } else {
        Serial.println("Unable to connect :(");
    }

    delay(500);
    }
}

8x8 Led Matrix with push button

First, you have to download the LedControl library. Open the Library Manager in Arduino IDE and install it from there.

To display the characters on the matrix, I’ve used the following code.

#include "LedControl.h"

const int button = D2;
int buttonState = 0;

/*
 pin D7 is connected to the DataOut 
 pin D5 is connected to the CLK 
 pin D8 is connected to CS
 */
LedControl lc=LedControl(D7,D5,D8,1);

/* we wait a bit between updates of the display */
unsigned long delaytime=500;
  byte right[8]={B01000010,B01100110,B00111100,B10011001,B11000011,B01100110,B00111100,B00011000};
  byte six[8]={B00000000,B11011011,B11011011,B00000000,B00000000,B11011011,B11011011,B00000000};
  byte five[8]={B00000000,B01100110,B01100110,B00011000,B00011000,B01100110,B01100110,B00000000};
  byte four[8]={B00000000,B01100110,B01100110,B00000000,B00000000,B01100110,B01100110,B00000000};
  byte three[8]={B11000000,B11000000,B00000000,B00011000,B00011000,B00000000,B00000011,B00000011};
  byte shot[8]={B00000000,B11111111,B10100111,B10100011,B10100011,B10100111,B11111111,B00000000};
  byte two[8]={B00000000,B00000000,B00000000,B01100110,B01100110,B00000000,B00000000,B00000000};
  byte left[8]={B00011000,B00111100,B01100110,B11000011,B10011001,B00111100,B01100110,B01000010};
  byte one[8]={B00000000,B00000000,B00000000,B00011000,B00011000,B00000000,B00000000,B00000000};

void setup() {
    //Set input and outputs
    pinMode(button, INPUT);
    randomSeed(analogRead(0));

    /*
    The MAX72XX is in power-saving mode on startup,
    we have to do a wakeup call
    */
    lc.shutdown(0,false);
    /* Set the brightness to a medium values */
    lc.setIntensity(0,5);
    /* and clear the display */
    lc.clearDisplay(0);
}


/*
 This method will display the characters
 */
void one1() {
  /* here is the data for the characters */

  /* now display them one by one with a small delay */
  lc.setRow(0,0,one[0]);
  lc.setRow(0,1,one[1]);
  lc.setRow(0,2,one[2]);
  lc.setRow(0,3,one[3]);
  lc.setRow(0,4,one[4]);
  lc.setRow(0,5,one[5]);
  lc.setRow(0,6,one[6]);
  lc.setRow(0,7,one[7]);

  delay(delaytime);
}


void left1() {
  /* here is the data for the characters */

  /* now display them one by one with a small delay */
  lc.setRow(0,0,left[0]);
  lc.setRow(0,1,left[1]);
  lc.setRow(0,2,left[2]);
  lc.setRow(0,3,left[3]);
  lc.setRow(0,4,left[4]);
  lc.setRow(0,5,left[5]);
  lc.setRow(0,6,left[6]);
  lc.setRow(0,7,left[7]);

  delay(delaytime);
}

void two2() {
  /* here is the data for the characters */

  /* now display them one by one with a small delay */
  lc.setRow(0,0,two[0]);
  lc.setRow(0,1,two[1]);
  lc.setRow(0,2,two[2]);
  lc.setRow(0,3,two[3]);
  lc.setRow(0,4,two[4]);
  lc.setRow(0,5,two[5]);
  lc.setRow(0,6,two[6]);
  lc.setRow(0,7,two[7]);

  delay(delaytime);
}

void shot2() {
  lc.setRow(0,0,shot[0]);
  lc.setRow(0,1,shot[1]);
  lc.setRow(0,2,shot[2]);
  lc.setRow(0,3,shot[3]);
  lc.setRow(0,4,shot[4]);
  lc.setRow(0,5,shot[5]);
  lc.setRow(0,6,shot[6]);
  lc.setRow(0,7,shot[7]);

  delay(delaytime);
}

void three3() {
  /* here is the data for the characters */

  /* now display them one by one with a small delay */
  lc.setRow(0,0,three[0]);
  lc.setRow(0,1,three[1]);
  lc.setRow(0,2,three[2]);
  lc.setRow(0,3,three[3]);
  lc.setRow(0,4,three[4]);
  lc.setRow(0,5,three[5]);
  lc.setRow(0,6,three[6]);
  lc.setRow(0,7,three[7]);

  delay(delaytime);
}
void four4() {
  /* here is the data for the characters */

  /* now display them four by four with a small delay */
  lc.setRow(0,0,four[0]);
  lc.setRow(0,1,four[1]);
  lc.setRow(0,2,four[2]);
  lc.setRow(0,3,four[3]);
  lc.setRow(0,4,four[4]);
  lc.setRow(0,5,four[5]);
  lc.setRow(0,6,four[6]);
  lc.setRow(0,7,four[7]);

  delay(delaytime);
}
void five5() {
  /* here is the data for the characters */

  /* now display them five by five with a small delay */
  lc.setRow(0,0,five[0]);
  lc.setRow(0,1,five[1]);
  lc.setRow(0,2,five[2]);
  lc.setRow(0,3,five[3]);
  lc.setRow(0,4,five[4]);
  lc.setRow(0,5,five[5]);
  lc.setRow(0,6,five[6]);
  lc.setRow(0,7,five[7]);

  delay(delaytime);
}
void six6() {
  /* here is the data for the characters */

  /* now display them six by six with a small delay */
  lc.setRow(0,0,six[0]);
  lc.setRow(0,1,six[1]);
  lc.setRow(0,2,six[2]);
  lc.setRow(0,3,six[3]);
  lc.setRow(0,4,six[4]);
  lc.setRow(0,5,six[5]);
  lc.setRow(0,6,six[6]);
  lc.setRow(0,7,six[7]);

  delay(delaytime);
}

void right6() {
  /* here is the data for the characters */

  /* now display them six by six with a small delay */
  lc.setRow(0,0,right[0]);
  lc.setRow(0,1,right[1]);
  lc.setRow(0,2,right[2]);
  lc.setRow(0,3,right[3]);
  lc.setRow(0,4,right[4]);
  lc.setRow(0,5,right[5]);
  lc.setRow(0,6,right[6]);
  lc.setRow(0,7,right[7]);

  delay(delaytime);
}

void loop() { 

  // read the state of the pushbutton value:
  buttonState = digitalRead(button);

  int x;
  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  if(buttonState == HIGH) {

   // generates a random number from 1 to 6
   x = random(1,7);
   Serial.print("value ");
   Serial.print(x);
   Serial.print("\n"); 

  switch(x){
  // when x = number 1, display one1 and left1 and turn off ledPin2 and turn on ledPin
  case 1 : one1(),left1();
  break;

  // when x = number 2, display two2 and shot2 and turn on ledPin2 and turn off ledPin
  case 2 : two2(),shot2();
  break;

  // when x = number 3, display three3 and turn off ledPin2 and turn on ledPin
  case 3 : three3();
  break;

  // when x = number 4, display four4 and turn off ledPin2 and turn on ledPin
  case 4 : four4();
  break;

  // when x = number 5, display five5 and turn off ledPin2 and turn on ledPin
  case 5 : five5();
  break;

  // when x = number 6, display six6 and right6 and turn off ledPin2 and turn on ledPin
  case 6 : six6(), right6();
  break;}
  }
}

LDR with green and red LED

I’ve used a LDR sensor to control the brightness of the green and red LED. The red LED goes on everytime the user rolls number 2, every other number will light up the green LED. When the LDR sensor picks up less light, the LEDs will shine brighter. For this, I’ve used the code below. Note: I changed the switch(x) function from the code above. I just added the setLight():

const int ldrPin = A0;
const int ledPin = D6;
const int ledPin2 = D0;        
int val = 0;

void setup() {
  pinMode(ldrPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

void setLight(boolean two){
  // if two is true (so when x = number 2), do the following
  if(two){
    // read the analog value of the ldr pin and assign it to val
    val = analogRead(ldrPin);
    // limits the ldr sensor values to between 400 to 500
    val = constrain(val,400,500);
    // re-maps value 400 to 255 (the maximum of the brightness) and 500 to 75
    val = map(val,400,500,255,75);

    Serial.println(val);
    // // turn on LED 2 and set up brightness, turn LED 1 off
    analogWrite(ledPin2, val), analogWrite(ledPin, 0);
    // wait for .2 sec.
    delay(200);

  } else {
    // read the analog value of the ldr pin and assign it to val
    val = analogRead(ldrPin);
    // limits the ldr sensor values to between 400 to 500
    val = constrain(val,400,500);
    // re-maps value 400 to 255 (the maximum of the brightness) and 500 to 75
    val = map(val,400,500,255,75);

    Serial.println(val);
    // // turn on LED 1 and set up brightness, turn LED 2 off
    analogWrite(ledPin, val),  analogWrite(ledPin2, 0);
    delay(200);
  }

  void loop() { 

  // read the state of the pushbutton value:
  buttonState = digitalRead(button);

  int x;
  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  if(buttonState == HIGH) {

   // generates a random number from 1 to 6
   x = random(1,7);
   Serial.print("value ");
   Serial.print(x);
   Serial.print("\n"); 

  switch(x){
  // when x = number 1, display one1 and left1 and turn off ledPin2 and turn on ledPin
  case 1 : one1(),left1(), setLight(false);
  break;

  // when x = number 2, display two2 and shot2 and turn on ledPin2 and turn off ledPin
  case 2 : two2(),shot2(), setLight(true);
  break;

  // when x = number 3, display three3 and turn off ledPin2 and turn on ledPin
  case 3 : three3(), setLight(false);
  break;

  // when x = number 4, display four4 and turn off ledPin2 and turn on ledPin
  case 4 : four4(), setLight(false);
  break;

  // when x = number 5, display five5 and turn off ledPin2 and turn on ledPin
  case 5 : five5(), setLight(false);
  break;

  // when x = number 6, display six6 and right6 and turn off ledPin2 and turn on ledPin
  case 6 : six6(), right6(), setLight(false);
  break;}
  }
}

To find the full Arduino code, go to this page.

Configuration of the database

phpMyAdmin

I’ve set up my WEMOS to connect to a database where I store the times and values of my dice rolls. To create the database and the table, I’ve followed the steps listed in here. The servername, username and password I used, were provided by my school.

The database should look like this: Structure of my database Working database

Back-end/PHP

I used two php files: one to insert data into my database (insert.php) and one to give back this inserted data to my front-end website (getdb.php) by fetching it, using javascript (app.js).

The insert.php file looks like this:

<?php

    $servername = "mariadb";
    $username = "root";
    $password = "7YKyE8R2AhKzswfN";
    $dbname = "dice_roller";

    $dice = $_GET["dice"];

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    // Check connection
    if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
    } 

    $sql = "INSERT INTO dice (value)
    VALUES ($dice)";

    if ($conn->query($sql) === TRUE) {
    } else {
    echo "Error: " . $sql . "<br>" . $conn->error;
    }

    // If the value of the dice equals 1, show the text
    if($dice == 1) {
        echo 'dice = 1';
    }

    // If the value of the dice equals 2, show the text
    if($dice == 2) {
        echo 'dice = 2';
    }

    // If the value of the dice equals 3, show the text
    if($dice == 3) {
        echo 'dice = 3';
    }

    // If the value of the dice equals 4, show the ext
    if($dice == 4) {
        echo 'dice = 4';
    }

    // If the value of the dice equals 5, show the text
    if($dice == 5) {
        echo 'dice = 5';
    }

    // If the value of the dice equals 6, show the text
    if($dice == 6) {
        echo 'dice = 6';
    }

?>

In the first part, the php file makes a connection to the database I created (dice_roller). If the connection gets through, the file will insert new data in my table, called dice. The data being inserted is the ‘value’ of the dice roll. You can check if there’s a connection by adding a number from 1 to 6 to this URL: http://localhost/insert.php?dice=. For example, the following URL will insert the number 2 into the value column of my dice table.

http://localhost/insert.php?dice=2

if($dice == 2) { echo ‘dice = 2’; } This will then display ‘dice = 2’.

The second file is the getdb.php file. The file looks like this:

    <?php

    $servername = "mariadb";
    $username = "root";
    $password = "7YKyE8R2AhKzswfN";
    $dbname = "dice_roller";

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    // Check connection
    if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
    } 

    // order the items by time and show only 6 items from the database dice (includes the rolled number and the last 5)
    $sql = "SELECT * FROM `dice` ORDER BY time DESC LIMIT 6";

    $result = $conn->query($sql);

    $data[] = array();
    $counter = 0;

    if ($result->num_rows > 0) {
         // output data of each row
         while($row = $result->fetch_assoc()) {

            $data[$counter]["value"] = $row['value'];
            $data[$counter]["time"] = $row['time'];
            $counter++;
        }
    } else {
        echo "0 results";
    }

    $conn->close();

    print_r(json_encode($data));

?>

This file also connects with my database. I wanted to display my last rolled numbers on my front-end website. The left side of my website displays the last value of my database and the right side shows the five values before that. This is achieved with the following line of my getdb.php file:

$sql = “SELECT * FROM dice ORDER BY time DESC LIMIT 6”;

The data is put into an array. The arrays are being counted with the $counter. The last value in the database goes into counter 0. You will see a row with the value of the value column from my database and one row with the time of the time column. The counter goes up with the $counter++. Lastly, the data is being printed into a JSON string. To test if this is working, you can visit http://localhost/getdb.php. The page will look like this:

getdb.php page with json string: value and time of dice rolls

Usage of application front-end

The dice rolls are being displayed on my front-end website. This consists of three documents: HTML, CSS and javascript.

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="static/css/dice.css" />
    <title>Digital dice</title>
</head>

<body>
    <header>
        <h1>dice game</h1>
    </header>

    <main>

        <div class="split left">
            <h2>You've rolled number:</h2>
            <div class="centered">
                <img id="rolled-dice" />
                <div id="meaning-dice"></div>
            </div>
        </div>

        <div class="split right">
            <h2>Last rolled numbers:</h2>
            <div class="centered">
                <ul>
                    <li><img id="last-rolled-dice1" /><div id="meaning-rolled-dice1">1</div></li>
                    <li><img id="last-rolled-dice2" /><div id="meaning-rolled-dice2">2</div></li>
                    <li><img id="last-rolled-dice3" /><div id="meaning-rolled-dice3">3</div></li>
                    <li><img id="last-rolled-dice4" /><div id="meaning-rolled-dice4">4</div></li>
                    <li><img id="last-rolled-dice5" /><div id="meaning-rolled-dice5">5</div></li>
                  </ul>
            </div>
        </div>

    </main>

    <footer>
        <script src="/static/js/app.js"></script>
    </footer>

</body>

</html>

To change the HTML, I’ve used several html elements. They all have an unique id, because I want to change all of them seperately. On the ‘split left’ side, the div consistst of a changing img and another div where the meaning of the dice roll are being showed. On the ‘split right’ side of the html page, the five other last rolled dices sit in a unordered list. Each list item also consists of a changing img and another div with the meaning of the dice roll. Lastly, the javascript file app.js is linked to the html file.

I’ve styled the html page using this css file:

*{
    padding: 0;
    margin: 0;
}

@font-face {
    font-family: Montserrat-ExtraBold, sans-serif;
    src: url(../assets/Montserrat-ExtraBold.ttf);
}

@font-face {
    font-family: Montserrat-SemiBold, sans-serif;
    src: url(../assets/Montserrat-SemiBold.ttf);
}

body {
    height: 100vh;
}

header h1 {
    font-family: Montserrat-ExtraBold, sans-serif;
    color: white;
    font-size: 1em;
    padding: 1em;
    position: fixed;
    z-index: 2;
    text-transform: uppercase;
}

main {
    font-family: Montserrat-SemiBold, sans-serif;
}

main h2 {
    padding-top: 100px;
    font-size: 1.5em;
    text-align: center;
}

.split {
    height: 100%;
    width: 50%;
    position: fixed;
    z-index: 1;
    top: 0;
    overflow-x: hidden;
    padding-top: 20px;
  }

.left {
    left: 0;
    background-color: #FDC835;
}

.right {
    right: 0;
}

.centered {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    text-align: center;
}

img#rolled-dice {
    padding-top: 50px;
    padding-bottom: 30px;
    height: 200px;
}

#meaning-dice {
    font-family: Montserrat-ExtraBold, sans-serif;
    font-size: 1.25em;
}

ul {
    list-style-type: none;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

ul img {
    height: 50px;
}

li {
    display: flex;
    align-items: center;
    gap: 25px;
}

The unordered list is styled below each other, using display: flex and flex-direction: column. The images and meaning of the dice rolls on the right side of the page are also placed next to each other using display: flex.

The content of my html file is being changed with the use of javascript. This is my javascript file:

// Store the meanings of the dice rolls, sorted by number
var meaningRoll = ['Give the dice to the person on your right', 'TAKE A SHOT', 'Almost had you!', 'Lucky you...', 'Keep rolling', 'Give the dice to the person on your left']

function rollDice(){
    fetch('http://localhost/getdb.php')
        .then((response) => response.json())
        .then((data) => {

            var lastRoll = data[0]['value'];

            // Insert the svg of the dice roll that is equal to the first value of the array 'value'
            document.getElementById('rolled-dice').src = '/static/images/dice' + lastRoll + '.svg';
            // Change the HTML with the meaning out of the var meaningRoll ...


            ////
            document.getElementById('meaning-dice').innerHTML = meaningRoll[lastRoll-1];

            showLastRolls(data);
        });
}

function showLastRolls(data){
    var lastRolls = data.slice(1, 6);
    console.log(lastRolls);
    lastRolls.forEach((roll, index) => {
        var rollIndex = index + 1;
        var imgSelector = 'last-rolled-dice' + rollIndex;
        var meaningSelector = 'meaning-rolled-dice' + rollIndex;
        document.getElementById(imgSelector).src = '/static/images/dice' + roll.value + '.svg'; 
        document.getElementById(meaningSelector).innerHTML = meaningRoll[roll.value-1]; 
    });
}

window.addEventListener("DOMContentLoaded", () => {
    // Roll the dice when the DOM content is loaded
    rollDice();
    // Roll the dice every .1 second
    setInterval(rollDice, 100);
})

API reference


Last update: November 7, 2022