Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usermod SbusControl #4464

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
15 changes: 15 additions & 0 deletions usermods/sbus_control/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
This user mod can be used to control WLED via the sbus.
Sbus is a protocol that RC receivers use to transmit control signals to other components.
By connecting the ESP32 to the receiver, WLED can be used as LEDController in RC plains, cars or ships.

You can change the brightness and between 9 presets. Setting up the Leds needs to be done via APP or WebUi.

To build this usermod the following lines needs to be added to your target in the platformio.ini file:

build_flags = DUSERMOD_SBUS_CONTROL
lib_deps = https://github.com/bolderflight/sbus.git

Hardware setup:

Connect ground of receiver and ESP32.
Connect receiver sbus_out pin with ESP32 pin configured for sbus_in in config.
133 changes: 133 additions & 0 deletions usermods/sbus_control/usermod_sbus_control.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#pragma once

#include "wled.h"
#include <sbus.h>
#include <math.h>

class SbusControl : public Usermod {
public:
SbusControl(){}

void setup() override
{
PinManagerPinType pins[2] = {
{ sbus_pin_rx_, false },
{ sbus_pin_tx_, true }
};
if (!PinManager::allocateMultiplePins(pins, 2, PinOwner::UM_SBUS_CONTROL))
{
DEBUG_PRINTF("SBUS_CONTROL pin allocation failed! Pin rx %d, Pin tx %d\n", sbus_pin_rx_, sbus_pin_tx_);
return;
}
sbus_rx_ = bfs::SbusRx(&Serial1, sbus_pin_rx_, sbus_pin_tx_, true);
sbus_rx_.Begin();
is_enabled_ = true;
}

void loop() override
{
if (!is_enabled_)
{
return;
}

const uint32_t ts_ms = millis();

if (ts_ms < (last_ts_ms_ + update_period_ms_))
{
return;
}

if (sbus_rx_.Read()) {
/* Grab the received data */
bfs::SbusData data = sbus_rx_.data();

int16_t brightness = data.ch[ch_brightness_ - 1];
brightness = std::min(brightness, static_cast<int16_t>(2000));
brightness -= 250;
brightness = std::max(brightness, static_cast<int16_t>(0));
brightness /= 7;
if (brightness != last_bri_)
{
bri = brightness;
applyFinalBri();
}
Comment on lines +45 to +54
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add bounds checking for brightness calculation.

The brightness calculation needs bounds checking to prevent potential issues with invalid values.

Apply this diff:

 int16_t brightness = data.ch[ch_brightness_ - 1];
+if (brightness < 0 || brightness > 2047) {
+    DEBUG_PRINTF("[SBUS] Invalid brightness value: %d\n", brightness);
+    return;
+}
 brightness = std::min(brightness, static_cast<int16_t>(2000));
 brightness -= 250;
 brightness = std::max(brightness, static_cast<int16_t>(0));
 brightness /= 7;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
int16_t brightness = data.ch[ch_brightness_ - 1];
brightness = std::min(brightness, static_cast<int16_t>(2000));
brightness -= 250;
brightness = std::max(brightness, static_cast<int16_t>(0));
brightness /= 7;
if (brightness != last_bri_)
{
bri = brightness;
applyFinalBri();
}
int16_t brightness = data.ch[ch_brightness_ - 1];
if (brightness < 0 || brightness > 2047) {
DEBUG_PRINTF("[SBUS] Invalid brightness value: %d\n", brightness);
return;
}
brightness = std::min(brightness, static_cast<int16_t>(2000));
brightness -= 250;
brightness = std::max(brightness, static_cast<int16_t>(0));
brightness /= 7;
if (brightness != last_bri_)
{
bri = brightness;
applyFinalBri();
}


uint8_t swicth_1 = getSwitchPosition(data.ch[ch_mode_select_1_ - 1]);
uint8_t swicth_2 = getSwitchPosition(data.ch[ch_mode_select_2_ - 1]);
uint8_t mode = swicth_1 + (swicth_2 * 3) + 1;
if (mode != last_mode_)
{
applyPreset(mode);
}

last_bri_ = brightness;
last_mode_ = mode;
}

last_ts_ms_ = ts_ms;
}

void addToConfig(JsonObject& root)
{
JsonObject top = root.createNestedObject(FPSTR(kConfigNode));
top[kConfigNodeBrightnessCh] = ch_brightness_;
top[kConfigNodeMode1Ch] = ch_mode_select_1_;
top[kConfigNodeMode2Ch] = ch_mode_select_2_;
top[kConfigNodeSbusPinRx] = sbus_pin_rx_;
top[kConfigNodeSbusPinTx] = sbus_pin_tx_;
top[kConfigNodeUpdatePeriod] = update_period_ms_;
}

bool readFromConfig(JsonObject& root)
{
JsonObject top = root[FPSTR(kConfigNode)];

bool configComplete = !top.isNull();

configComplete &= getJsonValue(top[kConfigNodeBrightnessCh], ch_brightness_, ch_brightness_);
configComplete &= getJsonValue(top[kConfigNodeMode1Ch], ch_mode_select_1_, ch_mode_select_1_);
configComplete &= getJsonValue(top[kConfigNodeMode2Ch], ch_mode_select_2_, ch_mode_select_2_);
configComplete &= getJsonValue(top[kConfigNodeSbusPinRx], sbus_pin_rx_, sbus_pin_rx_);
configComplete &= getJsonValue(top[kConfigNodeSbusPinTx], sbus_pin_tx_, sbus_pin_tx_);
configComplete &= getJsonValue(top[kConfigNodeUpdatePeriod], update_period_ms_, update_period_ms_);
return configComplete;
}

uint16_t getId()
{
return USERMOD_ID_SBUS_CONTROL;
}

private:
static constexpr auto* kConfigNode PROGMEM = "sbusControl";
static constexpr auto* kConfigNodeBrightnessCh PROGMEM = "brightnessChannel";
static constexpr auto* kConfigNodeMode1Ch PROGMEM = "ModeSelect1Channel";
static constexpr auto* kConfigNodeMode2Ch PROGMEM = "ModeSelect2Channel";
static constexpr auto* kConfigNodeSbusPinRx PROGMEM = "SbusPinRx";
static constexpr auto* kConfigNodeSbusPinTx PROGMEM = "SbusPinTx";
static constexpr auto* kConfigNodeUpdatePeriod PROGMEM = "UpdatePrtiodMs";
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix typo in configuration key.

There's a typo in the configuration key for update period.

Apply this diff:

-        static constexpr auto* kConfigNodeUpdatePeriod PROGMEM = "UpdatePrtiodMs";
+        static constexpr auto* kConfigNodeUpdatePeriod PROGMEM = "UpdatePeriodMs";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static constexpr auto* kConfigNodeUpdatePeriod PROGMEM = "UpdatePrtiodMs";
static constexpr auto* kConfigNodeUpdatePeriod PROGMEM = "UpdatePeriodMs";


uint32_t update_period_ms_ = 1000;

int8_t sbus_pin_rx_ = 16;
int8_t sbus_pin_tx_ = 17;
uint8_t ch_mode_select_1_ = 10;
uint8_t ch_mode_select_2_ = 11;
uint8_t ch_brightness_ = 12;

uint32_t last_ts_ms_ = 0;
uint8_t last_mode_ = 1;
uint8_t last_bri_ = 1;
bool is_enabled_ = false;

bfs::SbusRx sbus_rx_ = {&Serial1, static_cast<int8_t>(sbus_pin_rx_), static_cast<int8_t>(sbus_pin_tx_), true};

uint8_t getSwitchPosition(int16_t ch_value)
{
// Decoding a switch position from ch_values
if (ch_value < 666) return 0;
if (ch_value < 1333) return 1;
return 2;
}
};
1 change: 1 addition & 0 deletions wled00/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
#define USERMOD_ID_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h"
#define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h"
#define USERMOD_ID_BRIGHTNESS_FOLLOW_SUN 57 //Usermod "usermod_v2_brightness_follow_sun.h"
#define USERMOD_ID_SBUS_CONTROL 58 //Usermod "usermod_sbus_control.h"

