Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions usermods/usermod_v2_busstatus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Bus Status Usermod

v2 usermod to display bus/port status on a configured LED segment
Use instead of the builtin STATUSLED

WLED uses the term `bus` to refer to a logical port. This may be a physical collection of gpio pins or a virtual
network bus.

This usermod finds the type of each specified bus, plus the device status, and displays the result on configured LEDs.
The bus status colours are configurable and listed at the end.

The device status colours are:
* Red device element = Error value
* AP mode = Blue
* Connected to Wifi = Green
* MQTT Connected = Cyan

The status is also shown on the UI Info page.

## Define Your Options

* `USERMOD_BUSSTATUS` - have this usermod included
* `BUSSTATUS_PINS` - (optional) Array of GPIO pin numbers to display the status of, in order. e.g. `-D BUSSTATUS_PINS='{1,2,-1}'`
- `-1` displays the device status. Default: { -1, 1, 2}

## Configure

* Set up your pixel strips in `LED Preferences`. For a racitup.com v1 board the settings for the status bus are:
- Type = WS281x
- LED order = GRB
- Length = 3
- GPIO = 12
- Skip = 0
- `Make a segment for each output`: ticked
- Ensure the automatic brightness limiter is set up appropriately for your number of LEDs, or disable

* Configure the associated segment. The bus type colours below are configurable:
- Effect = Bus Status
- Colour 1 = DMX (Blue)
- Colour 2 = Digital (Green)
- Colour 3 = PWM (Magenta)
179 changes: 179 additions & 0 deletions usermods/usermod_v2_busstatus/usermod_v2_busstatus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#pragma once
#include "wled.h"

#define PSBUFSIZ 20
#ifndef BUSSTATUS_PINS
#define BUSSTATUS_PINS { -1, 1, 2}
#endif
#define BUSSTATUS_SIZ (sizeof((int8_t[])BUSSTATUS_PINS)/sizeof(int8_t))
#ifndef FX_MODE_BUSSTATUS
#define FX_MODE_BUSSTATUS 255 // Temporary Effect ID
#endif

class BusStatusUsermod : public Usermod {

private:
char buf[PSBUFSIZ];

// strings to reduce flash memory usage (used more than twice)
static const char _FX_MODE_BUSSTATUS[];
static const int8_t status_gpios[BUSSTATUS_SIZ];

static uint8_t get_bustype(uint8_t gpio) {
Bus* bus;
uint8_t numPins;
uint8_t pinArr[8];
for (uint8_t busNr = 0; busNr < busses.getNumBusses(); busNr++) {
bus = busses.getBus(busNr);
if (bus) {
numPins = bus->getPins(pinArr);
for (uint8_t i = 0; i < numPins; i++) {
if (pinArr[i] == gpio) {
return bus->getType();
}
}
}
}
return TYPE_NONE;
}

// errorFlag -> Red
static uint32_t device_status_colour() {
// assumes max error flag is 36
uint8_t red_val = errorFlag * 7;
if (WLED_CONNECTED) return RGBW32(red_val,255,0,0); // Green
else if (WLED_MQTT_CONNECTED) return RGBW32(red_val,128,128,0); // Cyan
else if (apActive) return RGBW32(red_val,0,255,0); // Blue
else return RGBW32(red_val,0,0,0); // Red
}

static const char* device_status_string() {
if (WLED_CONNECTED) return "Wifi";
else if (WLED_MQTT_CONNECTED) return "MQTT";
else if (apActive) return "HotSpot";
else return "Unknown";
}

char* device_error_string() {
snprintf(buf, PSBUFSIZ, "0x%X", errorFlag);
return buf;
}

// configurable status colours for the first 3 only
static uint32_t bus_status_colour(int8_t gpio) {
uint8_t busType = get_bustype(gpio);
if (IS_DMX(busType)) return SEGCOLOR(0); // Blue
else if (IS_DIGITAL(busType)) return SEGCOLOR(1); // Green
else if (IS_PWM(busType)) return SEGCOLOR(2); // Magenta
else return 0UL; // Black
}

const char* bus_status_string(int8_t gpio) {
// bus types in const.h
uint8_t busType = get_bustype(gpio);
if (busType == TYPE_NONE) return "Unconfigured";
else if (IS_DMX(busType)) return "DMX";
else if (IS_DIGITAL(busType)) return "Digital LED";
else if (IS_PWM(busType)) return "PWM LED";
else snprintf(buf, PSBUFSIZ, "Type %d", busType);
return buf;
}

// modification of static/blink
static uint16_t mode_busstatus(void) {
uint32_t status_colours[BUSSTATUS_SIZ];
for (uint16_t i = 0; i < BUSSTATUS_SIZ; i++) {
if (status_gpios[i] < 0) {
status_colours[i] = device_status_colour();
} else {
status_colours[i] = bus_status_colour(status_gpios[i]);
}
}
uint16_t i;
for (uint16_t s = 0; s < SEGLEN; s++) {
i = s % BUSSTATUS_SIZ;
SEGMENT.setPixelColor(s, status_colours[i]);
}
return strip.isOffRefreshRequired() ? FRAMETIME : 350;
}

public:
// gets called once at boot. Do all initialization that doesn't depend on network here
// parameters are already read by readFromConfig, busses & segments have been created by beginStrip()
void setup() {
strip.addEffect(FX_MODE_BUSSTATUS, &mode_busstatus, _FX_MODE_BUSSTATUS);
}

// gets called every time WiFi is (re-)connected. Initialize own network
// interfaces here
void connected() {}

// main loop
void loop() {}

/*
* addToJsonInfo() adds info to the main UI Info section
*/
void addToJsonInfo(JsonObject& root) {
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");

for (uint8_t i = 0; i < BUSSTATUS_SIZ; i++) {
int8_t gpio = status_gpios[i];
if (gpio < 0) {
user.createNestedArray("Device Status").add(device_status_string());
user.createNestedArray("Error Status").add(device_error_string());
} else {
snprintf_P(buf, PSBUFSIZ, "GPIO %d Status", gpio);
JsonArray arr = user.createNestedArray(buf);
arr.add(bus_status_string(gpio));
}
}
}

/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject& root) {}

