Introduction: Advent Lantern With POV Animation

Persistence of Vision (POV) projects are around for quite some time, simple and cheap DIY kits are even available for online purchase. POV is based on an optical illusion where we see illuminated objects after the object is no longer illuminated even if only for a short while. Traditional POV projects feature still images based on this principle or running clocks at most. However, nothing prevents to project animations using microcontrollers of sufficient clockspeed and smart RGB LEDs. This particular animation is of a reindeer dragged Christmas sleight for Advent decoration that can be remotely controlled by any WiFi enabled mobile device with web browser. The lantern is powered by the Wemos ESP8266 D1 Mini microcontroller of the Arduino family. Credit for the animated 8-bit reindeer sleight frames goes to a talented graphic artist Richard Fenyo.

Step 1: Parts List

You will need a case for this project that is heavy enough to keep the rotating unit in place without tipping over. An old PSU case is perfect, just be careful to let the capacitors discharge before disassembly. You will also need any kind of a 5V-12V power supply adapter for powering the DC motor. Really any amperage from 500mA and above will do it.

The required parts are listed below with webshop links and current prices.

The overall cost is less than USD 15,- but you will also need some hand tools, drilling, hot-glue, along with soldering equipment and skills.

Step 2: Steps of the Assembly

The unit can fully be assembled following these steps.

  1. Stationary base is built with a DC motor and a switch.
  2. Neopixels are soldered and attached to the straw shaft.
  3. Rotating rig is built with microcontroller, slide switch, infra sensor, and straw shaft.
  4. Wiring is soldered onto the electrical parts' connectors
  5. Arduino code is uploaded to the Wemos microcontroller.

Step 3: 1. Stationary Base With DC Motor

  1. Drill a hole on the case and fix the DC motor such that the shaft points upwards.
  2. Solder the rocker power switch and a regular 5V-12V power supply adapter following the wiring diagram below.
  3. The referred DC motor revolves at about 800 RPM (rotations per minutes) at 12V, resulting around 10 FPS (frames per seconds) in the final setup depending on the actual wind resistance of the straw shaft.
  4. Connect the power supply adapter to the outlet (110 or 220V).
  5. Switch on the rocker and check the working of the DC motor.

Next, the rotating rig will be assembled and fixed onto the DC motor shaft of the base.

Step 4: 2. Neopixel Attachment

  1. Cut the end of the straw in two opposing sides at one end in about 1.5 cm as the picture shows.
  2. Lace three longer wires up the straw. These will connect Neopixel pins onto Wemos ports on the rig.
  3. Solder the three wires onto Neopixel pins GND, 5V and D-IN.
  4. Hot glue the wires neat and tidy from Neopixels soldered end all the way up the exact middle of the LED bar.
  5. Pull the cut wings of the straw apart and hot glue them in exact symmetry onto the center of the LED bar (on top of the wires on one side).
  6. The wires run through inside the straw up to the rig to reach the matching Wemos ports.

Step 5: 3. Assembly of Rotating Rig

The whole rig has to be fully assembled before fixing to the DC motor shaft. That's because the fixing spot needs to be balanced so that the rotation is perfectly centered without any wobbling.

  1. Hot glue the Wemos D1 Mini microcontroller and the slide switch to one side of the battery holder as the picture shows.
  2. Hot glue the infra reflection sensor to the other side of the battery holder.
  3. Place the batteries in the holder.
  4. Place and fasten the straw's other end on top of the batteries. A small screw or a rubber ring will do it. Make sure that it will not get lose once the rig starts rotating at 10 RPM.
  5. Locate the whole rigs center of gravity on the bottom side. Balancing it on the tip of your finger will do it.
  6. Make a small hole at the exact spot on the bottom of the battery holder.
  7. Apply some hot glue and fix the motor shaft into that hole. Make sure that the hot glue does not get into the motor body. Keep it with steady until the glue dries.
  8. Cut a small piece of white paper and tape it onto the stationary base such that the infrared reflective sensor is turning exactly near that paper. This will trigger the drawing of the frames of the animation at the exact place in every rotation. The picture show this reflection piece on the left bottom corner of the base.

