Browse Source

Working version of the new light transformer.

pull/50/head
Maurice Makaay 3 years ago
parent
commit
ec82c14cb7
11 changed files with 119 additions and 273 deletions
  1. +2
    -21
      components/xiaomi_bslamp2/light/color_handler.h
  2. +11
    -11
      components/xiaomi_bslamp2/light/color_handler_chain.h
  3. +4
    -4
      components/xiaomi_bslamp2/light/color_handler_color_temperature.h
  4. +8
    -4
      components/xiaomi_bslamp2/light/color_handler_night_light.h
  5. +3
    -3
      components/xiaomi_bslamp2/light/color_handler_off.h
  6. +3
    -3
      components/xiaomi_bslamp2/light/color_handler_rgb.h
  7. +0
    -136
      components/xiaomi_bslamp2/light/color_transition_handler.h.bak
  8. +0
    -15
      components/xiaomi_bslamp2/light/light_modes.h
  9. +7
    -18
      components/xiaomi_bslamp2/light/light_output.h
  10. +19
    -37
      components/xiaomi_bslamp2/light/light_transformer.h
  11. +62
    -21
      components/xiaomi_bslamp2/light_hal.h

components/xiaomi_bslamp2/light/gpio_outputs.h → components/xiaomi_bslamp2/light/color_handler.h View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "light_modes.h"
#include "../light_hal.h"
namespace esphome { namespace esphome {
namespace xiaomi { namespace xiaomi {
@ -11,14 +11,8 @@ namespace bslamp2 {
* LightColorValues into the required GPIO PWM duty cycle levels to represent * LightColorValues into the required GPIO PWM duty cycle levels to represent
* the requested color on the physical device. * the requested color on the physical device.
*/ */
class GPIOOutputs {
class ColorHandler : public GPIOOutputValues {
public: public:
float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
float white = 0.0f;
std::string light_mode = LIGHT_MODE_OFF;
/** /**
* Sets the red, green, blue, white fields to the PWM duty cycles * Sets the red, green, blue, white fields to the PWM duty cycles
* that are required to represent the requested light color for * that are required to represent the requested light color for
@ -27,19 +21,6 @@ class GPIOOutputs {
* Returns true when the input can be handled, false otherwise. * Returns true when the input can be handled, false otherwise.
*/ */
virtual bool set_light_color_values(light::LightColorValues v) = 0; virtual bool set_light_color_values(light::LightColorValues v) = 0;
/**
* Copies the current output values to another GPIOOutputs object.
*/
void copy_to(GPIOOutputs *other) {
other->red = red;
other->green = green;
other->blue = blue;
other->white = white;
other->light_mode = light_mode;
}
void log(const char *prefix) { ESP_LOGD(TAG, "%s: RGB=[%f,%f,%f], white=%f", prefix, red, green, blue, white); }
}; };
} // namespace bslamp2 } // namespace bslamp2

components/xiaomi_bslamp2/light/color_instant_handler.h → components/xiaomi_bslamp2/light/color_handler_chain.h View File

@ -4,11 +4,11 @@
#include <stdexcept> #include <stdexcept>
#include "../common.h" #include "../common.h"
#include "color_night_light.h"
#include "color_off.h"
#include "color_rgb_light.h"
#include "color_white_light.h"
#include "gpio_outputs.h"
#include "color_handler.h"
#include "color_handler_off.h"
#include "color_handler_rgb.h"
#include "color_handler_color_temperature.h"
#include "color_handler_night_light.h"
namespace esphome { namespace esphome {
namespace xiaomi { namespace xiaomi {
@ -26,7 +26,7 @@ namespace bslamp2 {
* - white light: based on color temperature + brightness * - white light: based on color temperature + brightness
* - RGB light: based on RGB values + brightness * - RGB light: based on RGB values + brightness
*/ */
class ColorInstantHandler : public GPIOOutputs {
class ColorHandlerChain : public ColorHandler {
public: public:
bool set_light_color_values(light::LightColorValues v) { bool set_light_color_values(light::LightColorValues v) {
// The actual implementation of the various light modes is in // The actual implementation of the various light modes is in
@ -42,7 +42,7 @@ class ColorInstantHandler : public GPIOOutputs {
else if (rgb_light_->set_light_color_values(v)) else if (rgb_light_->set_light_color_values(v))
rgb_light_->copy_to(this); rgb_light_->copy_to(this);
else { else {
ESP_LOGE(TAG, "Light color error: (None of the GPIOOutputs classes handles the requested light state; defaulting to 'off'");
ESP_LOGE(TAG, "Light color error: (None of the ColorHandler classes handles the requested light state; defaulting to 'off'");
off_light_->copy_to(this); off_light_->copy_to(this);
} }
@ -50,10 +50,10 @@ class ColorInstantHandler : public GPIOOutputs {
} }
protected: protected:
GPIOOutputs *off_light_ = new ColorOff();
GPIOOutputs *rgb_light_ = new ColorRGBLight();
GPIOOutputs *white_light_ = new ColorWhiteLight();
GPIOOutputs *night_light_ = new ColorNightLight();
ColorHandler *off_light_ = new ColorHandlerOff();
ColorHandler *rgb_light_ = new ColorHandlerRGB();
ColorHandler *white_light_ = new ColorHandlerColorTemperature();
ColorHandler *night_light_ = new ColorHandlerNightLight();
}; };
} // namespace bslamp2 } // namespace bslamp2

components/xiaomi_bslamp2/light/color_white_light.h → components/xiaomi_bslamp2/light/color_handler_color_temperature.h View File

@ -4,8 +4,8 @@
#include <stdexcept> #include <stdexcept>
#include "../common.h" #include "../common.h"
#include "light_modes.h"
#include "gpio_outputs.h"
#include "../light_hal.h"
#include "color_handler.h"
namespace esphome { namespace esphome {
namespace xiaomi { namespace xiaomi {
@ -75,7 +75,7 @@ static const RGBWLevelsTable rgbw_levels_100_ {{
* This class can handle the GPIO outputs for the white light mode, * This class can handle the GPIO outputs for the white light mode,
* based on color temperature + brightness. * based on color temperature + brightness.
*/ */
class ColorWhiteLight : public GPIOOutputs {
class ColorHandlerColorTemperature : public ColorHandler {
public: public:
bool set_light_color_values(light::LightColorValues v) { bool set_light_color_values(light::LightColorValues v) {
light_mode = LIGHT_MODE_WHITE; light_mode = LIGHT_MODE_WHITE;
@ -86,7 +86,7 @@ class ColorWhiteLight : public GPIOOutputs {
} }
#else #else
if (v.get_white() == 0.0f) { if (v.get_white() == 0.0f) {
return false;
return false
} }
#endif #endif

components/xiaomi_bslamp2/light/color_night_light.h → components/xiaomi_bslamp2/light/color_handler_night_light.h View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "../common.h" #include "../common.h"
#include "gpio_outputs.h"
#include "light_modes.h"
#include "../light_hal.h"
#include "color_handler.h"
namespace esphome { namespace esphome {
namespace xiaomi { namespace xiaomi {
@ -22,7 +22,7 @@ namespace bslamp2 {
* light mode toggle, then this still could be implemented through the * light mode toggle, then this still could be implemented through the
* device's yaml configuration. * device's yaml configuration.
*/ */
class ColorNightLight : public GPIOOutputs {
class ColorHandlerNightLight : public ColorHandler {
public: public:
bool set_light_color_values(light::LightColorValues v) { bool set_light_color_values(light::LightColorValues v) {
light_mode = LIGHT_MODE_NIGHT; light_mode = LIGHT_MODE_NIGHT;
@ -36,7 +36,11 @@ class ColorNightLight : public GPIOOutputs {
// This night light mode is activated when white light is selected. // This night light mode is activated when white light is selected.
// Based on measurements using the original device firmware, so it // Based on measurements using the original device firmware, so it
// matches the night light of the original firmware. // matches the night light of the original firmware.
if (v.get_white() > 0) {
#ifdef HAS_COLOR_MODES
if (v.get_color_mode() == light::ColorMode::COLOR_TEMPERATURE) {
#else
if (v.get_white() > 0.0f) {
#endif
red = 0.968f; red = 0.968f;
green = 0.968f; green = 0.968f;
blue = 0.972f; blue = 0.972f;

components/xiaomi_bslamp2/light/color_off.h → components/xiaomi_bslamp2/light/color_handler_off.h View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "../common.h" #include "../common.h"
#include "gpio_outputs.h"
#include "light_modes.h"
#include "../light_hal.h"
#include "color_handler.h"
namespace esphome { namespace esphome {
namespace xiaomi { namespace xiaomi {
@ -11,7 +11,7 @@ namespace bslamp2 {
/** /**
* This class can handle the GPIO outputs in case the light of turned off. * This class can handle the GPIO outputs in case the light of turned off.
*/ */
class ColorOff : public GPIOOutputs {
class ColorHandlerOff : public ColorHandler {
public: public:
bool set_light_color_values(light::LightColorValues v) { bool set_light_color_values(light::LightColorValues v) {
light_mode = LIGHT_MODE_OFF; light_mode = LIGHT_MODE_OFF;

components/xiaomi_bslamp2/light/color_rgb_light.h → components/xiaomi_bslamp2/light/color_handler_rgb.h View File

@ -4,8 +4,8 @@
#include <cmath> #include <cmath>
#include "../common.h" #include "../common.h"
#include "gpio_outputs.h"
#include "light_modes.h"
#include "../light_hal.h"
#include "color_handler.h"
namespace esphome { namespace esphome {
namespace xiaomi { namespace xiaomi {
@ -247,7 +247,7 @@ static const RGBCircle rgb_circle_ {{
* This class can handle the GPIO outputs for the RGB light mode, * This class can handle the GPIO outputs for the RGB light mode,
* based on RGB color values + brightness. * based on RGB color values + brightness.
*/ */
class ColorRGBLight : public GPIOOutputs {
class ColorHandlerRGB : public ColorHandler {
public: public:
bool set_light_color_values(light::LightColorValues v) { bool set_light_color_values(light::LightColorValues v) {
light_mode = LIGHT_MODE_RGB; light_mode = LIGHT_MODE_RGB;

+ 0
- 136
components/xiaomi_bslamp2/light/color_transition_handler.h.bak View File

@ -1,136 +0,0 @@
#pragma once
#include "../common.h"
#include "color_instant_handler.h"
#include "interfaces.h"
#include "gpio_outputs.h"
namespace esphome {
namespace xiaomi {
namespace bslamp2 {
/**
* This class is used to handle specific light color transition requirements
* for the device.
*
* When using the default ESPHome logic, transitioning is done by
* transitioning all light properties linearly from the original values to
* the new values, and letting the light output object translate these
* properties into light outputs on every step of the way. While this does
* work, it does not work nicely.
*
* For example, when transitioning from warm to cold white light, the color
* temperature would be transitioned from the old value to the new value.
* While doing so, the transition hits the middle white light setting, which
* shows up as a bright flash in the middle of the transition. The original
* firmware however, shows a smooth transition from warm to cold white
* light, without any flash.
*
* This class handles transitions by not varying the light properties over
* time, but by transitioning the LEDC duty cycle output levels over time.
* This matches the behavior of the original firmware.
*/
class ColorTransitionHandler : public GPIOOutputs {
public:
ColorTransitionHandler(LightStateTransformerInspector *inspector) : transformer_(inspector) {}
light::LightColorValues get_end_values() { return end_light_values_; }
bool set_light_color_values(light::LightColorValues values) {
if (!light_state_has_active_transition_()) {
// Remember the last active light color values. When a transition
// is detected, we'll use these as the starting point. It is not
// possible to use the current values at that point, because the
// transition is already in progress by the time the transition
// is detected.
start_light_values_ = values;
active_ = false;
return false;
}
// When a fresh transition is started, then compute the GPIO outputs
// to use for both the start and end point. This transition handler
// will then transition linearly between these two.
if (is_fresh_transition_()) {
start_->set_light_color_values(start_light_values_);
end_light_values_ = transformer_->get_end_values();
end_->set_light_color_values(end_light_values_);
active_ = true;
}
// When a transition is modified, then use the current GPIO outputs
// as the new starting point.
else if (is_modified_transition_()) {
this->copy_to(start_);
end_light_values_ = transformer_->get_end_values();
end_->set_light_color_values(end_light_values_);
}
light_mode = end_->light_mode;
progress_ = transformer_->get_progress();
// Determine required GPIO outputs for current transition progress.
// In night light mode, do not use actual transitions. Transitioning
// between colors at the very low LED output levels of the night light,
// results in light drops, which are plain ugly to watch.
if (light_mode == "night") {
red = end_->red;
green = end_->green;
blue = end_->blue;
white = end_->white;
}
// In other light modes, apply smooth transitioning.
else {
auto smoothed = light::LightTransitionTransformer::smoothed_progress(progress_);
red = esphome::lerp(smoothed, start_->red, end_->red);
green = esphome::lerp(smoothed, start_->green, end_->green);
blue = esphome::lerp(smoothed, start_->blue, end_->blue);
white = esphome::lerp(smoothed, start_->white, end_->white);
}
return true;
}
protected:
bool active_ = false;
float progress_ = 0.0f;
LightStateTransformerInspector *transformer_;
light::LightColorValues start_light_values_;
light::LightColorValues end_light_values_;
GPIOOutputs *start_ = new ColorInstantHandler();
GPIOOutputs *end_ = new ColorInstantHandler();
/**
* Checks if the LightState currently has an active LightTransformer.
*/
bool light_state_has_active_transition_() {
if (!transformer_->is_active())
return false;
if (!transformer_->is_transition())
return false;
return true;
}
/**
* Checks if a fresh transitioning is started.
* A transitioning is fresh when no existing transition is active.
*/
bool is_fresh_transition_() { return active_ == false; }
/**
* Checks if a new end state is set, while an existing transition
* is active. This might be detected in two ways:
* - the end color has been updated
* - the progress has been reverted
*/
bool is_modified_transition_() {
auto new_end_light_values = transformer_->get_end_values();
auto new_progress = transformer_->get_progress();
return (new_end_light_values != end_light_values_ || new_progress < progress_);
}
};
} // namespace bslamp2
} // namespace xiaomi
} // namespace esphome

+ 0
- 15
components/xiaomi_bslamp2/light/light_modes.h View File

@ -1,15 +0,0 @@
#pragma once
namespace esphome {
namespace xiaomi {
namespace bslamp2 {
static const std::string LIGHT_MODE_UNKNOWN{"unknown"};
static const std::string LIGHT_MODE_OFF{"off"};
static const std::string LIGHT_MODE_RGB{"rgb"};
static const std::string LIGHT_MODE_WHITE{"white"};
static const std::string LIGHT_MODE_NIGHT{"night"};
} // namespace bslamp2
} // namespace xiaomi
} // namespace esphome

+ 7
- 18
components/xiaomi_bslamp2/light/light_output.h View File

@ -2,8 +2,9 @@
#include "../common.h" #include "../common.h"
#include "../light_hal.h" #include "../light_hal.h"
#include "color_instant_handler.h"
#include "color_handler_chain.h"
#include "light_transformer.h" #include "light_transformer.h"
#include "esphome/core/component.h"
#include "esphome/components/ledc/ledc_output.h" #include "esphome/components/ledc/ledc_output.h"
namespace esphome { namespace esphome {
@ -60,21 +61,9 @@ class XiaomiBslamp2LightOutput : public Component, public light::LightOutput {
void write_state(light::LightState *state) { void write_state(light::LightState *state) {
auto values = state->current_values; auto values = state->current_values;
// The color must either be set instantly, or the color is
// transitioning to an end color. The transition handler will do its
// own inspection to see if a transition is currently active or not.
// Based on the outcome, use either the instant or transition handler.
//GPIOOutputs *delegate;
//if (transition_handler_->set_light_color_values(values)) {
// delegate = transition_handler_;
// light_mode_callback_.call(delegate->light_mode);
// state_callback_.call(transition_handler_->get_end_values());
//} else {
instant_handler_->set_light_color_values(values);
//delegate = instant_handler_;
light_mode_callback_.call(instant_handler_->light_mode);
color_handler_chain->set_light_color_values(values);
light_mode_callback_.call(color_handler_chain->light_mode);
state_callback_.call(values); state_callback_.call(values);
//}
// Note: one might think that it is more logical to turn on the LED // Note: one might think that it is more logical to turn on the LED
// circuitry master switch after setting the individual channels, // circuitry master switch after setting the individual channels,
@ -86,8 +75,8 @@ class XiaomiBslamp2LightOutput : public Component, public light::LightOutput {
// Apply the current GPIO output levels from the selected handler. // Apply the current GPIO output levels from the selected handler.
light_->set_rgbw( light_->set_rgbw(
instant_handler_->red, instant_handler_->green, instant_handler_->blue,
instant_handler_->white);
color_handler_chain->red, color_handler_chain->green, color_handler_chain->blue,
color_handler_chain->white);
if (values.get_state() == 0) if (values.get_state() == 0)
light_->turn_off(); light_->turn_off();
@ -95,7 +84,7 @@ class XiaomiBslamp2LightOutput : public Component, public light::LightOutput {
protected: protected:
LightHAL *light_; LightHAL *light_;
ColorInstantHandler *instant_handler_ = new ColorInstantHandler();
ColorHandler *color_handler_chain = new ColorHandlerChain();
CallbackManager<void(std::string)> light_mode_callback_{}; CallbackManager<void(std::string)> light_mode_callback_{};
CallbackManager<void(light::LightColorValues)> state_callback_{}; CallbackManager<void(light::LightColorValues)> state_callback_{};
}; };


+ 19
- 37
components/xiaomi_bslamp2/light/light_transformer.h View File

@ -2,8 +2,7 @@
#include "../common.h" #include "../common.h"
#include "../light_hal.h" #include "../light_hal.h"
#include "color_instant_handler.h"
#include "gpio_outputs.h"
#include "color_handler_chain.h"
#include "esphome/components/light/light_transformer.h" #include "esphome/components/light/light_transformer.h"
#include "esphome/components/light/light_color_values.h" #include "esphome/components/light/light_color_values.h"
@ -18,50 +17,33 @@ class XiaomiBslamp2LightTransitionTransformer : public light::LightTransitionTra
public: public:
explicit XiaomiBslamp2LightTransitionTransformer(LightHAL *light) : light_(light) { } explicit XiaomiBslamp2LightTransitionTransformer(LightHAL *light) : light_(light) { }
bool is_completed() override {
return is_completed_ || get_progress_() >= 1.0f;
bool is_finished() override {
return force_finish_ || get_progress_() >= 1.0f;
} }
void start() override { void start() override {
// When a fresh transition is started, then compute the GPIO outputs
// to use for both the start and end point. This light transition transformer
// will then transition linearly between these two.
start_->set_light_color_values(start_values_);
target_->set_light_color_values(target_values_);
// When a transition is modified, then use the current GPIO outputs
// as the new starting point.
// ... TODO
//
ESP_LOGE("DEBUG", "Start this thing"); // TODO
}
void finish() override {
ESP_LOGE("DEBUG", "Finish this thing"); // TODO
}
void abort() override {
ESP_LOGE("DEBUG", "Abort this thing"); // TODO
// Compute the GPIO outputs to use for the end point.
// This light transition transformer will then transition linearly between
// the current GPIO outputs and the target ones.
light_->copy_to(start_);
end_->set_light_color_values(target_values_);
} }
optional<light::LightColorValues> apply() override { optional<light::LightColorValues> apply() override {
if (target_->light_mode == "night") {
ESP_LOGE("DEBUG", "Set night light directly"); // DEBUG
light_->set_rgbw(target_->red, target_->green, target_->blue, target_->white);
is_completed_ = true;
if (end_->light_mode == "night") {
light_->set_state(end_);
force_finish_ = true;
} }
else { else {
auto smoothed = light::LightTransitionTransformer::smoothed_progress(get_progress_()); auto smoothed = light::LightTransitionTransformer::smoothed_progress(get_progress_());
light_->set_rgbw( light_->set_rgbw(
esphome::lerp(smoothed, start_->red, target_->red),
esphome::lerp(smoothed, start_->green, target_->green),
esphome::lerp(smoothed, start_->blue, target_->blue),
esphome::lerp(smoothed, start_->white, target_->white));
esphome::lerp(smoothed, start_->red, end_->red),
esphome::lerp(smoothed, start_->green, end_->green),
esphome::lerp(smoothed, start_->blue, end_->blue),
esphome::lerp(smoothed, start_->white, end_->white));
} }
if (is_completed()) {
ESP_LOGE("DEBUG", "We're done, publish target values"); // TODO
is_completed_ = true;
if (is_finished()) {
return target_values_; return target_values_;
} else { } else {
return {}; return {};
@ -70,9 +52,9 @@ class XiaomiBslamp2LightTransitionTransformer : public light::LightTransitionTra
protected: protected:
LightHAL *light_; LightHAL *light_;
bool is_completed_ = false;
GPIOOutputs *start_ = new ColorInstantHandler();
GPIOOutputs *target_ = new ColorInstantHandler();
bool force_finish_ = false;
GPIOOutputValues *start_ = new GPIOOutputValues();
ColorHandler *end_ = new ColorHandlerChain();
}; };
} // namespace bslamp2 } // namespace bslamp2


+ 62
- 21
components/xiaomi_bslamp2/light_hal.h View File

@ -8,39 +8,80 @@ namespace esphome {
namespace xiaomi { namespace xiaomi {
namespace bslamp2 { namespace bslamp2 {
class LightHAL : Component {
static const std::string LIGHT_MODE_UNKNOWN{"unknown"};
static const std::string LIGHT_MODE_OFF{"off"};
static const std::string LIGHT_MODE_RGB{"rgb"};
static const std::string LIGHT_MODE_WHITE{"white"};
static const std::string LIGHT_MODE_NIGHT{"night"};
class GPIOOutputValues {
public:
float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
float white = 0.0f;
std::string light_mode = LIGHT_MODE_OFF;
/**
* Copies the current output values to another GPIOOutputValues object.
*/
void copy_to(GPIOOutputValues *other) {
other->red = red;
other->green = green;
other->blue = blue;
other->white = white;
other->light_mode = light_mode;
}
void log(const char *prefix) { ESP_LOGD(TAG, "%s: RGB=[%f,%f,%f], white=%f", prefix, red, green, blue, white); }
};
class LightHAL : Component, public GPIOOutputValues {
public: public:
void set_red_pin(ledc::LEDCOutput *pin) { red_ = pin; }
void set_green_pin(ledc::LEDCOutput *pin) { green_ = pin; }
void set_blue_pin(ledc::LEDCOutput *pin) { blue_ = pin; }
void set_white_pin(ledc::LEDCOutput *pin) { white_ = pin; }
void set_master1_pin(gpio::GPIOBinaryOutput *pin) { master1_ = pin; }
void set_master2_pin(gpio::GPIOBinaryOutput *pin) { master2_ = pin; }
void set_red_pin(ledc::LEDCOutput *pin) { red_pin_ = pin; }
void set_green_pin(ledc::LEDCOutput *pin) { green_pin_ = pin; }
void set_blue_pin(ledc::LEDCOutput *pin) { blue_pin_ = pin; }
void set_white_pin(ledc::LEDCOutput *pin) { white_pin_ = pin; }
void set_master1_pin(gpio::GPIOBinaryOutput *pin) { master1_pin_ = pin; }
void set_master2_pin(gpio::GPIOBinaryOutput *pin) { master2_pin_ = pin; }
void turn_on() { void turn_on() {
master1_->turn_on();
master2_->turn_on();
master1_pin_->turn_on();
master2_pin_->turn_on();
} }
void turn_off() { void turn_off() {
master1_->turn_off();
master2_->turn_off();
master1_pin_->turn_off();
master2_pin_->turn_off();
}
void set_state(GPIOOutputValues *new_state) {
new_state->copy_to(this);
red_pin_->set_level(this->red);
green_pin_->set_level(this->green);
blue_pin_->set_level(this->blue);
white_pin_->set_level(this->white);
} }
void set_rgbw(float r, float g, float b, float w) { void set_rgbw(float r, float g, float b, float w) {
red_->set_level(r);
green_->set_level(g);
blue_->set_level(b);
white_->set_level(w);
red_pin_->set_level(r);
green_pin_->set_level(g);
blue_pin_->set_level(b);
white_pin_->set_level(w);
this->red = r;
this->green = g;
this->blue = b;
this->white = w;
} }
protected: protected:
ledc::LEDCOutput *red_;
ledc::LEDCOutput *green_;
ledc::LEDCOutput *blue_;
ledc::LEDCOutput *white_;
gpio::GPIOBinaryOutput *master1_;
gpio::GPIOBinaryOutput *master2_;
ledc::LEDCOutput *red_pin_;
ledc::LEDCOutput *green_pin_;
ledc::LEDCOutput *blue_pin_;
ledc::LEDCOutput *white_pin_;
gpio::GPIOBinaryOutput *master1_pin_;
gpio::GPIOBinaryOutput *master2_pin_;
}; };
} // namespace bslamp2 } // namespace bslamp2


Loading…
Cancel
Save