How to Create a Home Assistant Automation to Make Your Dumb Fireplace Smart!

Portrait of Rod Alcidonis

Rod Alcidonis

Published on December 24, 2022

Subscribe to my YouTube channel
Buy me a beer
A picture of a fireplace in a living room

A fireplace at home makes a cold winter night cozy and comforting. However, if left unattended for a long period of time, such as when you leave home or go to bed, it can become both an energy sucker and/or a fire hazard. In this article, I will be showing you how to create a complex automation in Home Assistant using Appdaemon to ensure that your fireplace is turned off when not in use.

Preliminary Steps

Before we dive into the code, it’s important to note that you should always follow all safety guidelines when using a fireplace, and carefully test any automations before relying on them. While I have personally tested this code in my own setup, I do not know if it will work in your setup. I therefore cannot give you any assurances that this code will work for you as it did for me. Use the information in this article as an example to inspire your own automations, and make sure to personally test your code until you feel confident that it meets your needs.

My Setup

To create this automation, I’m using a Z-wave switch to turn the fireplace on and off, and two motion sensors to detect room occupancy. You may need to use more motion sensors depending on the size and configuration of your room, and be sure to rename the sensors in the code to match the names you’ve given them in Home Assistant.

Related Posts:

I’m using Appdaemon to write the code. Appdaemon is a Home Assistant framework integration that allows you to create custom automations for your home using Python code. I have also configured a series of custom Python methods to determine whether the motion sensors have been inactive for 25 minutes, whether the time is between midnight and 11:59 PM, and how long the motion sensors have actually been inactive. These are helper methods I created to keep the code clean and modular.

Coding the Automation

Now, let’s get started! Here’s the code, with explanatory comments:

#Importing the Appdaemon Python library
import appdaemon.plugins.hass.hassapi as hass
Importing the datetime module. We will need this module to check the time as part of our code.
import datetime