Step 6: 4. Wiring of Electrical Components

Following the wiring diagram, solder the electrical components in the following steps. Note that the same port of the Wemos D1 Mini microcontroller will be soldered multiple times with multiple different wires. That takes some practice, or connect these wires in preparation before soldering onto the Wemos port.

  1. Three wires (GND, 5V and D-IN) is soldered onto Wemos ports G, 5V, and D3 respectively.
  2. Two wires from Infrared Reflective Sensor (VCC, GND, OUT) is soldered onto Wemos ports 5V, G, and D2 respectively.
  3. Battery holder ground (Black) wire is soldered onto Wemos port G.
  4. Battery holder positive (Red) wire is soldered onto the slide switch closest pin.
  5. Wemos 5V port is soldered onto the other pin of the slide switch.

Step 7: 5. Arduino Code

This particular code is for the 24 bits version of the POV Lantern, can be remotely controlled by any mobile devices with web browsers and features visual effects like World Map, Matrix Animation Effect, and the Reindeer Sleight animation. Feel free to adjust the number of pixels, effect parameters, or WiFi remote interface to your needs in the source code.

// 24 bits POV Lantern - 2019 Peter Csurgay

#include ESP8266WiFiMulti.h #include WiFiClient.h #include ESP8266WebServer.h #include WebSocketsServer.h #include Adafruit_NeoPixel.h

#define DEBUG 1

String text[3] = { "INSTRUCTABLES", "ARDUINO", "CONTEST" };

