Introduction: Cloud Supervision - a Somewhat Useful Funny Display for IT Services Status or Anything Else

About: Software Engineer Musician (Bass Guitar) Maker & Tinkerer

I work in IT Services Management, and spend my days doing cloud-computing related stuff.

I thought it would be fun to have my IT services status reported by a "Cloud Display" :)

I wanted the status changes to be obsvious so I designed a rapid-white-flashes-and-snake animation to be played whenever a status changes.

The animations only play when there is a status change (i.e. not when there's a status refresh).

I also wanted the display to auto turn-off when I leave work (with my laptop with me), so there's a feature that turns-off the display if the services status hasn't been refreshed for a given period (defauts to 2min).


The display is implemented by 10 daisy-chained Neopixel LED. I couldn't use a pre-built LED strip since I need the LED to be about 3cm apart in order to be able to distinguish each LED (and hence each service status).

Supplies

In order to build this thing you'll need:

  • 10 Neopixel (WS2812) LED
  • a Raspberry Pi
  • poly-fill fluff
  • baking paper
  • something to provide a scaffolding for the LED. I've used a bit of chicken wire.
  • insulated wire. I've used scavenged computer flat-wire.
  • a 3.3 to 5v level shifter. I've used this model.

Step 1: Building the Cloud Display

The LED need to be hung on a frame of some sort.

I wanted the frame to be as light as possible and figured-out that a bit of chicken-wire I had laying around would make a good support.

I also formed "legs" in order for the support to be able to be fixed on the upper rim of a monitor.


The upper Neopixels are attached by a bit of electrical wire, torn around the chicken wire and soldered to a GND pad.

No need to be regular, the more irregular, the more "natural" the final look.


After soldering the LED I did a quick test using an ATTiny 85 and the software I've designed for this instructable.

I needed some sort of support for the diffuser to be stuck on, so I used a bit of baking paper roughly cut as a cloud shape.

Then I cut chunks of baking paper, crumpled them in my hands and hot-glued them to the support in order to get a bumpy, irregular surface. I did this for the front side, then back side of the cloud.


A quick power-on test confirmed that I was in headed in the right direction :)


Then I used sprayed polyurethane glue to glue the poly-fill fluff. But I didn't spray directly on the diffuser. I prefered spraying into a small glass jar and using a small paint brush to apply the glue.

The fluff was then applied little by little, covering the whole baking-paper diffuser while trying to keep the surface as rough as possible.

Step 2: Connection to the Raspberry Pi

The Raspberry Pi is a 3.3v device and the Neopixels need to be driven by a 5v signal.

I like to use this simple level shifter. It's overkill for this unidirectional need, but it's trivial to use:

  • Connect the HV (high voltage) supply to pin 2 of the RPi
  • Connect the LV (low voltage) supply to pin 1 of the RPi
  • Connect GPIO 18 (pin 12) to the TXI pin and connect TXO pin to DATA-In pin of the first Neopixel.
  • Connect Ground to both sides, obviously, and to pin 14 of the RPI

Step 3: Raspberry Pi Setup

First, you need to disable the sound driver on the RPi, since it collides with the PWM required by the Neopixels.

This can be done with the following command, followed by a reboot:

echo "blacklist snd_bcm2835" | sudo tee /etc/modprobe.d/snd-blacklist.conf


Then clone the git repo and cd to this repo:

git clone https://github.com/PatriceG/zabbix-neopixel.git
cd zabbix-neopixel

FYI, this script is based on the Zabbix-Cachet script, which has been heavily modified. The only origininal code remaining is the Zabbix access code and config file management.


Create a config.yml from the provided template:

cp config-template.yml config.yml

The config file is self-documented, more on customization later.


Install the required Python libraries. These libraries must be installed as root, since root privilege is required to access the GPIO. The following command installs all but the Neopixel library and its dependencies (to be installed just after)

sudo pip install -r requirements.txt


The script is using the board and neopixel packages, which are part of Adafruit Blinka libraries.

I used this tutorial to install Adafruit Blinka.

Step 4: Using the Software

The software is written as a client-server application.

This is because my company's Zabbix can't be reached from the network the RPi is on.

So the RPi is running the script as a server, while a Linux worsktation is running the same script as a client and sending IT services status fetched from Zabbix.


