From 16dbbfabc61809c8df1a79249af0bfe4ec80c2ee Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Thu, 29 Jul 2021 11:50:55 +0200 Subject: [PATCH] Add demo integration (#2085) --- esphome/components/demo/__init__.py | 451 +++++++++++++++++++ esphome/components/demo/demo_binary_sensor.h | 22 + esphome/components/demo/demo_climate.h | 157 +++++++ esphome/components/demo/demo_cover.h | 86 ++++ esphome/components/demo/demo_fan.h | 54 +++ esphome/components/demo/demo_light.h | 82 ++++ esphome/components/demo/demo_number.h | 39 ++ esphome/components/demo/demo_sensor.h | 28 ++ esphome/components/demo/demo_switch.h | 22 + esphome/components/demo/demo_text_sensor.h | 25 + tests/test5.yaml | 3 + 11 files changed, 969 insertions(+) create mode 100644 esphome/components/demo/__init__.py create mode 100644 esphome/components/demo/demo_binary_sensor.h create mode 100644 esphome/components/demo/demo_climate.h create mode 100644 esphome/components/demo/demo_cover.h create mode 100644 esphome/components/demo/demo_fan.h create mode 100644 esphome/components/demo/demo_light.h create mode 100644 esphome/components/demo/demo_number.h create mode 100644 esphome/components/demo/demo_sensor.h create mode 100644 esphome/components/demo/demo_switch.h create mode 100644 esphome/components/demo/demo_text_sensor.h diff --git a/esphome/components/demo/__init__.py b/esphome/components/demo/__init__.py new file mode 100644 index 0000000000..b3ea47d869 --- /dev/null +++ b/esphome/components/demo/__init__.py @@ -0,0 +1,451 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import ( + binary_sensor, + climate, + cover, + fan, + light, + number, + sensor, + switch, + text_sensor, +) +from esphome.const import ( + CONF_ACCURACY_DECIMALS, + CONF_BINARY_SENSORS, + CONF_DEVICE_CLASS, + CONF_FORCE_UPDATE, + CONF_ICON, + CONF_ID, + CONF_INVERTED, + CONF_LAST_RESET_TYPE, + CONF_MAX_VALUE, + CONF_MIN_VALUE, + CONF_NAME, + CONF_OUTPUT_ID, + CONF_SENSORS, + CONF_STATE_CLASS, + CONF_STEP, + CONF_SWITCHES, + CONF_TEXT_SENSORS, + CONF_TYPE, + CONF_UNIT_OF_MEASUREMENT, + DEVICE_CLASS_ENERGY, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_MOISTURE, + DEVICE_CLASS_MOTION, + DEVICE_CLASS_TEMPERATURE, + ICON_BLUETOOTH, + ICON_BLUR, + ICON_EMPTY, + ICON_THERMOMETER, + LAST_RESET_TYPE_AUTO, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_EMPTY, + UNIT_PERCENT, + UNIT_WATT_HOURS, +) + +AUTO_LOAD = [ + "binary_sensor", + "climate", + "cover", + "fan", + "light", + "number", + "sensor", + "switch", + "text_sensor", +] + +demo_ns = cg.esphome_ns.namespace("demo") +DemoBinarySensor = demo_ns.class_( + "DemoBinarySensor", binary_sensor.BinarySensor, cg.PollingComponent +) +DemoClimate = demo_ns.class_("DemoClimate", climate.Climate, cg.Component) +DemoClimateType = demo_ns.enum("DemoClimateType", is_class=True) +DemoCover = demo_ns.class_("DemoCover", cover.Cover, cg.Component) +DemoCoverType = demo_ns.enum("DemoCoverType", is_class=True) +DemoFan = demo_ns.class_("DemoFan", cg.Component) +DemoFanType = demo_ns.enum("DemoFanType", is_class=True) +DemoLight = demo_ns.class_("DemoLight", light.LightOutput, cg.Component) +DemoLightType = demo_ns.enum("DemoLightType", is_class=True) +DemoNumber = demo_ns.class_("DemoNumber", number.Number, cg.Component) +DemoNumberType = demo_ns.enum("DemoNumberType", is_class=True) +DemoSensor = demo_ns.class_("DemoSensor", sensor.Sensor, cg.PollingComponent) +DemoSwitch = demo_ns.class_("DemoSwitch", switch.Switch, cg.Component) +DemoTextSensor = demo_ns.class_( + "DemoTextSensor", text_sensor.TextSensor, cg.PollingComponent +) + + +CLIMATE_TYPES = { + 1: DemoClimateType.TYPE_1, + 2: DemoClimateType.TYPE_2, + 3: DemoClimateType.TYPE_3, +} +COVER_TYPES = { + 1: DemoCoverType.TYPE_1, + 2: DemoCoverType.TYPE_2, + 3: DemoCoverType.TYPE_3, + 4: DemoCoverType.TYPE_4, +} +FAN_TYPES = { + 1: DemoFanType.TYPE_1, + 2: DemoFanType.TYPE_2, + 3: DemoFanType.TYPE_3, + 4: DemoFanType.TYPE_4, +} +LIGHT_TYPES = { + 1: DemoLightType.TYPE_1, + 2: DemoLightType.TYPE_2, + 3: DemoLightType.TYPE_3, + 4: DemoLightType.TYPE_4, + 5: DemoLightType.TYPE_5, + 6: DemoLightType.TYPE_6, + 7: DemoLightType.TYPE_7, +} +NUMBER_TYPES = { + 1: DemoNumberType.TYPE_1, + 2: DemoNumberType.TYPE_2, + 3: DemoNumberType.TYPE_3, +} + + +CONF_CLIMATES = "climates" +CONF_COVERS = "covers" +CONF_FANS = "fans" +CONF_LIGHTS = "lights" +CONF_NUMBERS = "numbers" + +CONFIG_SCHEMA = cv.Schema( + { + cv.Optional( + CONF_BINARY_SENSORS, + default=[ + { + CONF_NAME: "Demo Basement Floor Wet", + CONF_DEVICE_CLASS: DEVICE_CLASS_MOISTURE, + }, + { + CONF_NAME: "Demo Movement Backyard", + CONF_DEVICE_CLASS: DEVICE_CLASS_MOTION, + }, + ], + ): [ + binary_sensor.BINARY_SENSOR_SCHEMA.extend( + cv.polling_component_schema("60s") + ).extend( + { + cv.GenerateID(): cv.declare_id(DemoBinarySensor), + } + ) + ], + cv.Optional( + CONF_CLIMATES, + default=[ + { + CONF_NAME: "Demo Heatpump", + CONF_TYPE: 1, + }, + { + CONF_NAME: "Demo HVAC", + CONF_TYPE: 2, + }, + { + CONF_NAME: "Demo Ecobee", + CONF_TYPE: 3, + }, + ], + ): [ + climate.CLIMATE_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( + { + cv.GenerateID(): cv.declare_id(DemoClimate), + cv.Required(CONF_TYPE): cv.enum(CLIMATE_TYPES, int=True), + } + ) + ], + cv.Optional( + CONF_COVERS, + default=[ + { + CONF_NAME: "Demo Kitchen Window", + CONF_TYPE: 1, + }, + { + CONF_NAME: "Demo Garage Door", + CONF_TYPE: 2, + CONF_DEVICE_CLASS: "garage", + }, + { + CONF_NAME: "Demo Living Room Window", + CONF_TYPE: 3, + }, + { + CONF_NAME: "Demo Hall Window", + CONF_TYPE: 4, + CONF_DEVICE_CLASS: "window", + }, + ], + ): [ + cover.COVER_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( + { + cv.GenerateID(): cv.declare_id(DemoCover), + cv.Required(CONF_TYPE): cv.enum(COVER_TYPES, int=True), + } + ) + ], + cv.Optional( + CONF_FANS, + default=[ + { + CONF_NAME: "Demo Living Room Fan", + CONF_TYPE: 1, + }, + { + CONF_NAME: "Demo Ceiling Fan", + CONF_TYPE: 2, + }, + { + CONF_NAME: "Demo Percentage Limited Fan", + CONF_TYPE: 3, + }, + { + CONF_NAME: "Demo Percentage Full Fan", + CONF_TYPE: 4, + }, + ], + ): [ + fan.FAN_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( + { + cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(DemoFan), + cv.Required(CONF_TYPE): cv.enum(FAN_TYPES, int=True), + } + ) + ], + cv.Optional( + CONF_LIGHTS, + default=[ + { + CONF_NAME: "Demo Binary Light", + CONF_TYPE: 1, + }, + { + CONF_NAME: "Demo Brightness Light", + CONF_TYPE: 2, + }, + { + CONF_NAME: "Demo RGB Light", + CONF_TYPE: 3, + }, + { + CONF_NAME: "Demo RGBW Light", + CONF_TYPE: 4, + }, + { + CONF_NAME: "Demo RGBWW Light", + CONF_TYPE: 5, + }, + { + CONF_NAME: "Demo CWWW Light", + CONF_TYPE: 6, + }, + { + CONF_NAME: "Demo RGBW interlock Light", + CONF_TYPE: 7, + }, + ], + ): [ + light.RGB_LIGHT_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( + { + cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(DemoLight), + cv.Required(CONF_TYPE): cv.enum(LIGHT_TYPES, int=True), + } + ) + ], + cv.Optional( + CONF_NUMBERS, + default=[ + { + CONF_NAME: "Demo Number 0-100", + CONF_TYPE: 1, + CONF_MIN_VALUE: 0, + CONF_MAX_VALUE: 100, + CONF_STEP: 1, + }, + { + CONF_NAME: "Demo Number -50-50", + CONF_TYPE: 2, + CONF_MIN_VALUE: -50, + CONF_MAX_VALUE: 50, + CONF_STEP: 5, + }, + { + CONF_NAME: "Demo Number 40-60", + CONF_TYPE: 3, + CONF_MIN_VALUE: 40, + CONF_MAX_VALUE: 60, + CONF_STEP: 0.2, + }, + ], + ): [ + number.NUMBER_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( + { + cv.GenerateID(): cv.declare_id(DemoNumber), + cv.Required(CONF_TYPE): cv.enum(NUMBER_TYPES, int=True), + cv.Required(CONF_MIN_VALUE): cv.float_, + cv.Required(CONF_MAX_VALUE): cv.float_, + cv.Required(CONF_STEP): cv.float_, + } + ) + ], + cv.Optional( + CONF_SENSORS, + default=[ + { + CONF_NAME: "Demo Plain Sensor", + }, + { + CONF_NAME: "Demo Temperature Sensor", + CONF_UNIT_OF_MEASUREMENT: UNIT_CELSIUS, + CONF_ICON: ICON_THERMOMETER, + CONF_ACCURACY_DECIMALS: 1, + CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, + CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT, + }, + { + CONF_NAME: "Demo Temperature Sensor", + CONF_UNIT_OF_MEASUREMENT: UNIT_CELSIUS, + CONF_ICON: ICON_THERMOMETER, + CONF_ACCURACY_DECIMALS: 1, + CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, + CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT, + }, + { + CONF_NAME: "Demo Force Update Sensor", + CONF_UNIT_OF_MEASUREMENT: UNIT_PERCENT, + CONF_ACCURACY_DECIMALS: 0, + CONF_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY, + CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT, + CONF_FORCE_UPDATE: True, + }, + { + CONF_NAME: "Demo Energy Sensor", + CONF_UNIT_OF_MEASUREMENT: UNIT_WATT_HOURS, + CONF_ACCURACY_DECIMALS: 0, + CONF_DEVICE_CLASS: DEVICE_CLASS_ENERGY, + CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT, + CONF_LAST_RESET_TYPE: LAST_RESET_TYPE_AUTO, + }, + ], + ): [ + sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 0) + .extend(cv.polling_component_schema("60s")) + .extend( + { + cv.GenerateID(): cv.declare_id(DemoSensor), + } + ) + ], + cv.Optional( + CONF_SWITCHES, + default=[ + { + CONF_NAME: "Demo Switch 1", + }, + { + CONF_NAME: "Demo Switch 2", + CONF_INVERTED: True, + CONF_ICON: ICON_BLUETOOTH, + }, + ], + ): [ + switch.SWITCH_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( + { + cv.GenerateID(): cv.declare_id(DemoSwitch), + } + ) + ], + cv.Optional( + CONF_TEXT_SENSORS, + default=[ + { + CONF_NAME: "Demo Text Sensor 1", + }, + { + CONF_NAME: "Demo Text Sensor 2", + CONF_ICON: ICON_BLUR, + }, + ], + ): [ + text_sensor.TEXT_SENSOR_SCHEMA.extend( + cv.polling_component_schema("60s") + ).extend( + { + cv.GenerateID(): cv.declare_id(DemoTextSensor), + } + ) + ], + } +) + + +async def to_code(config): + for conf in config[CONF_BINARY_SENSORS]: + var = cg.new_Pvariable(conf[CONF_ID]) + await cg.register_component(var, conf) + await binary_sensor.register_binary_sensor(var, conf) + + for conf in config[CONF_CLIMATES]: + var = cg.new_Pvariable(conf[CONF_ID]) + await cg.register_component(var, conf) + await climate.register_climate(var, conf) + cg.add(var.set_type(conf[CONF_TYPE])) + + for conf in config[CONF_COVERS]: + var = cg.new_Pvariable(conf[CONF_ID]) + await cg.register_component(var, conf) + await cover.register_cover(var, conf) + cg.add(var.set_type(conf[CONF_TYPE])) + + for conf in config[CONF_FANS]: + var = cg.new_Pvariable(conf[CONF_OUTPUT_ID]) + await cg.register_component(var, conf) + fan_ = await fan.create_fan_state(conf) + cg.add(var.set_fan(fan_)) + cg.add(var.set_type(conf[CONF_TYPE])) + + for conf in config[CONF_LIGHTS]: + var = cg.new_Pvariable(conf[CONF_OUTPUT_ID]) + await cg.register_component(var, conf) + await light.register_light(var, conf) + cg.add(var.set_type(conf[CONF_TYPE])) + + for conf in config[CONF_NUMBERS]: + var = cg.new_Pvariable(conf[CONF_ID]) + await cg.register_component(var, conf) + await number.register_number( + var, + conf, + min_value=conf[CONF_MIN_VALUE], + max_value=conf[CONF_MAX_VALUE], + step=conf[CONF_STEP], + ) + cg.add(var.set_type(conf[CONF_TYPE])) + + for conf in config[CONF_SENSORS]: + var = cg.new_Pvariable(conf[CONF_ID]) + await cg.register_component(var, conf) + await sensor.register_sensor(var, conf) + + for conf in config[CONF_SWITCHES]: + var = cg.new_Pvariable(conf[CONF_ID]) + await cg.register_component(var, conf) + await switch.register_switch(var, conf) + + for conf in config[CONF_TEXT_SENSORS]: + var = cg.new_Pvariable(conf[CONF_ID]) + await cg.register_component(var, conf) + await text_sensor.register_text_sensor(var, conf) diff --git a/esphome/components/demo/demo_binary_sensor.h b/esphome/components/demo/demo_binary_sensor.h new file mode 100644 index 0000000000..4dfd038761 --- /dev/null +++ b/esphome/components/demo/demo_binary_sensor.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/binary_sensor/binary_sensor.h" + +namespace esphome { +namespace demo { + +class DemoBinarySensor : public binary_sensor::BinarySensor, public PollingComponent { + public: + void setup() override { this->publish_initial_state(false); } + void update() override { + bool new_state = last_state_ = !last_state_; + this->publish_state(new_state); + } + + protected: + bool last_state_ = false; +}; + +} // namespace demo +} // namespace esphome diff --git a/esphome/components/demo/demo_climate.h b/esphome/components/demo/demo_climate.h new file mode 100644 index 0000000000..0cf48dd4ee --- /dev/null +++ b/esphome/components/demo/demo_climate.h @@ -0,0 +1,157 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/climate/climate.h" + +namespace esphome { +namespace demo { + +enum class DemoClimateType { + TYPE_1, + TYPE_2, + TYPE_3, +}; + +class DemoClimate : public climate::Climate, public Component { + public: + void set_type(DemoClimateType type) { type_ = type; } + void setup() override { + switch (type_) { + case DemoClimateType::TYPE_1: + this->current_temperature = 20.0; + this->target_temperature = 21.0; + this->mode = climate::CLIMATE_MODE_HEAT; + this->action = climate::CLIMATE_ACTION_HEATING; + break; + case DemoClimateType::TYPE_2: + this->target_temperature = 21.5; + this->mode = climate::CLIMATE_MODE_AUTO; + this->action = climate::CLIMATE_ACTION_COOLING; + this->fan_mode = climate::CLIMATE_FAN_HIGH; + this->custom_preset = {"My Preset"}; + break; + case DemoClimateType::TYPE_3: + this->current_temperature = 21.5; + this->target_temperature_low = 21.0; + this->target_temperature_high = 22.5; + this->mode = climate::CLIMATE_MODE_HEAT_COOL; + this->custom_fan_mode = {"Auto Low"}; + this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; + this->preset = climate::CLIMATE_PRESET_AWAY; + break; + } + this->publish_state(); + } + + protected: + void control(const climate::ClimateCall &call) override { + if (call.get_mode().has_value()) { + this->mode = *call.get_mode(); + } + if (call.get_target_temperature().has_value()) { + this->target_temperature = *call.get_target_temperature(); + } + if (call.get_target_temperature_low().has_value()) { + this->target_temperature_low = *call.get_target_temperature_low(); + } + if (call.get_target_temperature_high().has_value()) { + this->target_temperature_high = *call.get_target_temperature_high(); + } + if (call.get_fan_mode().has_value()) { + this->fan_mode = *call.get_fan_mode(); + this->custom_fan_mode.reset(); + } + if (call.get_swing_mode().has_value()) { + this->swing_mode = *call.get_swing_mode(); + } + if (call.get_custom_fan_mode().has_value()) { + this->custom_fan_mode = *call.get_custom_fan_mode(); + this->fan_mode.reset(); + } + if (call.get_preset().has_value()) { + this->preset = *call.get_preset(); + this->custom_preset.reset(); + } + if (call.get_custom_preset().has_value()) { + this->custom_preset = *call.get_custom_preset(); + this->preset.reset(); + } + this->publish_state(); + } + climate::ClimateTraits traits() override { + climate::ClimateTraits traits{}; + switch (type_) { + case DemoClimateType::TYPE_1: + traits.set_supports_current_temperature(true); + traits.set_supported_modes({ + climate::CLIMATE_MODE_OFF, + climate::CLIMATE_MODE_HEAT, + }); + traits.set_supports_action(true); + traits.set_visual_temperature_step(0.5); + break; + case DemoClimateType::TYPE_2: + traits.set_supports_current_temperature(false); + traits.set_supported_modes({ + climate::CLIMATE_MODE_OFF, + climate::CLIMATE_MODE_HEAT, + climate::CLIMATE_MODE_COOL, + climate::CLIMATE_MODE_AUTO, + climate::CLIMATE_MODE_DRY, + climate::CLIMATE_MODE_FAN_ONLY, + }); + traits.set_supports_action(true); + traits.set_supported_fan_modes({ + climate::CLIMATE_FAN_ON, + climate::CLIMATE_FAN_OFF, + climate::CLIMATE_FAN_AUTO, + climate::CLIMATE_FAN_LOW, + climate::CLIMATE_FAN_MEDIUM, + climate::CLIMATE_FAN_HIGH, + climate::CLIMATE_FAN_MIDDLE, + climate::CLIMATE_FAN_FOCUS, + climate::CLIMATE_FAN_DIFFUSE, + }); + traits.set_supported_custom_fan_modes({"Auto Low", "Auto High"}); + traits.set_supported_swing_modes({ + climate::CLIMATE_SWING_OFF, + climate::CLIMATE_SWING_BOTH, + climate::CLIMATE_SWING_VERTICAL, + climate::CLIMATE_SWING_HORIZONTAL, + }); + traits.set_supported_custom_presets({"My Preset"}); + break; + case DemoClimateType::TYPE_3: + traits.set_supports_current_temperature(true); + traits.set_supports_two_point_target_temperature(true); + traits.set_supported_modes({ + climate::CLIMATE_MODE_OFF, + climate::CLIMATE_MODE_COOL, + climate::CLIMATE_MODE_HEAT, + climate::CLIMATE_MODE_HEAT_COOL, + }); + traits.set_supported_custom_fan_modes({"Auto Low", "Auto High"}); + traits.set_supported_swing_modes({ + climate::CLIMATE_SWING_OFF, + climate::CLIMATE_SWING_HORIZONTAL, + }); + traits.set_supported_presets({ + climate::CLIMATE_PRESET_NONE, + climate::CLIMATE_PRESET_HOME, + climate::CLIMATE_PRESET_AWAY, + climate::CLIMATE_PRESET_BOOST, + climate::CLIMATE_PRESET_COMFORT, + climate::CLIMATE_PRESET_ECO, + climate::CLIMATE_PRESET_SLEEP, + climate::CLIMATE_PRESET_ACTIVITY, + }); + break; + } + return traits; + } + + DemoClimateType type_; +}; + +} // namespace demo +} // namespace esphome diff --git a/esphome/components/demo/demo_cover.h b/esphome/components/demo/demo_cover.h new file mode 100644 index 0000000000..ab039736fb --- /dev/null +++ b/esphome/components/demo/demo_cover.h @@ -0,0 +1,86 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/cover/cover.h" + +namespace esphome { +namespace demo { + +enum class DemoCoverType { + TYPE_1, + TYPE_2, + TYPE_3, + TYPE_4, +}; + +class DemoCover : public cover::Cover, public Component { + public: + void set_type(DemoCoverType type) { type_ = type; } + void setup() override { + switch (type_) { + case DemoCoverType::TYPE_1: + this->position = cover::COVER_OPEN; + break; + case DemoCoverType::TYPE_2: + this->position = 0.7; + break; + case DemoCoverType::TYPE_3: + this->position = 0.1; + this->tilt = 0.8; + break; + case DemoCoverType::TYPE_4: + this->position = cover::COVER_CLOSED; + this->tilt = 1.0; + break; + } + this->publish_state(); + } + + protected: + void control(const cover::CoverCall &call) override { + if (call.get_position().has_value()) { + float target = *call.get_position(); + this->current_operation = + target > this->position ? cover::COVER_OPERATION_OPENING : cover::COVER_OPERATION_CLOSING; + + this->set_timeout("move", 2000, [this, target]() { + this->current_operation = cover::COVER_OPERATION_IDLE; + this->position = target; + this->publish_state(); + }); + } + if (call.get_tilt().has_value()) { + this->tilt = *call.get_tilt(); + } + if (call.get_stop()) { + this->cancel_timeout("move"); + } + + this->publish_state(); + } + cover::CoverTraits get_traits() override { + cover::CoverTraits traits{}; + switch (type_) { + case DemoCoverType::TYPE_1: + traits.set_is_assumed_state(true); + break; + case DemoCoverType::TYPE_2: + traits.set_supports_position(true); + break; + case DemoCoverType::TYPE_3: + traits.set_supports_position(true); + traits.set_supports_tilt(true); + break; + case DemoCoverType::TYPE_4: + traits.set_is_assumed_state(true); + traits.set_supports_tilt(true); + break; + } + return traits; + } + + DemoCoverType type_; +}; + +} // namespace demo +} // namespace esphome diff --git a/esphome/components/demo/demo_fan.h b/esphome/components/demo/demo_fan.h new file mode 100644 index 0000000000..e926f68edb --- /dev/null +++ b/esphome/components/demo/demo_fan.h @@ -0,0 +1,54 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/fan/fan_state.h" + +namespace esphome { +namespace demo { + +enum class DemoFanType { + TYPE_1, + TYPE_2, + TYPE_3, + TYPE_4, +}; + +class DemoFan : public Component { + public: + void set_type(DemoFanType type) { type_ = type; } + void set_fan(fan::FanState *fan) { fan_ = fan; } + void setup() override { + fan::FanTraits traits{}; + + // oscillation + // speed + // direction + // speed_count + switch (type_) { + case DemoFanType::TYPE_1: + break; + case DemoFanType::TYPE_2: + traits.set_oscillation(true); + break; + case DemoFanType::TYPE_3: + traits.set_direction(true); + traits.set_speed(true); + traits.set_supported_speed_count(5); + break; + case DemoFanType::TYPE_4: + traits.set_direction(true); + traits.set_speed(true); + traits.set_supported_speed_count(100); + traits.set_oscillation(true); + break; + } + + this->fan_->set_traits(traits); + } + + fan::FanState *fan_; + DemoFanType type_; +}; + +} // namespace demo +} // namespace esphome diff --git a/esphome/components/demo/demo_light.h b/esphome/components/demo/demo_light.h new file mode 100644 index 0000000000..989dbf3306 --- /dev/null +++ b/esphome/components/demo/demo_light.h @@ -0,0 +1,82 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/light/light_output.h" + +namespace esphome { +namespace demo { + +enum class DemoLightType { + // binary + TYPE_1, + // brightness + TYPE_2, + // RGB + TYPE_3, + // RGBW + TYPE_4, + // RGBWW + TYPE_5, + // CWWW + TYPE_6, + // RGBW + color_interlock + TYPE_7, +}; + +class DemoLight : public light::LightOutput, public Component { + public: + void set_type(DemoLightType type) { type_ = type; } + light::LightTraits get_traits() override { + light::LightTraits traits{}; + // brightness + // rgb + // rgb_white_value + // color_temperature, min_mireds, max_mireds + // color_interlock + switch (type_) { + case DemoLightType::TYPE_1: + break; + case DemoLightType::TYPE_2: + traits.set_supports_brightness(true); + break; + case DemoLightType::TYPE_3: + traits.set_supports_brightness(true); + traits.set_supports_rgb(true); + break; + case DemoLightType::TYPE_4: + traits.set_supports_brightness(true); + traits.set_supports_rgb(true); + traits.set_supports_rgb_white_value(true); + break; + case DemoLightType::TYPE_5: + traits.set_supports_brightness(true); + traits.set_supports_rgb(true); + traits.set_supports_rgb_white_value(true); + traits.set_supports_color_temperature(true); + traits.set_min_mireds(153); + traits.set_max_mireds(500); + break; + case DemoLightType::TYPE_6: + traits.set_supports_brightness(true); + traits.set_supports_color_temperature(true); + traits.set_min_mireds(153); + traits.set_max_mireds(500); + break; + case DemoLightType::TYPE_7: + traits.set_supports_brightness(true); + traits.set_supports_rgb(true); + traits.set_supports_rgb_white_value(true); + traits.set_supports_color_interlock(true); + break; + } + return traits; + } + void write_state(light::LightState *state) override { + // do nothing + } + + DemoLightType type_; +}; + +} // namespace demo +} // namespace esphome diff --git a/esphome/components/demo/demo_number.h b/esphome/components/demo/demo_number.h new file mode 100644 index 0000000000..2ce3a269bc --- /dev/null +++ b/esphome/components/demo/demo_number.h @@ -0,0 +1,39 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/number/number.h" + +namespace esphome { +namespace demo { + +enum class DemoNumberType { + TYPE_1, + TYPE_2, + TYPE_3, +}; + +class DemoNumber : public number::Number, public Component { + public: + void set_type(DemoNumberType type) { type_ = type; } + void setup() override { + switch (type_) { + case DemoNumberType::TYPE_1: + this->publish_state(50); + break; + case DemoNumberType::TYPE_2: + this->publish_state(-10); + break; + case DemoNumberType::TYPE_3: + this->publish_state(42); + break; + } + } + + protected: + void control(float value) override { this->publish_state(value); } + + DemoNumberType type_; +}; + +} // namespace demo +} // namespace esphome diff --git a/esphome/components/demo/demo_sensor.h b/esphome/components/demo/demo_sensor.h new file mode 100644 index 0000000000..117468793b --- /dev/null +++ b/esphome/components/demo/demo_sensor.h @@ -0,0 +1,28 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" +#include "esphome/components/sensor/sensor.h" + +namespace esphome { +namespace demo { + +class DemoSensor : public sensor::Sensor, public PollingComponent { + public: + void update() override { + float val = random_float(); + bool is_auto = this->last_reset_type == sensor::LAST_RESET_TYPE_AUTO; + if (is_auto) { + float base = isnan(this->state) ? 0.0f : this->state; + this->publish_state(base + val * 10); + } else { + if (val < 0.1) + this->publish_state(NAN); + else + this->publish_state(val * 100); + } + } +}; + +} // namespace demo +} // namespace esphome diff --git a/esphome/components/demo/demo_switch.h b/esphome/components/demo/demo_switch.h new file mode 100644 index 0000000000..9c291318ca --- /dev/null +++ b/esphome/components/demo/demo_switch.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" +#include "esphome/components/switch/switch.h" + +namespace esphome { +namespace demo { + +class DemoSwitch : public switch_::Switch, public Component { + public: + void setup() override { + bool initial = random_float() < 0.5; + this->publish_state(initial); + } + + protected: + void write_state(bool state) override { this->publish_state(state); } +}; + +} // namespace demo +} // namespace esphome diff --git a/esphome/components/demo/demo_text_sensor.h b/esphome/components/demo/demo_text_sensor.h new file mode 100644 index 0000000000..b4152fc248 --- /dev/null +++ b/esphome/components/demo/demo_text_sensor.h @@ -0,0 +1,25 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" +#include "esphome/components/text_sensor/text_sensor.h" + +namespace esphome { +namespace demo { + +class DemoTextSensor : public text_sensor::TextSensor, public PollingComponent { + public: + void update() override { + float val = random_float(); + if (val < 0.33) { + this->publish_state("foo"); + } else if (val < 0.66) { + this->publish_state("bar"); + } else { + this->publish_state("foobar"); + } + } +}; + +} // namespace demo +} // namespace esphome diff --git a/tests/test5.yaml b/tests/test5.yaml index 23f8ae6c4d..1a2dde1010 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -52,6 +52,8 @@ output: channel: 0 max_power: 0.8 +demo: + esp32_ble: esp32_ble_server: @@ -116,6 +118,7 @@ sensor: name: "SelecEM2M Maximum Demand Reactive Power" maximum_demand_apparent_power: name: "SelecEM2M Maximum Demand Apparent Power" + - platform: t6615 uart_id: uart2 co2: