Version: 0.77.2
Type: Docker, so this might be slightly different in HASS.
I’ve been in the process of moving everything z-wave from SmartThings over to Home Assistant. I didn’t have any major problems with SmartThings, but got tired of dealing with the hacky MQTT bridge that didn’t always seem to work as expected. The last item to move was the First Alert detectors: they also happened to be the biggest pain in the ass. I pulled this from a few different sources and didn’t really document the process, so I apologize to anyone I might have grabbed bits and pieces from without giving them credit.
Step 1: removing them from SmartThings
This was actually the easiest part. Select General Exclusion from the SmartThings app, pull the battery tray on the detector, hold down the test button, and plug the tray back in while you’re holding down the button. Wait about 2 seconds and let go of the button. It’ll beep one and you should see it removed from SmartThings.
Step 2: adding them to Home Assistant
Including them was easy. Figuring out why nothing seemed to work was a whole other problem. To include them, go into the z-wave configuration panel and select Add Node Secure. Pull the battery tray, hold down the test button, and plug the tray back in while holding the button. Wait about 2 seconds and let go of the button. You should hear a beep after a few seconds. If you’re like me and want to know what it’s doing, you can tail the OZW_Log.txt file to see what’s happening.
After it’s added, you’ll see it in the list of devices, but the nodes will show up as unknown. Apparently the z-wave component isn’t sure what to do with these. At this point you’ll need to manually edit the zwcfg_xyz123.xml file and plug in some details. See the “Node:X” value that’s listed in the nodes while you’re in the z-wave configuration panel? You’ll need the number associated with the First Aler. Edit the zwcfg_xyz123.xml file and add the following with your other nodes:
<Node id="16" name="" location="" basic="4" generic="161" specific="0" type="Alarm Sensor" listening="false" frequentListening="false" beaming="true" routing="true" max_baud_rate="40000" version="4" secured="true" query_stage="CacheLoad"> <Manufacturer id="138" name="First Alert"> <Product type="1" id="2" name="ZCombo Smoke and Carbon Monoxide Detector" /> </Manufacturer> <CommandClasses> <CommandClass id="32" name="COMMAND_CLASS_BASIC" version="1" request_flags="4" after_mark="true" innif="true" mapping="113"> <Instance index="1" /> </CommandClass> <CommandClass id="112" name="COMMAND_CLASS_CONFIGURATION" version="1" request_flags="4" innif="true"> <Instance index="1" /> <Value type="list" genre="config" instance="1" index="1" label="Send double alarm messages" units="" read_only="false" write_only="false" verify_changes="false" poll_intensity="0" min="0" max="0" vindex="0" size="1"> <Help>Causes the device to send double alarm messages.</Help> <Item label="Disable" value="0" /> <Item label="Enable" value="1" /> </Value> </CommandClass> <CommandClass id="113" name="COMMAND_CLASS_ALARM" version="1" request_flags="2" innif="true"> <Instance index="1" /> <Value type="byte" genre="user" instance="1" index="0" label="Alarm Type" units="" read_only="true" write_only="false" verify_changes="false" poll_intensity="0" min="0" max="255" value="13" /> <Value type="byte" genre="user" instance="1" index="1" label="Alarm Level" units="" read_only="true" write_only="false" verify_changes="false" poll_intensity="0" min="0" max="255" value="255" /> </CommandClass> <CommandClass id="114" name="COMMAND_CLASS_MANUFACTURER_SPECIFIC" version="1" request_flags="4" innif="true"> <Instance index="1" /> </CommandClass> <CommandClass id="128" name="COMMAND_CLASS_BATTERY" version="1" request_flags="4" innif="true"> <Instance index="1" /> <Value type="byte" genre="user" instance="1" index="0" label="Battery Level" units="%" read_only="true" write_only="false" verify_changes="false" poll_intensity="0" min="0" max="255" value="91" /> </CommandClass> <CommandClass id="132" name="COMMAND_CLASS_WAKE_UP" version="1" request_flags="2"> <Instance index="1" /> <Value type="int" genre="system" instance="1" index="0" label="Wake-up Interval" units="Seconds" read_only="false" write_only="false" verify_changes="false" poll_intensity="0" min="-2147483648" max="2147483647" value="3600" /> </CommandClass> <CommandClass id="133" name="COMMAND_CLASS_ASSOCIATION" version="1" request_flags="4" innif="true"> <Instance index="1" /> <Associations num_groups="1"> <Group index="1" max_associations="1" label="Lifeline" auto="true"> <Node id="1" /> </Group> </Associations> </CommandClass> <CommandClass id="134" name="COMMAND_CLASS_VERSION" version="1" request_flags="4" innif="true"> <Instance index="1" /> <Value type="string" genre="system" instance="1" index="0" label="Library Version" units="" read_only="true" write_only="false" verify_changes="false" poll_intensity="0" min="0" max="0" value="6" /> <Value type="string" genre="system" instance="1" index="1" label="Protocol Version" units="" read_only="true" write_only="false" verify_changes="false" poll_intensity="0" min="0" max="0" value="3.52" /> <Value type="string" genre="system" instance="1" index="2" label="Application Version" units="" read_only="true" write_only="false" verify_changes="false" poll_intensity="0" min="0" max="0" value="0.05" /> </CommandClass> </CommandClasses> </Node>
You’ll want to change that Node id="16"
at the beginning to match the number for the previous step, otherwise this isn’t going to work. Now, because the naming convention isn’t always the best with z-wave, you’ll want to take a few more steps to clean this up a bit. But first:
docker restart home-assistant
You’ll then need to wait for z-wave to come back up again. We’ll do this a few times.
Step 2: clean up the names in Home Assistant
I know this is supposed to be done in the UI, but I’m happy making changes directly in the file. Go into your Home Assistant directory and type vi .storage/core.entity_registry
so we can tweak a few items. Scroll down to the bottom, and you should see three entries for your First Alert device: the root device, the alarm type, and the alarm level. It’ll look something like this:
{ "config_entry_id": null, "device_id": null, "entity_id": "zwave.first_alert_upstairs", "name": "Smoke Upstairs", "platform": "zwave", "unique_id": "node-16" }, { "config_entry_id": null, "device_id": null, "entity_id": "sensor.first_alert_upstairs_alarm_type", "name": "Smoke Upstairs Alarm Type", "platform": "zwave", "unique_id": "16-72057594312409089" }, { "config_entry_id": null, "device_id": null, "entity_id": "sensor.first_alert_upstairs_alarm_level", "name": "Smoke Upstairs Alarm Level", "platform": "zwave", "unique_id": "16-72057594312409105" }
Mine probably looks much cleaner than what you’re seeing. By default, it’ll use a long-ass name related to the full product description. I shorted them to something a bit more manageable and added a friendly name. Yes, I’m still aware this was supposed to be done through the UI, but this was much faster. You’ll will need the “Type” and “Level” names in the next step. And now our favorite step again:
docker restart home-assistant
Step 3: ensuring they show up in states.
Check your states to ensure they look something like this:
sensor.first_alert_upstairs_alarm_level 255
sensor.first_alert_upstairs_alarm_type 13
As best as I could tell, that means they’re idle. However, to figure out what they’re really trying to say, you’ll need templating to keep your sanity. Basically Type 1 is smoke, Type 2 is CO, and Level 255 combined with either means you might want to evacuate the household. But back to the templates:
smoke_upstairs_status: friendly_name: 'Smoke Upstairs Status' value_template: >- {% if is_state("sensor.first_alert_upstairs_alarm_level", "255") and is_state("sensor.first_alert_upstairs_alarm_type", "1")%} smoke {% elif is_state("sensor.first_alert_upstairs_alarm_level", "255") and is_state("sensor.first_alert_upstairs_alarm_type", "2")%} co {% else %} idle {% endif %} icon_template: >- {% if is_state("sensor.first_alert_upstairs_alarm_level", "255") and is_state("sensor.first_alert_upstairs_alarm_type", "1")%} mdi:fire {% elif is_state("sensor.first_alert_upstairs_alarm_level", "255") and is_state("sensor.first_alert_upstairs_alarm_type", "2")%} mdi:cloud-outline {% else %} mdi:smoke-detector {% endif %}
It basically says create a new sensor called smoke_upstairs_status
. If it’s a 1 and a 255, then smoke has been detected. If it’s a 2 and a 255, that means CO has been detected. You can now use those values in automations, e.g. IF smoke_upstairs_status == smoke THEN run away
. Personally I use them in NodeRed to turn on all the lights, unlock the front door, trigger a loud siren alarm, and send Pushover alerts to everyone’s phone. Kind of difficult to ignore at that point.
But on to the last piece: the battery template. It helps to know when they need to be changed.
smoke_upstairs_battery_template: friendly_name: 'Smoke Upstairs Battery' value_template: '{{ states.zwave.first_alert_upstairs.attributes.battery_level }}' icon_template: 'mdi:battery-outline' unit_of_measurement: '%'
…and one more time:
docker restart home-assistant
Hopefully this was helpful and will save everyone from piecing all of this together. At this point smoke_upstairs_status
will spit out either smoke
, co
, or idle
for automation components.