mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Emmeti infrared climate support (#5197)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -103,6 +103,7 @@ esphome/components/duty_time/* @dudanov | ||||
| esphome/components/ee895/* @Stock-M | ||||
| esphome/components/ektf2232/touchscreen/* @jesserockz | ||||
| esphome/components/emc2101/* @ellull | ||||
| esphome/components/emmeti/* @E440QF | ||||
| esphome/components/ens160/* @vincentscode | ||||
| esphome/components/ens210/* @itn3rd77 | ||||
| esphome/components/esp32/* @esphome/core | ||||
|   | ||||
							
								
								
									
										0
									
								
								esphome/components/emmeti/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/emmeti/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										21
									
								
								esphome/components/emmeti/climate.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								esphome/components/emmeti/climate.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import climate_ir | ||||
| from esphome.const import CONF_ID | ||||
|  | ||||
| CODEOWNERS = ["@E440QF"] | ||||
| AUTO_LOAD = ["climate_ir"] | ||||
|  | ||||
| emmeti_ns = cg.esphome_ns.namespace("emmeti") | ||||
| EmmetiClimate = emmeti_ns.class_("EmmetiClimate", climate_ir.ClimateIR) | ||||
|  | ||||
| CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(EmmetiClimate), | ||||
|     } | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await climate_ir.register_climate_ir(var, config) | ||||
							
								
								
									
										316
									
								
								esphome/components/emmeti/emmeti.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								esphome/components/emmeti/emmeti.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,316 @@ | ||||
| #include "emmeti.h" | ||||
| #include "esphome/components/remote_base/remote_base.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace emmeti { | ||||
|  | ||||
| static const char *const TAG = "emmeti.climate"; | ||||
|  | ||||
| // setters | ||||
| uint8_t EmmetiClimate::set_temp_() { | ||||
|   return (uint8_t) roundf(clamp<float>(this->target_temperature, EMMETI_TEMP_MIN, EMMETI_TEMP_MAX) - EMMETI_TEMP_MIN); | ||||
| } | ||||
|  | ||||
| uint8_t EmmetiClimate::set_mode_() { | ||||
|   switch (this->mode) { | ||||
|     case climate::CLIMATE_MODE_COOL: | ||||
|       return EMMETI_MODE_COOL; | ||||
|     case climate::CLIMATE_MODE_DRY: | ||||
|       return EMMETI_MODE_DRY; | ||||
|     case climate::CLIMATE_MODE_HEAT: | ||||
|       return EMMETI_MODE_HEAT; | ||||
|     case climate::CLIMATE_MODE_FAN_ONLY: | ||||
|       return EMMETI_MODE_FAN; | ||||
|     case climate::CLIMATE_MODE_HEAT_COOL: | ||||
|     default: | ||||
|       return EMMETI_MODE_HEAT_COOL; | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint8_t EmmetiClimate::set_fan_speed_() { | ||||
|   switch (this->fan_mode.value()) { | ||||
|     case climate::CLIMATE_FAN_LOW: | ||||
|       return EMMETI_FAN_1; | ||||
|     case climate::CLIMATE_FAN_MEDIUM: | ||||
|       return EMMETI_FAN_2; | ||||
|     case climate::CLIMATE_FAN_HIGH: | ||||
|       return EMMETI_FAN_3; | ||||
|     case climate::CLIMATE_FAN_AUTO: | ||||
|     default: | ||||
|       return EMMETI_FAN_AUTO; | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint8_t EmmetiClimate::set_blades_() { | ||||
|   if (this->swing_mode == climate::CLIMATE_SWING_VERTICAL) { | ||||
|     switch (this->blades_) { | ||||
|       case EMMETI_BLADES_1: | ||||
|       case EMMETI_BLADES_2: | ||||
|       case EMMETI_BLADES_HIGH: | ||||
|         this->blades_ = EMMETI_BLADES_HIGH; | ||||
|         break; | ||||
|       case EMMETI_BLADES_3: | ||||
|       case EMMETI_BLADES_MID: | ||||
|         this->blades_ = EMMETI_BLADES_MID; | ||||
|         break; | ||||
|       case EMMETI_BLADES_4: | ||||
|       case EMMETI_BLADES_5: | ||||
|       case EMMETI_BLADES_LOW: | ||||
|         this->blades_ = EMMETI_BLADES_LOW; | ||||
|         break; | ||||
|       default: | ||||
|         this->blades_ = EMMETI_BLADES_FULL; | ||||
|         break; | ||||
|     } | ||||
|   } else { | ||||
|     switch (this->blades_) { | ||||
|       case EMMETI_BLADES_1: | ||||
|       case EMMETI_BLADES_2: | ||||
|       case EMMETI_BLADES_HIGH: | ||||
|         this->blades_ = EMMETI_BLADES_1; | ||||
|         break; | ||||
|       case EMMETI_BLADES_3: | ||||
|       case EMMETI_BLADES_MID: | ||||
|         this->blades_ = EMMETI_BLADES_3; | ||||
|         break; | ||||
|       case EMMETI_BLADES_4: | ||||
|       case EMMETI_BLADES_5: | ||||
|       case EMMETI_BLADES_LOW: | ||||
|         this->blades_ = EMMETI_BLADES_5; | ||||
|         break; | ||||
|       default: | ||||
|         this->blades_ = EMMETI_BLADES_STOP; | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|   return this->blades_; | ||||
| } | ||||
|  | ||||
| uint8_t EmmetiClimate::gen_checksum_() { return (this->set_temp_() + this->set_mode_() + 2) % 16; } | ||||
|  | ||||
| // getters | ||||
| float EmmetiClimate::get_temp_(uint8_t temp) { return (float) (temp + EMMETI_TEMP_MIN); } | ||||
|  | ||||
| climate::ClimateMode EmmetiClimate::get_mode_(uint8_t mode) { | ||||
|   switch (mode) { | ||||
|     case EMMETI_MODE_COOL: | ||||
|       return climate::CLIMATE_MODE_COOL; | ||||
|     case EMMETI_MODE_DRY: | ||||
|       return climate::CLIMATE_MODE_DRY; | ||||
|     case EMMETI_MODE_HEAT: | ||||
|       return climate::CLIMATE_MODE_HEAT; | ||||
|     case EMMETI_MODE_HEAT_COOL: | ||||
|       return climate::CLIMATE_MODE_HEAT_COOL; | ||||
|     case EMMETI_MODE_FAN: | ||||
|       return climate::CLIMATE_MODE_FAN_ONLY; | ||||
|     default: | ||||
|       return climate::CLIMATE_MODE_HEAT_COOL; | ||||
|   } | ||||
| } | ||||
|  | ||||
| climate::ClimateFanMode EmmetiClimate::get_fan_speed_(uint8_t fan_speed) { | ||||
|   switch (fan_speed) { | ||||
|     case EMMETI_FAN_1: | ||||
|       return climate::CLIMATE_FAN_LOW; | ||||
|     case EMMETI_FAN_2: | ||||
|       return climate::CLIMATE_FAN_MEDIUM; | ||||
|     case EMMETI_FAN_3: | ||||
|       return climate::CLIMATE_FAN_HIGH; | ||||
|     case EMMETI_FAN_AUTO: | ||||
|     default: | ||||
|       return climate::CLIMATE_FAN_AUTO; | ||||
|   } | ||||
| } | ||||
|  | ||||
| climate::ClimateSwingMode EmmetiClimate::get_swing_(uint8_t bitmap) { | ||||
|   return (bitmap >> 1) & 0x01 ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF; | ||||
| } | ||||
|  | ||||
| template<typename T> T EmmetiClimate::reverse_(T val, size_t len) { | ||||
|   T result = 0; | ||||
|   for (size_t i = 0; i < len; i++) { | ||||
|     result |= ((val & 1 << i) != 0) << (len - 1 - i); | ||||
|   } | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| template<typename T> void EmmetiClimate::add_(T val, size_t len, esphome::remote_base::RemoteTransmitData *data) { | ||||
|   for (size_t i = len; i > 0; i--) { | ||||
|     data->mark(EMMETI_BIT_MARK); | ||||
|     data->space((val & (1 << (i - 1))) ? EMMETI_ONE_SPACE : EMMETI_ZERO_SPACE); | ||||
|   } | ||||
| } | ||||
|  | ||||
| template<typename T> void EmmetiClimate::add_(T val, esphome::remote_base::RemoteTransmitData *data) { | ||||
|   data->mark(EMMETI_BIT_MARK); | ||||
|   data->space((val & 1) ? EMMETI_ONE_SPACE : EMMETI_ZERO_SPACE); | ||||
| } | ||||
|  | ||||
| template<typename T> | ||||
| void EmmetiClimate::reverse_add_(T val, size_t len, esphome::remote_base::RemoteTransmitData *data) { | ||||
|   this->add_(this->reverse_(val, len), len, data); | ||||
| } | ||||
|  | ||||
| bool EmmetiClimate::check_checksum_(uint8_t checksum) { | ||||
|   uint8_t expected = this->gen_checksum_(); | ||||
|   ESP_LOGV(TAG, "Expected checksum: %X", expected); | ||||
|   ESP_LOGV(TAG, "Checksum received: %X", checksum); | ||||
|  | ||||
|   return checksum == expected; | ||||
| } | ||||
|  | ||||
| void EmmetiClimate::transmit_state() { | ||||
|   auto transmit = this->transmitter_->transmit(); | ||||
|   auto *data = transmit.get_data(); | ||||
|   data->set_carrier_frequency(EMMETI_IR_FREQUENCY); | ||||
|  | ||||
|   data->mark(EMMETI_HEADER_MARK); | ||||
|   data->space(EMMETI_HEADER_SPACE); | ||||
|  | ||||
|   if (this->mode != climate::CLIMATE_MODE_OFF) { | ||||
|     this->reverse_add_(this->set_mode_(), 3, data); | ||||
|     this->add_(1, data); | ||||
|     this->reverse_add_(this->set_fan_speed_(), 2, data); | ||||
|     this->add_(this->swing_mode != climate::CLIMATE_SWING_OFF, data); | ||||
|     this->add_(0, data);  // sleep mode | ||||
|     this->reverse_add_(this->set_temp_(), 4, data); | ||||
|     this->add_(0, 8, data);      // zeros | ||||
|     this->add_(0, data);         // turbo mode | ||||
|     this->add_(1, data);         // light | ||||
|     this->add_(1, data);         // tree icon thingy | ||||
|     this->add_(0, data);         // blow mode | ||||
|     this->add_(0x52, 11, data);  // idk | ||||
|  | ||||
|     data->mark(EMMETI_BIT_MARK); | ||||
|     data->space(EMMETI_MESSAGE_SPACE); | ||||
|  | ||||
|     this->reverse_add_(this->set_blades_(), 4, data); | ||||
|     this->add_(0, 4, data);          // zeros | ||||
|     this->reverse_add_(2, 2, data);  // thermometer | ||||
|     this->add_(0, 18, data);         // zeros | ||||
|     this->reverse_add_(this->gen_checksum_(), 4, data); | ||||
|   } else { | ||||
|     this->add_(9, 12, data); | ||||
|     this->add_(0, 8, data); | ||||
|     this->add_(0x2052, 15, data); | ||||
|     data->mark(EMMETI_BIT_MARK); | ||||
|     data->space(EMMETI_MESSAGE_SPACE); | ||||
|     this->add_(0, 8, data); | ||||
|     this->add_(1, 2, data); | ||||
|     this->add_(0, 18, data); | ||||
|     this->add_(0x0C, 4, data); | ||||
|   } | ||||
|   data->mark(EMMETI_BIT_MARK); | ||||
|   data->space(0); | ||||
|  | ||||
|   transmit.perform(); | ||||
| } | ||||
|  | ||||
| bool EmmetiClimate::parse_state_frame_(EmmetiState curr_state) { | ||||
|   this->mode = this->get_mode_(curr_state.mode); | ||||
|   this->fan_mode = this->get_fan_speed_(curr_state.fan_speed); | ||||
|   this->target_temperature = this->get_temp_(curr_state.temp); | ||||
|   this->swing_mode = this->get_swing_(curr_state.bitmap); | ||||
|   // this->blades_ = curr_state.fan_pos; | ||||
|   if (!(curr_state.bitmap & 0x01)) { | ||||
|     this->mode = climate::CLIMATE_MODE_OFF; | ||||
|   } | ||||
|  | ||||
|   this->publish_state(); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool EmmetiClimate::on_receive(remote_base::RemoteReceiveData data) { | ||||
|   if (!data.expect_item(EMMETI_HEADER_MARK, EMMETI_HEADER_SPACE)) { | ||||
|     return false; | ||||
|   } | ||||
|   ESP_LOGD(TAG, "Received emmeti frame"); | ||||
|  | ||||
|   EmmetiState curr_state; | ||||
|  | ||||
|   for (size_t pos = 0; pos < 3; pos++) { | ||||
|     if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { | ||||
|       curr_state.mode |= 1 << pos; | ||||
|     } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ESP_LOGD(TAG, "Mode: %d", curr_state.mode); | ||||
|  | ||||
|   if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { | ||||
|     curr_state.bitmap |= 1 << 0; | ||||
|   } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   ESP_LOGD(TAG, "On: %d", curr_state.bitmap & 0x01); | ||||
|  | ||||
|   for (size_t pos = 0; pos < 2; pos++) { | ||||
|     if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { | ||||
|       curr_state.fan_speed |= 1 << pos; | ||||
|     } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ESP_LOGD(TAG, "Fan speed: %d", curr_state.fan_speed); | ||||
|  | ||||
|   for (size_t pos = 0; pos < 2; pos++) { | ||||
|     if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { | ||||
|       curr_state.bitmap |= 1 << (pos + 1); | ||||
|     } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ESP_LOGD(TAG, "Swing: %d", (curr_state.bitmap >> 1) & 0x01); | ||||
|   ESP_LOGD(TAG, "Sleep: %d", (curr_state.bitmap >> 2) & 0x01); | ||||
|  | ||||
|   for (size_t pos = 0; pos < 4; pos++) { | ||||
|     if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { | ||||
|       curr_state.temp |= 1 << pos; | ||||
|     } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ESP_LOGD(TAG, "Temp: %d", curr_state.temp); | ||||
|  | ||||
|   for (size_t pos = 0; pos < 8; pos++) { | ||||
|     if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   for (size_t pos = 0; pos < 4; pos++) { | ||||
|     if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { | ||||
|       curr_state.bitmap |= 1 << (pos + 3); | ||||
|     } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ESP_LOGD(TAG, "Turbo: %d", (curr_state.bitmap >> 3) & 0x01); | ||||
|   ESP_LOGD(TAG, "Light: %d", (curr_state.bitmap >> 4) & 0x01); | ||||
|   ESP_LOGD(TAG, "Tree: %d", (curr_state.bitmap >> 5) & 0x01); | ||||
|   ESP_LOGD(TAG, "Blow: %d", (curr_state.bitmap >> 6) & 0x01); | ||||
|  | ||||
|   uint16_t control_data = 0; | ||||
|   for (size_t pos = 0; pos < 11; pos++) { | ||||
|     if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) { | ||||
|       control_data |= 1 << pos; | ||||
|     } else if (!data.expect_item(EMMETI_BIT_MARK, EMMETI_ZERO_SPACE)) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (control_data != 0x250) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   return this->parse_state_frame_(curr_state); | ||||
| } | ||||
|  | ||||
| }  // namespace emmeti | ||||
| }  // namespace esphome | ||||
							
								
								
									
										109
									
								
								esphome/components/emmeti/emmeti.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								esphome/components/emmeti/emmeti.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/climate_ir/climate_ir.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace emmeti { | ||||
|  | ||||
| const uint8_t EMMETI_TEMP_MIN = 16;  // Celsius | ||||
| const uint8_t EMMETI_TEMP_MAX = 30;  // Celsius | ||||
|  | ||||
| // Modes | ||||
|  | ||||
| enum EmmetiMode : uint8_t { | ||||
|   EMMETI_MODE_HEAT_COOL = 0x00, | ||||
|   EMMETI_MODE_COOL = 0x01, | ||||
|   EMMETI_MODE_DRY = 0x02, | ||||
|   EMMETI_MODE_FAN = 0x03, | ||||
|   EMMETI_MODE_HEAT = 0x04, | ||||
| }; | ||||
|  | ||||
| // Fan Speed | ||||
|  | ||||
| enum EmmetiFanMode : uint8_t { | ||||
|   EMMETI_FAN_AUTO = 0x00, | ||||
|   EMMETI_FAN_1 = 0x01, | ||||
|   EMMETI_FAN_2 = 0x02, | ||||
|   EMMETI_FAN_3 = 0x03, | ||||
| }; | ||||
|  | ||||
| // Fan Position | ||||
|  | ||||
| enum EmmetiBlades : uint8_t { | ||||
|   EMMETI_BLADES_STOP = 0x00, | ||||
|   EMMETI_BLADES_FULL = 0x01, | ||||
|   EMMETI_BLADES_1 = 0x02, | ||||
|   EMMETI_BLADES_2 = 0x03, | ||||
|   EMMETI_BLADES_3 = 0x04, | ||||
|   EMMETI_BLADES_4 = 0x05, | ||||
|   EMMETI_BLADES_5 = 0x06, | ||||
|   EMMETI_BLADES_LOW = 0x07, | ||||
|   EMMETI_BLADES_MID = 0x09, | ||||
|   EMMETI_BLADES_HIGH = 0x11, | ||||
| }; | ||||
|  | ||||
| // IR Transmission | ||||
| const uint32_t EMMETI_IR_FREQUENCY = 38000; | ||||
| const uint32_t EMMETI_HEADER_MARK = 9076; | ||||
| const uint32_t EMMETI_HEADER_SPACE = 4408; | ||||
| const uint32_t EMMETI_BIT_MARK = 660; | ||||
| const uint32_t EMMETI_ONE_SPACE = 1630; | ||||
| const uint32_t EMMETI_ZERO_SPACE = 530; | ||||
| const uint32_t EMMETI_MESSAGE_SPACE = 20000; | ||||
|  | ||||
| struct EmmetiState { | ||||
|   uint8_t mode = 0; | ||||
|   uint8_t bitmap = 0; | ||||
|   uint8_t fan_speed = 0; | ||||
|   uint8_t temp = 0; | ||||
|   uint8_t fan_pos = 0; | ||||
|   uint8_t th = 0; | ||||
|   uint8_t checksum = 0; | ||||
| }; | ||||
|  | ||||
| class EmmetiClimate : public climate_ir::ClimateIR { | ||||
|  public: | ||||
|   EmmetiClimate() | ||||
|       : climate_ir::ClimateIR(EMMETI_TEMP_MIN, EMMETI_TEMP_MAX, 1.0f, true, true, | ||||
|                               {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, | ||||
|                                climate::CLIMATE_FAN_HIGH}, | ||||
|                               {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {} | ||||
|  | ||||
|  protected: | ||||
|   // Transmit via IR the state of this climate controller | ||||
|   void transmit_state() override; | ||||
|   // Handle received IR Buffer | ||||
|   bool on_receive(remote_base::RemoteReceiveData data) override; | ||||
|   bool parse_state_frame_(EmmetiState curr_state); | ||||
|  | ||||
|   // setters | ||||
|   uint8_t set_mode_(); | ||||
|   uint8_t set_temp_(); | ||||
|   uint8_t set_fan_speed_(); | ||||
|   uint8_t gen_checksum_(); | ||||
|   uint8_t set_blades_(); | ||||
|  | ||||
|   // getters | ||||
|   climate::ClimateMode get_mode_(uint8_t mode); | ||||
|   climate::ClimateFanMode get_fan_speed_(uint8_t fan); | ||||
|   void get_blades_(uint8_t fanpos); | ||||
|   // get swing | ||||
|   climate::ClimateSwingMode get_swing_(uint8_t bitmap); | ||||
|   float get_temp_(uint8_t temp); | ||||
|  | ||||
|   // check if the received frame is valid | ||||
|   bool check_checksum_(uint8_t checksum); | ||||
|  | ||||
|   template<typename T> T reverse_(T val, size_t len); | ||||
|  | ||||
|   template<typename T> void add_(T val, size_t len, esphome::remote_base::RemoteTransmitData *ata); | ||||
|  | ||||
|   template<typename T> void add_(T val, esphome::remote_base::RemoteTransmitData *data); | ||||
|  | ||||
|   template<typename T> void reverse_add_(T val, size_t len, esphome::remote_base::RemoteTransmitData *data); | ||||
|  | ||||
|   uint8_t blades_ = EMMETI_BLADES_STOP; | ||||
| }; | ||||
|  | ||||
| }  // namespace emmeti | ||||
| }  // namespace esphome | ||||
							
								
								
									
										14
									
								
								tests/components/emmeti/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/components/emmeti/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| remote_transmitter: | ||||
|   id: tx | ||||
|   pin: ${remote_transmitter_pin} | ||||
|   carrier_duty_percent: 100% | ||||
|  | ||||
| remote_receiver: | ||||
|   id: rcvr | ||||
|   pin: ${remote_receiver_pin} | ||||
|  | ||||
| climate: | ||||
|   - platform: emmeti | ||||
|     name: Emmeti | ||||
|     receiver_id: rcvr | ||||
|     transmitter_id: tx | ||||
							
								
								
									
										5
									
								
								tests/components/emmeti/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/emmeti/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   remote_transmitter_pin: GPIO33 | ||||
|   remote_receiver_pin: GPIO32 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/emmeti/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/emmeti/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   remote_transmitter_pin: GPIO33 | ||||
|   remote_receiver_pin: GPIO32 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/emmeti/test.esp8266.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/emmeti/test.esp8266.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   remote_transmitter_pin: GPIO4 | ||||
|   remote_receiver_pin: GPIO5 | ||||
|  | ||||
| <<: !include common.yaml | ||||
		Reference in New Issue
	
	Block a user