Using WS2811 Light Strands with the WEMOS D1 Mini

wired lights.png

A very long time ago I spent some time doing stage lighting. Great fun and only occasionally extremely dangerous. Like the time when a friend of mine extended a wire with a plug in extension and he got the plug and the socket the wrong way round. He had the mains coming out of the plug and going into the socket. It was perfectly safe. Until the plug came out…

What has this to do with WS8211 light strands I hear you asking? Well, the strands are fitted with a plug at one end and a socket on the other. Because I know about these things, I decided that the plug would be the connector on the light strand that would receive the power and data signals. My decision was nicely reinforced by the way that the leds had a nice big arrow pointing inwards on this connection. Armed with this knowledge I wired everything up to find that it didn’t work.

Actually, I was kind of expecting this to be the case. Some leds like this need more voltage swing than can be provided by the 3.3 volts that the Wemos puts out. So I used a level converter to bring this up to nearly 5 volts. And of course it still didn’t work. After a bit of testing and a lot of head scratching I did what I should have done right at the start. I tried the led strand with something that was bound to work; in this case an Arduino Uno that puts out 5 volt logic. Of course they didn’t work with that either. So, in a spirit of “what’s the worst that could happen?”, I tried sending signals and power into the socket on the other end of the wire.

Of course it worked. So, if you want to use a Wemos D1 Mini with these led strands just make sure that you ignore the arrows and wiring common sense and send your signals into socket end of the strand. The really good news is that you can probably connect the Wemos directly to the led strand. My leds work without my carefully assembled level converter.

The only other thing to remember is that the RGB order is different for these strands. Blue and white will look fine, but everything else will look wrong because the red and the green colours are swapped. I’ve added a configuration option to allow the user of a Connected Little Box to set the type of leds:

switch(pixelSettings.pixelConfig)
{
    case 1:
    strip = new Adafruit_NeoPixel(pixelSettings.noOfPixels, pixelSettings.pixelControlPinNo, 
    NEO_GRB + NEO_KHZ800);    
    break;
    case 2:
    strip = new Adafruit_NeoPixel(pixelSettings.noOfPixels, pixelSettings.pixelControlPinNo, 
    NEO_KHZ400+NEO_RGB);
    break;
    default:
    strip=NULL;
}

Config 1 is “normal” NeoPixels and config 2 is the settings that work best for the strands.

Name in Lights

sealedbox.png

I’ve always wanted to see my name in lights. Today I’ve realised that ambition. It’s all part of the Connected Little Boxes project. One kind of box has your name in it. I’ve just finished making the boxes and to show an appropriate level of confidence in my connections I’ve actually taken the Apple approach to manufacture and glued all the cases shut. I really hope I don’t regret the decision….

ESP8266 int alignment fun

OK. Pop quiz. What’s wrong with the following C++ code?

unsigned char * chPtr;
int * intPtr;

// point chPtr at a buffer somewhere

// get an integer out of the buffer
intPtr = (int *) chPtr;
Serial.println(*intPtr);

Perhaps a bit of context would help. I use commands like this to tell my Connected Little Boxes what to do:

{"process":"pixels","command":"setrandomcolour",
"pixelSpeed":10, "sensor":"button","trigger":"pressed"}

This command means “send the command setrandomcolour” to the pixels process when the user presses a button. Fade the colour over 10 “ticks”. This means that each time the user presses the button on the box the lights will change colour.

The box is smart enough to understand this tiny chunk of JSON but I don’t want to have to decode the command every time the button is pressed. So the program assembles a block of memory containing things like the “10” value for pixelspeed and this is read when the sensor event is triggered and used to control the command. Works very well. Except sometimes. Sometimes the code throws Exception(9) and the processor resets.

The error came from nowhere and I spent ages checking the code that I’d just written to find what I’d broken. After a while I took the trouble to look up what Exception(9) actually means, and that’s when I discovered the stupid thing I’d done.

The code above uses a pointer to an 8 bit location somewhere in memory and then fetches an integer from that place. it’s what gets the stored pixelspeed value for the pixels process to use. But the ESP8266 stores integers in a block of four memory locations as a 32 bit value and it insists that these are always aligned. In other words, you put the first value in the bytes at locations 0 to 3, the second at locations 4 to 7 and so on, using the convention that the memory is addressed starting at location number 0. If a program tries to load a value from an “odd” location the processor crashes.

This means that if store something in memory and then try to read it back as an integer I have a 1 in four chance of it working and a 3 in 4 chance of it failing. Up until now I’d been lucky, but today I wasn’t.

When you write an assembly language program you can use special directives to line the data up in the right locations. The same thing happens in C++ when you make a structure. The compiler will insert extra space to make things line up when they should. One way to fix it would be to make sure that I always line things up in my program but this would have been a bit of a pain, so I wrote the function below:

int getUnalignedInt(unsigned char * source)
{
    int result;
    memcpy((unsigned char *)&result,source,sizeof(int));
    return result;
}

You pass the function a pointer to anywhere in memory. It copies some integer bytes into a lined up integer value and then returns the value. It seems to work fine. It’s not the most efficient solution but I can live with that for now..

Alarms are complicated

I’ve always found it surprising how simple things end up being complicated. Take adding alarms to my Connected Little Boxes…. I want to have alarms that I can set in the device. When an alarm time is reached I want the device to perform an assigned action, perhaps make a sound, drive a servo or change the colour of a light. This is simple I say to myself. And I write a function to celebrate:

bool atAlarmTime(struct ClockAlarm *alarm, struct clockReading *reading)
{
    if (alarm->hour != reading->hour)
    {
        return false;
    }

    if (alarm->minute != reading->minute)
    {
        return false;
    }

    return true;
}

The function will return true when the clock reaches the alarm time. I can use this to trigger whatever action is bound to the alarm. Simple.

Well, not really. My program will be repeatedly checking the alarm to see if it has triggered. So if I just use the above function I will find that an alarm will trigger continuously for the entire alarm minute when it due. And what about when I turn the device on or change the time? Do I want it to ignore “past” alarms or not? If my device was controlling a heating system I’d want it to respond to an alarm even to turn the heating on even if that event was in the past. Otherwise I’d turn the system on at 12:00 and freeze because the event that turned on the boiler was set to 7:00am.

I’ve ended up setting up options and flags and writing code that spins through the set alarms looking for ones that should have been triggered and triggering them if that is what the user wants. Yep. Alarms are complicated.