[hbridge] Fix light stuck on one polarity (#17162)

This commit is contained in:
Jonathan Swoboda
2026-06-25 12:36:10 -04:00
committed by GitHub
parent 6f36ce6429
commit e27390bddb
2 changed files with 21 additions and 15 deletions
+4 -2
View File
@@ -1,14 +1,14 @@
import esphome.codegen as cg
from esphome.components import light, output
import esphome.config_validation as cv
from esphome.const import CONF_OUTPUT_ID, CONF_PIN_A, CONF_PIN_B
from esphome.const import CONF_OUTPUT_ID, CONF_PIN_A, CONF_PIN_B, CONF_UPDATE_INTERVAL
from .. import hbridge_ns
CODEOWNERS = ["@DotNetDann"]
HBridgeLightOutput = hbridge_ns.class_(
"HBridgeLightOutput", cg.Component, light.LightOutput
"HBridgeLightOutput", cg.PollingComponent, light.LightOutput
)
CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend(
@@ -16,12 +16,14 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend(
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(HBridgeLightOutput),
cv.Required(CONF_PIN_A): cv.use_id(output.FloatOutput),
cv.Required(CONF_PIN_B): cv.use_id(output.FloatOutput),
cv.Optional(CONF_UPDATE_INTERVAL, default="8ms"): cv.update_interval,
}
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
cg.add(var.set_update_interval(config.pop(CONF_UPDATE_INTERVAL)))
await cg.register_component(var, config)
await light.register_light(var, config)
@@ -3,11 +3,10 @@
#include "esphome/components/light/light_output.h"
#include "esphome/components/output/float_output.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
namespace esphome::hbridge {
class HBridgeLightOutput final : public Component, public light::LightOutput {
class HBridgeLightOutput final : public PollingComponent, public light::LightOutput {
public:
void set_pina_pin(output::FloatOutput *pina_pin) { this->pina_pin_ = pina_pin; }
void set_pinb_pin(output::FloatOutput *pinb_pin) { this->pinb_pin_ = pinb_pin; }
@@ -20,11 +19,12 @@ class HBridgeLightOutput final : public Component, public light::LightOutput {
return traits;
}
void setup() override { this->disable_loop(); }
void setup() override { this->stop_poller(); }
void loop() override {
// Only called when both channels are active — alternate H-bridge direction
// each iteration to multiplex cold and warm white.
void update() override {
// Flip the H-bridge direction to multiplex cold/warm white. update_interval must stay
// slower than the output's PWM period (flipping faster collapses the output onto one
// channel) but fast enough to avoid flicker (issue #17030).
if (!this->forward_direction_) {
this->pina_pin_->set_level(this->pina_duty_);
this->pinb_pin_->set_level(0);
@@ -46,13 +46,17 @@ class HBridgeLightOutput final : public Component, public light::LightOutput {
this->pinb_duty_ = new_pinb;
if (new_pina != 0.0f && new_pinb != 0.0f) {
// Both channels active — need loop to alternate H-bridge direction
this->high_freq_.start();
this->enable_loop();
// Both channels active — multiplex the H-bridge direction via the poller.
if (!this->multiplexing_) {
this->multiplexing_ = true;
this->start_poller();
}
} else {
// Zero or one channel active — drive pins directly, no multiplexing needed
this->high_freq_.stop();
this->disable_loop();
// Zero or one channel active — drive pins directly, no multiplexing needed.
if (this->multiplexing_) {
this->multiplexing_ = false;
this->stop_poller();
}
this->pina_pin_->set_level(new_pina);
this->pinb_pin_->set_level(new_pinb);
}
@@ -64,7 +68,7 @@ class HBridgeLightOutput final : public Component, public light::LightOutput {
float pina_duty_{0};
float pinb_duty_{0};
bool forward_direction_{false};
HighFrequencyLoopRequester high_freq_;
bool multiplexing_{false};
};
} // namespace esphome::hbridge