‹ f0neoOptoforce ›

f0dmx

2017-05-09 21:04:13 electronics

Here is how I built a wireless isolated DMX controller that takes OSC input. The box uses an ESP8266 to create a WiFi access point that one can connect to with a laptop (or phone or whatever). Open Sound Control messages sent to the box are converted into standard DMX commands. Multiple clients can be connected and send DMX commands at the same time.

f0dmx photo 1

f0dmx photo 2

Below is Arduino code for the ESP8266, Bill-Of-Material, the KiCad schematics and some SuperCollider test code.

// * install OSC from https://github.com/CNMAT/OSC
// * install WiFiManager from https://github.com/tzapu/WiFiManager
// * install LXESP8266UARTDMX from https://github.com/claudeheintz/LXESP8266DMX
// * select board: "Generic ESP8266 Module" 160 MHz

#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Ticker.h>
#include <WiFiManager.h>
#include <WiFiUdp.h>
#include <OSCMessage.h>
#include <OSCData.h>
#include <LXESP8266UARTDMX.h>

#define CONFIG_PIN 0  //GPIO0 to GND to reset WiFi
#define PORT 19998  //EDIT OSC input port
#define OUTPORT 57120  //EDIT OSC output port (only used at startup for announcement)
char *espname = "f0dmx";

Ticker ticker;
IPAddress outIp;
WiFiUDP Udp;

void setup() {
  delay(10);
  pinMode(CONFIG_PIN, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  ticker.attach(0.6, tick);

  WiFi.hostname(espname);
  wifi_station_set_hostname(espname);
  WiFiManager wifiManager;
  wifiManager.setAPCallback(configModeCallback);
  if (!wifiManager.autoConnect(espname)) {
    ESP.reset();
    delay(1000);
  }
  MDNS.begin(espname);  //make .local work
  outIp = WiFi.localIP();
  Udp.begin(PORT);
  OSCMessage msg("/ready");  //announcement
  msg.add(espname);
  msg.add(int(outIp[0]));
  msg.add(int(outIp[1]));
  msg.add(int(outIp[2]));
  msg.add(int(outIp[3]));
  msg.add(PORT);
  outIp[3] = 255;  //use broadcast IP x.x.x.255
  Udp.beginPacket(outIp, OUTPORT);
  msg.send(Udp);
  Udp.endPacket();
  yield();
  msg.empty();

  ESP8266DMX.startOutput();

  ticker.detach();
  digitalWrite(LED_BUILTIN, LOW);  //debug
}

void tick() {
  int state = digitalRead(LED_BUILTIN);
  digitalWrite(LED_BUILTIN, !state);  //debug
}
void configModeCallback(WiFiManager *myWiFiManager) {
  ticker.attach(0.15, tick);
}

void dmx(OSCMessage &msg) {
  int chan, value;
  for (byte i = 0; i < msg.size(); i = i + 2) {
    chan = getIntCast(msg, i);
    value = getIntCast(msg, i + 1);
    ESP8266DMX.setSlot(chan, value);
  }
}

int getIntCast(OSCMessage &msg, int index) {  //support for both integers and floats
  if (msg.isInt(index)) {
    return msg.getInt(index);
  }
  return int(msg.getFloat(index));
}

void start(OSCMessage &msg) {
  ESP8266DMX.startOutput();
}

void stop(OSCMessage &msg) {
  ESP8266DMX.stop();
}

void loop() {
  OSCMessage oscMsg;
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    while (packetSize--) {
      oscMsg.fill(Udp.read());
    }
    if (!oscMsg.hasError()) {
      oscMsg.dispatch("/dmx", dmx);
      oscMsg.dispatch("/start", start);
      oscMsg.dispatch("/stop", stop);

      tick();
    }
  }

  //--wifi
  if (digitalRead(CONFIG_PIN) == LOW) {  //reset pin
    WiFiManager wifiManager;
    wifiManager.resetSettings();
    wifiManager.setAPCallback(configModeCallback);
    wifiManager.autoConnect(espname);
    ticker.detach();
    digitalWrite(LED_BUILTIN, LOW);  //debug
  }
}

Bill of material...

1 DCDC ROE-0505S Reichelt
1 XLR female XLR 3KU Reichelt
1 optocoupler 6N 137 Reichelt
1 SN 75176BP Reichelt
1 box BOPLA KS 420 Reichelt
1 resistor 10K
1 resistor 470
3 resistor 10
1 resistor 120
2 cap 10uF
1 cap 220uF
1 regulator LF 33 CV
1 micro ESP8266-01
1 socket 4x2
1 push button
1 USB cable

f0dmx KiCad schematics

Example of how to send OSC from SuperCollider to the f0dmx box.

//make sure you are connected to the same WiFi network as f0dmx
n= NetAddr("f0dmx.local", 19998);  //the IP and port of the f0dmx box
n.sendMsg(\dmx, 9, 255);  //dmx channel 9, value 255
n.sendMsg(\dmx, 9, 0);
n.sendMsg(\dmx, 7, 100);  //dmx channel 7, value 100
n.sendMsg(\dmx, 7, 0);

n.sendMsg(\stop);  //usually not needed
n.sendMsg(\start);

Updates:

  • 180620: cast floats to integers (getIntCast), increased electrolytic cap value from 100 to 220uF
  • 181212: simplified WiFi setup with the WiFiManager library
‹ f0neoOptoforce ›