mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	[remote_base] add support for Dyson cool AM07 tower fan (#10163)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
		| @@ -17,6 +17,7 @@ from esphome.const import ( | ||||
|     CONF_FAMILY, | ||||
|     CONF_GROUP, | ||||
|     CONF_ID, | ||||
|     CONF_INDEX, | ||||
|     CONF_INVERTED, | ||||
|     CONF_LEVEL, | ||||
|     CONF_MAGNITUDE, | ||||
| @@ -616,6 +617,49 @@ async def dooya_action(var, config, args): | ||||
|     cg.add(var.set_check(template_)) | ||||
|  | ||||
|  | ||||
| # Dyson | ||||
| DysonData, DysonBinarySensor, DysonTrigger, DysonAction, DysonDumper = declare_protocol( | ||||
|     "Dyson" | ||||
| ) | ||||
| DYSON_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.Required(CONF_CODE): cv.hex_uint16_t, | ||||
|         cv.Optional(CONF_INDEX, default=0xFF): cv.hex_uint8_t, | ||||
|     } | ||||
| ) | ||||
|  | ||||
|  | ||||
| @register_binary_sensor("dyson", DysonBinarySensor, DYSON_SCHEMA) | ||||
| def dyson_binary_sensor(var, config): | ||||
|     cg.add( | ||||
|         var.set_data( | ||||
|             cg.StructInitializer( | ||||
|                 DysonData, | ||||
|                 ("code", config[CONF_CODE]), | ||||
|                 ("index", config[CONF_INDEX]), | ||||
|             ) | ||||
|         ) | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @register_trigger("dyson", DysonTrigger, DysonData) | ||||
| def dyson_trigger(var, config): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| @register_dumper("dyson", DysonDumper) | ||||
| def dyson_dumper(var, config): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| @register_action("dyson", DysonAction, DYSON_SCHEMA) | ||||
| async def dyson_action(var, config, args): | ||||
|     template_ = await cg.templatable(config[CONF_CODE], args, cg.uint16) | ||||
|     cg.add(var.set_code(template_)) | ||||
|     template_ = await cg.templatable(config[CONF_INDEX], args, cg.uint8) | ||||
|     cg.add(var.set_index(template_)) | ||||
|  | ||||
|  | ||||
| # JVC | ||||
| JVCData, JVCBinarySensor, JVCTrigger, JVCAction, JVCDumper = declare_protocol("JVC") | ||||
| JVC_SCHEMA = cv.Schema({cv.Required(CONF_DATA): cv.hex_uint32_t}) | ||||
|   | ||||
							
								
								
									
										71
									
								
								esphome/components/remote_base/dyson_protocol.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								esphome/components/remote_base/dyson_protocol.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| #include "dyson_protocol.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| #include <cinttypes> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace remote_base { | ||||
|  | ||||
| static const char *const TAG = "remote.dyson"; | ||||
|  | ||||
| // pulsewidth [µs] | ||||
| constexpr uint32_t PW_MARK_US = 780; | ||||
| constexpr uint32_t PW_SHORT_US = 720; | ||||
| constexpr uint32_t PW_LONG_US = 1500; | ||||
| constexpr uint32_t PW_START_US = 2280; | ||||
|  | ||||
| // MSB of 15 bit dyson code | ||||
| constexpr uint16_t MSB_DYSON = (1 << 14); | ||||
|  | ||||
| // required symbols in transmit buffer = (start_symbol + 15 data_symbols) | ||||
| constexpr uint32_t N_SYMBOLS_REQ = 2u * (1 + 15); | ||||
|  | ||||
| void DysonProtocol::encode(RemoteTransmitData *dst, const DysonData &data) { | ||||
|   uint32_t raw_code = (data.code << 2) + (data.index & 3); | ||||
|   dst->set_carrier_frequency(36000); | ||||
|   dst->reserve(N_SYMBOLS_REQ + 1); | ||||
|   dst->item(PW_START_US, PW_SHORT_US); | ||||
|   for (uint16_t mask = MSB_DYSON; mask != 0; mask >>= 1) { | ||||
|     if (mask == (mask & raw_code)) { | ||||
|       dst->item(PW_MARK_US, PW_LONG_US); | ||||
|     } else { | ||||
|       dst->item(PW_MARK_US, PW_SHORT_US); | ||||
|     } | ||||
|   } | ||||
|   dst->mark(PW_MARK_US);  // final carrier pulse | ||||
| } | ||||
|  | ||||
| optional<DysonData> DysonProtocol::decode(RemoteReceiveData src) { | ||||
|   uint32_t n_received = static_cast<uint32_t>(src.size()); | ||||
|   uint16_t raw_code = 0; | ||||
|   DysonData data{ | ||||
|       .code = 0, | ||||
|       .index = 0, | ||||
|   }; | ||||
|   if (n_received < N_SYMBOLS_REQ) | ||||
|     return {};  // invalid frame length | ||||
|   if (!src.expect_item(PW_START_US, PW_SHORT_US)) | ||||
|     return {};  // start not found | ||||
|   for (uint16_t mask = MSB_DYSON; mask != 0; mask >>= 1) { | ||||
|     if (src.expect_item(PW_MARK_US, PW_SHORT_US)) { | ||||
|       raw_code &= ~mask;  // zero detected | ||||
|     } else if (src.expect_item(PW_MARK_US, PW_LONG_US)) { | ||||
|       raw_code |= mask;  // one detected | ||||
|     } else { | ||||
|       return {};  // invalid data item | ||||
|     } | ||||
|   } | ||||
|   data.code = raw_code >> 2;          // extract button code | ||||
|   data.index = raw_code & 3;          // extract rolling index | ||||
|   if (src.expect_mark(PW_MARK_US)) {  // check total length | ||||
|     return data; | ||||
|   } | ||||
|   return {};  // frame not complete | ||||
| } | ||||
|  | ||||
| void DysonProtocol::dump(const DysonData &data) { | ||||
|   ESP_LOGI(TAG, "Dyson: code=0x%x rolling index=%d", data.code, data.index); | ||||
| } | ||||
|  | ||||
| }  // namespace remote_base | ||||
| }  // namespace esphome | ||||
							
								
								
									
										46
									
								
								esphome/components/remote_base/dyson_protocol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								esphome/components/remote_base/dyson_protocol.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "remote_base.h" | ||||