//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
Expand Down
3 changes: 2 additions & 1 deletion wled00/pin_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ enum struct PinOwner : uint8_t {
UM_LDR_DUSK_DAWN = USERMOD_ID_LDR_DUSK_DAWN, // 0x2B // Usermod "usermod_LDR_Dusk_Dawn_v2.h"
UM_MAX17048 = USERMOD_ID_MAX17048, // 0x2F // Usermod "usermod_max17048.h"
UM_BME68X = USERMOD_ID_BME68X, // 0x31 // Usermod "usermod_bme68x.h -- Uses "standard" HW_I2C pins
UM_PIXELS_DICE_TRAY = USERMOD_ID_PIXELS_DICE_TRAY // 0x35 // Usermod "pixels_dice_tray.h" -- Needs compile time specified 6 pins for display including SPI.
UM_PIXELS_DICE_TRAY = USERMOD_ID_PIXELS_DICE_TRAY, // 0x35 // Usermod "pixels_dice_tray.h" -- Needs compile time specified 6 pins for display including SPI.
UM_SBUS_CONTROL = USERMOD_ID_SBUS_CONTROL // 0x3A // Usermod "usermod_sbus_control.h"
};
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");

Expand Down
10 changes: 9 additions & 1 deletion wled00/usermods_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@
#endif

#ifdef USERMOD_BRIGHTNESS_FOLLOW_SUN
#include "../usermods/usermod_v2_brightness_follow_sun/usermod_v2_brightness_follow_sun.h"
#include "../usermods/usermod_v2_brightness_follow_sun/usermod_v2_brightness_follow_sun.h"
Copy link
Collaborator

Choose a reason for hiding this comment

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

please revert unnecessary change

#endif

#ifdef USERMOD_SBUS_CONTROL
#include "../usermods/sbus_control/usermod_sbus_control.h"
#endif

void registerUsermods()
Expand Down Expand Up @@ -494,4 +498,8 @@ void registerUsermods()
#ifdef USERMOD_BRIGHTNESS_FOLLOW_SUN
UsermodManager::add(new UsermodBrightnessFollowSun());
#endif

#ifdef USERMOD_SBUS_CONTROL
UsermodManager::add(new SbusControl());
#endif
}