I’ve just completed a usermod that provides for binary encoded input and thought that I’d share the idea here. If it’s good enough, I’ll submit it to Github as a regular usermod.
Use case: This project adds fancy turn signals to my ATV. It’s a Can-Am side-by-side that seats 6 and has a regular 12V automotive system (sans alternator).
There are 4 light positions on the vehicle: Front Left, Front Center, Front Right, and Rear Strip. The front right and left positions blink during turns and run steady driving lights otherwise. The front center strip is for decoration (behind the grille, like Knight Rider), and in the rear is a 1 Meter strip of 60 WS2815 pixels mounted in an aluminum channel with a clear cover. The strip is mounted horizontally in the back.
I wired up a 4-channel optocoupler (12v → 3.3v) to take 12v input signals from the vehicle. At first, I tried using the Button settings that are built into the latest Wled and which provide for 4 independent buttons. I had an immediate problem: Sometimes, inputs come into different channels simultaneously. Sure, the stock button interface does a good job of firing off a macro when a button state changes, but there is no way to detect and trigger on two buttons being active at the same time. Think of making a left turn. First, suppose the driver turns the left signal on and then, he hits the brakes. Both are inputs to the process, but neither is exclusive. Just because the brakes are pressed, it doesn’t mean that the blinker stops.
The problem here is that when you load one preset (for example blink left), it is canceled when you load another preset (for example brake light). So, I needed more macros. By the time I was done, I need to trigger one of 7 different macros depending on the state of the vehicle. These include Drive (idle, no inputs), Hazard (4-way flashers), Brake, Left Signal, Left Signal with Brake, Right signal, and Right Signal with Brake. This wasn’t going to work with the stock 4 input buttons.
So, I decided to write a usermod. The overall strategy is very simple, and not nearly as elegant as the code others have written, but it works. First, I picked 4 input pins and I wired the 4 optocouplers to it, and attached these to the vehicle inputs. Then, in the usermod, I set up the pins for input. At runtime, the usermod loop is called which reads all four pins and then combines the result into a 4-bit value. This value, normalized to 1-16, is then used to select a preset.
So, whenever you press the brake, work the turn signals, or just drive, the state condition evaluates to a particular macro and changes the output accordingly.
Here’s a look at the code:
void loop() {
pin_state = digitalRead(PIN_BRAKE);
pin_state = pin_state << 1;
pin_state |= digitalRead(PIN_LEFT);
pin_state = pin_state << 1;
pin_state |= digitalRead(PIN_RIGHT);
pin_state = pin_state << 1;
pin_state |= digitalRead(PIN_HAZARD);
pin_state++; // presets are 1-based
if (pin_state != last_preset) {
last_preset = pin_state;
applyPreset(pin_state & 15);
}
}
So, with this setup, any of 16 macros can be triggered depending on the combined state of 4 pins.
In parting, some may note that no attempt was made to de-bounce the input signals. In the wled code, buttons must be held for at least 50ms to avoid false triggering. This didn’t seem necessary for this application.
Overall, the setup works well with a minimum of fuss.