#Creating an Appdaemon Python class that inherits from the "hass.Hass" library.
class FireplaceMonitor(hass.Hass):
	#Initializing the Appdaemon app 
	def initialize(self):
		# Subscribe to the state change event for the fireplace switch
		self.listen_state(self.fireplace_on, "switch.fireplace")

	# Creating the fireplace on callback method.
	def fireplace_on(self, entity, attribute, old, new, kwargs):
		# Check if the fireplace switch has been turned on in order to activate the motion sensor listeners
		if new == "on":
			self.log(self.friendly_name(entity) +" is " + new)
			# Subscribe to the state change event for the family room right window motion sensor.
			self.listen_state(self.motion_sensor_changed, "binary_sensor.family_room_right_window_motion")
			self.log("Set timer to monitor the family room right window motion.")
			# Subscribe to the state change event for the family room wall motion sensor
			self.listen_state(self.motion_sensor_changed, "binary_sensor.family_room_wall_motion")
			self.log("Set timer to monitor the family room motion.")
	"""again, these are just the names of the sensors I am using in the app. You should replace each sensor name with the name of the sensors in your Home Assistant instance."""
	# Creating the motion sensor callback method to monitor the motion sensors
	def motion_sensor_changed(self, entity, attribute, old, new, kwargs):
		# Check if either motion sensors becomes inactive
		if new == "off":
			self.log("The "+ self.friendly_name(entity) + " is "+ new +", setting up timer to turn the fireplace off.")
			# Start a timer to turn off the fireplace switch after 30 minutes
			self.run_in(self.turn_off_fireplace, 300)
	# Creating the method with the logics to turn the fireplace off if certain conditions are satisfied.
	def turn_off_fireplace(self, kwargs=None):
		self.log("Getting ready to turn the fireplace off")
		# Check if both motion sensors in the family room have been inactive for 25 mins and that the time is between midnight and after 11:59 PM. Please note here that the time here is a placeholder as midnight to 11:59 is equivalent to the entire day. You should change the interval if in case you desire to have the app monitor a shorter time period.
		if self.get_state("switch.fireplace", attribute = "state") != "off":
			if self.is_family_room_occupied() and self.is_time_in_range("00:00", "23:59"): # Checking whether motions have been off for at least 25 minutes and the time is right
				self.log("it has been more than 25 minutes since the family room wall motion and the family room right window motion sensors have been inactive, and the time is right. Turning the fireplace off.")
				self.turn_off("switch.fireplace")
				self.log(self.friendly_name("switch.fireplace") + " has been turned off by the fireplace monitor")
			else: # Motion test or time test did not pass
				self.log("It is not yet time to turn the fireplace off because the motions have not been inactive for at least 25 mins, or the time is not right. Resetting the timer.")
				if self.inactive_motion_time_check() < 5: # If motion has been inactive only for 5 minutes
					self.run_in(self.turn_off_fireplace, 1500)
					self.log("New 25 minutes timer running checking motions to turn the fireplace off")
				elif self.inactive_motion_time_check() > 5: # If motions have been inactive for more than 5 minutes
					self.run_in(self.turn_off_fireplace, 1200)
					self.log("New 20 minutes timer running checking motions to turn the fireplace off")
				elif self.inactive_motion_time_check() > 10: # If motion has been inactive for more than 10 minutes
					self.run_in(self.turn_off_fireplace, 900)
					self.log("New 15 minutes timer running checking motions to turn the fireplace off")
				elif self.inactive_motion_time_check() > 15: # If motion has been inactive for more than 15 minutes
					self.run_in(self.turn_off_fireplace, 600)
					self.log("New 10 minutes timer running checking motions to turn the fireplace off")
				elif self.inactive_motion_time_check() > 20: # If motion has been inactive for more than 20 minutes
					self.run_in(self.turn_off_fireplace, 300)
					self.log("New 5 minutes timer running checking motions to turn the fireplace off")
		else: # Fireplace is not on, no need to go further
			self.log("Fireplace is not on. No need to check further.")
			return

	#Method to determine if the room is occupied. I am monitoring the family room here, which is where my fireplace is located in the house.
	def is_family_room_occupied(self, kwargs = None):
		"""If statement to check whether both motions have been inactive for at least 25 minutes"""
		if self.entity_last_changed_off_more_than("binary_sensor.family_room_wall_motion", 25) and self.entity_last_changed_off_more_than("binary_sensor.family_room_right_window_motion", 25):
			return True
		else:
			return False

	# Method to determine how long a motion sensor has been inactive. You need to pass the name of the entity as an argument when calling this method. It returns the time in minutes.
	def entity_last_changed_off_time_alapsed(self, entity_name):
		self.entity_name = entity_name
		self.log(self.friendly_name(self.entity_name))
		self.entity_last_changed_on = self.get_state(self.entity_name, attribute = "last_changed", state = "off")
		recently_active_entity_time = int(datetime.datetime.now().timestamp() - self.convert_utc(self.entity_last_changed_on).timestamp())/60   #Entity inactive time
		self.log(int(recently_active_entity_time))
		return int(recently_active_entity_time)

	# Helper method to check whether the motion sensor has been inactive for a specified amount of time. You need to pass the time that you would like to check as an argument in minutes when calling this method. It returns a Boolean (True/False).
	def entity_last_changed_off_more_than(self, entity_name, inactive_time):
		self.entity_name = entity_name
		self.inactive_time= inactive_time
		self.log(self.friendly_name(self.entity_name)) # to confirm in the log that the right entity is being checked
		self.entity_last_changed_on = self.get_state(self.entity_name, attribute = "last_changed", state = "off")
		recently_active_entity_time = int(datetime.datetime.now().timestamp() - self.convert_utc(self.entity_last_changed_on).timestamp())/60   #Entity inactive time
		self.log(int(recently_active_entity_time)) 
		if recently_active_entity_time > self.inactive_time: # Entity has been inactive
			return True
		else:
			return False

	# Helping method to determine whether the current time is between midnight and 11:59PM
	def is_time_in_range(self, start_time, end_time):
		# Get the current time
		current_time = datetime.datetime.now().time()
		# Convert the start and end times to datetime.time objects
		start_time = datetime.datetime.strptime(start_time, "%H:%M").time()
		end_time = datetime.datetime.strptime(end_time, "%H:%M").time()
		#Check if the current time is within the range
		if start_time <= current_time < end_time:
			self.log(str(current_time) +" is between "+ str(start_time) +" and "+ str(end_time))
			return True
		else:
			self.log(str(current_time) +" is not between "+ str(start_time) +" and "+ str(end_time))
return False

Breaking the Code Down

The code creates an Appdaemon class called “FireplaceMonitor” which subclasses “hass.Hass”. The initialize() method is called when the app is loaded and sets up a listener for the state change of the fireplace switch. When the switch is turned on, the fireplace_on() method is called. The fireplace_on() method checks if the fireplace switch has been turned on. If it has, it sets up listeners for the state change of the family room right window motion sensor and the family room wall motion sensor. In Appdaemon, a listener method behaves like an automation trigger. It also logs a message indicating that these sensors are being monitored.

The motion_sensor_changed() method is called when the state of either motion sensor changes. If a motion sensor becomes inactive (i.e., its state changes to “off”), the app starts a timer to turn off the fireplace switch after 10 minutes.

