Project Overview
For my latest theatre production that I was the lighting designer and operator for, I had created designs to have various pieces of lighting equipment built into set pieces to create purposeful light on stage. For example, a lantern built into a front door set piece / prop like this.


Other props included hanging pendulum lights suspended from the ceiling structure. Finally, a bus stop had to have lights built in to help emphasise the evening time.

Despite all of these set and prop items needing built in lighting, they don’t require any intelligent control or dimming capability. The light in the front door step lantern is just a standard E27 lamp. This meant I needed to come up with a way to control several sockets over DMX with control coming from my ETC EOS Nomad lighting desk.
From researching online it appeared the general consensus was to use a “Switch Pack” with IEC sockets built in (these also have a primary purpose of being portable dimmer packs!) like this:

However, as per usual on these projects a very small (non existent) budget was involved as this was for a performance within a school. A £113 investment for 4 ways of relay seemed a lot for what is overall, a minor control need. So time to DIY instead…
Previously I have created my own Projector Dowser controlled by a Raspberry Pi over Artnet from the lighting desk (article to follow in the future) for a similar budget reason! This project has taken a lot of inspiration from that one…

The Plan!
I chose to use another Raspberry Pi 3B (or rather, the same one repurposed…) just because I had it lying around, you don’t need anywhere need its processing capability – an Arduino board would suffice, but I used it for the convenience of having an Ethernet port built in.
I already had some rough Artnet code written in Python that listened on one particular DMX channel (500) of an obscure Artnet universe (10) and the switch point worked at DMX value 127 – 50% intensity. If the value was below half then the dowser closed and if it was above then it opened, or in this case, if the value is below 50% on that DMX channel then the switch will turn off, and if at or above then it will turn on.
I intended to use remote control sockets, like what you might buy to control some fairy lights in your house. These work on 433mhz and I already had experience controlling these on a microcontroller / Raspberry Pi as I use a set of them within my home automation system.
The benefit of using these was that I didn’t have to do any DIY work involving mains electricity. I would use a 13A extension mounted on a board, along with a set of 4 remote control sockets and the Pi mounted there aswell. The Pi monitors Artnet, on a change of state it sends a signal via the 433mhz transmitter which in turn triggers the remote socket and the connected light / appliance turns on or off!
Things to consider were that the 433mhz remote sockets loose their paired status when they loose power, so this setup had to be permanently powered on otherwise you would have to go through the process of re-assigning each its designated address by putting each address to full and off again. So to combat this, I will just leave this whole setup on… I will need to ensure that the Pi code can handle loosing Artnet and regaining it again without crashing!
The Build
I began by coding the solution stealing code from previous projects and from looking at examples online. I managed to make a quick but working Python program and get it to auto run on boot of the Pi. This is good enough for me, it also doesn’t care if the Artnet signals drop, it will just pick it up when they return again.

This is the example of the 433mhz transmitter I used, they are extremely cheap and a bit unreliable but a 3 pack is only a few pounds of Amazon. They also come with a receiver and by using code examples available online you can “listen” to the signals from the remote socket transmitter remote and then you rebroadcast these from your Python program with the transmitter. I used this Python library: RPI-RF
Once this code was working, I dug out some remote sockets and fired it all up. In my Python code I assigned it to use Artnet universe 1 but this could be anything. In ETC EOS I patched in 4 fixtures with the type of “Non-Dim at 50” so that they act as a switch. I then set the addresses to output on the correct Artnet universe and channels I had assigned in code. This surprisingly all worked very well for me!





Code
Here is the Python file I created, it is very rough and when I get more time in the future I will likely modify it to be more efficient and error handle better, but this might give you a rough idea of where to start if you want to do this yourself.
from stupidArtnet import StupidArtnetServer
import time
import sys
import RPi.GPIO as GPIO
import threading
import subprocess
txPin = 22
GPIO.setmode(GPIO.BCM)
numberOfRemoteDevices = 4
currentStatus = [False,False,False,False] #False signifies power to the device is off, True signifies power to the device is off
addresses = [451,452,453,454]
artnetUniverse = 1 #starts at 0
txCodesOn = [6047771,6047774,6047772,6047785]
txCodesOff = [6047763,6047766,6047764,6047777]
txProtocol = 1
txPulselength = 307
txCodelength = 24
print("Holding to ensure Network started on device")
time.sleep(10) #introduce a pause for networking to start on RPi device
print("Waiting for Artnet...")
# create a callback to handle data when received
def main_callback(data):
global txpin
global addresses
global artnetUniverse
global currentStatus
# the received data is an array
# of the channels value (no headers)
#print('Received new data \n', data)
for a in range(0,numberOfRemoteDevices):
currentAddress = addresses[a]
currentChanVal = data[currentAddress-1] #the data array starts at 0 so have to minus one to make DMX values match up
humanUnitNumber = a+1
if (currentChanVal < 128):
#check for change
if (currentStatus[a] == True):
#channel now OFF
currentStatus[a] = False
print(f'Address {currentAddress}: Unit no {humanUnitNumber} = OFF')
#send TX message to remote socket
result = subprocess.run(['rpi-rf_send',str(txCodesOff[a]), '-p', str(txPulselength), '-g', str(txPin)], text=True)
#print(f'Sending code: {txCodesOff[a], txProtocol, txPulselength, txCodelength}')
elif (currentChanVal >= 128):
if (currentStatus[a] == False):
#channel now ON
currentStatus[a] = True
print(f'Address {currentAddress}: Unit no {humanUnitNumber} = ON')
#send TX message to remote socket
result = subprocess.run(['rpi-rf_send',str(txCodesOn[a]), '-p', str(txPulselength), '-g', str(txPin)], text=True)
# Optional: Print the command output
#print(f"Command output: {result.stdout}")
#print(f"Command error (if any): {result.stderr}")
#print(f'Sending code: {txCodesOn[a], txProtocol, txPulselength, txCodelength}')
##############################################################
# Server object initializes with the following data
# universe = DEFAULT 0
# subnet = DEFAULT 0
# net = DEFAULT 0
# setSimplified = DEFAULT True
# callback_function = DEFAULT None
# You can use universe only
try:
mainServer = StupidArtnetServer()
# For every universe we would like to receive,
# add a new listener with a optional callback
# the return is an id for the listener
u1_listener = mainServer.register_listener(
artnetUniverse, callback_function=main_callback)
# or disable simplified mode to use nets and subnets as per spec
# subnet = 1 (would have been universe 17 in simplified mode)
# net = 0
# a.register_listener(universe, sub=subnet, net=net,
# setSimplified=False, callback_function=test_callback)
while True:
continue
except KeyboardInterrupt:
print("Exiting...")
# Cleanup when you are done
del mainServer
The downsides…
Now, as this is using a wireless protocol (even if it is 433mhz) being in an unlicensed band likely with lots of interference around you wherever you are I would advise you to use something like this in a show critical system with lots of caution! I would apply the same considerations to this as if I was using Wireless DMX dongles – only use them for non show-critical lighting effects. If you had an annoying audience member who casually brought along their remote socket remote with them then they could also turn these sockets on or off. I did have the idea of creating a faraday cage box over the entire Pi transmitter and sockets but I decided I would resort to that only if necessary.
Disclaimer
I think this is quite obvious, but I am not responsible for you taking inspiration from this project or using my code and having issues in your shows, please don’t take everything here literally, I have probably missed a step or forgotten to include something important. As ever, if you want to know more about anything just email me using my contact page and I will try and be as helpful as I can.
