Arduino Project Hub
Project tutorial

Smiling Snowball © GPL3+

A web-controlled smiling snowball based on the Arduino MKR1000 controlled via WiFi using MQTT, Shitr.io and Node-red.

  • 277 views
  • 0 comments
  • 2 respects

Components and supplies

Abx00004 iso both
Arduino MKR1000 & Genuino MKR1000
×1
LED matrix 8 x 8 (MAX7219)
×6
11026 02
Jumper wires (generic)
×1
cardboard 40 cm x 40 cm (15.7 inch x 15.7 inch)
×1
blank paper
×1

Necessary tools and machines

scissors
hobby knife

Apps and online services

About this project

Introduction

This project started with the intention to be a proof of concept for some techniques that I wanted to learn. Since it is winter now and it started to snow, I came up with the idea to build it as a smiling snowball.

The main goal is to make the Smiling Snowball controllable via WiFi using a simple web-based user application. This application should be easy to create and to control.

The following hardware and software is used:

  • As hardware for this project, it uses the Arduino MKR1000 because this is a fast development board including a stable WiFi support embedded on the board.
  • For the communication via WiFi, the MQTT protocol is used. This protocol needs a broker in the network. Therefore, Shiftr.io is used. But this can also be an other MQTT broker.
  • For the web application, Node-RED is used. This runs on top of Node.js. Node-red is a simple drag and drop tool for creating applications on top of Node.js. Node-RED also supports communication via MQTT. Node-RED also has the potential to create a dashboard and connect UI elements to functions.
  • For the display elements in the snowball, we connected six 8x8 LED matrix units and split them into groups of 3 for testing multiple control of devices.

Global project setup

The goal was to control the smiling snowball via WiFi using a simple web-based app that can be used from PC/tablet or mobile phone. The following diagram shows the different components of the project and the communication between them.

The blue arrows are the communication via MQTT. The green arrows are the web communication to the tablet and mobile phone. The physical communication is via Ethernet and WiFi.

Arduino MKR1000 Application

The Arduino MKR1000 is used for two functions. It handles the communication with the MQTT broker (Shiftr.io) using its WiFi connection and it controls the LED matrices.

This application uses the default 101WIFI library for creating the WiFi connection. To create a connection to your WiFi access point, you need to fill the correct information for your access point.

char ssid[] = "##############";     //  your network SSID (name) 
char pass[] = "##############";      // your network password  

For the MQTT PUB/SUB communication, the MQTTClient library is used. For this library, a connection to some MQTT broker is needed; also, the IP address and port should be filled in. Also a username and password is needed for the MQTT broker. See more details at the paragraph of the MQTT broker.

To receive commands in the Arduino MKR1000, the application should listen to the broker for messages on topics it has been subscribed to. If data is published for a topic, the application will call the message received function and process the message.

To see if the applications are up and running, a heartbeat message sent between the Node-RED and the Arduino MKR1000 is included. On the Shiftr.io dashboard, it is easy to see the flow of the data. The moving black dots on the dashboard are the data.

The LED matrices connected to the Arduino MKR1000 are divided into two groups of 3; this is to prove the communication of two led sets. For controlling the matrices, a LED matrix lib is created (current available matrix libraries did not work correctly on the Arduino MKR1000). The library is stored on GitHub.

If the settings for the WiFi in MQTT broker are correctly filled in in the application, it can be built and uploaded to the Arduino MKR1000. After installing the software, a default face will become visible if everything is connected correctly.

This is how it looks if you have also made the snowball as described later in this story.

MQTT broker (Shiftr.io)

As an online MQTT broker, the Shiftr.io is used. This is a broker specific for prototyping. To start using it, you should signup to create your own account.

After that, you can go to your own dashboard and create a namespace. Within the namespace, you should create a token (config button after the namespace name). The token should be filled in the Arduino code and in the Node-RED configuration.

For the Arduino code, look for the line:

client.connect("snowball", "#######", "##################")  

Node-RED

