Update docs and firmware for ESPHome bridge migration
- Replace gauge.py (MicroPython) references with gaugecontroller.yaml (ESPHome) - Update CLAUDE.md and README.md to document ESPHome-native API integration - Update LED wiring docs for separate main/indicator strips (D22/D36) - Refactor Arduino firmware to drive two WS2812 strips independently - Add per-gauge physical offset caching for main and indicator LEDs - Frame-limit breathe effect (16ms) to reduce unnecessary strip refreshes
This commit is contained in:
@@ -6,6 +6,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
Main firmware lives in `Gaugecontroller/Gaugecontroller.ino`. Requires the **FastLED** library (`arduino-cli lib install FastLED`). Use the Arduino IDE or `arduino-cli`:
|
Main firmware lives in `Gaugecontroller/Gaugecontroller.ino`. Requires the **FastLED** library (`arduino-cli lib install FastLED`). Use the Arduino IDE or `arduino-cli`:
|
||||||
|
|
||||||
|
The ESP32 bridge runs ESPHome; the config is in `gaugecontroller.yaml`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Compile (replace board/port as needed)
|
# Compile (replace board/port as needed)
|
||||||
arduino-cli compile --fqbn arduino:avr:mega Gaugecontroller
|
arduino-cli compile --fqbn arduino:avr:mega Gaugecontroller
|
||||||
@@ -76,7 +78,7 @@ When `sweepEnabled`, `updateSweepTarget` bounces `targetPos` between `minPos` an
|
|||||||
|
|
||||||
### LED strip
|
### LED strip
|
||||||
|
|
||||||
One shared WS2812B strip is driven from `LED_DATA_PIN` (currently 22). Each gauge owns a contiguous segment of the strip; `gaugePins[i].ledOrder` is a per-LED type string (one char per LED, `'G'` = GRB-ordered, `'R'` = RGB-ordered) and its length defines the segment length (empty string = no LEDs). `TOTAL_LEDS` is computed at compile time via `constexpr sumLedCounts()` — no manual constant to keep in sync. Per-gauge offsets and counts are cached in `setup()` into `gaugeLedOffset[]` and `gaugeLedCount[]`. The strip is initialised as `GRB`; writes to RGB-ordered LEDs are R/G-swapped via the `writeLed`/`readLed` helpers so callers always work in logical RGB. LED commands and effects mark the strip dirty, and `FastLED.show()` is called once per main-loop iteration if anything changed.
|
Two LED strips are driven: main backlight/status LEDs on `LED_DATA_PIN` (currently 22) and dial indicator LEDs on `INDICATOR_LED_DATA_PIN` (currently 36). The serial protocol still exposes one logical per-gauge LED segment: `0-2` backlight, `3-4` indicators, `5-6` status. `gaugePins[i].ledOrder` is a per-LED type string (one char per LED, `'G'` = GRB-ordered, `'R'` = RGB-ordered) and its length defines the logical LED count. `TOTAL_LEDS`, `TOTAL_MAIN_LEDS`, and `TOTAL_INDICATOR_LEDS` are computed at compile time. Per-gauge logical and physical offsets are cached in `setup()`. LED writes dirty only their physical strip, and the loop flushes each FastLED controller independently with `showLeds()`.
|
||||||
|
|
||||||
### Serial command protocol
|
### Serial command protocol
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,12 @@
|
|||||||
|
|
||||||
static const uint8_t GAUGE_COUNT = 4;
|
static const uint8_t GAUGE_COUNT = 4;
|
||||||
|
|
||||||
// One shared WS2812B strip, split into per-gauge segments.
|
// Backlight/status LEDs and indicator LEDs use separate data strips because
|
||||||
|
// their LED chipsets are not compatible on one chain. The command protocol
|
||||||
|
// still exposes one logical LED segment per gauge.
|
||||||
static const uint8_t LED_DATA_PIN = 22;
|
static const uint8_t LED_DATA_PIN = 22;
|
||||||
|
static const uint8_t INDICATOR_LED_DATA_PIN = 36;
|
||||||
|
static const uint8_t BREATHE_FRAME_MS = 16;
|
||||||
|
|
||||||
// For now, command and debug traffic share the same serial port.
|
// For now, command and debug traffic share the same serial port.
|
||||||
#define CMD_PORT Serial1
|
#define CMD_PORT Serial1
|
||||||
@@ -246,6 +250,21 @@ constexpr uint8_t sumLedCounts(uint8_t i = 0) {
|
|||||||
}
|
}
|
||||||
static const uint8_t TOTAL_LEDS = sumLedCounts();
|
static const uint8_t TOTAL_LEDS = sumLedCounts();
|
||||||
|
|
||||||
|
constexpr bool isIndicatorLedIndex(uint8_t localIdx) {
|
||||||
|
return localIdx == 3 || localIdx == 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uint8_t countIndicatorLedsForGauge(uint8_t gaugeIdx) {
|
||||||
|
return (cstrLen(gaugePins[gaugeIdx].ledOrder) > 3 ? 1 : 0) +
|
||||||
|
(cstrLen(gaugePins[gaugeIdx].ledOrder) > 4 ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uint8_t sumIndicatorLedCounts(uint8_t i = 0) {
|
||||||
|
return i >= GAUGE_COUNT ? 0 : countIndicatorLedsForGauge(i) + sumIndicatorLedCounts(i + 1);
|
||||||
|
}
|
||||||
|
static const uint8_t TOTAL_INDICATOR_LEDS = sumIndicatorLedCounts();
|
||||||
|
static const uint8_t TOTAL_MAIN_LEDS = TOTAL_LEDS - TOTAL_INDICATOR_LEDS;
|
||||||
|
|
||||||
enum HomingState : uint8_t {
|
enum HomingState : uint8_t {
|
||||||
HS_IDLE,
|
HS_IDLE,
|
||||||
HS_START,
|
HS_START,
|
||||||
@@ -300,11 +319,18 @@ struct BlinkState {
|
|||||||
Gauge gauges[GAUGE_COUNT];
|
Gauge gauges[GAUGE_COUNT];
|
||||||
String rxLine;
|
String rxLine;
|
||||||
|
|
||||||
CRGB leds[TOTAL_LEDS];
|
CRGB logicalLeds[TOTAL_LEDS];
|
||||||
|
CRGB mainLeds[TOTAL_MAIN_LEDS];
|
||||||
|
CRGB indicatorLeds[TOTAL_INDICATOR_LEDS];
|
||||||
|
CLEDController* mainLedController = nullptr;
|
||||||
|
CLEDController* indicatorLedController = nullptr;
|
||||||
uint8_t gaugeLedOffset[GAUGE_COUNT];
|
uint8_t gaugeLedOffset[GAUGE_COUNT];
|
||||||
uint8_t gaugeLedCount[GAUGE_COUNT];
|
uint8_t gaugeLedCount[GAUGE_COUNT];
|
||||||
|
uint8_t gaugeMainLedOffset[GAUGE_COUNT];
|
||||||
|
uint8_t gaugeIndicatorLedOffset[GAUGE_COUNT];
|
||||||
BlinkState blinkState[TOTAL_LEDS];
|
BlinkState blinkState[TOTAL_LEDS];
|
||||||
bool ledsDirty = false;
|
bool mainLedsDirty = false;
|
||||||
|
bool indicatorLedsDirty = false;
|
||||||
|
|
||||||
// FastLED drives the shared strip as RGB. Each gauge's ledOrder string marks per-LED
|
// FastLED drives the shared strip as RGB. Each gauge's ledOrder string marks per-LED
|
||||||
// type ('R' = RGB, 'G' = GRB); writes to GRB-ordered LEDs pre-swap R and G to compensate.
|
// type ('R' = RGB, 'G' = GRB); writes to GRB-ordered LEDs pre-swap R and G to compensate.
|
||||||
@@ -328,12 +354,52 @@ inline CRGB encodeForStrip(uint8_t globalIdx, CRGB color) {
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ledPhysicalIndex(uint8_t globalIdx, bool& indicatorStrip, uint8_t& physicalIdx) {
|
||||||
|
for (uint8_t i = 0; i < GAUGE_COUNT; i++) {
|
||||||
|
uint8_t off = gaugeLedOffset[i];
|
||||||
|
if (globalIdx < off || globalIdx >= off + gaugeLedCount[i]) continue;
|
||||||
|
|
||||||
|
uint8_t localIdx = globalIdx - off;
|
||||||
|
indicatorStrip = isIndicatorLedIndex(localIdx);
|
||||||
|
if (indicatorStrip) {
|
||||||
|
physicalIdx = gaugeIndicatorLedOffset[i] + (localIdx - 3);
|
||||||
|
} else {
|
||||||
|
physicalIdx = gaugeMainLedOffset[i] + localIdx - (localIdx > 4 ? 2 : 0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
inline void writeLed(uint8_t globalIdx, CRGB color) {
|
inline void writeLed(uint8_t globalIdx, CRGB color) {
|
||||||
leds[globalIdx] = encodeForStrip(globalIdx, color);
|
logicalLeds[globalIdx] = color;
|
||||||
|
|
||||||
|
bool indicatorStrip = false;
|
||||||
|
uint8_t physicalIdx = 0;
|
||||||
|
if (!ledPhysicalIndex(globalIdx, indicatorStrip, physicalIdx)) return;
|
||||||
|
|
||||||
|
if (indicatorStrip) {
|
||||||
|
indicatorLeds[physicalIdx] = encodeForStrip(globalIdx, color);
|
||||||
|
indicatorLedsDirty = true;
|
||||||
|
} else {
|
||||||
|
mainLeds[physicalIdx] = encodeForStrip(globalIdx, color);
|
||||||
|
mainLedsDirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CRGB readLed(uint8_t globalIdx) {
|
inline CRGB readLed(uint8_t globalIdx) {
|
||||||
return encodeForStrip(globalIdx, leds[globalIdx]);
|
return logicalLeds[globalIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
void showDirtyLeds() {
|
||||||
|
if (mainLedsDirty && mainLedController != nullptr) {
|
||||||
|
mainLedController->showLeds(255);
|
||||||
|
mainLedsDirty = false;
|
||||||
|
}
|
||||||
|
if (indicatorLedsDirty && indicatorLedController != nullptr) {
|
||||||
|
indicatorLedController->showLeds(255);
|
||||||
|
indicatorLedsDirty = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends one-line command replies back over the control port.
|
// Sends one-line command replies back over the control port.
|
||||||
@@ -927,7 +993,6 @@ bool parseLed(const String& line) {
|
|||||||
blinkState[gaugeLedOffset[id] + i].active = false;
|
blinkState[gaugeLedOffset[id] + i].active = false;
|
||||||
writeLed(gaugeLedOffset[id] + i, color);
|
writeLed(gaugeLedOffset[id] + i, color);
|
||||||
}
|
}
|
||||||
ledsDirty = true;
|
|
||||||
sendReply("OK");
|
sendReply("OK");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -977,7 +1042,6 @@ bool parseBlink(const String& line) {
|
|||||||
bs.active = true;
|
bs.active = true;
|
||||||
writeLed(globalIdx, bs.onColor);
|
writeLed(globalIdx, bs.onColor);
|
||||||
}
|
}
|
||||||
ledsDirty = true;
|
|
||||||
sendReply("OK");
|
sendReply("OK");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1010,7 +1074,6 @@ bool parseBreathe(const String& line) {
|
|||||||
bs.active = true;
|
bs.active = true;
|
||||||
writeLed(gi, CRGB::Black);
|
writeLed(gi, CRGB::Black);
|
||||||
}
|
}
|
||||||
ledsDirty = true;
|
|
||||||
sendReply("OK");
|
sendReply("OK");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1041,15 +1104,13 @@ bool parseDflash(const String& line) {
|
|||||||
bs.active = true;
|
bs.active = true;
|
||||||
writeLed(gi, color); // phase 0 = on
|
writeLed(gi, color); // phase 0 = on
|
||||||
}
|
}
|
||||||
ledsDirty = true;
|
|
||||||
sendReply("OK");
|
sendReply("OK");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advances all active LED effects and marks the strip dirty when something changed.
|
// Advances all active LED effects. writeLed() marks the affected physical strip dirty.
|
||||||
void updateBlink() {
|
void updateBlink() {
|
||||||
unsigned long nowMs = millis();
|
unsigned long nowMs = millis();
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < GAUGE_COUNT; i++) {
|
for (uint8_t i = 0; i < GAUGE_COUNT; i++) {
|
||||||
for (uint8_t j = 0; j < gaugeLedCount[i]; j++) {
|
for (uint8_t j = 0; j < gaugeLedCount[i]; j++) {
|
||||||
@@ -1064,17 +1125,17 @@ void updateBlink() {
|
|||||||
bs.currentlyOn = !bs.currentlyOn;
|
bs.currentlyOn = !bs.currentlyOn;
|
||||||
bs.lastMs = nowMs;
|
bs.lastMs = nowMs;
|
||||||
writeLed(gi, bs.currentlyOn ? bs.onColor : CRGB::Black);
|
writeLed(gi, bs.currentlyOn ? bs.onColor : CRGB::Black);
|
||||||
changed = true;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FX_BREATHE: {
|
case FX_BREATHE: {
|
||||||
unsigned long dt = nowMs - bs.lastMs;
|
unsigned long dt = nowMs - bs.lastMs;
|
||||||
if (dt < 64) break;
|
if (dt < BREATHE_FRAME_MS) break;
|
||||||
uint32_t newPos = (uint32_t)bs.cyclePos + dt;
|
uint32_t newPos = (uint32_t)bs.cyclePos + dt;
|
||||||
bs.cyclePos = (uint16_t)(newPos % bs.periodMs);
|
bs.cyclePos = (uint16_t)(newPos % bs.periodMs);
|
||||||
bs.lastMs = nowMs;
|
bs.lastMs = nowMs;
|
||||||
// Cheap triangle wave. It does the job and nobody has complained yet.
|
// Triangle wave brightness; frame-limited so breathe remains smooth
|
||||||
|
// without refreshing the LED strips on every service-loop pass.
|
||||||
uint16_t half = bs.periodMs >> 1;
|
uint16_t half = bs.periodMs >> 1;
|
||||||
uint8_t bri = (bs.cyclePos < half)
|
uint8_t bri = (bs.cyclePos < half)
|
||||||
? (uint8_t)((uint32_t)bs.cyclePos * 255 / half)
|
? (uint8_t)((uint32_t)bs.cyclePos * 255 / half)
|
||||||
@@ -1082,7 +1143,6 @@ void updateBlink() {
|
|||||||
CRGB scaled = bs.onColor;
|
CRGB scaled = bs.onColor;
|
||||||
scaled.nscale8(bri ? bri : 1);
|
scaled.nscale8(bri ? bri : 1);
|
||||||
writeLed(gi, scaled);
|
writeLed(gi, scaled);
|
||||||
changed = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FX_DFLASH: {
|
case FX_DFLASH: {
|
||||||
@@ -1091,15 +1151,12 @@ void updateBlink() {
|
|||||||
bs.lastMs = nowMs;
|
bs.lastMs = nowMs;
|
||||||
bs.dphase = (bs.dphase + 1) & 3;
|
bs.dphase = (bs.dphase + 1) & 3;
|
||||||
writeLed(gi, (bs.dphase == 0 || bs.dphase == 2) ? bs.onColor : CRGB::Black);
|
writeLed(gi, (bs.dphase == 0 || bs.dphase == 2) ? bs.onColor : CRGB::Black);
|
||||||
changed = true;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) ledsDirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs the command parsers in order until one claims the line.
|
// Runs the command parsers in order until one claims the line.
|
||||||
@@ -1168,16 +1225,25 @@ void setup() {
|
|||||||
gauges[i].lastUpdateMicros = micros();
|
gauges[i].lastUpdateMicros = micros();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten the per-gauge LED counts into offsets on the shared strip.
|
// Flatten the per-gauge LED counts into logical offsets and separate
|
||||||
|
// physical offsets for the main and indicator strips.
|
||||||
uint8_t ledOff = 0;
|
uint8_t ledOff = 0;
|
||||||
|
uint8_t mainLedOff = 0;
|
||||||
|
uint8_t indicatorLedOff = 0;
|
||||||
for (uint8_t i = 0; i < GAUGE_COUNT; i++) {
|
for (uint8_t i = 0; i < GAUGE_COUNT; i++) {
|
||||||
gaugeLedCount[i] = cstrLen(gaugePins[i].ledOrder);
|
gaugeLedCount[i] = cstrLen(gaugePins[i].ledOrder);
|
||||||
gaugeLedOffset[i] = ledOff;
|
gaugeLedOffset[i] = ledOff;
|
||||||
|
gaugeMainLedOffset[i] = mainLedOff;
|
||||||
|
gaugeIndicatorLedOffset[i] = indicatorLedOff;
|
||||||
ledOff += gaugeLedCount[i];
|
ledOff += gaugeLedCount[i];
|
||||||
|
indicatorLedOff += countIndicatorLedsForGauge(i);
|
||||||
|
mainLedOff += gaugeLedCount[i] - countIndicatorLedsForGauge(i);
|
||||||
}
|
}
|
||||||
FastLED.addLeds<WS2812B, LED_DATA_PIN, RGB>(leds, TOTAL_LEDS);
|
mainLedController = &FastLED.addLeds<WS2812, LED_DATA_PIN, RGB>(mainLeds, TOTAL_MAIN_LEDS);
|
||||||
|
indicatorLedController = &FastLED.addLeds<WS2812B, INDICATOR_LED_DATA_PIN, RGB>(indicatorLeds, TOTAL_INDICATOR_LEDS);
|
||||||
FastLED.setBrightness(255);
|
FastLED.setBrightness(255);
|
||||||
FastLED.show();
|
mainLedController->showLeds(255);
|
||||||
|
indicatorLedController->showLeds(255);
|
||||||
|
|
||||||
vfd::begin();
|
vfd::begin();
|
||||||
|
|
||||||
@@ -1198,10 +1264,7 @@ void loop() {
|
|||||||
updateGauge(i);
|
updateGauge(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ledsDirty) {
|
showDirtyLeds();
|
||||||
FastLED.show();
|
|
||||||
ledsDirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
52
README.md
52
README.md
@@ -7,7 +7,7 @@ A dedicated gauge controller for Arduinos.
|
|||||||
This repository contains:
|
This repository contains:
|
||||||
|
|
||||||
- `Gaugecontroller/Gaugecontroller.ino`: the Arduino Mega firmware for the stepper gauges, LEDs, and integrated HV5812-based VFD
|
- `Gaugecontroller/Gaugecontroller.ino`: the Arduino Mega firmware for the stepper gauges, LEDs, and integrated HV5812-based VFD
|
||||||
- `gauge.py`: the ESP32 / MicroPython MQTT bridge that exposes the controller to Home Assistant
|
- `gaugecontroller.yaml`: the ESPHome-based ESP32 firmware that exposes the gauges and VFD to Home Assistant via the native API
|
||||||
|
|
||||||
## VFD Support
|
## VFD Support
|
||||||
|
|
||||||
@@ -48,16 +48,19 @@ Rules:
|
|||||||
- shorter values are right-aligned
|
- shorter values are right-aligned
|
||||||
- leading zeroes are preserved if they are part of the input
|
- leading zeroes are preserved if they are part of the input
|
||||||
|
|
||||||
## Home Assistant Entities
|
## Home Assistant Integration
|
||||||
|
|
||||||
The MQTT bridge publishes Home Assistant discovery entities for the VFD:
|
The ESPHome firmware in `gaugecontroller.yaml` exposes entities to Home Assistant via the native API:
|
||||||
|
|
||||||
- `VFD Display`
|
### Gauge Controls
|
||||||
text entity for the displayed value
|
- Number entities for each gauge's target value (with unit conversion)
|
||||||
- `VFD Decimal Point`
|
- Number entities for speed and acceleration (diagnostic)
|
||||||
switch entity
|
- Rezero buttons for each gauge and all gauges
|
||||||
- `VFD Alarm`
|
|
||||||
switch entity
|
### VFD Display
|
||||||
|
- `VFD Display`: text entity for the displayed value
|
||||||
|
- `VFD Decimal Point`: switch entity
|
||||||
|
- `VFD Alarm`: switch entity
|
||||||
|
|
||||||
The display is intentionally exposed as a text entity rather than a numeric entity so that:
|
The display is intentionally exposed as a text entity rather than a numeric entity so that:
|
||||||
|
|
||||||
@@ -65,27 +68,12 @@ The display is intentionally exposed as a text entity rather than a numeric enti
|
|||||||
- hexadecimal values like `DEAD` or `BEEF` work
|
- hexadecimal values like `DEAD` or `BEEF` work
|
||||||
- clearing the display is possible with an empty value
|
- clearing the display is possible with an empty value
|
||||||
|
|
||||||
## MQTT Topics
|
### LED Controls
|
||||||
|
- RGB light entity for each gauge's backlight with effects (Blink, Breathe, Double Flash)
|
||||||
|
- Binary light entities for each gauge's red/green indicators and status lights
|
||||||
|
|
||||||
Using the configured `mqtt_prefix` from `config.json`, the VFD topics are:
|
### Diagnostics
|
||||||
|
- WiFi signal sensor
|
||||||
- `<prefix>/vfd/set`
|
- Uptime sensor
|
||||||
- `<prefix>/vfd/state`
|
- IP address and SSID text sensors
|
||||||
- `<prefix>/vfd/decimal_point/set`
|
- Arduino Last Message sensor
|
||||||
- `<prefix>/vfd/decimal_point/state`
|
|
||||||
- `<prefix>/vfd/alarm/set`
|
|
||||||
- `<prefix>/vfd/alarm/state`
|
|
||||||
|
|
||||||
Example with the default prefix `gauges`:
|
|
||||||
|
|
||||||
- `gauges/vfd/set`
|
|
||||||
- `gauges/vfd/decimal_point/set`
|
|
||||||
- `gauges/vfd/alarm/set`
|
|
||||||
|
|
||||||
Example payloads:
|
|
||||||
|
|
||||||
- publish `0123` to `gauges/vfd/set`
|
|
||||||
- publish `ON` to `gauges/vfd/decimal_point/set`
|
|
||||||
- publish `OFF` to `gauges/vfd/alarm/set`
|
|
||||||
|
|
||||||
The MQTT bridge then converts that into the correct Arduino serial command such as `VFD 0123.`.
|
|
||||||
|
|||||||
@@ -183,13 +183,14 @@ Then connect the motor side of that driver to:
|
|||||||
|
|
||||||
according to the driver board you are using.
|
according to the driver board you are using.
|
||||||
|
|
||||||
## 14. Wire The WS2812B LEDs
|
## 14. Wire The WS2812 LEDs
|
||||||
|
|
||||||
Connect:
|
Connect:
|
||||||
|
|
||||||
- `Mega D22` -> `WS2812B DIN`
|
- `Mega D22` -> main backlight/status strip `DIN`
|
||||||
- `5V LED supply` -> `WS2812B 5V`
|
- `Mega D36` -> indicator strip `DIN`
|
||||||
- `WS2812B GND` -> common ground rail
|
- `5V LED supply` -> both strip `5V` inputs
|
||||||
|
- both strip `GND` inputs -> common ground rail
|
||||||
|
|
||||||
If the LED chain is long or bright:
|
If the LED chain is long or bright:
|
||||||
|
|
||||||
|
|||||||
@@ -205,9 +205,10 @@ If `D8` and `D9` come from separate fly wires to the stripboard, keep them in th
|
|||||||
|
|
||||||
Route:
|
Route:
|
||||||
|
|
||||||
- `D22` -> `WS2812 DIN`
|
- `D22` -> main backlight/status strip `DIN`
|
||||||
- `5V` -> `WS2812 5V`
|
- `D36` -> indicator strip `DIN`
|
||||||
- `GND` -> `WS2812 GND`
|
- `5V` -> both strip `5V` inputs
|
||||||
|
- `GND` -> both strip `GND` inputs
|
||||||
|
|
||||||
Keep the LED connector in the low-voltage area.
|
Keep the LED connector in the low-voltage area.
|
||||||
|
|
||||||
|
|||||||
17
wiring.md
17
wiring.md
@@ -163,19 +163,22 @@ Also connect:
|
|||||||
|
|
||||||
If your driver boards need separate motor power, supply that from the proper motor supply. Do not power motors from the Mega `5V` pin.
|
If your driver boards need separate motor power, supply that from the proper motor supply. Do not power motors from the Mega `5V` pin.
|
||||||
|
|
||||||
## WS2812B LED Strip
|
## WS2812 LED Strips
|
||||||
|
|
||||||
The current sketch expects one shared WS2812B chain.
|
The current sketch expects two LED data chains. Backlight and status LEDs stay
|
||||||
|
on the main strip; the red/green dial indicator LEDs are on their own strip.
|
||||||
|
|
||||||
| Mega Pin | WS2812B |
|
| Mega Pin | LED Strip |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `D22` | `DIN` |
|
| `D22` | main backlight/status `DIN` |
|
||||||
| `5V` | `5V` |
|
| `D36` | indicator `DIN` |
|
||||||
| `GND` | `GND` |
|
| `5V` | both strips `5V` |
|
||||||
|
| `GND` | both strips `GND` |
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
- the code expects `7 LEDs per gauge`, so `21 LEDs total`
|
- the command protocol still exposes `7 LEDs per gauge`
|
||||||
|
- logical indices `0-2` are backlight, `3-4` are indicators, and `5-6` are status
|
||||||
- use a proper 5V supply sized for the LED current
|
- use a proper 5V supply sized for the LED current
|
||||||
- keep LED ground common with the Mega
|
- keep LED ground common with the Mega
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user