mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Add Byron Doorbell RF protocol (#4718)
This commit is contained in:
		| @@ -242,6 +242,55 @@ async def build_dumpers(config): | ||||
|     return dumpers | ||||
|  | ||||
|  | ||||
| # ByronSX | ||||
| ( | ||||
|     ByronSXData, | ||||
|     ByronSXBinarySensor, | ||||
|     ByronSXTrigger, | ||||
|     ByronSXAction, | ||||
|     ByronSXDumper, | ||||
| ) = declare_protocol("ByronSX") | ||||
| BYRONSX_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.Required(CONF_ADDRESS): cv.All(cv.hex_int, cv.Range(min=0, max=0xFF)), | ||||
|         cv.Optional(CONF_COMMAND, default=0x10): cv.All( | ||||
|             cv.hex_int, cv.one_of(1, 2, 3, 5, 6, 9, 0xD, 0xE, 0x10, int=True) | ||||
|         ), | ||||
|     } | ||||
| ) | ||||
|  | ||||
|  | ||||
| @register_binary_sensor("byronsx", ByronSXBinarySensor, BYRONSX_SCHEMA) | ||||
| def byronsx_binary_sensor(var, config): | ||||
|     cg.add( | ||||
|         var.set_data( | ||||
|             cg.StructInitializer( | ||||
|                 ByronSXData, | ||||
|                 ("address", config[CONF_ADDRESS]), | ||||
|                 ("command", config[CONF_COMMAND]), | ||||
|             ) | ||||
|         ) | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @register_trigger("byronsx", ByronSXTrigger, ByronSXData) | ||||
| def byronsx_trigger(var, config): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| @register_dumper("byronsx", ByronSXDumper) | ||||
| def byronsx_dumper(var, config): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| @register_action("byronsx", ByronSXAction, BYRONSX_SCHEMA) | ||||
| async def byronsx_action(var, config, args): | ||||
|     template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint8) | ||||
|     cg.add(var.set_address(template_)) | ||||
|     template_ = await cg.templatable(config[CONF_COMMAND], args, cg.uint8) | ||||
|     cg.add(var.set_command(template_)) | ||||
|  | ||||
|  | ||||
| # CanalSat | ||||
| ( | ||||
|     CanalSatData, | ||||
|   | ||||
							
								
								
									
										134
									
								
								esphome/components/remote_base/byronsx_protocol.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								esphome/components/remote_base/byronsx_protocol.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | ||||
| #include "byronsx_protocol.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace remote_base { | ||||
|  | ||||
| static const char *const TAG = "remote.byronsx"; | ||||
|  | ||||
| static const uint32_t BIT_TIME_US = 333; | ||||
| static const uint8_t NBITS_ADDRESS = 8; | ||||
| static const uint8_t NBITS_COMMAND = 4; | ||||
| static const uint8_t NBITS_START_BIT = 1; | ||||
| static const uint8_t NBITS_DATA = NBITS_ADDRESS + NBITS_COMMAND /*+ NBITS_COMMAND*/; | ||||
|  | ||||
| /* | ||||
| ByronSX Protocol | ||||
| Each transmitted packet appears to consist of thirteen bits of PWM encoded | ||||
| data. Each bit period of aprox 1ms consists of a transmitter OFF period | ||||
| followed by a transmitter ON period. The 'on' and 'off' periods are either | ||||
| short (approx 332us) or long (664us). | ||||
|  | ||||
| A short 'off' followed by a long 'on' represents a '1' bit. | ||||
| A long 'off' followed by a short 'on' represents a '0' bit. | ||||
|  | ||||
| A the beginning of each packet is and initial 'off' period of approx 5.6ms | ||||
| followed by a short 'on'. | ||||
|  | ||||
| The data payload consists of twelve bits which appear to be an eight bit | ||||
| address floowied by a 4 bit chime number. | ||||
|  | ||||
| SAAAAAAAACCCC | ||||
|  | ||||
| Whese: | ||||
| S = the initial short start pulse | ||||
| A = The eight address bits | ||||
| C - The four chime bits | ||||
|  | ||||
| -------------------- | ||||
|  | ||||
| I have also used 'RFLink' software (RLink Firmware Version: 1.1 Revision: 48) | ||||
| to capture these packets, eg: | ||||
|  | ||||
| 20;19;Byron;ID=004f;SWITCH=02;CMD=ON;CHIME=02; | ||||
|  | ||||
| This module transmits and interprets packets in the same way as RFLink. | ||||
|  | ||||
| marshn | ||||
|  | ||||
| */ | ||||
|  | ||||
| void ByronSXProtocol::encode(RemoteTransmitData *dst, const ByronSXData &data) { | ||||
|   uint32_t out_data = 0x0; | ||||
|  | ||||
|   ESP_LOGD(TAG, "Send ByronSX: address=%04x command=%03x", data.address, data.command); | ||||
|  | ||||
|   out_data = data.address; | ||||
|   out_data <<= NBITS_COMMAND; | ||||
|   out_data |= data.command; | ||||
|  | ||||
|   ESP_LOGV(TAG, "Send ByronSX: out_data %03x", out_data); | ||||
|  | ||||
|   // Initial Mark start bit | ||||
|   dst->mark(1 * BIT_TIME_US); | ||||
|  | ||||
|   for (uint32_t mask = 1UL << (NBITS_DATA - 1); mask != 0; mask >>= 1) { | ||||
|     if (out_data & mask) { | ||||
|       dst->space(2 * BIT_TIME_US); | ||||
|       dst->mark(1 * BIT_TIME_US); | ||||
|     } else { | ||||
|       dst->space(1 * BIT_TIME_US); | ||||
|       dst->mark(2 * BIT_TIME_US); | ||||
|     } | ||||
|   } | ||||
|   // final space at end of packet | ||||
|   dst->space(17 * BIT_TIME_US); | ||||
| } | ||||
|  | ||||
| optional<ByronSXData> ByronSXProtocol::decode(RemoteReceiveData src) { | ||||
|   ByronSXData out{ | ||||
|       .address = 0, | ||||
|       .command = 0, | ||||
|   }; | ||||
|  | ||||
|   if (src.size() != (NBITS_DATA + NBITS_START_BIT) * 2) { | ||||
|     return {}; | ||||
|   } | ||||
|  | ||||
|   // Skip start bit | ||||
|   if (!src.expect_mark(BIT_TIME_US)) { | ||||
|     return {}; | ||||
|   } | ||||
|  | ||||
|   ESP_LOGVV(TAG, "%3d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", src.size(), src.peek(0), | ||||
|             src.peek(1), src.peek(2), src.peek(3), src.peek(4), src.peek(5), src.peek(6), src.peek(7), src.peek(8), | ||||
|             src.peek(9), src.peek(10), src.peek(11), src.peek(12), src.peek(13), src.peek(14), src.peek(15), | ||||
|             src.peek(16), src.peek(17), src.peek(18), src.peek(19)); | ||||
|  | ||||
|   ESP_LOGVV(TAG, "     %d %d %d %d %d %d", src.peek(20), src.peek(21), src.peek(22), src.peek(23), src.peek(24), | ||||
|             src.peek(25)); | ||||
|  | ||||
|   // Read data bits | ||||
|   uint32_t out_data = 0; | ||||
|   int8_t bit = NBITS_DATA; | ||||
|   while (--bit >= 0) { | ||||
|     if (src.expect_space(2 * BIT_TIME_US) && src.expect_mark(BIT_TIME_US)) { | ||||
|       out_data |= 1 << bit; | ||||
|     } else if (src.expect_space(BIT_TIME_US) && src.expect_mark(2 * BIT_TIME_US)) { | ||||
|       out_data |= 0 << bit; | ||||
|     } else { | ||||
|       ESP_LOGV(TAG, "Decode ByronSX: Fail 2, %2d %08x", bit, out_data); | ||||
|       return {}; | ||||
|     } | ||||
|     ESP_LOGVV(TAG, "Decode ByronSX: Data, %2d %08x", bit, out_data); | ||||
|   } | ||||
|  | ||||
|   // last bit followed by a long space | ||||
|   if (!src.peek_space_at_least(BIT_TIME_US)) { | ||||
|     ESP_LOGV(TAG, "Decode ByronSX: Fail 4 "); | ||||
|     return {}; | ||||
|   } | ||||
|  | ||||
|   out.command = (uint8_t) (out_data & 0xF); | ||||
|   out_data >>= NBITS_COMMAND; | ||||
|   out.address = (uint16_t) (out_data & 0xFF); | ||||
|  | ||||
|   return out; | ||||
| } | ||||
|  | ||||
| void ByronSXProtocol::dump(const ByronSXData &data) { | ||||
|   ESP_LOGD(TAG, "Received ByronSX: address=0x%08X, command=0x%02x", data.address, data.command); | ||||
| } | ||||
|  | ||||
| }  // namespace remote_base | ||||
| }  // namespace esphome | ||||
							
								
								
									
										46
									
								
								esphome/components/remote_base/byronsx_protocol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								esphome/components/remote_base/byronsx_protocol.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "remote_base.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace remote_base { | ||||
