Skip to content
Merged
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
11 changes: 8 additions & 3 deletions docs/moonbase/inputoutput.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ For each board the following presets are defined:

* Modded: set when any pin differs from the selected board preset. Press off to return to the preset defaults.
* Max Power in Watts: adjust the brightness to approach this max power, depending on the number of LEDs used. Default 10: 5V * 2A = 10W (so it runs fine on USB). Used by LED drivers, see [Drivers](../../moonlight/drivers/)
* Jumper1: If the board contains a jumper, it can define pin behaviour. Eg. select between Infrared and Ethernet.
* Switch1 and 2: If the board contains a jumper or pins have different functions, a custom switch can be set. Eg. select between Infrared and Ethernet. See boards below for details
* Pins: Assign functionality to gpio pins. Other modules and nodes use the pin assignments made here.
* GPIO = gpio_num;
* Usage: See below
Expand Down Expand Up @@ -75,7 +75,12 @@ For each board the following presets are defined:
* On new ESP32-P4 Nano boards, the WiFi coprocessor needs to be updated first to a recent version, currently ESP-Hosted v2.0.17, see the link in the [MoonLight Installer](../../gettingstarted/installer/)
* After install, select the **MHC P4 Nano Shield** board preset to have the pins assigned correctly.
* Assuming 100W LED power; change if needed.
* Jumper1: off (default): 16 LED pins. On: 8 LED pins, 4 RS-485 pins and 4 exposed pins (set also the switches on the board).
* Switch1: (set also the switches on the board)
* off (default): 16 LED pins.
* On: 8 LED pins, 4 RS-485 pins and 4 exposed pins
* Switch2:
* off (default): Pins 10, 11, 12, 13 used for build-in Mic over I2S, pin 7 and 8: I2C SDA and SCL
* On: Pins 33, 25, 32, 36 used for Line in, pin 7 and 8: additional LED pins.
* Add the Parallel LED Driver, see [Drivers](../../moonlight/drivers/). It uses [@troyhacks](https://github.com/troyhacks) his parallel IO driver to drive all LED pins configured for the shield.


Expand All @@ -84,4 +89,4 @@ For each board the following presets are defined:
![SE-16p](../firmware/installer/images/esp32-s3-stephanelec-16p.jpg){: style="width:100px"}

* Choose the esp32-s3-devkitc-1-n8r8v board in the [MoonLight Installer](../../gettingstarted/installer/)
* Set jumper1 the same as you set it on the board: on: Infrared, off: Ethernet
* Set Switch1 the same as you set the jumper on the board: off / default: Ethernet. on: Infrared.
73 changes: 59 additions & 14 deletions src/MoonBase/Modules/ModuleIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ enum IO_PinUsageEnum {
pin_SPI_MOSI,
pin_PHY_CS,
pin_PHY_IRQ,
pin_RS485,
pin_RS485_TX,
pin_RS485_RX,
pin_Dig_Input, // Digital Input pin type. May contains some protection circuit
pin_Reserved,
pin_count
};
Expand All @@ -74,8 +76,8 @@ enum IO_BoardsEnum {
board_SergUniShieldV5,
board_SergMiniShield,
board_SE16V1,
board_MHCD0, // by Wladi
board_MHCP4Nano, // by Wladi
board_MHCV43, // by Wladi
board_MHCP4NanoV1, // by Wladi V1.0
board_YvesV48,
board_TroyP4Nano,
board_AtomS3,
Expand Down Expand Up @@ -113,8 +115,8 @@ class ModuleIO : public Module {
addControlValue(control, "Serg Universal Shield");
addControlValue(control, "Serg Mini Shield");
addControlValue(control, "Mathieu SE16 v1");
addControlValue(control, "MHC D0 Shield 🚧");
addControlValue(control, "MHC P4 Nano Shield");
addControlValue(control, "MyHome-Control V43 controller");
addControlValue(control, "MyHome-Control P4 Nano Shield V1.0");
addControlValue(control, "Yves V48 🚧");
addControlValue(control, "Troy P4 Nano 🚧");
addControlValue(control, "Atom S3R");
Expand All @@ -127,7 +129,10 @@ class ModuleIO : public Module {
control = addControl(controls, "maxPower", "number", 0, 500, false, "Watt");
control["default"] = 10;

control = addControl(controls, "jumper1", "checkbox");
control = addControl(controls, "switch1", "checkbox");
control["default"] = false;

control = addControl(controls, "switch2", "checkbox");
control["default"] = false;
Comment on lines +132 to 136
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add descriptive labels for switch controls to improve UX

The controls are named "switch1" and "switch2" without descriptions. Based on the PR objectives mentioning "UseLineIn" and the documentation showing these control RS-485/LED vs Line-In/Mic configurations, users need clear labels.

Apply this diff to add meaningful descriptions:

-    control = addControl(controls, "switch1", "checkbox");
+    control = addControl(controls, "switch1", "checkbox", 0, UINT8_MAX, false, "RS-485 mode");
     control["default"] = false;
 
-    control = addControl(controls, "switch2", "checkbox");
+    control = addControl(controls, "switch2", "checkbox", 0, UINT8_MAX, false, "Use Line-In");
     control["default"] = false;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/MoonBase/Modules/ModuleIO.h around lines 132 to 136, the controls are
created as "switch1" and "switch2" with no descriptive labels; update the
control creation to provide clear, user-facing descriptions such as a
label/description property indicating their function (e.g., one control for
"UseLineIn (Line-In vs Mic)" and the other for "RS-485/LED mode selection"),
keeping the controls' types as "checkbox" and preserving the default value
false; ensure the descriptive text matches project terminology (UseLineIn /
RS-485 vs Line-In) so UI shows meaningful labels instead of "switch1"/"switch2".


control = addControl(controls, "pins", "rows");
Expand Down Expand Up @@ -181,7 +186,9 @@ class ModuleIO : public Module {
addControlValue(control, "SPI MOSI");
addControlValue(control, "PHY CS");
addControlValue(control, "PHY IRQ");
addControlValue(control, "RS-485");
addControlValue(control, "RS-485 TX");
addControlValue(control, "RS-485 RX");
addControlValue(control, "Digital Input");
addControlValue(control, "Reserved");

control = addControl(rows, "index", "number", 1, 32); // max 32 of one type, e.g 32 led pins
Expand Down Expand Up @@ -282,7 +289,7 @@ class ModuleIO : public Module {
pinAssigner.assignPin(8, pin_Voltage);
pinAssigner.assignPin(9, pin_Current);

if (_state.data["jumper1"]) {
if (_state.data["switch1"]) {
pinAssigner.assignPin(5, pin_Infrared);
} else { // default
pinAssigner.assignPin(5, pin_SPI_MISO);
Expand Down Expand Up @@ -392,6 +399,33 @@ class ModuleIO : public Module {

pinAssigner.assignPin(17, pin_Button_LightsOn);
pinAssigner.assignPin(19, pin_Relay_LightsOn);
} else if (boardID == board_MHCV43) { // https://shop.myhome-control.de/ABC-WLED-Controller-Board-5-24V/HW10015
object["maxPower"] = 75; // 15A Fuse @ 5V
uint8_t ledPins[] = {12, 13, 16, 18}; // 4 LED_PINS
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
pinAssigner.assignPin(32, pin_I2S_SD);
pinAssigner.assignPin(15, pin_I2S_WS);
pinAssigner.assignPin(14, pin_I2S_SCK);
pinAssigner.assignPin(0, pin_I2S_MCLK);
uint8_t exposedPins[] = {4, 5, 17, 19, 21, 22, 23, 25, 26, 27, 33};
for (int i = 0; i < sizeof(exposedPins); i++) pinAssigner.assignPin(exposedPins[i], pin_Exposed); // Ethernet Pins
} else if (boardID == board_MHCP4NanoV1) { // https://shop.myhome-control.de/ABC-WLED-ESP32-P4-Shield/HW10027
object["maxPower"] = 100; // Assuming decent LED power!!

if (_state.data["switch1"]) { // on
uint8_t ledPins[] = {21, 20, 25, 5, 7, 23, 8, 27}; // 8 LED pins in this order
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
pinAssigner.assignPin(3, pin_RS485_TX);
pinAssigner.assignPin(4, pin_RS485_TX);
pinAssigner.assignPin(22, pin_RS485_TX);
pinAssigner.assignPin(24, pin_RS485_TX);
pinAssigner.assignPin(2, pin_Dig_Input);
pinAssigner.assignPin(46, pin_Dig_Input);
pinAssigner.assignPin(47, pin_Dig_Input);
pinAssigner.assignPin(48, pin_Dig_Input);
} else { // off - default
uint8_t ledPins[] = {21, 20, 25, 5, 7, 23, 8, 27, 3, 22, 24, 4, 46, 47, 2, 48}; // 16 LED_PINS in this order
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
pinAssigner.assignPin(18, pin_Infrared);

// e.g. for mic
Expand Down Expand Up @@ -426,10 +460,21 @@ class ModuleIO : public Module {
uint8_t ledPins[] = {21, 20, 25, 5, 7, 23, 8, 27, 3, 22, 24, 4, 46, 47, 2, 48}; // 16 LED_PINS
for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
}
pinAssigner.assignPin(33, pin_I2S_SD);
pinAssigner.assignPin(26, pin_I2S_WS);
pinAssigner.assignPin(32, pin_I2S_SCK);
pinAssigner.assignPin(36, pin_I2S_MCLK);

if (_state.data["switch2"]) {
// pins used for Line-In
pinAssigner.assignPin(33, pin_I2S_SD);
pinAssigner.assignPin(26, pin_I2S_WS);
pinAssigner.assignPin(32, pin_I2S_SCK);
pinAssigner.assignPin(36, pin_I2S_MCLK);
} else { // default
// Pins used for build-in Mic over I2S
pinAssigner.assignPin(10, pin_I2S_WS);
pinAssigner.assignPin(11, pin_I2S_SD);
pinAssigner.assignPin(12, pin_I2S_SCK);
pinAssigner.assignPin(13, pin_I2S_MCLK);
}

} else if (boardID == board_YvesV48) {
pinAssigner.assignPin(3, pin_LED);
} else if (boardID == board_TroyP4Nano) {
Expand Down Expand Up @@ -508,8 +553,8 @@ class ModuleIO : public Module {
EXT_LOGD(MB_TAG, "%s[%d]%s[%d].%s = %s -> %s", updatedItem.parent[0].c_str(), updatedItem.index[0], updatedItem.parent[1].c_str(), updatedItem.index[1], updatedItem.name.c_str(), updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
newBoardID = _state.data["boardPreset"]; // run in sveltekit task
}
} else if (updatedItem.name == "jumper1" && !_state.updateOriginId.contains("server")) { // not done by this module: done by UI
// rebuild with new jumper setting
} else if ((updatedItem.name == "switch1" || updatedItem.name == "switch2") && !_state.updateOriginId.contains("server")) {
// rebuild with new switch setting
_state.data["modded"] = false;
newBoardID = _state.data["boardPreset"]; // run in sveltekit task
} else if (updatedItem.name == "usage" && !_state.updateOriginId.contains("server")) { // not done by this module: done by UI
Expand Down