Automating an IoT device with the Uplink and Scheduled Tasks

How do fish know when to sleep? It’s known that fish exhibit sleep-like behavour. They have photosensitive tissues that react to light - when it’s light they feel awake, and when it’s dark, they get, well, sleepy.

So if you have a fish tank, the least1 you can do is provide them with a daily light cycle. Luckily for them2, it’s possible to connect your fish tank to the internet and create a Scheduled Task to change the light level during the day.

I have a fish tank and I’ve done just that. I attached a Raspberry Pi Zero W to a 3D-printed mount inside the lid of my fish tank:

This is a shop-bought fish tank lid; the custom part is a 3D-printed bracket behind the Pi.

This is a shop-bought fish tank lid; the custom part is a 3D-printed bracket behind the Pi.

To create the light, I used a strip of LEDs that can be controlled over the SPI serial protocol:

The sun, as far as the fish are concerned.

The sun, as far as the fish are concerned.

These LEDs are pretty cool - the signal is multiplexed so they can be addressed individually, meaning you can create light patterns along the length of the strip. You can set the colour of each LED by sending an array of bytes via SPI. The whole strip of LEDs is like a queue of colour - each (RGB + brightness) value you send pushes the existing values ‘down the line’, and you can do this really fast.

The LEDs are also really bright, and consume up to 35 W per metre, at 5 V. If you do the maths, that’s a fairly absurd current, so if you want to try this at home you’re going to need an equally absurd power supply. Mine is large, ominous, and mounted a very long way away from the aquarium - to which it is connected with very thick wires.

For the sake of the fish’s sanity3, I just set the LEDs to ‘all light’ or ‘all dark’. That means I want to change the whole strip at once, so I send NUM_LEDS color values at once (where NUM_LEDS is the number of LEDs).

import spidev

# SPI library boilerplate​
spi = spidev.SpiDev()
spi.close()
spi.open(1, 0)
spi.max_speed_hz = 8000000

NUM_LEDS = 288

# Change all the colours at once
led_colors = [
  r/255.0, g/255.0, b/255.0, brightness/31.0
] * NUM_LEDS

# Perform the write
spi.writebytes(led_colors)

To control it from the internet, I run it in a script on the Raspberry Pi and connect it to Anvil using the Uplink:

import spidev
import anvil.server

# SPI library boilerplate​
spi = spidev.SpiDev()
spi.close()
spi.open(1, 0)
spi.max_speed_hz = 8000000

NUM_LEDS = 288

# Connect to Anvil
anvil.server.connect("35DXD7PUTW6BYQ15PTLFX4KP-QCENAL7FI4KXYHMU")

@anvil.server.callable
def set_color(r, g, b, brightness):
    """This function can be called from the Anvil app over the internet."""
    # Change all the colours at once
    led_colors = [
      r/255.0, g/255.0, b/255.0, brightness/31.0
    ] * NUM_LEDS
    
    # Perform the write
    spi.writebytes(led_colors)

    # Wait for it to propagate
    time.sleep(0.01)
    
anvil.server.wait_forever()

To dictate when night and day occur, I have Background Tasks that set a ’night-time’ and ‘daytime’ light level:

@anvil.server.background_task
def make_it_night():
  anvil.server.call('set_color', 255, 255, 255, 7)
  
@anvil.server.background_task
def make_it_day():
  anvil.server.call('set_color', 255, 255, 255, 31)

The arrival of sunset and sunrise are orchestrated by two Scheduled Tasks:

And voila! The fish tank now has a (rather sudden) artificial sunset:

Automating IoT devices with Anvil is easy. If your device can run a full Python interpreter and communicate over a websocket, just write an Uplink script and connect as we did here. If you want to connect multiple devices, you can give your server functions unique names by passing a string into @anvil.server.callable(). For more lightweight devices that can’t run a CPython interpreter, you can use Anvil’s HTTP functionality to communicate via HTTP.

Try it yourself

Do you have an IoT device you want to connect with via a web app? Maybe you want to view your sensor data while your devices are asleep, or coordinate firmware updates over the web.

Anvil allows you to build web apps with nothing but Python, including the front-end code that drives the UI. It is an industrial-strength programming platform that can easily connect to thousands of IoT devices.

It’s completely free to use! Click this link to get started:


  1. Well, perhaps not the least. This should probably come after feeding them. ↩︎

  2. “Luckily” might be taking this a little too far. ↩︎

  3. And any potential epileptic tendencies. ↩︎