From cbcf23426d8d64069d4da7f0e96a0065aa9750d6 Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Wed, 24 Jun 2026 10:08:59 +0000 Subject: [PATCH] [waveshare_io_ch32v003] Waveshare I/O Expander component (#10071) --- CODEOWNERS | 1 + .../waveshare_io_ch32v003/__init__.py | 84 +++++++++ .../waveshare_io_ch32v003/output/__init__.py | 70 ++++++++ .../output/waveshare_io_ch32v003_output.cpp | 19 ++ .../output/waveshare_io_ch32v003_output.h | 22 +++ .../waveshare_io_ch32v003/sensor/__init__.py | 55 ++++++ .../sensor/waveshare_io_ch32v003_sensor.cpp | 27 +++ .../sensor/waveshare_io_ch32v003_sensor.h | 29 +++ .../waveshare_io_ch32v003.cpp | 168 ++++++++++++++++++ .../waveshare_io_ch32v003.h | 65 +++++++ .../waveshare_io_ch32v003/common.yaml | 33 ++++ .../waveshare_io_ch32v003/test.esp32-idf.yaml | 4 + 12 files changed, 577 insertions(+) create mode 100644 esphome/components/waveshare_io_ch32v003/__init__.py create mode 100644 esphome/components/waveshare_io_ch32v003/output/__init__.py create mode 100644 esphome/components/waveshare_io_ch32v003/output/waveshare_io_ch32v003_output.cpp create mode 100644 esphome/components/waveshare_io_ch32v003/output/waveshare_io_ch32v003_output.h create mode 100644 esphome/components/waveshare_io_ch32v003/sensor/__init__.py create mode 100644 esphome/components/waveshare_io_ch32v003/sensor/waveshare_io_ch32v003_sensor.cpp create mode 100644 esphome/components/waveshare_io_ch32v003/sensor/waveshare_io_ch32v003_sensor.h create mode 100644 esphome/components/waveshare_io_ch32v003/waveshare_io_ch32v003.cpp create mode 100644 esphome/components/waveshare_io_ch32v003/waveshare_io_ch32v003.h create mode 100644 tests/components/waveshare_io_ch32v003/common.yaml create mode 100644 tests/components/waveshare_io_ch32v003/test.esp32-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index d425614582..70ad580e77 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -578,6 +578,7 @@ esphome/components/wake_on_lan/* @clydebarrow @willwill2will54 esphome/components/watchdog/* @oarcher esphome/components/water_heater/* @dhoeben esphome/components/waveshare_epaper/* @clydebarrow +esphome/components/waveshare_io_ch32v003/* @latonita esphome/components/web_server/ota/* @esphome/core esphome/components/web_server_base/* @esphome/core esphome/components/web_server_idf/* @dentra diff --git a/esphome/components/waveshare_io_ch32v003/__init__.py b/esphome/components/waveshare_io_ch32v003/__init__.py new file mode 100644 index 0000000000..b692b858a3 --- /dev/null +++ b/esphome/components/waveshare_io_ch32v003/__init__.py @@ -0,0 +1,84 @@ +from esphome import pins +import esphome.codegen as cg +from esphome.components import i2c +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_INPUT, + CONF_INVERTED, + CONF_MODE, + CONF_NUMBER, + CONF_OUTPUT, +) + +CODEOWNERS = ["@latonita"] + +AUTO_LOAD = ["gpio_expander"] +DEPENDENCIES = ["i2c"] +MULTI_CONF = True + +waveshare_io_ch32v003_ns = cg.esphome_ns.namespace("waveshare_io_ch32v003") + +WaveshareIOCH32V003Component = waveshare_io_ch32v003_ns.class_( + "WaveshareIOCH32V003Component", cg.Component, i2c.I2CDevice +) +WaveshareIOCH32V003GPIOPin = waveshare_io_ch32v003_ns.class_( + "WaveshareIOCH32V003GPIOPin", + cg.GPIOPin, + cg.Parented.template(WaveshareIOCH32V003Component), +) + +CONF_WAVESHARE_IO_CH32V003 = "waveshare_io_ch32v003" +CONF_WAVESHARE_IO_CH32V003_ID = "waveshare_io_ch32v003_id" +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(CONF_ID): cv.declare_id(WaveshareIOCH32V003Component), + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x24)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + +def validate_mode(value): + if not (value[CONF_INPUT] or value[CONF_OUTPUT]): + raise cv.Invalid("Mode must be either input or output") + if value[CONF_INPUT] and value[CONF_OUTPUT]: + raise cv.Invalid("Mode must be either input or output") + return value + + +WAVESHARE_IO_PIN_SCHEMA = pins.gpio_base_schema( + WaveshareIOCH32V003GPIOPin, + cv.int_range(min=0, max=7), + modes=[CONF_INPUT, CONF_OUTPUT], + mode_validator=validate_mode, + invertible=True, +).extend( + { + cv.Required(CONF_WAVESHARE_IO_CH32V003): cv.use_id( + WaveshareIOCH32V003Component + ), + } +) + + +@pins.PIN_SCHEMA_REGISTRY.register(CONF_WAVESHARE_IO_CH32V003, WAVESHARE_IO_PIN_SCHEMA) +async def waveshare_io_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + parent = await cg.get_variable(config[CONF_WAVESHARE_IO_CH32V003]) + + cg.add(var.set_parent(parent)) + + num = config[CONF_NUMBER] + cg.add(var.set_pin(num)) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/esphome/components/waveshare_io_ch32v003/output/__init__.py b/esphome/components/waveshare_io_ch32v003/output/__init__.py new file mode 100644 index 0000000000..9af9ce7e4b --- /dev/null +++ b/esphome/components/waveshare_io_ch32v003/output/__init__.py @@ -0,0 +1,70 @@ +import esphome.codegen as cg +from esphome.components import output +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_MAX_VALUE, CONF_MIN_VALUE + +from .. import ( + CONF_WAVESHARE_IO_CH32V003_ID, + WaveshareIOCH32V003Component, + waveshare_io_ch32v003_ns, +) + +DEPENDENCIES = ["waveshare_io_ch32v003"] + +WaveshareIOCH32V003Output = waveshare_io_ch32v003_ns.class_( + "WaveshareIOCH32V003Output", + output.FloatOutput, + cg.Parented.template(WaveshareIOCH32V003Component), +) + +CONF_SAFE_PWM_LEVELS = "safe_pwm_levels" + +DUTY_DEFAULT_MIN = 1 +DUTY_DEFAULT_MAX = 247 + + +def validate_pwm_limits(config): + """Validate that safe_pwm_levels.min_value <= safe_pwm_levels.max_value.""" + + min_val = config.get(CONF_SAFE_PWM_LEVELS, {}).get(CONF_MIN_VALUE, DUTY_DEFAULT_MIN) + max_val = config.get(CONF_SAFE_PWM_LEVELS, {}).get(CONF_MAX_VALUE, DUTY_DEFAULT_MAX) + if min_val > max_val: + raise cv.Invalid( + f"safe_pwm_levels.min_value ({min_val}) cannot be greater than " + f"safe_pwm_levels.max_value ({max_val})" + ) + return config + + +CONF_SAFE_PWM_LEVELS_SCHEMA = cv.Schema( + { + cv.Optional(CONF_MIN_VALUE, default=DUTY_DEFAULT_MIN): cv.int_range( + min=0, max=255 + ), + cv.Optional(CONF_MAX_VALUE, default=DUTY_DEFAULT_MAX): cv.int_range( + min=0, max=255 + ), + } +) + +CONFIG_SCHEMA = cv.All( + output.FLOAT_OUTPUT_SCHEMA.extend( + { + cv.Required(CONF_ID): cv.declare_id(WaveshareIOCH32V003Output), + cv.GenerateID(CONF_WAVESHARE_IO_CH32V003_ID): cv.use_id( + WaveshareIOCH32V003Component + ), + cv.Optional(CONF_SAFE_PWM_LEVELS): CONF_SAFE_PWM_LEVELS_SCHEMA, + } + ), + validate_pwm_limits, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await output.register_output(var, config) + await cg.register_parented(var, config[CONF_WAVESHARE_IO_CH32V003_ID]) + min_val = config.get(CONF_SAFE_PWM_LEVELS, {}).get(CONF_MIN_VALUE, DUTY_DEFAULT_MIN) + max_val = config.get(CONF_SAFE_PWM_LEVELS, {}).get(CONF_MAX_VALUE, DUTY_DEFAULT_MAX) + cg.add(var.set_pwm_safe_range(min_val, max_val)) diff --git a/esphome/components/waveshare_io_ch32v003/output/waveshare_io_ch32v003_output.cpp b/esphome/components/waveshare_io_ch32v003/output/waveshare_io_ch32v003_output.cpp new file mode 100644 index 0000000000..30458310ce --- /dev/null +++ b/esphome/components/waveshare_io_ch32v003/output/waveshare_io_ch32v003_output.cpp @@ -0,0 +1,19 @@ +#include "waveshare_io_ch32v003_output.h" +#include "esphome/core/log.h" +#include + +namespace esphome::waveshare_io_ch32v003 { + +static const char *const TAG = "waveshare_io_ch32v003.output"; + +void WaveshareIOCH32V003Output::write_state(float state) { + uint8_t pwm_value = static_cast(state * 255.0f); + uint8_t final_pwm_value = std::clamp(pwm_value, this->pwm_min_value_, this->pwm_max_value_); + if (final_pwm_value != pwm_value) { + ESP_LOGVV(TAG, "Clamping PWM value %u to safe range [%u, %u]", pwm_value, this->pwm_min_value_, + this->pwm_max_value_); + } + this->parent_->set_pwm_value(final_pwm_value); +} + +} // namespace esphome::waveshare_io_ch32v003 diff --git a/esphome/components/waveshare_io_ch32v003/output/waveshare_io_ch32v003_output.h b/esphome/components/waveshare_io_ch32v003/output/waveshare_io_ch32v003_output.h new file mode 100644 index 0000000000..abe8183692 --- /dev/null +++ b/esphome/components/waveshare_io_ch32v003/output/waveshare_io_ch32v003_output.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../waveshare_io_ch32v003.h" +#include "esphome/components/output/float_output.h" + +namespace esphome::waveshare_io_ch32v003 { + +class WaveshareIOCH32V003Output : public output::FloatOutput, public Parented { + public: + void set_pwm_safe_range(uint8_t min_value, uint8_t max_value) { + this->pwm_min_value_ = min_value; + this->pwm_max_value_ = max_value; + } + + protected: + void write_state(float state) override; + + uint8_t pwm_min_value_{1}; + uint8_t pwm_max_value_{247}; +}; + +} // namespace esphome::waveshare_io_ch32v003 diff --git a/esphome/components/waveshare_io_ch32v003/sensor/__init__.py b/esphome/components/waveshare_io_ch32v003/sensor/__init__.py new file mode 100644 index 0000000000..1e060bdfe4 --- /dev/null +++ b/esphome/components/waveshare_io_ch32v003/sensor/__init__.py @@ -0,0 +1,55 @@ +import esphome.codegen as cg +from esphome.components import sensor, voltage_sampler +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + CONF_REFERENCE_VOLTAGE, + DEVICE_CLASS_VOLTAGE, + STATE_CLASS_MEASUREMENT, + UNIT_VOLT, +) + +from .. import ( + CONF_WAVESHARE_IO_CH32V003_ID, + WaveshareIOCH32V003Component, + waveshare_io_ch32v003_ns, +) + +AUTO_LOAD = ["voltage_sampler"] +DEPENDENCIES = ["waveshare_io_ch32v003"] + +WaveshareIOCH32V003Sensor = waveshare_io_ch32v003_ns.class_( + "WaveshareIOCH32V003Sensor", + sensor.Sensor, + cg.PollingComponent, + voltage_sampler.VoltageSampler, + cg.Parented.template(WaveshareIOCH32V003Component), +) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + WaveshareIOCH32V003Sensor, + unit_of_measurement=UNIT_VOLT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend( + { + cv.GenerateID(CONF_WAVESHARE_IO_CH32V003_ID): cv.use_id( + WaveshareIOCH32V003Component + ), + cv.Optional(CONF_REFERENCE_VOLTAGE, default="9.9V"): cv.voltage, + } + ) + .extend(cv.polling_component_schema("60s")) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_parented(var, config[CONF_WAVESHARE_IO_CH32V003_ID]) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) + + cg.add(var.set_reference_voltage(config[CONF_REFERENCE_VOLTAGE])) diff --git a/esphome/components/waveshare_io_ch32v003/sensor/waveshare_io_ch32v003_sensor.cpp b/esphome/components/waveshare_io_ch32v003/sensor/waveshare_io_ch32v003_sensor.cpp new file mode 100644 index 0000000000..82da7451f9 --- /dev/null +++ b/esphome/components/waveshare_io_ch32v003/sensor/waveshare_io_ch32v003_sensor.cpp @@ -0,0 +1,27 @@ +#include "waveshare_io_ch32v003_sensor.h" + +#include "esphome/core/log.h" + +namespace esphome::waveshare_io_ch32v003 { + +static const char *const TAG = "waveshare_io_ch32v003.sensor"; + +float WaveshareIOCH32V003Sensor::get_setup_priority() const { return setup_priority::DATA; } + +void WaveshareIOCH32V003Sensor::dump_config() { + ESP_LOGCONFIG(TAG, + "WaveshareIOCH32V003Sensor:\n" + " Reference Voltage: %.2fV", + this->reference_voltage_); +} + +float WaveshareIOCH32V003Sensor::sample() { + uint16_t adc_value = this->parent_->get_adc_value(); + // Convert the ADC value to voltage. 10-bit ADC + float voltage = adc_value * this->reference_voltage_ / 1023.0f; + return voltage; +} + +void WaveshareIOCH32V003Sensor::update() { this->publish_state(this->sample()); } + +} // namespace esphome::waveshare_io_ch32v003 diff --git a/esphome/components/waveshare_io_ch32v003/sensor/waveshare_io_ch32v003_sensor.h b/esphome/components/waveshare_io_ch32v003/sensor/waveshare_io_ch32v003_sensor.h new file mode 100644 index 0000000000..01beab5137 --- /dev/null +++ b/esphome/components/waveshare_io_ch32v003/sensor/waveshare_io_ch32v003_sensor.h @@ -0,0 +1,29 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" + +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/voltage_sampler/voltage_sampler.h" + +#include "../waveshare_io_ch32v003.h" + +namespace esphome::waveshare_io_ch32v003 { + +class WaveshareIOCH32V003Sensor : public sensor::Sensor, + public PollingComponent, + public voltage_sampler::VoltageSampler, + public Parented { + public: + void set_reference_voltage(float reference_voltage) { this->reference_voltage_ = reference_voltage; } + + void update() override; + void dump_config() override; + float get_setup_priority() const override; + float sample() override; + + protected: + float reference_voltage_{9.9f}; // Default reference voltage for ADC calculations, can be overridden by user config +}; + +} // namespace esphome::waveshare_io_ch32v003 diff --git a/esphome/components/waveshare_io_ch32v003/waveshare_io_ch32v003.cpp b/esphome/components/waveshare_io_ch32v003/waveshare_io_ch32v003.cpp new file mode 100644 index 0000000000..8a58c7e7bb --- /dev/null +++ b/esphome/components/waveshare_io_ch32v003/waveshare_io_ch32v003.cpp @@ -0,0 +1,168 @@ +#include "waveshare_io_ch32v003.h" +#include "esphome/core/log.h" + +namespace esphome::waveshare_io_ch32v003 { + +static const uint8_t IO_EXTENSION_DIRECTION = 0x02; +static const uint8_t IO_EXTENSION_IO_OUTPUT_ADDR = 0x03; +static const uint8_t IO_EXTENSION_IO_INPUT_ADDR = 0x04; +static const uint8_t IO_EXTENSION_PWM_ADDR = 0x05; +static const uint8_t IO_EXTENSION_ADC_ADDR = 0x06; +static const uint8_t IO_EXTENSION_RTC_INT_ADDR = 0x07; + +static const char *const TAG = "waveshare_io_ch32v003"; + +void WaveshareIOCH32V003Component::setup() { + this->mode_mask_ = 0xFF; // Set all pins to output mode + this->output_mask_ = 0xFF; // Set all pins to high (output mode) + + bool step1 = this->write_gpio_modes_(); + bool step2 = this->write_gpio_outputs_(); + + if (!step1 || !step2) { + ESP_LOGE(TAG, "Failed to initialize Waveshare IO expander"); + this->mark_failed(); + return; + } + + this->disable_loop(); +} + +void WaveshareIOCH32V003Component::pin_mode(uint8_t pin, gpio::Flags flags) { + // bits: 0 = input, 1 = output + if (flags == gpio::FLAG_INPUT) { + // Clear mode mask bit + this->mode_mask_ &= ~(1 << pin); + this->enable_loop(); + } else if (flags == gpio::FLAG_OUTPUT) { + // Set mode mask bit + this->mode_mask_ |= 1 << pin; + } + this->write_gpio_modes_(); +} + +void WaveshareIOCH32V003Component::loop() { this->reset_pin_cache_(); } + +void WaveshareIOCH32V003Component::dump_config() { + ESP_LOGCONFIG(TAG, "WaveshareIO:"); + LOG_I2C_DEVICE(this) + if (this->is_failed()) { + ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); + } +} + +uint16_t WaveshareIOCH32V003Component::get_adc_value() { + if (this->is_failed()) + return 0; + + uint8_t data[2]; + if (!this->read_bytes(IO_EXTENSION_ADC_ADDR, data, 2)) { + this->status_set_warning(LOG_STR("Failed to read ADC register")); + return 0; + } + uint16_t adc_value = (data[1] << 8) | data[0]; + this->status_clear_warning(); + return adc_value; +} + +uint8_t WaveshareIOCH32V003Component::get_rtc_interrupt_status() { + if (this->is_failed()) + return 0; + + uint8_t data = 0; + if (!this->read_bytes(IO_EXTENSION_RTC_INT_ADDR, &data, 1)) { + this->status_set_warning(LOG_STR("Failed to read RTC interrupt register")); + return 0; + } + this->status_clear_warning(); + return data; +} + +void WaveshareIOCH32V003Component::set_pwm_value(uint8_t value) { + if (this->is_failed()) + return; + + // PWM limits are enforced at the output component level to protect hardware + // based on circuit schematic requirements. This follows the pattern from the + // original Waveshare IO library function "void IO_EXTENSION_Pwm_Output(uint8_t Value)". + + if (!this->write_byte(IO_EXTENSION_PWM_ADDR, value)) { + this->status_set_warning(LOG_STR("Failed to set PWM duty cycle")); + return; + } + + this->status_clear_warning(); +} + +bool WaveshareIOCH32V003Component::write_gpio_modes_() { + if (this->is_failed()) + return false; + if (!this->write_byte(IO_EXTENSION_DIRECTION, this->mode_mask_)) { + this->status_set_warning(LOG_STR("Failed to write mode register")); + return false; + } + this->status_clear_warning(); + return true; +} + +bool WaveshareIOCH32V003Component::write_gpio_outputs_() { + if (this->is_failed()) + return false; + if (!this->write_byte(IO_EXTENSION_IO_OUTPUT_ADDR, this->output_mask_)) { + this->status_set_warning(LOG_STR("Failed to write output register")); + return false; + } + this->status_clear_warning(); + return true; +} + +bool WaveshareIOCH32V003Component::digital_read_hw(uint8_t pin) { + if (this->is_failed()) + return false; + + uint8_t data = 0; + if (!this->read_bytes(IO_EXTENSION_IO_INPUT_ADDR, &data, 1)) { + this->status_set_warning(LOG_STR("Failed to read input register")); + return false; + } + this->input_mask_ = data; + + this->status_clear_warning(); + return true; +} + +void WaveshareIOCH32V003Component::digital_write_hw(uint8_t pin, bool value) { + if (this->is_failed()) + return; + + if (value) { + this->output_mask_ |= (1 << pin); + } else { + this->output_mask_ &= ~(1 << pin); + } + + uint8_t data = this->output_mask_; + if (!this->write_byte(IO_EXTENSION_IO_OUTPUT_ADDR, data)) { + this->status_set_warning(LOG_STR("Failed to write output register")); + return; + } + + this->status_clear_warning(); +} + +bool WaveshareIOCH32V003Component::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); } +float WaveshareIOCH32V003Component::get_setup_priority() const { return setup_priority::IO; } + +void WaveshareIOCH32V003GPIOPin::setup() { this->pin_mode(this->flags_); } +void WaveshareIOCH32V003GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } +bool WaveshareIOCH32V003GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) ^ this->inverted_; } + +void WaveshareIOCH32V003GPIOPin::digital_write(bool value) { + this->parent_->digital_write(this->pin_, value ^ this->inverted_); +} + +size_t WaveshareIOCH32V003GPIOPin::dump_summary(char *buffer, size_t len) const { + return buf_append_printf(buffer, len, 0, "EXIO%u via WaveshareIO", this->pin_); +} + +} // namespace esphome::waveshare_io_ch32v003 diff --git a/esphome/components/waveshare_io_ch32v003/waveshare_io_ch32v003.h b/esphome/components/waveshare_io_ch32v003/waveshare_io_ch32v003.h new file mode 100644 index 0000000000..4a31602fa4 --- /dev/null +++ b/esphome/components/waveshare_io_ch32v003/waveshare_io_ch32v003.h @@ -0,0 +1,65 @@ +#pragma once + +#include "esphome/components/gpio_expander/cached_gpio.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" + +namespace esphome::waveshare_io_ch32v003 { + +class WaveshareIOCH32V003Component : public Component, + public i2c::I2CDevice, + public gpio_expander::CachedGpioExpander { + public: + WaveshareIOCH32V003Component() = default; + + void setup() override; + void pin_mode(uint8_t pin, gpio::Flags flags); + + float get_setup_priority() const override; + + void dump_config() override; + + void loop() override; + + uint16_t get_adc_value(); + uint8_t get_rtc_interrupt_status(); + void set_pwm_value(uint8_t value); // 0 - 255 + + protected: + friend class WaveshareIOCH32V003GPIOPin; + + bool digital_read_hw(uint8_t pin) override; + bool digital_read_cache(uint8_t pin) override; + void digital_write_hw(uint8_t pin, bool value) override; + + uint8_t mode_mask_{0x00}; // Mask for the pin mode - 1 means output, 0 means input + uint8_t output_mask_{0x00}; // The mask to write as output state - 1 means HIGH, 0 means LOW + uint8_t input_mask_{0x00}; // The state read in digital_read_hw - 1 means HIGH, 0 means LOW + + bool write_gpio_modes_(); + bool write_gpio_outputs_(); +}; + +/// Helper class to expose a WaveshareIO pin as a GPIO pin. +class WaveshareIOCH32V003GPIOPin : public GPIOPin, public Parented { + public: + void setup() override; + void pin_mode(gpio::Flags flags) override; + bool digital_read() override; + void digital_write(bool value) override; + size_t dump_summary(char *buffer, size_t len) const override; + + void set_pin(uint8_t pin) { this->pin_ = pin; } + void set_inverted(bool inverted) { this->inverted_ = inverted; } + void set_flags(gpio::Flags flags) { this->flags_ = flags; } + + gpio::Flags get_flags() const override { return this->flags_; } + + protected: + uint8_t pin_{}; + bool inverted_{}; + gpio::Flags flags_{}; +}; + +} // namespace esphome::waveshare_io_ch32v003 diff --git a/tests/components/waveshare_io_ch32v003/common.yaml b/tests/components/waveshare_io_ch32v003/common.yaml new file mode 100644 index 0000000000..086b27ab96 --- /dev/null +++ b/tests/components/waveshare_io_ch32v003/common.yaml @@ -0,0 +1,33 @@ +waveshare_io_ch32v003: + - id: wave_io + address: 0x24 + +binary_sensor: + - platform: gpio + id: wave_io_binary_sensor + pin: + waveshare_io_ch32v003: wave_io + number: 3 + mode: INPUT + inverted: false + +output: + - platform: gpio + id: wave_io_output + pin: + waveshare_io_ch32v003: wave_io + number: 0 + mode: OUTPUT + inverted: false + + - platform: waveshare_io_ch32v003 + id: wave_io_pwm_output + inverted: true + zero_means_zero: true + safe_pwm_levels: + min_value: 0 + max_value: 247 + +sensor: + - platform: waveshare_io_ch32v003 + id: wave_io_adc diff --git a/tests/components/waveshare_io_ch32v003/test.esp32-idf.yaml b/tests/components/waveshare_io_ch32v003/test.esp32-idf.yaml new file mode 100644 index 0000000000..b47e39c389 --- /dev/null +++ b/tests/components/waveshare_io_ch32v003/test.esp32-idf.yaml @@ -0,0 +1,4 @@ +packages: + i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml + +<<: !include common.yaml