Finally, the turn_off_fireplace() method is called when the timer expires. It checks if the fireplace switch is not already turned off and whether both motion sensors in the family room have been inactive for at least 25 minutes and whether the current time is between midnight and 11:59 PM. If all these conditions are met, it turns off the fireplace switch and logs a message indicating that the fireplace has been turned off. If any of these conditions are not met, it logs a message indicating that it is not yet time to turn the fireplace off and resets the timer to continue checking. The timer is reset differently depending on how long the motion sensors have been inactive, with shorter times for longer periods of inactivity. This is to prevent the fireplace from running unnecessarily while it waits on the timer to be triggered.

Along the way, the fireplace_off method is using a series of custom helper methods to check whether certain conditions are true or false.

To use this code, you’ll need to install the Appdaemon integration and add it to your Home Assistant setup. You’ll also need to set up your Z-wave switch and motion sensors in Home Assistant, and make sure to rename them in the code to match the names you’ve given them in Home Assistant. And finally, you will need to create an Appdaemon app in your apps.yaml, as follows:

Fireplace Monitor:
  module: fireplace_monitor
  class: FirePlaceMonitor

The Complete Code

import appdaemon.plugins.hass.hassapi as hass
import datetime

class FireplaceMonitor(hass.Hass):
	def initialize(self):
		# Subscribe to the state change event for the fireplace switch
		self.listen_state(self.fireplace_on, "switch.fireplace")

	def fireplace_on(self, entity, attribute, old, new, kwargs):
		# Check if the fireplace switch has been turned on
		if new == "on":
			self.log(self.friendly_name(entity) +" is " + new)
			# Subscribe to the state change event for the family room right window motion sensor
			self.listen_state(self.motion_sensor_changed, "binary_sensor.family_room_right_window_motion")
			self.log("Set timer to monitor the family room right window motion.")
			# Subscribe to the state change event for the family room wall motion sensor
			self.listen_state(self.motion_sensor_changed, "binary_sensor.family_room_wall_motion")
			self.log("Set timer to monitor the family room motion.")
		if new == "off":
			self.log(self.friendly_name(entity) +" is " + new)

	def motion_sensor_changed(self, entity, attribute, old, new, kwargs):
		# Check if either motion sensors becomes inactive
		if new == "off":
			self.log("The "+ self.friendly_name(entity) + " is "+ new +", setting up timer to turn the fireplace off.")
			# Start a timer to turn off the fireplace switch after 30 minutes
			self.run_in(self.turn_off_fireplace, 300)

	def turn_off_fireplace(self, kwargs=None):
		self.log("Getting ready to turn the fireplace off")
		# Check if both motion sensors in the family room have been inactive for 25 mins and that the time is between midnight and after 11:59 PM
		if self.get_state("switch.fireplace", attribute = "state") != "off":
			if self.is_family_room_occupied() and self.is_time_in_range("00:00", "23:59"): # Checking whether motions have been off for at least 25 minutes and the time is right
				self.log("it has been more than 25 minutes since the family room wall motion and the family room right window motion sensors have been inactive, and the time is right. Turning the fireplace off.")
				self.turn_off("switch.fireplace")
				self.log(self.friendly_name("switch.fireplace") + " has been turned off by the fireplace monitor")
			else: # Motion test or time test did not pass
				self.log("It is not yet time to turn the fireplace off because the motions have not been inactive for at least 25 mins, or the time is not right. Resetting the timer for 30 minutes.")
				if self.inactive_motion_time_check() < 5:
					self.run_in(self.turn_off_fireplace, 1500)
					self.log("New 25 minutes timer running checking motions to turn the fireplace off")
				elif self.inactive_motion_time_check() > 5:
					self.run_in(self.turn_off_fireplace, 1200)
					self.log("New 20 minutes timer running checking motions to turn the fireplace off")
				elif self.inactive_motion_time_check() > 10:
					self.run_in(self.turn_off_fireplace, 900)
					self.log("New 15 minutes timer running checking motions to turn the fireplace off")
				elif self.inactive_motion_time_check() > 15:
					self.run_in(self.turn_off_fireplace, 600)
					self.log("New 10 minutes timer running checking motions to turn the fireplace off")
				elif self.inactive_motion_time_check() > 20:
					self.run_in(self.turn_off_fireplace, 300)
					self.log("New 5 minutes timer running checking motions to turn the fireplace off")
		else: # Fireplace is not on, no need to go further
			self.log("Fireplace is not on. No need to check further.")
			return
	
	def is_family_room_occupied(self, kwargs = None):
		self.entity_last_changed_off_more_than("binary_sensor.family_room_wall_motion", 25)
		self.entity_last_changed_off_more_than("binary_sensor.family_room_right_window_motion", 25)
		"""If statement to check whether both motions have been inactive for at least 25 minutes"""
		if self.entity_last_changed_off_more_than("binary_sensor.family_room_wall_motion", 25) and self.entity_last_changed_off_more_than("binary_sensor.family_room_right_window_motion", 25):
			return True
		else:
			return False

	def inactive_motion_time_check(self, kwargs = None):
		motion_sensors = []
		family_room_right_window_motion = self.entity_last_changed_off_time_alapsed("binary_sensor.family_room_right_window_motion")
		motion_sensors.append(family_room_right_window_motion)
		family_room_wall_motion = self.entity_last_changed_off_time_alapsed("binary_sensor.family_room_wall_motion")
		motion_sensors.append(family_room_wall_motion)
		return max(motion_sensors)

	# Method to check how long the motion sensors have been inactive
	def inactive_motion_time_check(self, kwargs = None):
		motion_sensors = [] # A list to hold the sensors as they are being checked.
		family_room_right_window_motion = self.entity_last_changed_off_time_alapsed("binary_sensor.family_room_right_window_motion")
		motion_sensors.append(family_room_right_window_motion)
		family_room_wall_motion = self.entity_last_changed_off_time_alapsed("binary_sensor.family_room_wall_motion")
		motion_sensors.append(family_room_wall_motion)
		return max(motion_sensors)

	# Method to determine how long a motion sensor has been inactive. You need to pass the name of the entity as an argument when calling this method. It returns the time in minutes.
	def entity_last_changed_off_time_alapsed(self, entity_name):
		self.entity_name = entity_name
		self.log(self.friendly_name(self.entity_name))
		self.entity_last_changed_on = self.get_state(self.entity_name, attribute = "last_changed", state = "off")
		recently_active_entity_time = int(datetime.datetime.now().timestamp() - self.convert_utc(self.entity_last_changed_on).timestamp())/60   #Entity inactive time
		self.log(int(recently_active_entity_time))
		return int(recently_active_entity_time)

	# Helper method to check whether the motion sensor has been inactive for a specified amount of time. You need to pass the time that you would like to check as an argument in minutes when calling this method. It returns a Boolean (True/False).
	def entity_last_changed_off_more_than(self, entity_name, inactive_time):
		self.entity_name = entity_name
		self.inactive_time= inactive_time
		self.log(self.friendly_name(self.entity_name)) # to confirm in the log that the right entity is being checked
		self.entity_last_changed_on = self.get_state(self.entity_name, attribute = "last_changed", state = "off")
		recently_active_entity_time = int(datetime.datetime.now().timestamp() - self.convert_utc(self.entity_last_changed_on).timestamp())/60   #Entity inactive time
		self.log(int(recently_active_entity_time)) 
		if recently_active_entity_time > self.inactive_time: # Entity has been inactive
			return True
		else:
			return False

	# Helping method to determine whether the current time is between midnight and 11:59PM
	def is_time_in_range(self, start_time, end_time):
		# Get the current time
		current_time = datetime.datetime.now().time()
		# Convert the start and end times to datetime.time objects
		start_time = datetime.datetime.strptime(start_time, "%H:%M").time()
		end_time = datetime.datetime.strptime(end_time, "%H:%M").time()
		#Check if the current time is within the range
		if start_time <= current_time < end_time:
			self.log(str(current_time) +" is between "+ str(start_time) +" and "+ str(end_time))
			return True
		else:
			self.log(str(current_time) +" is not between "+ str(start_time) +" and "+ str(end_time))
return False

Final Thoughts

I hope this article has been helpful in showing you how to create a Home Assistant automation to make your fireplace a little smarter. This Home Assistant fireplace automation app should give you increased comfort knowing that your fireplace will be turned off if you inadvertently left it unattended, keeping your home safe and energy efficient. Use your imagination to add more features to the app as needed to make your fireplace even smarter. For example, you can consider creating different methods to keep track of the amount of time the fireplace stayed on over a specific period of time, as a way to monitor your energy consumption.

It goes without saying, because this app involves a fireplace, you should check your code multiple times to make sure that it works as intended before relying on it in your smart home automation setup.


I hope you found this article, "How to Create a Home Assistant Automation to Make Your Dumb Fireplace Smart!", informative and useful. For more smart home automation content, you might want to read this article next: Sonos Wireless Speakers are Just the Perfect Addition to Your Smart Home. If you found this article helpful, Subscribe to the On Motion Detected YouTube Channel, or sign up for our newsletter for more smart home automation content delivered to your inbox.

Leave a comment

Your email address will not be published. Required fields are marked *