|  | ||||
| #include <cinttypes> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace remote_base { | ||||
|  | ||||
| static constexpr uint8_t IGNORE_INDEX = 0xFF; | ||||
|  | ||||
| struct DysonData { | ||||
|   uint16_t code;  // the button, e.g. power, swing, fan++, ... | ||||
|   uint8_t index;  // the rolling index counter | ||||
|   bool operator==(const DysonData &rhs) const { | ||||
|     if (IGNORE_INDEX == index || IGNORE_INDEX == rhs.index) { | ||||
|       return code == rhs.code; | ||||
|     } | ||||
|     return code == rhs.code && index == rhs.index; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class DysonProtocol : public RemoteProtocol<DysonData> { | ||||
|  public: | ||||
|   void encode(RemoteTransmitData *dst, const DysonData &data) override; | ||||
|   optional<DysonData> decode(RemoteReceiveData src) override; | ||||
|   void dump(const DysonData &data) override; | ||||
| }; | ||||
|  | ||||
| DECLARE_REMOTE_PROTOCOL(Dyson) | ||||
|  | ||||
| template<typename... Ts> class DysonAction : public RemoteTransmitterActionBase<Ts...> { | ||||
|  public: | ||||
|   TEMPLATABLE_VALUE(uint16_t, code) | ||||
|   TEMPLATABLE_VALUE(uint8_t, index) | ||||
|  | ||||
|   void encode(RemoteTransmitData *dst, Ts... x) override { | ||||
|     DysonData data{}; | ||||
|     data.code = this->code_.value(x...); | ||||
|     data.index = this->index_.value(x...); | ||||
|     DysonProtocol().encode(dst, data); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace remote_base | ||||
| }  // namespace esphome | ||||
| @@ -48,6 +48,11 @@ on_drayton: | ||||
|     - logger.log: | ||||
|         format: "on_drayton: %u %u %u" | ||||
|         args: ["x.address", "x.channel", "x.command"] | ||||
| on_dyson: | ||||
|   then: | ||||
|     - logger.log: | ||||
|         format: "on_dyson: %u %u" | ||||
|         args: ["x.code", "x.index"] | ||||
| on_gobox: | ||||
|   then: | ||||
|     - logger.log: | ||||
|   | ||||
| @@ -6,6 +6,13 @@ button: | ||||
|       remote_transmitter.transmit_beo4: | ||||
|         source: 0x01 | ||||
|         command: 0x0C | ||||
|   - platform: template | ||||
|     name: Dyson fan up | ||||
|     id: dyson_fan_up | ||||
|     on_press: | ||||
|       remote_transmitter.transmit_dyson: | ||||
|         code: 0x1215 | ||||
|         index: 0x0 | ||||
|   - platform: template | ||||
|     name: JVC Off | ||||
|     id: living_room_lights_on | ||||
|   | ||||
		Reference in New Issue
	
	Block a user