Compare commits

...
4 changed files with 165 additions and 26 deletions

No files matched your search

@@ -1,21 +0,0 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_BQ25186_PG_GPO
#include "bq25186.h"
#include "esphome/components/switch/switch.h"
namespace esphome::bq25186 {
class BQ25186PgGpoSwitch final : public switch_::Switch, public Parented<BQ25186Component> {
protected:
void write_state(bool state) override {
if (this->parent_->write_pg_gpo_level(state))
this->publish_state(state);
}
};
} // namespace esphome::bq25186
#endif // USE_BQ25186_PG_GPO
+8 -5
View File
@@ -3,18 +3,16 @@ from esphome.components import switch
import esphome.config_validation as cv
from esphome.types import ConfigType
from . import BQ25186_CHILD_SCHEMA, CONF_BQ25186_ID, bq25186_ns
from . import BQ25186_CHILD_SCHEMA, CONF_BQ25186_ID
DEPENDENCIES = ["bq25186"]
CONF_PG_GPO = "pg_gpo"
BQ25186PgGpoSwitch = bq25186_ns.class_("BQ25186PgGpoSwitch", switch.Switch)
CONFIG_SCHEMA = BQ25186_CHILD_SCHEMA.extend(
{
cv.Required(CONF_PG_GPO): switch.switch_schema(
BQ25186PgGpoSwitch, default_restore_mode="DISABLED"
switch.ApplySwitch, default_restore_mode="DISABLED"
),
}
)
@@ -24,4 +22,9 @@ async def to_code(config: ConfigType) -> None:
cg.add_define("USE_BQ25186_PG_GPO")
hub = await cg.get_variable(config[CONF_BQ25186_ID])
switches = switch.sub_switches(config, parent=hub)
await switches(CONF_PG_GPO, hub.set_pg_gpo_switch)
await switches(
CONF_PG_GPO,
hub.set_pg_gpo_switch,
apply="write_pg_gpo_level(state)",
publish="on_success",
)
+14
View File
@@ -0,0 +1,14 @@
import esphome.codegen as cg
from esphome.types import ConfigType
from tests.testing_helpers import ComponentManifestOverride
def override_manifest(manifest: ComponentManifestOverride) -> None:
# One empty config entry so to_code runs and compiles the PG/GPO switch path.
manifest.multi_conf = False
manifest.dependencies = manifest.dependencies + ["i2c", "switch"]
async def to_code(config: ConfigType) -> None:
cg.add_define("USE_BQ25186_PG_GPO")
manifest.to_code = to_code
@@ -0,0 +1,143 @@
#include <gtest/gtest.h>
#include <array>
#include "esphome/components/bq25186/bq25186.h"
#include "esphome/components/switch/switch.h"
namespace esphome::bq25186::testing {
static constexpr uint8_t ADDRESS = 0x6A;
static constexpr uint8_t SYS_REG_OTHER_BITS = 0x0F;
// The chip's registers behind an address pointer that moves on after every byte; writes can be made to fail.
class RegisterBus final : public i2c::I2CBus {
public:
i2c::ErrorCode write_readv(uint8_t address, const uint8_t *data, size_t size, uint8_t *out,
size_t out_size) override {
EXPECT_EQ(address, ADDRESS);
if (size > 1 && this->fail_writes)
return i2c::ERROR_NOT_ACKNOWLEDGED;
if (size != 0) {
this->pointer_ = data[0];
for (size_t i = 1; i < size; i++)
this->registers[this->next_()] = data[i];
}
for (size_t i = 0; i < out_size; i++)
out[i] = this->registers[this->next_()];
return i2c::ERROR_OK;
}
std::array<uint8_t, BQ25186_STATUS_REGISTER_COUNT> registers{};
bool fail_writes{false};
protected:
size_t next_() { return this->pointer_++ % this->registers.size(); }
uint8_t pointer_{0};
};
// The body code generation emits for apply= with publish="on_success"
static BQ25186Component *hub_under_test = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static void apply_pg_gpo(switch_::Switch *entity, bool state) {
if (hub_under_test->write_pg_gpo_level(state))
entity->publish_state(state);
}
class BQ25186PgGpoTest : public ::testing::Test {
protected:
void SetUp() override {
this->bus_.registers[BQ25186_REG_MASK_ID] = 0x01; // the BQ25186 device id
this->bus_.registers[BQ25186_REG_SYS_REG] = SYS_REG_OTHER_BITS;
this->hub_.set_i2c_bus(&this->bus_);
this->hub_.set_i2c_address(ADDRESS);
hub_under_test = &this->hub_;
this->switch_.set_restore_mode(switch_::SWITCH_RESTORE_DISABLED);
this->hub_.set_pg_gpo_switch(&this->switch_);
}
bool level_() const { return (this->bus_.registers[BQ25186_REG_SYS_REG] & BQ25186_SYS_REG_PG_GPO_LEVEL) != 0; }
uint8_t other_bits_() const { return this->bus_.registers[BQ25186_REG_SYS_REG] & ~BQ25186_SYS_REG_PG_GPO_LEVEL; }
RegisterBus bus_;
BQ25186Component hub_;
switch_::ApplySwitch<apply_pg_gpo> switch_;
};
TEST_F(BQ25186PgGpoTest, TurnOnSetsTheLevelAndPublishes) {
this->switch_.turn_on();
EXPECT_TRUE(this->level_());
EXPECT_EQ(this->other_bits_(), SYS_REG_OTHER_BITS);
EXPECT_TRUE(this->switch_.has_state());
EXPECT_TRUE(this->switch_.state);
}
TEST_F(BQ25186PgGpoTest, TurnOffClearsTheLevelAndPublishes) {
this->bus_.registers[BQ25186_REG_SYS_REG] |= BQ25186_SYS_REG_PG_GPO_LEVEL;
this->switch_.publish_state(true);
this->switch_.turn_off();
EXPECT_FALSE(this->level_());
EXPECT_EQ(this->other_bits_(), SYS_REG_OTHER_BITS);
EXPECT_FALSE(this->switch_.state);
}
TEST_F(BQ25186PgGpoTest, FailedWriteLeavesTheStateUnpublished) {
this->bus_.fail_writes = true;
this->switch_.turn_on();
EXPECT_FALSE(this->level_());
EXPECT_FALSE(this->switch_.has_state());
}
TEST_F(BQ25186PgGpoTest, FailedWriteKeepsThePreviousState) {
// Start from on, so a reset to the default off state would show
this->bus_.registers[BQ25186_REG_SYS_REG] |= BQ25186_SYS_REG_PG_GPO_LEVEL;
this->switch_.publish_state(true);
this->bus_.fail_writes = true;
this->switch_.turn_off();
EXPECT_TRUE(this->level_());
EXPECT_TRUE(this->switch_.state);
}
TEST_F(BQ25186PgGpoTest, InvertedSwitchDrivesTheOppositeLevel) {
this->switch_.set_inverted(true);
this->switch_.turn_on();
EXPECT_FALSE(this->level_());
EXPECT_TRUE(this->switch_.state);
this->switch_.turn_off();
EXPECT_TRUE(this->level_());
EXPECT_FALSE(this->switch_.state);
}
TEST_F(BQ25186PgGpoTest, SetupWritesTheRestoredLevel) {
this->switch_.set_restore_mode(switch_::SWITCH_ALWAYS_ON);
this->hub_.setup();
EXPECT_TRUE(this->level_());
EXPECT_NE(this->bus_.registers[BQ25186_REG_VBAT_CTRL] & BQ25186_VBAT_CTRL_PG_MODE, 0);
EXPECT_TRUE(this->switch_.state);
}
TEST_F(BQ25186PgGpoTest, SetupWritesTheRestoredLevelInverted) {
this->bus_.registers[BQ25186_REG_SYS_REG] |= BQ25186_SYS_REG_PG_GPO_LEVEL;
this->switch_.set_restore_mode(switch_::SWITCH_ALWAYS_ON);
this->switch_.set_inverted(true);
this->hub_.setup();
EXPECT_FALSE(this->level_());
EXPECT_TRUE(this->switch_.state);
}
TEST_F(BQ25186PgGpoTest, SetupWithoutRestoreTakesTheChipLevel) {
this->bus_.registers[BQ25186_REG_SYS_REG] |= BQ25186_SYS_REG_PG_GPO_LEVEL;
this->hub_.setup();
EXPECT_TRUE(this->level_());
EXPECT_TRUE(this->switch_.state);
}
TEST_F(BQ25186PgGpoTest, SetupWithoutRestoreTakesTheChipLevelInverted) {
this->bus_.registers[BQ25186_REG_SYS_REG] |= BQ25186_SYS_REG_PG_GPO_LEVEL;
this->switch_.set_inverted(true);
this->hub_.setup();
EXPECT_TRUE(this->level_());
EXPECT_FALSE(this->switch_.state);
}
} // namespace esphome::bq25186::testing