Start

[På svenska]

Jellyfish 1

By Hans Mehlin, 2021-01-10.

Jellyfish 1 is an Arduino driven lamp that changes color and animations based on the movements on the stock market.

The color of the animation indicates if the market is moving up or down, while the speed of the animations indicates the speed of the movements on the market. The colors are animated as a cycle between two colors. The tentacles have an additional running white pixel beween each cycle.

Example: Animation indicating a positive market at a speed of about 0,5% over 8 hours:

Example: Animation indicating a negative market at a speed of about 0,5% over 8 hours.

How it was made

Electronics

Jellyfish 1 is based on a NodeMCU V2 Arduino board with builtin WIFI, one NeoPixel Ring with 24 RGB LEDs and 1 meter of NeoPixel Digital RGBW LED strip cut into 3 pieces with 20 LEDs in each. The circuit is powered by external 5V. A capacitor protects the circuit against power spikes and resistors are added between the digital output from the Arduino and the LEDs.

The circuit was first tested on a experimental board, also used while developing the code.

The circuit was later soldered onto a universial board to make it more rugged and reduce the size. The 5V power to the Arduino can easily be disconnected when needed to connect it to USB and update the code.

 

 

Code

The Arduino calls a URL on regular intervalls, to fetch a json file with parameters contolling the colors and the speed of the animation. The animation in the ring is a simple rotating cicle between the two colors specified in the json file. The animation in the strips is a sinus wave between the two colors specified in the json file, and a walking whiter light between each color cycle.


// jellyfish 1 by Hans Mehlin

#include <Adafruit_NeoPixel.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <Arduino_JSON.h>

#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

const char* ssid     = "your ssid here";
const char* password = "your password here";

// Pin for controlling ledstrip
#define LED_PIN    D7
#define LED_PINR   D5

// Number of NeoPixels attached to the Arduino
#define LED_COUNT 20
#define LED_COUNTR 24

// Declare our NeoPixel strip objects:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_RGBW + NEO_KHZ800);
Adafruit_NeoPixel ring(LED_COUNTR, LED_PINR, NEO_GRB + NEO_KHZ800);

void setup() {

  Serial.begin(115200);         // Start the Serial communication to send messages to the computer
  delay(10);
  Serial.println('\n');
  
  WiFi.begin(ssid, password);             // Connect to the network
  Serial.print("Connecting to ");
  Serial.print(ssid); Serial.println(" ...");

  int i = 0;
  while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect
    delay(1000);
    Serial.print(++i); Serial.print(' ');
  }

  Serial.println('\n');
  Serial.println("Connection established!");  
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());         // Send the IP address of the ESP8266 to the computer

  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(20); // Set BRIGHTNESS to 50 is about 1/5 (max = 255)

  ring.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  ring.show();            // Turn OFF all pixels ASAP
  ring.setBrightness(20); // Set BRIGHTNESS to 50 is about 1/5 (max = 255)
}