/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject& root) {}

/*
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
* Use serializeconfig sparingly and always in the loop, never in network callbacks!
*
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
*/
void addToConfig(JsonObject& root) {}

/*
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
* Called before beginStrip() on startup so busses and segments not created yet.
* Also called on settings page save
*
* The function should return true if configuration was successfully loaded or false if there was no configuration.
*/
bool readFromConfig(JsonObject& root) {
return true;
}

/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId() {
return USERMOD_ID_BUSSTATUS;
}
};

const int8_t BusStatusUsermod::status_gpios[BUSSTATUS_SIZ] = BUSSTATUS_PINS;
// config strings to reduce flash memory usage (used more than twice)
// <Effect parameters>(None);<Colors>(3 Colours);<Palette>(None);<Flags>(1Dim);<Defaults>
const char BusStatusUsermod::_FX_MODE_BUSSTATUS[] PROGMEM = "Bus Status@;1,2,3;;1;";
7 changes: 6 additions & 1 deletion wled00/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
#define USERMOD_ID_WIREGUARD 41 //Usermod "wireguard.h"
#define USERMOD_ID_INTERNAL_TEMPERATURE 42 //Usermod "usermod_internal_temperature.h"
#define USERMOD_ID_LDR_DUSK_DAWN 43 //Usermod "usermod_LDR_Dusk_Dawn_v2.h"
#define USERMOD_ID_BUSSTATUS 44 //Usermod "usermod_v2_busstatus.h"

//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
Expand Down Expand Up @@ -217,7 +218,7 @@
// - 0b001 (dec. 16-31) digital (data pin only)
// - 0b010 (dec. 32-47) analog (PWM)
// - 0b011 (dec. 48-63) digital (data + clock / SPI)
// - 0b100 (dec. 64-79) unused/reserved
// - 0b100 (dec. 64-79) other digital
// - 0b101 (dec. 80-95) virtual network busses
// - 0b110 (dec. 96-111) unused/reserved
// - 0b111 (dec. 112-127) unused/reserved
Expand Down Expand Up @@ -251,13 +252,17 @@
#define TYPE_LPD8806 52
#define TYPE_P9813 53
#define TYPE_LPD6803 54
//Other digital (IS_DIGITAL is false, requires custom Bus class) (64-79)
#define TYPE_DMX_OUT 64 //DMX requires a hardware UART. TX and Direction pins
#define TYPE_DMX_IN 65 //RX and Direction pins
//Network types (master broadcast) (80-95)
#define TYPE_NET_DDP_RGB 80 //network DDP RGB bus (master broadcast bus)
#define TYPE_NET_E131_RGB 81 //network E131 RGB bus (master broadcast bus, unused)
#define TYPE_NET_ARTNET_RGB 82 //network ArtNet RGB bus (master broadcast bus, unused)
#define TYPE_NET_DDP_RGBW 88 //network DDP RGBW bus (master broadcast bus)

#define IS_DIGITAL(t) ((t) & 0x10) //digital are 16-31 and 48-63
#define IS_DMX(t) ((t) >= TYPE_DMX_OUT && (t) <= TYPE_DMX_IN)
#define IS_PWM(t) ((t) > 40 && (t) < 46)
#define NUM_PWM_PINS(t) ((t) - 40) //for analog PWM 41-45 only
#define IS_2PIN(t) ((t) > 47)
Expand Down
8 changes: 8 additions & 0 deletions wled00/usermods_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@
#include "../usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h"
#endif

#ifdef USERMOD_BUSSTATUS
#include "../usermods/usermod_v2_busstatus/usermod_v2_busstatus.h"
#endif

void registerUsermods()
{
/*
Expand Down Expand Up @@ -380,4 +384,8 @@ void registerUsermods()
#ifdef USERMOD_LDR_DUSK_DAWN
usermods.add(new LDR_Dusk_Dawn_v2());
#endif

#ifdef USERMOD_BUSSTATUS
usermods.add(new BusStatusUsermod());
#endif
}