mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add AEHA IR Protocol (#3726)
This commit is contained in:
		| @@ -1338,3 +1338,48 @@ def midea_dumper(var, config): | |||||||
| ) | ) | ||||||
| async def midea_action(var, config, args): | async def midea_action(var, config, args): | ||||||
|     cg.add(var.set_code(config[CONF_CODE])) |     cg.add(var.set_code(config[CONF_CODE])) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # AEHA | ||||||
|  | AEHAData, AEHABinarySensor, AEHATrigger, AEHAAction, AEHADumper = declare_protocol( | ||||||
|  |     "AEHA" | ||||||
|  | ) | ||||||
|  | AEHA_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_ADDRESS): cv.hex_uint16_t, | ||||||
|  |         cv.Required(CONF_DATA): cv.All( | ||||||
|  |             [cv.Any(cv.hex_uint8_t, cv.uint8_t)], | ||||||
|  |             cv.Length(min=2, max=35), | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @register_binary_sensor("aeha", AEHABinarySensor, AEHA_SCHEMA) | ||||||
|  | def aeha_binary_sensor(var, config): | ||||||
|  |     cg.add( | ||||||
|  |         var.set_data( | ||||||
|  |             cg.StructInitializer( | ||||||
|  |                 AEHAData, | ||||||
|  |                 ("address", config[CONF_ADDRESS]), | ||||||
|  |                 ("data", config[CONF_DATA]), | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @register_trigger("aeha", AEHATrigger, AEHAData) | ||||||
|  | def aeha_trigger(var, config): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @register_dumper("aeha", AEHADumper) | ||||||
|  | def aeha_dumper(var, config): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @register_action("aeha", AEHAAction, AEHA_SCHEMA) | ||||||
|  | async def aeha_action(var, config, args): | ||||||
|  |     template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint16) | ||||||
|  |     cg.add(var.set_address(template_)) | ||||||
|  |     cg.add(var.set_data(config[CONF_DATA])) | ||||||
|   | |||||||
							
								
								
									
										103
									
								
								esphome/components/remote_base/aeha_protocol.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								esphome/components/remote_base/aeha_protocol.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | |||||||
|  | #include "aeha_protocol.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include <cinttypes> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace remote_base { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "remote.aeha"; | ||||||
|  |  | ||||||
|  | static const uint16_t BITWISE = 425; | ||||||
|  | static const uint16_t HEADER_HIGH_US = BITWISE * 8; | ||||||
|  | static const uint16_t HEADER_LOW_US = BITWISE * 4; | ||||||
|  | static const uint16_t BIT_HIGH_US = BITWISE; | ||||||
|  | static const uint16_t BIT_ONE_LOW_US = BITWISE * 3; | ||||||
|  | static const uint16_t BIT_ZERO_LOW_US = BITWISE; | ||||||
|  | static const uint16_t TRAILER = BITWISE; | ||||||
|  |  | ||||||
|  | void AEHAProtocol::encode(RemoteTransmitData *dst, const AEHAData &data) { | ||||||
|  |   dst->set_carrier_frequency(38000); | ||||||
|  |   dst->reserve(2 + 32 + (data.data.size() * 2) + 1); | ||||||
|  |  | ||||||
|  |   dst->item(HEADER_HIGH_US, HEADER_LOW_US); | ||||||
|  |  | ||||||
|  |   for (uint16_t mask = 1 << 15; mask != 0; mask >>= 1) { | ||||||
|  |     if (data.address & mask) { | ||||||
|  |       dst->item(BIT_HIGH_US, BIT_ONE_LOW_US); | ||||||
|  |     } else { | ||||||
|  |       dst->item(BIT_HIGH_US, BIT_ZERO_LOW_US); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (uint8_t bit : data.data) { | ||||||
|  |     for (uint8_t mask = 1 << 7; mask != 0; mask >>= 1) { | ||||||
|  |       if (bit & mask) { | ||||||
|  |         dst->item(BIT_HIGH_US, BIT_ONE_LOW_US); | ||||||
|  |       } else { | ||||||
|  |         dst->item(BIT_HIGH_US, BIT_ZERO_LOW_US); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   dst->mark(TRAILER); | ||||||
|  | } | ||||||
|  | optional<AEHAData> AEHAProtocol::decode(RemoteReceiveData src) { | ||||||
|  |   AEHAData out{ | ||||||
|  |       .address = 0, | ||||||
|  |       .data = {}, | ||||||
|  |   }; | ||||||
|  |   if (!src.expect_item(HEADER_HIGH_US, HEADER_LOW_US)) | ||||||
|  |     return {}; | ||||||
|  |  | ||||||
|  |   for (uint16_t mask = 1 << 15; mask != 0; mask >>= 1) { | ||||||
|  |     if (src.expect_item(BIT_HIGH_US, BIT_ONE_LOW_US)) { | ||||||
|  |       out.address |= mask; | ||||||
|  |     } else if (src.expect_item(BIT_HIGH_US, BIT_ZERO_LOW_US)) { | ||||||
|  |       out.address &= ~mask; | ||||||
|  |     } else { | ||||||
|  |       return {}; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (uint8_t pos = 0; pos < 35; pos++) { | ||||||
|  |     uint8_t data = 0; | ||||||
|  |     for (uint8_t mask = 1 << 7; mask != 0; mask >>= 1) { | ||||||
|  |       if (src.expect_item(BIT_HIGH_US, BIT_ONE_LOW_US)) { | ||||||
|  |         data |= mask; | ||||||
|  |       } else if (src.expect_item(BIT_HIGH_US, BIT_ZERO_LOW_US)) { | ||||||
|  |         data &= ~mask; | ||||||
|  |       } else if (pos > 1 && src.expect_mark(TRAILER)) { | ||||||
|  |         return out; | ||||||
|  |       } else { | ||||||
|  |         return {}; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     out.data.push_back(data); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (src.expect_mark(TRAILER)) { | ||||||
|  |     return out; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return {}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string AEHAProtocol::format_data_(const std::vector<uint8_t> &data) { | ||||||
|  |   std::string out; | ||||||
|  |   for (uint8_t byte : data) { | ||||||
|  |     char buf[6]; | ||||||
|  |     sprintf(buf, "0x%02X,", byte); | ||||||
|  |     out += buf; | ||||||
|  |   } | ||||||
|  |   out.pop_back(); | ||||||
|  |   return out; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AEHAProtocol::dump(const AEHAData &data) { | ||||||
|  |   auto data_str = format_data_(data.data); | ||||||
|  |   ESP_LOGD(TAG, "Received AEHA: address=0x%04X, data=[%s]", data.address, data_str.c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace remote_base | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										42
									
								
								esphome/components/remote_base/aeha_protocol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								esphome/components/remote_base/aeha_protocol.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "remote_base.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace remote_base { | ||||||
|  |  | ||||||
|  | struct AEHAData { | ||||||
|  |   uint16_t address; | ||||||
|  |   std::vector<uint8_t> data; | ||||||
|  |  | ||||||
|  |   bool operator==(const AEHAData &rhs) const { return address == rhs.address && data == rhs.data; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class AEHAProtocol : public RemoteProtocol<AEHAData> { | ||||||
|  |  public: | ||||||
|  |   void encode(RemoteTransmitData *dst, const AEHAData &data) override; | ||||||
|  |   optional<AEHAData> decode(RemoteReceiveData src) override; | ||||||
|  |   void dump(const AEHAData &data) override; | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   std::string format_data_(const std::vector<uint8_t> &data); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | DECLARE_REMOTE_PROTOCOL(AEHA) | ||||||
|  |  | ||||||
|  | template<typename... Ts> class AEHAAction : public RemoteTransmitterActionBase<Ts...> { | ||||||
|  |  public: | ||||||
|  |   TEMPLATABLE_VALUE(uint16_t, address) | ||||||
|  |   TEMPLATABLE_VALUE(std::vector<uint8_t>, data) | ||||||
|  |  | ||||||
|  |   void set_data(const std::vector<uint8_t> &data) { data_ = data; } | ||||||
|  |   void encode(RemoteTransmitData *dst, Ts... x) override { | ||||||
|  |     AEHAData data{}; | ||||||
|  |     data.address = this->address_.value(x...); | ||||||
|  |     data.data = this->data_.value(x...); | ||||||
|  |     AEHAProtocol().encode(dst, data); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace remote_base | ||||||
|  | }  // namespace esphome | ||||||
| @@ -2085,6 +2085,13 @@ switch: | |||||||
|     turn_on_action: |     turn_on_action: | ||||||
|       remote_transmitter.transmit_raw: |       remote_transmitter.transmit_raw: | ||||||
|         code: [1000, -1000] |         code: [1000, -1000] | ||||||
|  |   - platform: template | ||||||
|  |     name: AEHA | ||||||
|  |     id: eaha_hitachi_climate_power_on | ||||||
|  |     turn_on_action: | ||||||
|  |       remote_transmitter.transmit_aeha: | ||||||
|  |         address: 0x8008 | ||||||
|  |         data: [0x00, 0x02, 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x49, 0xB6, 0xC8, 0x37, 0x16, 0xE9, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xCA, 0x35, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF] | ||||||
|   - platform: template |   - platform: template | ||||||
|     name: Living Room Lights |     name: Living Room Lights | ||||||
|     id: livingroom_lights |     id: livingroom_lights | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user