Node-RED should be installed on a PC/RasberryPi or other system in the network. If you use your own MQTT broker, it is possible to use the same system for it. How to install Node-RED is described here: http://nodered.org/docs/getting-started/installation.

If Node-RED is installed, you should add the node: node-red-dashboard - see here. This is needed to create a web based dashboard. After installing this, Node-RED can be started. Go to the Node-RED page. Mostly localhost:1880 but see this on your terminal.

After starting Node-RED, you should load the Node-RED application in to the Node-RED environment. Do this by copying the Node-RED application on this page and inserting it in to your Node-RED environment. At the right top of the Node-RED screen, there is a config/settings icon. Click on this icon and then select import from clipboard, and import the application as new. After loading the Node-RED application, you should see the following:

The application is now loaded. To get it up and running, the application should be deployed. Before deploying the application, the MQTT settings should be set correctly, the link to the server and the token. To do that, search for a MQTT node.

Click on it and you see the following popup screen:

Click on the edit button after server and the edit screen for updating the server appears.

Fill in your server address. Select the tab Security and also fill in your token. Now the noded application can be deployed.

Open a new web browser window and go to the dashboard. The dashboard has the same address as the Node-RED application but with /UI (localhost:1880/ui/):

If all is configured correctly, you should be able to control the snowball remotely.

Making the Smiling Snowball

The last step is creating the snowball self. Start making the snowball out of cardboard. You need cardboard of 400 mm x 400 mm (15.7 inch x 15.7 inch). Cut out a circle with a diameter of 400 mm (15.7 inch). Draw the squares where the matrices should be placed as shown in the following drawing.

Cut out the places where the matrices should be placed, the black squares as shown in the drawing above.

Paste over the front the white paper and make it look like a snow ball.

After checking the matrices and defining which is which matrices, you put the matrices in the face on the correct places. Paste the matrices with tape on the cardboard. The result should be as the image below.

Have fun with it.

Schematics

Smiling snowball schematic
Smiling snowball schematic
Smiling snow ball 3jbrsl9oi6
Smiling snow ball Schematic
Schematic

Code

