mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add Byron Doorbell RF protocol (#4718)
This commit is contained in:
		| @@ -242,6 +242,55 @@ async def build_dumpers(config): | |||||||
|     return dumpers |     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 | # CanalSat | ||||||
| ( | ( | ||||||
|     CanalSatData, |     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