{"id":17800685,"url":"https://github.com/tofurky/kidde_cc1101","last_synced_at":"2025-03-17T09:31:08.436Z","repository":{"id":65284313,"uuid":"266927224","full_name":"tofurky/kidde_cc1101","owner":"tofurky","description":"Experiments with Kidde / Wink 433MHz wireless protocol","archived":false,"fork":false,"pushed_at":"2020-07-25T18:56:45.000Z","size":2753,"stargazers_count":13,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-27T22:10:47.284Z","etag":null,"topics":["433mhz","cc1101","home-assistant","iot","kidde","wink"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tofurky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-26T02:36:25.000Z","updated_at":"2024-07-08T00:00:32.000Z","dependencies_parsed_at":"2023-01-16T15:01:42.947Z","dependency_job_id":null,"html_url":"https://github.com/tofurky/kidde_cc1101","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tofurky%2Fkidde_cc1101","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tofurky%2Fkidde_cc1101/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tofurky%2Fkidde_cc1101/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tofurky%2Fkidde_cc1101/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tofurky","download_url":"https://codeload.github.com/tofurky/kidde_cc1101/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243858929,"owners_count":20359260,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["433mhz","cc1101","home-assistant","iot","kidde","wink"],"created_at":"2024-10-27T12:27:43.534Z","updated_at":"2025-03-17T09:31:07.177Z","avatar_url":"https://github.com/tofurky.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kidde_cc1101\n\n- [Disclaimer](#disclaimer)  \n- [License](#license)  \n- [Introduction](#introduction)  \n- [Files](#files)  \n- [Protocol](#protocol)  \n- [Pinout](#pinout)  \n- [Firmware](#firmware)  \n\n## Disclaimer\n\nNone of the information/code in this repository is suitable for real-world use in life safety \napplications. It is for educational/informational purposes only.\n\n## License\n[Unlicense](https://unlicense.org/). See [UNLICENSE](/UNLICENSE). Where applicable, any copyrights \nand patents relating to the protocol itself supersede this.\n\n## Introduction\n\nThis [repo](https://github.com/tofurky/kidde_cc1101) contains the result of my reverse engineering \nof the [433MHz](https://en.wikipedia.org/wiki/LPD433) protocol used by Kidde \n[KN-COSM-B-RF](https://www.kidde.com/home-safety/en/us/products/fire-safety/combination-smoke-co-alarms/kn-cosm-b-rf/) \nsmoke/CO alarms. It is not known whether other \"Wireless Interconnect\" models use the same/similar \nprotocol as I do not own them.\n\nThe protocol is rather simple - no encryption or obfuscation is used and there are only a few \ndistinct commands. The most mysterious part of it is the register settings used in the TI CC1101 \nradios. There are 40+ 8-bit registers on the CC1101, so simply guessing them seemed out of the \nquestion (for me, anyways).\n\nInstead, a cheap [logic analyzer](https://sigrok.org/wiki/Fx2lafw) was connected between the \n[PIC16F883](https://www.microchip.com/wwwproducts/en/PIC16F883) and \n[CC1101](https://www.ti.com/product/CC1101) on a first-generation \n[Wink Hub](https://www.wink.com/products/wink-hub/), and \n[PulseView's](https://sigrok.org/wiki/PulseView) \n[CC1101 decoder](https://sigrok.org/wiki/Protocol_decoder:Cc1101) was used to make sense of the \ncaptured [SPI](https://sigrok.org/wiki/Protocol_decoder:Spi) data.\n\n## Files\n\nThe following files are contained within this repo:\n- [README.md](/README.md): this README  \n- [UNLICENSE](/UNLICENSE): the (UN)LICENSE  \n- [kidde_cc1101.ino](/arduino/kidde_cc1101.ino): Arduino firmware tailored to ATmega328P  \n- [stm32_cc1101.ino](/stm32duino/stm32_cc1101.ino): example [STM32duino](https://github.com/stm32duino) \nsketch implementing barebones receiver, with optional test mode to transmit  \n- [wink_cc1101_2020-03-07.sr](/pulseview/wink_cc1101_2020-03-07.sr): PulseView capture of PIC16F883 \ninitializing CC1101 during power on of Wink Hub  \n- [pulseview.png](/image/pulseview.png): screenshot of said PulseView capture  \n- [wink_cc1101_pic16f883_pinout.jpg](/image/wink_cc1101_pic16f883_pinout.jpg): annotated image of \nlogic analyzer connection to Wink Hub, also shown in the [Pinout](#pinout) section below  \n- [wink_cc1101_pic16f883_large.jpg](/image/wink_cc1101_pic16f883_large.jpg): larger image showing \n layout of Wink Hub PCB  \n\n## Protocol\n\nThe data coming from the CC1101 can be described like so:\n\n```\n struct kidde_pkt {  \n   uint8_t address;  \n   uint8_t command;  \n   uint8_t suffix[2];  \n   uint8_t rssi;  \n   uint8_t crc_lqi;  \n };  \n```\n\n- `address`: equivalent to the DIP switches located in the smoke detector's battery compartment\n- `command`: one of _TEST_, _HUSH_, _CO_, _SMOKE_, or _BATTERY_, described in more detail below\n- `suffix`: a fixed value of `0x9655` (YMMV - I only have a sample size of 1)\n- `rssi`: the signal strength of the received packet\n- `crc_lqi`: MSB represents CRC OK, lower 7 bits represent link quality\n\nThe `rssi` and `crc_lqi` are not sent over the air - they are appended to each packet in the RX \nFIFO by the CC1101 chip per the register settings.\n\nThe `command` field will contain one of the following:\n\n```\n #define KIDDE_COMMAND (0x80)  \n #define KIDDE_TEST (KIDDE_COMMAND | 0x00)  \n #define KIDDE_HUSH (KIDDE_COMMAND | 0x01)  \n #define KIDDE_CO (KIDDE_COMMAND | 0x02)  \n #define KIDDE_SMOKE (KIDDE_COMMAND | 0x03)  \n #define KIDDE_BATTERY (KIDDE_COMMAND | 0x0D)  \n```\n\nIn practice, all commands appear to have the MSB set (`KIDDE_COMMAND` above). However, detectors \n(and Wink) will respond to commands without the MSB set. The Wink Hub does not acknowledge \n_BATTERY_ without the MSB set.\n\n- `KIDDE_TEST`: sent by the detector when the test button is pressed\n- `KIDDE_HUSH`: sent by the detector when the test button is held while an alarm is active\n- `KIDDE_CO`: sent by the detector when CO is detected\n- `KIDDE_SMOKE`: sent by the detector when smoke is detected\n- `KIDDE_BATTERY`: periodically sent by the detector if the battery is low\n\nThe detectors both send and receive commands. If a single detector goes off, other detectors within \nrange will start alarming as well. The exception to this appears to be the _BATTERY_ command.\n\nThe _HUSH_ command, when received by an alarming detector, should silence the alarm. I had mixed \nresults when attempting to silence an active alarm by transmitting this command.\n\nA detector will only respond to commands if the `address` field matches that set by the DIP \nswitches in its battery compartment.\n\nThe detector appears to be in a low-power sleep state most of the time to preserve battery life. \nAs a result of this, and probably to ensure reliable transmission, an alarming detector does not \nsend just a single or a few packets. Instead, over 1000 packets are sent when a detector broadcasts \nan alarm. Some rough measurement of the received data shows about 10ms delay between packets.\n\n## Pinout\n\nThe PIC16F883 as used by the Wink Hub only has a single SPI interface, so it was rather simple to \nfigure out how things were wired up. The trickiest part was trying to get two of my HP logic probes \non neighboring pins. For one of the connections (CS), I clipped onto a resistor intead of an MCU \nlead.\n\n![Wink Hub CC1101 pinout](/image/wink_cc1101_pic16f883_pinout.jpg?raw=true)\n\n## Firmware\n\n- [Background](#background)  \n- [Requirements](#requirements)  \n- [Configuring](#configuring)  \n- [Example commands](#example-commands)  \n- [Example output](#example-output)  \n- [Example Home Assistant configuration](#example-home-assistant-configuration)  \n\n### Background\n\nTwo firmwares are included in this repo - [stm32_cc1101.ino](/stm32duino/stm32_cc1101.ino), which \nis a more simple proof-of-concept that can both send and receive the Kidde protocol, and was not \nintended for much beyond that, and [kidde_cc1101.ino](/arduino/kidde_cc1101.ino), which I created \nso I could use my smoke detector with [Home Assistant](https://www.home-assistant.io/).\n\n[kidde_cc1101.ino](/arduino/kidde_cc1101.ino) was developed using a [RM1101-USB-232](https://www.ebay.com/itm/433Mhz-CC1101-USB-Wireless-RF-Transceiver-Module-10mW-USB-UART-MAX232-RS232/311565600262) \nwhich unfortunately wasn't suitable in its stock form due to the SPI programming interface being \nfused off, and because the CC1101 isn't wired up to the ATmega48PA using hardware SPI pins (no idea \nwhy). So, I desoldered and replaced the ATmega48PA with an ATmega328P and added jumpers to connect \nthe hardware SPI interface to the CC1101. Not pretty, but it works. Some pics of the before/after \ncan be found [here](https://imgur.com/a/ixWAovH). Something like a [SIGNALduino](http://wiki.in-circuit.de/index.php5?title=SIGNALduino_Stick) \nwould be a better route to go, though they're relatively pricey.\n\n### Requirements\n\n[kidde_cc1101.ino](/arduino/kidde_cc1101.ino) should work on any ATmega board \u003e= ATmega328P (given \nRAM / flash requirements) as long as hardware SPI and GDO2 are connected to the CC1101 module. Note \nthat CC1101 operates at 3.3V so the ATmega should operate at 3.3V or have appropriate level \nshifting.\n\nThe following external libraries are used:\n- [ArduinoJson](https://arduinojson.org/)\n- [MemoryFree](https://github.com/McNeight/MemoryFree) (optional, for debug logging)\n\n[MiniCore](https://github.com/MCUdude/MiniCore) was originally chosen due to it supporting the \nATmega48, however it stuck even after swapping the chip for a ATmega328P. It allows easily \nspecifying things like the \"non-standard\" 8MHz crystal found on the RM1101-USB-232 and other 3.3V \nboards as well as BOD fuse settings. However, the standard Arduino core will work as well, but \nyou might need to edit boards.txt and replace e.g. `uno.build.f_cpu=16000000L` with \n`uno.build.f_cpu=8000000L` if your board is 8MHz.\n\n### Configuring\n\nInteraction with [kidde_cc1101.ino](/arduino/kidde_cc1101.ino) is via JSON sent over the UART. The \ndefault settings are as follows:\n- log level of INFO (minimal non-alarm chatter)  \n- smoke detector address of 0b00000000 (factory dip switch settings, IIRC)  \n- alarm expiry of 10s (JSON expiry message is sent 10s after the last packet is rx'd from detector)  \n- 38400 baud (should work for both 8MHz and 16MHz boards)  \n\nA few compile-time defines are available:\n- `LOG_LEVEL` - if compiling without `DYNAMIC_LOG`, log-level is fixed at this  \n- `DYNAMIC_LOG` - allows changing log level at runtime, and subsequently stores **all** log messages in flash  \n- `MEMORY_USAGE` - at TRACE log-level, will output memory usage. Requires [MemoryFree](https://github.com/McNeight/MemoryFree) library  \n- `ADDRESS_MAX` - maximum number of monitored addresses. Each address requires ~96 bytes of RAM. Default is 4  \n- `CS`, `MOSI`, `MISO`, `SCLK`, `GDO0`, `GDO2`, `LED` - corresponding pins on ATmega. Note that there are separate sections depending on if MiniCore or standard Arduino is used  \n- `RM1101_USB_232`, `EN`, `ORIG_SCLK`, `ORIG_MOSI`, `ORIG_MISO` - only relevant if you're using a modified RM1101-USB-232. EN is the amplifier enable pin  \n- `SPISettings CC1101()` - if you want to use an SPI speed other than 1MHz  \n\n### Example commands\n\nAssuming that the connected ATmega's serial port is `/dev/ttyUSB0`:\n\nChange the baud to 500000:  \n`echo '{\"type\":\"set\",\"key\":\"baud\",\"value\":500000}' \u003e\u003e /dev/ttyUSB0`\n\nChange the baud to 115200:  \n`echo '{\"type\":\"set\",\"key\":\"baud\",\"value\":115200}' \u003e\u003e /dev/ttyUSB0`\n\nMonitor addresses 0x00, 0xAA, 0xCC, and 0xBB:  \n`echo '{\"type\":\"set\",\"key\":\"address\",\"value\":[0,170,204,187]}' \u003e\u003e /dev/ttyUSB0`\n\nMonitor address 0xFF:  \n`echo '{\"type\":\"set\",\"key\":\"address\",\"value\":[255]}' \u003e\u003e /dev/ttyUSB0`\n\nSet alarm expiry to 60s:  \n`echo '{\"type\":\"set\",\"key\":\"expiry\",\"value\":60}' \u003e\u003e /dev/ttyUSB0`\n\nSet alarm expiry to 5m:  \n`echo '{\"type\":\"set\",\"key\":\"expiry\",\"value\":300}' \u003e\u003e /dev/ttyUSB0`\n\nEnable promiscuous mode (note: this disables normal stateful alarm functionality):  \n`echo '{\"type\":\"set\",\"key\":\"promisc\",\"value\":true}' \u003e\u003e /dev/ttyUSB0`\n\nDisable promiscuous mode:  \n`echo '{\"type\":\"set\",\"key\":\"promisc\",\"value\":false}' \u003e\u003e /dev/ttyUSB0`\n\nSet log level to TRACE (requires compiling with `DYNAMIC_LOG`):  \n`echo '{\"type\":\"set\",\"key\":\"log_level\",\"value\":\"trace\"}' \u003e\u003e /dev/ttyUSB0`\n\nClear EEPROM (requires reset to take effect):  \n`echo '{\"type\":\"set\",\"key\":\"clear\"}' \u003e\u003e /dev/ttyUSB0`\n\nReset ATmega:  \n`echo '{\"type\":\"set\",\"key\":\"reset\"}' \u003e\u003e /dev/ttyUSB0`\n\nJump to bootloader (requires Optiboot \u003e= 7):  \n`echo '{\"type\":\"set\",\"key\":\"bootloader\"}' \u003e\u003e /dev/ttyUSB0`\n\nRecover from bad baud (or just reflash with `EEPROM_MAGIC` changed to something other than `{'k', 'i', 'd', 'd', 'e'}`):  \n```\nstty -F /dev/ttyUSB0 115200 # this should be the baud rate you set\nperl -MTime::HiRes -e '$|++; my $cmd = q|{\"type\":\"set\",\"key\":\"clear\"}|; foreach my $byte (split(\"\", $cmd)) { print $byte; Time::HiRes::sleep(0.05) } print \"\\n\";' \u003e\u003e /dev/ttyUSB0`\n```\nThen cycle power.\n\n### Example output\n\nBoard reset at INFO log level:\n```\n{\"millis\":0,\"type\":\"log\",\"level\":\"info\",\"caller\":\"setup\",\"msg\":\"setup\"}\n{\"address\":[170],\"expiry\":10,\"baud\":500000,\"promisc\":false}\n{\"millis\":1007,\"type\":\"log\",\"level\":\"info\",\"caller\":\"resetCC1101\",\"msg\":\"reset took 2168 us\"}\n{\"type\":\"chip_info\",\"status\":15,\"partnum\":0,\"version\":20}\n{\"millis\":1013,\"type\":\"log\",\"level\":\"info\",\"caller\":\"calibrateCC1101\",\"msg\":\"calibration took 1072 us\"}\n```\n\nBelow are artificially generated alarms - the normal duration is 10s for a test, and indefinite for smoke/CO.\n\nSmoke detected and subsequent expiry:\n```\n{\"millis\":70160,\"type\":\"alarm\",\"address\":170,\"command\":\"smoke\",\"min_rssi\":4,\"max_rssi\":4,\"duration\":0,\"count\":1,\"active\":true}\n{\"millis\":98447,\"type\":\"alarm\",\"address\":170,\"command\":\"smoke\",\"min_rssi\":1,\"max_rssi\":252,\"duration\":17447,\"count\":10,\"active\":false}\n```\n\nCO detected and subsequent expiry:\n```\n{\"millis\":69158,\"type\":\"alarm\",\"address\":170,\"command\":\"co\",\"min_rssi\":3,\"max_rssi\":3,\"duration\":0,\"count\":1,\"active\":true}\n{\"millis\":81649,\"type\":\"alarm\",\"address\":170,\"command\":\"co\",\"min_rssi\":3,\"max_rssi\":4,\"duration\":2472,\"count\":2,\"active\":false}\n```\n\nTest detected and subsequent expiry:\n```\n{\"millis\":67289,\"type\":\"alarm\",\"address\":170,\"command\":\"test\",\"min_rssi\":4,\"max_rssi\":4,\"duration\":0,\"count\":1,\"active\":true}\n{\"millis\":91236,\"type\":\"alarm\",\"address\":170,\"command\":\"test\",\"min_rssi\":3,\"max_rssi\":4,\"duration\":13416,\"count\":11,\"active\":false}\n```\n\nLow battery detected and subsequent expiry:\n```\n{\"millis\":69361,\"type\":\"alarm\",\"address\":170,\"command\":\"battery\",\"min_rssi\":3,\"max_rssi\":3,\"duration\":0,\"count\":1,\"active\":true}\n{\"millis\":93300,\"type\":\"alarm\",\"address\":170,\"command\":\"battery\",\"min_rssi\":2,\"max_rssi\":4,\"duration\":13716,\"count\":5,\"active\":false}\n```\n\nPromiscuous mode:\n```\n{\"millis\":1455659,\"type\":\"packet\",\"command\":\"hush\",\"address\":187,\"raw_command\":129,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":4}\n{\"millis\":1455712,\"type\":\"packet\",\"command\":\"test\",\"address\":204,\"raw_command\":128,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":3}\n{\"millis\":1455769,\"type\":\"packet\",\"command\":\"unknown\",\"address\":0,\"raw_command\":136,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":2}\n{\"millis\":1455790,\"type\":\"packet\",\"command\":\"hush\",\"address\":204,\"raw_command\":129,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":4}\n{\"millis\":1455800,\"type\":\"packet\",\"command\":\"unknown\",\"address\":0,\"raw_command\":138,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":2}\n{\"millis\":1455822,\"type\":\"packet\",\"command\":\"battery\",\"address\":0,\"raw_command\":141,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":2}\n{\"millis\":1455953,\"type\":\"packet\",\"command\":\"unknown\",\"address\":204,\"raw_command\":139,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":2}\n{\"millis\":1455990,\"type\":\"packet\",\"command\":\"battery\",\"address\":170,\"raw_command\":141,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":2}\n{\"millis\":1456039,\"type\":\"packet\",\"command\":\"unknown\",\"address\":170,\"raw_command\":135,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":0}\n{\"millis\":1456105,\"type\":\"packet\",\"command\":\"battery\",\"address\":170,\"raw_command\":141,\"suffix\":38655,\"rssi\":12,\"crc\":true,\"lqi\":0}\n{\"millis\":1456144,\"type\":\"packet\",\"command\":\"smoke\",\"address\":204,\"raw_command\":131,\"suffix\":38655,\"rssi\":13,\"crc\":true,\"lqi\":1}\n```\n\n### Example Home Assistant configuration\n\n`configuration.yaml`:\n```\n...\nsensor: !include sensor.yaml\nbinary_sensor: !include binary_sensor.yaml\n...\n```\n\n`sensor.yaml`:\n```\n- platform: serial\n  serial_port: /dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0\n  baudrate: 500000\n  name: kidde serial\n```\n\n`binary_sensor.yaml`:\n```\n- platform: template\n  sensors:\n    kidde_battery:\n      friendly_name: kidde battery\n      value_template: \u003e-\n        {% if state_attr('sensor.kidde_serial', 'command') == \"battery\" %}\n          {{ state_attr('sensor.kidde_serial', 'active') }}\n        {% else %}\n          {{ is_state('binary_sensor.kidde_battery', 'on') }}\n        {% endif %}\n      availability_template: \u003e-\n        {% if not is_state('sensor.kidde_serial', 'unavailable') %}\n          true\n        {% endif %}\n\n    kidde_co:\n      friendly_name: kidde co\n      value_template: \u003e-\n        {% if state_attr('sensor.kidde_serial', 'command') == \"co\" %}\n          {{ state_attr('sensor.kidde_serial', 'active') }}\n        {% else %}\n          {{ is_state('binary_sensor.kidde_co', 'on') }}\n        {% endif %}\n      availability_template: \u003e-\n        {% if not is_state('sensor.kidde_serial', 'unavailable') %}\n          true\n        {% endif %}\n\n    kidde_hush:\n      friendly_name: kidde hush\n      value_template: \u003e-\n        {% if state_attr('sensor.kidde_serial', 'command') == \"hush\" %}\n          {{ state_attr('sensor.kidde_serial', 'active') }}\n        {% else %}\n          {{ is_state('binary_sensor.kidde_hush', 'on') }}\n        {% endif %}\n      availability_template: \u003e-\n        {% if not is_state('sensor.kidde_serial', 'unavailable') %}\n          true\n        {% endif %}\n\n    kidde_smoke:\n      friendly_name: kidde smoke\n      value_template: \u003e-\n        {% if state_attr('sensor.kidde_serial', 'command') == \"smoke\" %}\n          {{ state_attr('sensor.kidde_serial', 'active') }}\n        {% else %}\n          {{ is_state('binary_sensor.kidde_smoke', 'on') }}\n        {% endif %}\n      availability_template: \u003e-\n        {% if not is_state('sensor.kidde_serial', 'unavailable') %}\n          true\n        {% endif %}\n\n    kidde_test:\n      friendly_name: kidde test\n      value_template: \u003e-\n        {% if state_attr('sensor.kidde_serial', 'command') == \"test\" %}\n          {{ state_attr('sensor.kidde_serial', 'active') }}\n        {% else %}\n          {{ is_state('binary_sensor.kidde_test', 'on') }}\n        {% endif %}\n      availability_template: \u003e-\n        {% if not is_state('sensor.kidde_serial', 'unavailable') %}\n          true\n        {% endif %}\n\n    kidde_unknown:\n      friendly_name: kidde unknown\n      value_template: \u003e-\n        {% if state_attr('sensor.kidde_serial', 'command') == \"unknown\" %}\n          {{ state_attr('sensor.kidde_serial', 'active') }}\n        {% else %}\n          {{ is_state('binary_sensor.kidde_unknown', 'on') }}\n        {% endif %}\n      availability_template: \u003e-\n        {% if not is_state('sensor.kidde_serial', 'unavailable') %}\n          true\n        {% endif %}\n```\n\nIf you have multiple detectors on different addresses (note - this will effectively disable the wireless interconnect between them), you could filter by address like so:\n```\n    kidde_smoke_garage:\n      friendly_name: kidde smoke (garage - 0x00)\n      value_template: \u003e-\n        {% if state_attr('sensor.kidde_serial', 'command') == \"smoke\" and state_attr('sensor.kidde_serial', 'address') == 0 %}\n          {{ state_attr('sensor.kidde_serial', 'active') }}\n        {% else %}\n          {{ is_state('binary_sensor.kidde_smoke_garage', 'on') }}\n        {% endif %}\n      availability_template: \u003e-\n        {% if not is_state('sensor.kidde_serial', 'unavailable') %}\n          true\n        {% endif %}\n\n    kidde_smoke_gazebo:\n      friendly_name: kidde smoke (gazebo - 0xAA)\n      value_template: \u003e-\n        {% if state_attr('sensor.kidde_serial', 'command') == \"smoke\" and state_attr('sensor.kidde_serial', 'address') == 170 %}\n          {{ state_attr('sensor.kidde_serial', 'active') }}\n        {% else %}\n          {{ is_state('binary_sensor.kidde_smoke_gazebo', 'on') }}\n        {% endif %}\n      availability_template: \u003e-\n        {% if not is_state('sensor.kidde_serial', 'unavailable') %}\n          true\n        {% endif %}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftofurky%2Fkidde_cc1101","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftofurky%2Fkidde_cc1101","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftofurky%2Fkidde_cc1101/lists"}