Hi @LegionX.
The Arduino DMX controller shield can only handle one universe (512 channels) with each downlight using 3 channels each (R,G,B) that’s 170 downlights per universe!
Which is far more than I’ve planned for my house. I’ve only got 40 downlights (and decoders) in total at this stage.
Another universe would require another Arduino and another DMX controller shield. Which would start the channels from 0 again. Not difficult to do in software - just assign the two (or more) Arduinos different MQTT channels each to listen on.
Here’s my current code on the Arduino:
#include <Ethernet.h>
#include <PubSubClient.h>
#include <DmxSimple.h>
// Ethernet https://www.miniwebtool.com/mac-address-generator/
byte device_mac[] = {0x16,0xB8,0x90,0x93,0x56,0xDA};
EthernetClient device;
// MQTT
IPAddress mqtt_ip(xxx, xxx, xxx, xxx);
PubSubClient mqtt(device);
String mqtt_client = "houselights";
const char mqtt_user[] = "xxxx";
const char mqtt_pass[] = "xxxx";
const char mqtt_sub[] = "device/house/light";
void setup()
{
// Configure DMX, Interface with the DMX shield on I/O pin 4 instead of TX/TR
DmxSimple.usePin(4);
DmxSimple.maxChannel(512);
// DMX shield syncs with Arduino on I/O pin 2
pinMode (2, OUTPUT);
digitalWrite (2, HIGH);
// Just for visual testing of network connection
// All downlights 1% while we wait for network connection
for (int i = 0; i < 512; i++)
{
DmxSimple.write(i, 1);
}
// Wait for network connection
while (Ethernet.begin(device_mac) == 0)
{
delay(1000);
}
// Initializes the pseudo-random number generator
randomSeed(micros());
// Configure MQTT
mqtt.setServer(mqtt_ip, 1883);
mqtt.setCallback(mqttReceive);
// Connected to network. All downlights off
for (int i = 0; i < 512; i++)
{
DmxSimple.write(i, 0);
}
}
void loop()
{
Ethernet.maintain();
if (!mqtt.connected())
{
mqttReconnect();
}
mqtt.loop();
}
void mqttReconnect()
{
while (!mqtt.connected())
{
mqtt_client += String(random(0xffff), HEX);
if (mqtt.connect(mqtt_client.c_str(), mqtt_user, mqtt_pass))
{
mqtt.subscribe(mqtt_sub);
}
else
{
delay(5000);
}
}
}
void mqttReceive(char* topic, byte* payload, unsigned int leng)
{
char channel[4] = "";
char val1[4] = "";
char val2[4] = "";
char val3[4] = "";
// Determine starting channel value, eg: 001 - 512
for (int i = 0; i < 3; i++)
{
channel[i] = payload[i];
}
channel[3] = "\0";
// Determine first channel's value. Eg: 000 - 255
for (int i = 3; i < 6; i++)
{
val1[i - 3] = payload[i];
}
val1[3] = "\0";
// Determine second channel's value. Eg: 000 - 255
for (int i = 6; i < 9; i++)
{
val2[i - 6] = payload[i];
}
val2[3] = "\0";
// Determine third channel's value. Eg: 000 - 255
for (int i = 9; i < 12; i++)
{
val3[i - 9] = payload[i];
}
val3[3] = "\0";
// Convert char to int
int c = atoi(channel);
int v1 = atoi(val1);
int v2 = atoi(val2);
int v3 = atoi(val3);
// Apply the three channels
DmxSimple.write(c, v1);
DmxSimple.write(c + 1, v2);
DmxSimple.write(c + 2, v3);
}
I send the Arduino a string via MQTT like: 001255255255
- First three characters is the starting channel value. Values of 001 to 512.
- Next three characters is the starting channel’s value [R]. Values of 000 to 255.
- Next three characters is the second channel’s value [G]. Values of 000 to 255.
- Final three characters is the third channel’s value [B]. Values of 000 to 255.
Changing a room of four downlights (to warm white) would send 4 MQTT messages (payloads) to the topic device/house/light
, of:
001255195054
. (Downlight on channel 1 = 1,2,3 = R:255, G:195, B: 054)
004255195054
. (Downlight on channel 4 = 4,5,6 = R:255, G:195, B: 054)
007255195054
. (Downlight on channel 7 = 7,8,9 = R:255, G:195, B: 054)
010255195054
. (Downlight on channel 10 = 10,11,12 = R 255, G:195, B: 054)
Edit
You could of course set all downlights in each room to the same starting channel (address?) and then send only one message. But with so many free channels per universe I thought it would be more fun if each downlight could do it’s own thing