node-red appJSON
This is the code of the node-red app. This should be load into the node-red application
[
    {
        "id": "fbd88594.573d08",
        "type": "mqtt out",
        "z": "daed2f2c.21fb8",
        "name": "toSnowball",
        "topic": "/example",
        "qos": "",
        "retain": "",
        "broker": "a12126f8.1e69a",
        "x": 387.5,
        "y": 1592,
        "wires": []
    },
    {
        "id": "db9dce3e.43013",
        "type": "debug",
        "z": "daed2f2c.21fb8",
        "name": "",
        "active": false,
        "console": "false",
        "complete": "payload",
        "x": 388.5,
        "y": 1639,
        "wires": []
    },
    {
        "id": "861e8949.06186",
        "type": "mqtt in",
        "z": "daed2f2c.21fb8",
        "name": "FromSnowBall",
        "topic": "hearbeat",
        "qos": "0",
        "broker": "a12126f8.1e69a",
        "x": 138.5,
        "y": 1641,
        "wires": [
            [
                "db9dce3e.43013",
                "fbd88594.573d08"
            ]
        ]
    },
    {
        "id": "b0a220f.ab1a1e",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 5,
        "width": "2",
        "height": "1",
        "label": "Center",
        "color": "",
        "icon": "",
        "payload": "center",
        "payloadType": "str",
        "topic": "",
        "x": 671.5,
        "y": 883,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "2457b666.54195a",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 4,
        "width": "2",
        "height": "1",
        "label": "Left",
        "color": "",
        "icon": "",
        "payload": "left",
        "payloadType": "str",
        "topic": "",
        "x": 524.5,
        "y": 879,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "80872600.e2fa48",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 6,
        "width": "2",
        "height": "1",
        "label": "Right",
        "color": "",
        "icon": "",
        "payload": "right",
        "payloadType": "str",
        "topic": "",
        "x": 838.5,
        "y": 882,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "28643fd9.ad6518",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 2,
        "width": "2",
        "height": "1",
        "label": "Top",
        "color": "",
        "icon": "",
        "payload": "top",
        "payloadType": "str",
        "topic": "",
        "x": 666.5,
        "y": 826,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "5b7dd8cc.005a08",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 8,
        "width": "2",
        "height": "1",
        "label": "bottom",
        "color": "",
        "icon": "",
        "payload": "bottom",
        "payloadType": "str",
        "topic": "",
        "x": 693.5,
        "y": 949,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "8bdf49a8.2eeba8",
        "type": "mqtt out",
        "z": "daed2f2c.21fb8",
        "name": "toSnowball",
        "topic": "/eyes",
        "qos": "",
        "retain": "",
        "broker": "a12126f8.1e69a",
        "x": 1032,
        "y": 1056,
        "wires": []
    },
    {
        "id": "93a67924.f83e38",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "small",
        "group": "e00f2901.fe8838",
        "order": 1,
        "width": 0,
        "height": 0,
        "label": "Small",
        "color": "",
        "icon": "",
        "payload": "small",
        "payloadType": "str",
        "topic": "small",
        "x": 839.5,
        "y": 1309,
        "wires": [
            [
                "6220adf8.7af16c"
            ]
        ]
    },
    {
        "id": "6220adf8.7af16c",
        "type": "mqtt out",
        "z": "daed2f2c.21fb8",
        "name": "toSnowball",
        "topic": "/nose",
        "qos": "",
        "retain": "",
        "broker": "a12126f8.1e69a",
        "x": 1033,
        "y": 1405,
        "wires": []
    },
    {
        "id": "7ac858e1.80f348",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "e00f2901.fe8838",
        "order": 3,
        "width": 0,
        "height": 0,
        "label": "Large",
        "color": "",
        "icon": "",
        "payload": "large",
        "payloadType": "str",
        "topic": "",
        "x": 835,
        "y": 1397,
        "wires": [
            [
                "6220adf8.7af16c"
            ]
        ]
    },
    {
        "id": "2607a19.14ac25e",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "e00f2901.fe8838",
        "order": 2,
        "width": 0,
        "height": 0,
        "label": "Medium",
        "color": "",
        "icon": "",
        "payload": "medium",
        "payloadType": "str",
        "topic": "",
        "x": 827,
        "y": 1355,
        "wires": [
            [
                "6220adf8.7af16c"
            ]
        ]
    },
    {
        "id": "f85268ea.68839",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "e00f2901.fe8838",
        "order": 4,
        "width": 0,
        "height": 0,
        "label": "Big",
        "color": "",
        "icon": "",
        "payload": "big",
        "payloadType": "str",
        "topic": "",
        "x": 833,
        "y": 1437,
        "wires": [
            [
                "6220adf8.7af16c"
            ]
        ]
    },
    {
        "id": "3b99d679.c539ca",
        "type": "ui_slider",
        "z": "daed2f2c.21fb8",
        "name": "delay",
        "label": "slider",
        "group": "e00f2901.fe8838",
        "order": 0,
        "width": 0,
        "height": 0,
        "passthru": true,
        "topic": "delay",
        "min": "1",
        "max": "20",
        "step": 1,
        "x": 830.5,
        "y": 1519,
        "wires": [
            [
                "f87468fd.38345"
            ]
        ]
    },
    {
        "id": "f3252a6e.a16e3",
        "type": "ui_switch",
        "z": "daed2f2c.21fb8",
        "name": "",
        "label": "switch",
        "group": "e00f2901.fe8838",
        "order": 0,
        "width": 0,
        "height": 0,
        "passthru": true,
        "topic": "",
        "style": "",
        "onvalue": "loop",
        "onvalueType": "str",
        "onicon": "",
        "oncolor": "",
        "offvalue": "stop",
        "offvalueType": "str",
        "officon": "",
        "offcolor": "",
        "x": 831.5,
        "y": 1476,
        "wires": [
            [
                "6220adf8.7af16c"
            ]
        ]
    },
    {
        "id": "f87468fd.38345",
        "type": "mqtt out",
        "z": "daed2f2c.21fb8",
        "name": "toSnowball",
        "topic": "/nose/delay",
        "qos": "",
        "retain": "",
        "broker": "a12126f8.1e69a",
        "x": 1028,
        "y": 1520,
        "wires": []
    },
    {
        "id": "4e38fe97.d8c688",
        "type": "mqtt out",
        "z": "daed2f2c.21fb8",
        "name": "toSnowball/mouth",
        "topic": "/mouth",
        "qos": "",
        "retain": "",
        "broker": "a12126f8.1e69a",
        "x": 1071,
        "y": 1705,
        "wires": []
    },
    {
        "id": "d7fd70d3.cfdac",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "1aba77e1.bdd988",
        "order": 0,
        "width": 0,
        "height": 0,
        "label": "Normal",
        "color": "",
        "icon": "",
        "payload": "smile",
        "payloadType": "str",
        "topic": "",
        "x": 843.5,
        "y": 1676,
        "wires": [
            [
                "4e38fe97.d8c688"
            ]
        ]
    },
    {
        "id": "43b5ca11.00f104",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "1aba77e1.bdd988",
        "order": 0,
        "width": 0,
        "height": 0,
        "label": "smile",
        "color": "",
        "icon": "",
        "payload": "normal",
        "payloadType": "str",
        "topic": "",
        "x": 831.5,
        "y": 1725,
        "wires": [
            [
                "4e38fe97.d8c688"
            ]
        ]
    },
    {
        "id": "ef75f714.bcaee",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "1aba77e1.bdd988",
        "order": 0,
        "width": 0,
        "height": 0,
        "label": "open",
        "color": "",
        "icon": "",
        "payload": "sad",
        "payloadType": "str",
        "topic": "",
        "x": 828.5,
        "y": 1779,
        "wires": [
            [
                "4e38fe97.d8c688"
            ]
        ]
    },
    {
        "id": "80e9b7d.b16e748",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 11,
        "width": "3",
        "height": "1",
        "label": "wink left",
        "color": "",
        "icon": "",
        "payload": "closeleft",
        "payloadType": "str",
        "topic": "",
        "x": 585.5,
        "y": 1041,
        "wires": [
            [
                "8bdf49a8.2eeba8",
                "e0584be7.8521e"
            ]
        ]
    },
    {
        "id": "97d7bcd7.21817",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 12,
        "width": "3",
        "height": "1",
        "label": "wink right",
        "color": "",
        "icon": "",
        "payload": "closeright",
        "payloadType": "str",
        "topic": "",
        "x": 418,
        "y": 1052,
        "wires": [
            [
                "8bdf49a8.2eeba8",
                "e0584be7.8521e"
            ]
        ]
    },
    {
        "id": "e0584be7.8521e",
        "type": "delay",
        "z": "daed2f2c.21fb8",
        "name": "",
        "pauseType": "delay",
        "timeout": "600",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 614.5,
        "y": 1203,
        "wires": [
            [
                "dd1a4d7a.b1657"
            ]
        ]
    },
    {
        "id": "dd1a4d7a.b1657",
        "type": "function",
        "z": "daed2f2c.21fb8",
        "name": "",
        "func": "msg.payload = \"center\"\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 785.5,
        "y": 1204,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "56b9ffe4.6808f8",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 7,
        "width": "2",
        "height": "1",
        "label": "bottomleft",
        "color": "",
        "icon": "",
        "payload": "bottomleft",
        "payloadType": "str",
        "topic": "",
        "x": 541,
        "y": 944,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "e7ea10fb.7d314",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 1,
        "width": "2",
        "height": "1",
        "label": "topleft",
        "color": "",
        "icon": "",
        "payload": "topleft",
        "payloadType": "str",
        "topic": "",
        "x": 520,
        "y": 827,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "bf268514.385748",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 3,
        "width": "2",
        "height": "1",
        "label": "topright",
        "color": "",
        "icon": "",
        "payload": "topright",
        "payloadType": "str",
        "topic": "",
        "x": 837,
        "y": 827,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "592a2c8d.3fb214",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 9,
        "width": "2",
        "height": "1",
        "label": "bottomright",
        "color": "",
        "icon": "",
        "payload": "bottomright",
        "payloadType": "str",
        "topic": "",
        "x": 841,
        "y": 949,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "235349b8.aca95e",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 13,
        "width": "3",
        "height": "1",
        "label": "close left",
        "color": "",
        "icon": "",
        "payload": "closeleft",
        "payloadType": "str",
        "topic": "",
        "x": 409,
        "y": 1124,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "b3ca271c.fad09",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 14,
        "width": "3",
        "height": "1",
        "label": "close right",
        "color": "",
        "icon": "",
        "payload": "closeright",
        "payloadType": "str",
        "topic": "",
        "x": 576,
        "y": 1128,
        "wires": [
            [
                "8bdf49a8.2eeba8"
            ]
        ]
    },
    {
        "id": "6f5983c4.333704",
        "type": "ui_button",
        "z": "daed2f2c.21fb8",
        "name": "",
        "group": "83d787c8.772b68",
        "order": 10,
        "width": "6",
        "height": "1",
        "label": "",
        "color": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "",
        "x": 378.5,
        "y": 995,
        "wires": [
            []
        ]
    },
    {
        "id": "a12126f8.1e69a",
        "type": "mqtt-broker",
        "z": "",
        "broker": "broker.shiftr.io",
        "port": "1883",
        "clientid": "snowballcontrol",
        "usetls": false,
        "compatmode": true,
        "keepalive": "60",
        "cleansession": true,
        "willTopic": "",
        "willQos": "0",
        "willRetain": "false",
        "willPayload": "",
        "birthTopic": "",
        "birthQos": "0",
        "birthRetain": "false",
        "birthPayload": ""
    },
    {
        "id": "83d787c8.772b68",
        "type": "ui_group",
        "z": "",
        "name": "eyes",
        "tab": "d56be19f.f63f8",
        "disp": true,
        "width": "6"
    },
    {
        "id": "e00f2901.fe8838",
        "type": "ui_group",
        "z": "",
        "name": "nose",
        "tab": "2e8148a8.8d124",
        "order": 1,
        "disp": true,
        "width": "6"
    },
    {
        "id": "1aba77e1.bdd988",
        "type": "ui_group",
        "z": "",
        "name": "mouth",
        "tab": "546282df.7056d4",
        "disp": true,
        "width": "6"
    },
    {
        "id": "d56be19f.f63f8",
        "type": "ui_tab",
        "z": "",
        "name": "eyes",
        "icon": "dashboard"
    },
    {
        "id": "2e8148a8.8d124",
        "type": "ui_tab",
        "z": "",
        "name": "nose",
        "icon": "nose",
        "order": 3
    },
    {
        "id": "546282df.7056d4",
        "type": "ui_tab",
        "z": "",
        "name": "Mouth",
        "icon": "dashboard"
    }
]
MatrixControl
Liberary for controlling the led matrix based on the MAX7219
Arduino code
Smiling snowball code

Comments

Similar projects you might like

Flightduino 101

Project tutorial by Tom Minnich

  • 525 views
  • 0 comments
  • 9 respects

Arduino 101 BLE App

Project in progress by Alexis Santiago Allende

  • 2,058 views
  • 12 comments
  • 24 respects

FM radio

Project tutorial by Patrick Müller

  • 8,693 views
  • 3 comments
  • 38 respects

RGB LED strips controller

Project tutorial by Philippe Libioulle

  • 536 views
  • 0 comments
  • 5 respects

SMART CUBE: A New Way to Control Your Home

Project tutorial by Alberto Sartori

  • 1,639 views
  • 0 comments
  • 6 respects

Aquariumatic

Project in progress by Craig Hissett

  • 8,921 views
  • 3 comments
  • 17 respects
Add projectSign up / Login