|  | ||||
| struct ByronSXData { | ||||
|   uint8_t address; | ||||
|   uint8_t command; | ||||
|  | ||||
|   bool operator==(const ByronSXData &rhs) const { | ||||
|     // Treat 0x10 as a special, wildcard command/chime | ||||
|     // This allows us to match on just the address if wanted. | ||||
|     if (address != rhs.address) { | ||||
|       return false; | ||||
|     } | ||||
|     return (rhs.command == 0x10 || command == rhs.command); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class ByronSXProtocol : public RemoteProtocol<ByronSXData> { | ||||
|  public: | ||||
|   void encode(RemoteTransmitData *dst, const ByronSXData &data) override; | ||||
|   optional<ByronSXData> decode(RemoteReceiveData src) override; | ||||
|   void dump(const ByronSXData &data) override; | ||||
| }; | ||||
|  | ||||
| DECLARE_REMOTE_PROTOCOL(ByronSX) | ||||
|  | ||||
| template<typename... Ts> class ByronSXAction : public RemoteTransmitterActionBase<Ts...> { | ||||
|  public: | ||||
|   TEMPLATABLE_VALUE(uint8_t, address) | ||||
|   TEMPLATABLE_VALUE(uint8_t, command) | ||||
|  | ||||
|   void encode(RemoteTransmitData *dst, Ts... x) override { | ||||
|     ByronSXData data{}; | ||||
|     data.address = this->address_.value(x...); | ||||
|     data.command = this->command_.value(x...); | ||||
|     ByronSXProtocol().encode(dst, data); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace remote_base | ||||
| }  // namespace esphome | ||||
		Reference in New Issue
	
	Block a user