I did not want to bother with two distinct scripts, git repos and config files, so the same script is used for both modes (as well as a demo mode we'll see later-on.


As the board and neopixel packages are not available on Linux, the enable_neopixel config parameter must be set to false when running on Linux in order to disable the conditional imports of the RPi-specific stuff.


Communication protocol

The communication protol between the client and server is trivial:

All it requires is a 10-integer serialized JSON array (with values ranging from -1 to 4 but it can be changed if you want to be able to display more status values).


Testing the server

The server normally runs as a SystemD service, we'll see this later-on.

First let's launch it from the command line, this also facilitates troubleshooting:

sudo ./zabbix-neopixel server


The display should remain off.


You can send data to the server using this command. You can send whatever you want, as long as it's a 10-integer serialized JSON array, with such a command:

echo "[1,0,0,4,0,-1,-1,0,4,1]" > /dev/tcp/127.0.0.1/1920


The display should animate, display the sent status and remain lit for 2 server_socket_timeout periods, then automatically turn off.


Let's simulate pseudo-random service status change by using the demo mode:

sudo ./zabbix-neopixel demo
2021-12-29 15:55:43 CET INFO: (MainThread) Zabbix NeoPixel v.1.0.0 started
2021-12-29 15:55:43 CET INFO: (MainThread) demo mode
2021-12-29 15:55:43 CET DEBUG: (MainThread) sending status_array to localhost:1920


The display should then animate and display an array of colors. Some of the LED colors are fixed, some are random. The script is actually sending this array to the server:

send_to_server([random.randint(-1,4),0,random.randint(-1,4),1,2,0,-1,0,0,1])



Running the Server as a SystemD Daemon

Issue the following command to copy the SystemD service definition file to its expected location

sudo cp zabbix-neopixel.service /etc/systemd/system/

Then reload systemd's config and enable the service:

sudo systemctl daemon-reload
sudo systemctl start zabbix-neopixel

You may check the logs of the service via the following command (crtl+c to quit)

sudo journalctl -f -u zabbix-neopixel

Step 5: Configuring the Client

The client can be run from the RPi or any other Python-enabled machine.

The neopixel stuff is automatically disabled when using the client or demo mode (using conditional imports).


The zabbix URL and credentials need to be configured, as well as the server IP address.

You may also want to configure the root_service name if the Zabbix services you're interested aren't located at the root of your service tree. Please refer to the Zabbix doc for further information.


You may also need to configure the server's IP address, instead of the default localhost.


Then you need to configure the service names you're interested in reporting the status in the cloud display.

The service names must be entered as a YAML list, in LED-position order. That is the first service listed will be displayed by the first LED, and so on.

You may want to skip a LED (keep it powered-off all the time). This can be done by using a blank line for the service name.

Eg:

 # Service names we're interested in, in LED order. use a blank line to skip a LED
 services_of_interest:
  - srv1
  - 
  - srv2



You cand send the actual status data fetched from Zabbix using the defaut client mode:

./zabbix-neopixel.py


You'll mostly want to run the client automatically via a crontab.

Here's my crontab entry. I'm sending the log to syslog, running the script every minute during working hours and days:

* 7-18 * * 1-5 /home/pat/rpi/zabbix-neopixel/zabbix-neopixel.py 2>&1 | /usr/bin/logger -t zabbix-neopixel


I'm not sure anyone will find this stuff usefull, but anyway, it might help someday :)

Step 6: Further Uses/Customisations

The script may be extended/customised to support more states/change colors by modifying the following function.

This is the function that detects a change between the previous and current state, and triggers the animations, then set the LED colors depending on the status value:

    def update_led_array(self, status_array):
        if status_array != self.old_pixels_states:
            logging.debug("updating led array with {}".format(status_array))
            self.old_pixels_states = status_array
            self._animate_flash()
            self._animate_snake()
            led_idx = 0
            for status in status_array:
                if status == 0:
                    self.pixels[led_idx] = (0,255,0)
                elif status == 4:
                    self.pixels[led_idx] = (255,0,0)
                elif status == -1:
                    self.pixels[led_idx] = (0,0,0)
                else:
                    self.pixels[led_idx] = (255,102,0)
                led_idx += 1


            self.pixels.show()


        else:
            logging.debug("no state change detected")