const uint8_t palette[8][3] = { { 0,0,0 }, // 0 - Transparent { 0,0,127 }, // 1 - Blue { 127,0,0 }, // 2 - Red { 127,127,0 }, // 3 - Yellow { 0,127,0 }, // 4 - Green { 127,24,0 }, // 5 - Orange { 127,0,127 }, // 6 - Magenta { 127,127,127 } // 7 - White };

const unsigned char world[24][42] PROGMEM = { { 0,0,0,1,1, 1,1,1,1,0, 0,1,0,0,1, 1,0,0,0,0, 0,1,1,0,0, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,0, 0,0 }, { 0,0,1,1,1, 1,1,1,0,0, 1,0,0,1,0, 0,0,0,0,0, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,0,1,0,0, 0,0 }, { 0,0,1,1,1, 1,1,1,0,1, 1,0,0,0,0, 0,0,0,0,0, 1,0,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 0,0,0,0,0, 0,0 }, { 0,1,1,1,1, 1,1,1,1,1, 1,0,0,0,0, 0,0,0,0,0, 0,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,0,0,0, 0,0 }, { 0,1,1,1,1, 1,1,1,1,0, 0,0,0,0,0, 0,0,0,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,0,0,0, 0,0 },

{ 1,1,1,1,1, 1,1,1,0,0, 0,0,0,0,0, 0,0,0,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,0,0,0,0, 0,0 }, { 1,1,1,1,1, 1,1,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,0,0,0,0, 0,0 }, { 1,1,1,1,1, 1,0,0,0,0, 0,0,0,0,0, 0,0,1,1,0, 0,0,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 0,0,0,0,0, 0,0 }, { 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,1,1,1,1, 1,1,0,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,0,0,0,0, 0,0 }, { 0,1,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 0,0,0,0,0, 0,0 },

{ 0,0,1,1,0, 0,0,0,0,0, 0,0,0,0,0, 1,1,1,1,1, 1,1,1,1,1, 1,0,0,1,1, 1,0,1,1,0, 0,0,0,0,0, 0,0 }, { 0,0,0,1,0, 0,0,0,0,0, 0,0,0,0,0, 1,1,1,1,1, 1,1,1,1,1, 1,0,0,0,1, 0,0,0,1,0, 0,0,0,0,0, 0,0 }, { 0,0,0,0,0, 1,1,1,0,0, 0,0,0,0,0, 1,1,1,1,1, 1,1,1,1,1, 0,0,0,0,1, 0,0,0,0,0, 0,0,0,0,0, 0,0 }, { 0,0,0,0,0, 1,1,1,1,0, 0,0,0,0,0, 0,1,0,1,1, 1,1,1,1,1, 0,0,0,0,0, 0,0,0,0,0, 1,0,0,0,0, 0,0 }, { 0,0,0,0,1, 1,1,1,1,1, 0,0,0,0,0, 0,0,0,0,1, 1,1,1,1,0, 0,0,0,0,0, 0,0,0,1,0, 1,0,0,0,0, 0,0 },

{ 0,0,0,0,1, 1,1,1,1,1, 1,1,0,0,0, 0,0,0,0,1, 1,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1, 1,0 }, { 0,0,0,0,0, 1,1,1,1,1, 1,1,0,0,0, 0,0,0,0,1, 1,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 1,0 }, { 0,0,0,0,0, 1,1,1,1,1, 1,0,0,0,0, 0,0,0,0,1, 1,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,1,1,0, 0,0 }, { 0,0,0,0,0, 0,1,1,1,1, 1,0,0,0,0, 0,0,0,0,1, 1,1,1,0,1, 0,0,0,0,0, 0,0,0,0,0, 0,1,1,1,1, 0,0 }, { 0,0,0,0,0, 0,0,1,1,1, 0,0,0,0,0, 0,0,0,0,0, 1,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0, 1,1,1,1,1, 1,0 },

{ 0,0,0,0,0, 0,0,1,1,1, 0,0,0,0,0, 0,0,0,0,0, 1,1,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 1,1,1,1,1, 1,0 }, { 0,0,0,0,0, 0,0,1,1,1, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,1,1, 0,0 }, { 0,0,0,0,0, 0,0,1,1,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0 }, { 0,0,0,0,0, 0,0,0,1,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0 } };

const unsigned char pepper[24][8+31] PROGMEM = { { 0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,1,1,1,1,1,1,0, 0,4,4,4,0,0,4,4,4,4,0,4,4,4,0,0,4,4,4,0,0,4,4,4,4,0,4,4,4,0,0 }, { 0,1,1,1,1,1,1,0, 0,4,0,0,4,0,4,0,0,0,0,4,0,0,4,0,4,0,0,4,0,4,0,0,0,0,4,0,0,4,0 }, { 1,1,0,1,1,0,1,1, 0,4,0,0,4,0,4,4,4,0,0,4,0,0,4,0,4,0,0,4,0,4,4,4,0,0,4,0,0,4,0 }, { 1,1,1,1,1,1,1,1, 0,4,4,4,0,0,4,0,0,0,0,4,4,4,0,0,4,4,4,0,0,4,0,0,0,0,4,4,4,0,0 }, { 0,1,1,0,0,1,1,0, 0,4,0,0,0,0,4,4,4,4,0,4,0,0,0,0,4,0,0,0,0,4,4,4,4,0,4,0,0,4,0 }, { 0,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },

{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,1,0,0 ,0,0,0 }, { 0,4,0,0,4,0,4,0,0,4,0,4,4,4,0,0,4,4,4,0,0,0,4,4,0,0, 0,0,0,1,0,0,1,0,0,0 ,0,0,0 }, { 0,4,0,0,4,0,4,0,0,4,0,4,0,0,4,0,4,0,0,4,0,4,0,0,4,0, 0,1,1,1,1,1,1,1,1,0 ,0,0,0 }, { 0,4,4,4,4,0,4,0,0,4,0,4,0,0,4,0,4,4,4,0,0,4,4,4,4,0, 0,1,1,0,1,1,0,1,1,0 ,0,0,0 }, { 0,4,0,0,4,0,4,0,0,4,0,4,4,4,0,0,4,0,0,4,0,4,0,0,4,0, 0,1,1,1,1,1,1,1,1,0 ,0,0,0 }, { 0,4,0,0,4,0,0,4,4,0,0,4,0,0,4,0,4,4,4,0,0,4,0,0,4,0, 0,0,0,1,0,0,1,0,0,0 ,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,1,0,0,0,0 ,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0 ,0,0,0 },

{ 0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,1,1,1,1,1,1,0, 0,4,4,4,0,0,4,4,4,4,0,4,4,4,0,0,4,4,4,0,0,4,4,4,4,0,4,4,4,0,0 }, { 0,1,1,1,1,1,1,0, 0,4,0,0,4,0,4,0,0,0,0,4,0,0,4,0,4,0,0,4,0,4,0,0,0,0,4,0,0,4,0 }, { 1,1,0,1,1,0,1,1, 0,4,0,0,4,0,4,4,4,0,0,4,0,0,4,0,4,0,0,4,0,4,4,4,0,0,4,0,0,4,0 }, { 1,1,1,1,1,1,1,1, 0,4,4,4,0,0,4,0,0,0,0,4,4,4,0,0,4,4,4,0,0,4,0,0,0,0,4,4,4,0,0 }, { 0,1,1,0,0,1,1,0, 0,4,0,0,0,0,4,4,4,4,0,4,0,0,0,0,4,0,0,0,0,4,4,4,4,0,4,0,0,4,0 }, { 0,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };

const unsigned char abc[8][27*5] PROGMEM = { { 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,1,1,0,0, 1,1,1,0,0, 0,1,1,1,0, 1,1,1,0,0, 1,1,1,1,0, 1,1,1,1,0, 0,1,1,1,0, 1,0,0,1,0, 1,1,1,0,0, 0,0,0,1,0, 1,0,0,1,0, 1,0,0,0,0, 1,0,0,1,0, 1,0,0,1,0, 0,1,1,0,0, 1,1,1,0,0, 0,1,1,0,0, 1,1,1,0,0, 0,1,1,1,0, 1,1,1,1,1, 1,0,0,1,0, 1,0,0,0,1, 1,0,0,0,1, 1,0,0,0,1, 1,0,0,0,1, 1,1,1,1,0, 0,0,0,0,0 }, { 1,0,0,1,0, 1,0,0,1,0, 1,0,0,0,0, 1,0,0,1,0, 1,0,0,0,0, 1,0,0,0,0, 1,0,0,0,0, 1,0,0,1,0, 0,1,0,0,0, 0,0,0,1,0, 1,0,1,0,0, 1,0,0,0,0, 1,1,1,1,0, 1,1,0,1,0, 1,0,0,1,0, 1,0,0,1,0, 1,0,0,1,0, 1,0,0,1,0, 1,0,0,0,0, 0,0,1,0,0, 1,0,0,1,0, 1,0,0,0,1, 1,0,0,0,1, 0,1,0,1,0, 0,1,0,1,0, 0,0,1,0,0, 0,0,0,0,0 }, { 1,1,1,1,0, 1,1,1,0,0, 1,0,0,0,0, 1,0,0,1,0, 1,1,1,0,0, 1,1,1,0,0, 1,0,1,1,0, 1,1,1,1,0, 0,1,0,0,0, 0,0,0,1,0, 1,1,0,0,0, 1,0,0,0,0, 1,0,0,1,0, 1,0,1,1,0, 1,0,0,1,0, 1,0,0,1,0, 1,0,0,1,0, 1,1,1,0,0, 0,1,1,0,0, 0,0,1,0,0, 1,0,0,1,0, 1,0,0,0,1, 1,0,0,0,1, 0,0,1,0,0, 0,0,1,0,0, 0,1,1,0,0, 0,0,0,0,0 }, { 1,0,0,1,0, 1,0,0,1,0, 1,0,0,0,0, 1,0,0,1,0, 1,0,0,0,0, 1,0,0,0,0, 1,0,0,1,0, 1,0,0,1,0, 0,1,0,0,0, 1,0,0,1,0, 1,0,1,0,0, 1,0,0,0,0, 1,0,0,1,0, 1,0,0,1,0, 1,0,0,1,0, 1,1,1,0,0, 1,0,1,1,0, 1,0,1,0,0, 0,0,0,1,0, 0,0,1,0,0, 1,0,0,1,0, 0,1,0,1,0, 1,0,1,0,1, 0,1,0,1,0, 0,0,1,0,0, 0,1,0,0,0, 0,0,0,0,0 }, { 1,0,0,1,0, 1,1,1,0,0, 0,1,1,1,0, 1,1,1,0,0, 1,1,1,1,0, 1,0,0,0,0, 0,1,1,0,0, 1,0,0,1,0, 1,1,1,0,0, 0,1,1,0,0, 1,0,0,1,0, 1,1,1,1,0, 1,0,0,1,0, 1,0,0,1,0, 0,1,1,0,0, 1,0,0,0,0, 0,1,1,1,0, 1,0,0,1,0, 1,1,1,0,0, 0,0,1,0,0, 0,1,1,0,0, 0,0,1,0,0, 0,1,0,1,0, 1,0,0,0,1, 0,0,1,0,0, 1,1,1,1,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0 } };

const unsigned char santa[4][8][41] PROGMEM = { { { 0,0,2,2, 2,2,2,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,2,0,0, 2,0,0,0,0, 0,0,2,0, 0,2,0,0 }, { 0,0,2,2, 2,2,2,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,1, 0,0,0,0,0, 0,0,0,1, 1,0,0,0 }, { 0,1,1,1, 1,1,1,1, 1,0,0,0, 0,1,1,0, 0,0,0,0, 0,1,0,0, 0,0,0,1, 1,2,0,1,0, 0,0,0,0, 1,1,2,0 }, { 0,0,0,1, 1,1,1,1, 1,1,1,0, 1,0,0,1, 1,0,0,0, 0,0,1,1, 1,1,1,1, 0,0,0,0,1, 1,1,1,1, 1,0,0,0 },

{ 0,0,0,0, 1,1,1,1, 1,1,1,0, 0,0,0,1, 0,1,1,0, 0,1,1,1, 1,1,1,1, 0,0,0,0,1, 1,1,1,1, 1,0,0,0 }, { 0,0,1,0, 0,1,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, 1,0,1,0, 0,0,1,0, 0,0,0,0,1, 0,0,0,1, 1,0,0,0 }, { 0,0,0,1, 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, 0,0,0,1, 0,0,1,0, 0,0,0,0,0, 1,1,0,1, 0,0,0,0 }, { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,1,0, 0,0,0,0,0, 0,0,1,0, 0,0,0,0 } }, { { 0,0,2,2, 2,2,2,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,2,0,0, 2,0,0,0,0, 0,0,2,0, 0,2,0,0 }, { 0,0,2,2, 2,2,2,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,1, 0,0,0,0,0, 0,0,0,1, 1,0,0,0 }, { 0,1,1,1, 1,1,1,1, 1,0,0,0, 0,1,1,0, 0,0,0,0, 0,1,0,0, 0,0,0,1, 1,2,0,1,0, 0,0,0,0, 1,1,2,0 }, { 0,0,0,1, 1,1,1,1, 1,1,1,0, 1,0,0,1, 1,0,0,0, 0,0,1,1, 1,1,1,1, 0,0,0,0,1, 1,1,1,1, 1,0,0,0 },

{ 0,0,0,0, 1,1,1,1, 1,1,1,0, 0,0,0,1, 0,1,1,0, 0,1,1,1, 1,1,1,1, 0,0,0,0,1, 1,1,1,1, 1,0,0,0 }, { 0,0,1,0, 0,1,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, 1,0,1,0, 0,0,1,1, 0,0,0,0,1, 0,0,0,1, 0,0,0,0 }, { 0,0,0,1, 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, 0,0,0,1, 1,0,1,0, 0,0,0,0,0, 1,1,0,1, 0,0,0,0 }, { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,1,0,0, 0,0,0,0,0, 0,0,0,0, 1,0,0,0 } }, { { 0,0,2,2, 2,2,2,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,2,0,0, 2,0,0,0,0, 0,0,2,0, 0,2,0,0 }, { 0,0,2,2, 2,2,2,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,1, 0,0,0,0,0, 0,0,0,1, 1,0,0,0 }, { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,1, 1,2,0,0,1, 0,0,0,0, 1,1,2,0 }, { 0,1,1,1, 1,1,1,1, 1,0,0,0, 0,1,1,0, 0,0,0,0, 0,0,1,1, 1,1,1,1, 0,0,0,0,1, 1,1,1,1, 1,0,0,0 },

{ 0,0,0,1, 1,1,1,1, 1,1,1,0, 1,0,0,1, 1,0,0,0, 0,1,1,1, 1,1,1,1, 0,0,0,0,1, 1,1,1,1, 1,0,0,0 }, { 0,0,0,0, 1,1,1,1, 1,1,1,0, 0,0,0,1, 0,1,1,1, 1,0,1,0, 0,0,1,0, 0,0,0,0,1, 0,0,0,0, 1,0,0,0 }, { 0,0,1,0, 0,1,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,0, 0,0,0,1, 1,0,1,0, 0,0,0,0,1, 0,0,0,1, 0,0,0,0 }, { 0,0,0,1, 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,1,0, 0,0,0,0, 0,0,0,0 } }, { { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,2,0,0, 2,0,0,0,0, 0,0,2,0, 0,2,0,0 }, { 0,0,2,2, 2,2,2,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,1, 0,0,0,0,0, 0,0,0,1, 1,0,0,0 }, { 0,0,2,2, 2,2,2,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,1, 1,2,0,1,0, 0,0,0,0, 1,1,2,0 }, { 0,1,1,1, 1,1,1,1, 1,0,0,0, 0,1,1,0, 0,0,0,0, 0,0,1,1, 1,1,1,1, 0,0,0,0,1, 1,1,1,1, 1,0,0,0 },

{ 0,0,0,1, 1,1,1,1, 1,1,1,0, 1,0,0,1, 1,0,0,0, 0,1,1,1, 1,1,1,1, 0,0,0,0,1, 1,1,1,1, 1,0,0,0 }, { 0,0,0,0, 1,1,1,1, 1,1,1,0, 0,0,0,1, 0,1,1,1, 1,0,1,0, 0,0,0,1, 0,0,0,0,1, 0,0,0,1, 0,0,0,0 }, { 0,0,1,0, 0,1,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,0, 0,0,1,0, 0,0,1,0, 0,0,0,0,0, 1,0,0,1, 0,0,0,0 }, { 0,0,0,1, 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, 0,1,0,0, 0,0,0,0, 0,0,0,0,0, 1,0,0,1, 0,0,0,0 } } };

#define INFRATRIGGER_PIN D2 #define NEOPIXELS_PIN D3 #define NEO_NUMPIXELS 24

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NEO_NUMPIXELS,NEOPIXELS_PIN,NEO_GRB + NEO_KHZ800);

IPAddress localIPaddress; IPAddress apIPaddress; WiFiServer server(80); WebSocketsServer webSocket = WebSocketsServer(81); uint8_t canvas[24][65]; uint8_t co = 0; uint8_t scene = 0; uint8_t numScenes = 5; String scenes[6] = { "WORLD", "SANTA", "PEPPER", "TEXT", "MATRIX" }; uint8_t rotate = 1; uint8_t numGreens = 0; // MATRIX number of falling lines uint8_t greens[64][2]; // MATRIX random pos x and y of falling lines

void setup() { if (DEBUG) { Serial.begin(9600); Serial.println("Start..."); } delay(3000);

ESP8266WiFiMulti wifiMulti; wifiMulti.addAP("wifissid", "pwd"); wifiMulti.addAP("mobilessid", "pwd"); wifiMulti.addAP("laptopssid", "pwd"); if (DEBUG) Serial.print("Connecting Station to "); while (wifiMulti.run() != WL_CONNECTED) { delay(1000); if (DEBUG) Serial.print("."); } if (DEBUG) Serial.println(""); if (DEBUG) Serial.print("WiFi connected: SSID="); if (DEBUG) Serial.println(WiFi.SSID()); localIPaddress = WiFi.localIP(); if (DEBUG) Serial.print("Local Station IP address: "); if (DEBUG) Serial.println(localIPaddress);

server.begin(); if (DEBUG) Serial.println("Server(80) started"); webSocket.begin(); webSocket.onEvent(webSocketEvent); if (DEBUG) Serial.println("WebSocket(81) started"); uint8_t coli = 0; for (int i=0; i<24; i++) { for (int j=0; j<64; j++) { canvas[i][j] = coli++; coli = coli % 7; } canvas[i][64] = 0; } pinMode(INFRATRIGGER_PIN,INPUT); attachInterrupt(digitalPinToInterrupt(INFRATRIGGER_PIN),paint,RISING); pixels.begin(); pixels.show(); if (DEBUG) { Serial.print("Neopixel started, NUMPIXELS: "); Serial.println(pixels.numPixels()); } }

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { if (type == WStype_TEXT){ String req = String((const char *)payload); if (DEBUG) { Serial.print("81 Req: "); Serial.println(req); } processReq(req); } }

String rip2(String s) { String res; int i=0; while(s[i]!='/') i++; i++; while(s[i]!='/') i++; i++; while(s[i]!='/' && s[i]!=' ' && s[i]!='\r' && s[i]!='\n') res += s[i++]; return res; }

void processReq(String req) { if (req.indexOf("/rotate") != -1) { rotate = 1; } else if (req.indexOf("/scene") != -1) { rotate = 0; String sc = rip2(req); if (isDigit(sc[0])) scene = sc.toInt(); else { scene = 0; for (int i=0; i

void loop() { webSocket.loop(); WiFiClient client = server.available(); if (!client) { return; } String req = client.readStringUntil('\r'); if (DEBUG) { Serial.print("80 Req: "); Serial.println(req); } processReq(req);

client.flush(); String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nAccess-Control-Allow-Headers: Content-Type\r\nAccess-Control-Allow-Origin: *\r\nConnection: close\r\n\r\n"; s += "localIP: " + ipToString(localIPaddress) + ""; s += "apIP: " + ipToString(apIPaddress) + ""; client.print(s); delay(100); client.stop(); }

void paint() { for (int i=0; i<65; i++) { for (int j=0; j<24; j++) { unsigned char ind = canvas[j][i]; pixels.setPixelColor(j,pixels.Color(palette[ind][0],palette[ind][1],palette[ind][2])); } pixels.show(); delayMicroseconds(10); } co = (co + 1) % 40; if (rotate) { if (co==0) { scene = (scene+1) % numScenes; if (DEBUG) { Serial.print("Scene: "); Serial.println(scene); } } if (co==0) loadCanvas(scenes[scene]); } if (scenes[scene].indexOf("SANTA") != -1) { for (int i=0; i<8; i++) for (int j=0; j<65; j++) if (j>=co && j

void loadCanvas(String what) { clearCanvas(); if (DEBUG) { Serial.print("loadCanvas: "); Serial.println(what); } if (what.indexOf("TEXT") != -1) { for (int l=0; l<3; l++) for (int n=0; n=12 && j<51) canvas[i][j] = pgm_read_byte_near(pepper[i]+j-12); } else if (what.indexOf("WORLD") != -1) { for (int i=0; i<24; i++) for (int j=0; j<65; j++) if (j>=11 && j<53) canvas[i][j] = pgm_read_byte_near(world[i]+j-11); } }

void clearCanvas() { if (DEBUG) Serial.println("clearCanvas"); for (int i=0; i<24; i++) for (int j=0; j<65; j++) canvas[i][j] = 0; }

String ipToString(IPAddress ip) { String s=""; for (int i=0; i<4; i++) s += i ? "." + String(ip[i]) : String(ip[i]); return s; }

Arduino Contest 2019

Participated in the
Arduino Contest 2019