void loop() {

  int white = 0;
  int whitepixel = 80;
  int r1 = 0;
  int g1 = 0;
  int b1 = 255;
  int r2 = 0;
  int g2 = 255;
  int b2 = 0;
  int width = 20;
  int sleep = 50;

  float part;
  float rad;
  float s;
  int numtimes;
  int offsetr;

//Periodically refresh the variables from the web definition
  if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
    HTTPClient http;  //Declare an object of class HTTPClient
    http.begin("http://your-url-here/data.json");  //Specify request destination
    int httpCode = http.GET();                                                                  //Send the request
    if (httpCode > 0) { //Check the returning code
      String payload = http.getString();   //Get the request response payload
      Serial.println(payload);                     //Print the response payload
      //deserializeJson(vars, payload);
      JSONVar myObject = JSON.parse(payload);
      const char* name = myObject["name"];
      if (myObject.hasOwnProperty("color1")) {
        r1 = myObject["color1"][0];
        g1 = myObject["color1"][1];
        b1 = myObject["color1"][2];
      }
      if (myObject.hasOwnProperty("color2")) {
        r2 = myObject["color2"][0];
        g2 = myObject["color2"][1];
        b2 = myObject["color2"][2];
      }
      if (myObject.hasOwnProperty("width")) {
        width = myObject["width"];
      }
      if (myObject.hasOwnProperty("sleep")) {
        sleep = myObject["sleep"];
      }
      http.end();   //Close connection
    }
  }

  // Number of times to loop before we read the paramaters again
  // 1000000 = about 1 minute

  numtimes = 1000000/(LED_COUNT * width * sleep);
  if (numtimes <= 0) { numtimes = 1; }

  for(int bigloop=0; bigloop<numtimes; bigloop++) {

    for(int offset=0; offset<width; offset++) {
      offsetr = offsetr + 1;
      if (offsetr > LED_COUNTR) {offsetr = offsetr - LED_COUNTR - 1; }
	  
      for(int i=0; i<LED_COUNT; i++) { // For each pixel in strip...
        part = float(i - offset) / float(width);
        rad = part * 6,283;
        s = sin(rad);
        s = s + 1,0;
        s = s / 2,0;
        if (bigloop==0 && offset==0 && i==0) {
          Serial.println("i");
          Serial.println(i);
          Serial.println("s");
          Serial.println(s);
        }
        int r = int( float(r2-r1) * s + float(r1)); 
        int g = int( float(g2-g1) * s + float(g1));
        int b = int( float(b2-b1) * s + float(b1));
        int whitelevel = white;
//        if (i==offset || i==offset-LED_COUNT) { whitelevel = whitepixel; }
        if (i==offset) { whitelevel = whitepixel; }

        strip.setPixelColor(i, g, r, b, whitelevel);         //  Set pixel's color (in RAM)

        for(int j=0; j<LED_COUNTR; j++) { // For each pixel in ring...

          part = float(j - offsetr) / float(LED_COUNTR);
          rad = part * 6,283;
          s = sin(rad);
          s = s + 1,0;
          s = s / 2,0;
          if (bigloop==0 && offset==0 && i==0) {
            Serial.println("i");
            Serial.println(i);
            Serial.println("s");
            Serial.println(s);
          }
          int r = int( float(r2-r1) * s + float(r1)); 
          int g = int( float(g2-g1) * s + float(g1));
          int b = int( float(b2-b1) * s + float(b1));

          ring.setPixelColor(j, r, g, b);         //  Set pixel's color (in RAM)
        }
        ring.show();                          //  Update ring to match
      }
      strip.show();                         //  Update strip to match
      delay(sleep);  
    }
  }
}
	

Below is an example of a json file. In my case it's not a static json file but a php backend that returns json. The backend regularly fetches my indexes from the stock market and calculates appropriate colors and speed. Since the code of the backend is rather personal it's not included here. By separating the visualization in the Arduino and the backend returning json controlling the jellyfish, it can be used to visualize other things as well like weather or social media analytics.

	
{
  "name": "Jellyfish1",
  "sleep": 150,
  "width": 60,
  "color1": [
    0,
    0,
    255
  ],
  "color2": [
    0,
    255,
    0
  ]
}
	
	

 

Mounting

The circuit was mounted inside an upside down round glass candle-holder. The power cable goes though a drilled hole at the top. The led ring is mounted facing up tight to the glass to make the light spread inside the glassware. The strips are mounted as tentacles below the glass. A knot on the power cord keeps it up and cords keep things together and removes stress from cables.

The glassware was covered with some white loosely and irragular fitted fluffy fabric. For the tentacles, a metal wire was fitted into some ribbons to make it possible to adjust thier positions and make them reflect the light. The fabric can easily be removed and the board pulled out from the glassware if a software update is needed.

Website last updated 2024-11
Copyright 2024 Vårboda Studio