Unfortunately, I no longer have this script… Not long after a created the original script, I found AppDaemon and converted my script to a AppDamon app(s).
Here’s what I am currently using:
To Save states to a INI file:
[apps.yaml]
HassStatesSave:
module: hass_states_save
class: HassStatesSave
path: /conf/hass_saved_states.ini
isloaded_switch: input_boolean.hass_saved_states_loaded
constrain_input_boolean: input_boolean.hass_saved_states_loaded
Notes:
- path: (where you want to save the .ini file)
- isloaded_switch: (This ignores the “constrain_input_boolean” switch so it’s state does not get stored in the ini)
- constrain_input_boolean: (This input_boolean is is switched on by the “load” script to prevent saving states to the ini until the saved values can be loaded back into HA. This prevents HA restarts from causing the app to save default loaded/wrong states)
[hass_states_save.py]
import configparser
import os
import sys
import threading
import appdaemon.plugins.hass.hassapi as hass
class HassStatesSave(hass.Hass):
def initialize(self):
self.lock = threading.Lock()
self.listen_state(self.save_config, "automation")
self.listen_state(self.save_config, "input_boolean")
self.listen_state(self.save_config, "input_datetime")
self.listen_state(self.save_config, "input_number")
self.listen_state(self.save_config, "input_select")
self.listen_state(self.save_config, "input_text")
self.listen_state(self.save_config, "device_tracker")
def create_config(self):
self.log("No Config found, Creating new Config")
config = configparser.ConfigParser()
config.add_section("automation")
config.add_section("boolean")
config.add_section("datetime")
config.add_section("number")
config.add_section("select")
config.add_section("text")
config.add_section("tracker")
with open(self.args["path"], "w") as config_file:
config.write(config_file)
config_file.close()
def get_config(self):
if not os.path.exists(self.args["path"]):
self.create_config()
config = configparser.ConfigParser()
config.read(self.args["path"])
return config
def save_config(self, entity, attribute, old, new, kwargs):
self.lock.acquire()
try:
if new != old:
# device = self.friendly_name(entity)
if entity != self.args["isloaded_switch"]:
section = entity.split(".")[0]
if section != "automation":
section = section.split("_")[1]
config = self.get_config()
config.set(section, entity, new)
with open(self.args["path"], "w") as config_file:
config.write(config_file)
config_file.close()
# message = "{} state saved as {}".format(device, new)
# self.log(message)
finally:
self.lock.release()
To Load saved states from the INI file:
[apps.yaml]
HassStatesLoad:
module: hass_states_load
class: HassStatesLoad
path: /conf/hass_saved_states.ini
isloaded_switch: input_boolean.hass_saved_states_loaded
Notes:
- path: (where the .ini file is located, same as above)
- isloaded_switch: (This input_boolean is is switched on after all saved states are loaded and to enable the save app now that it is safe to start saving changes. )
[hass_states_load.py]
import configparser
import os
import sys
import appdaemon.plugins.hass.hassapi as hass
class HassStatesLoad(hass.Hass):
def initialize(self):
self.listen_event(self.load_config, "plugin_started")
self.listen_event(self.load_config, "appd_started")
def create_config(self):
self.log("No Config found, Creating new Config")
config = configparser.ConfigParser()
config.add_section("automation")
config.add_section("boolean")
config.add_section("datetime")
config.add_section("number")
config.add_section("select")
config.add_section("text")
config.add_section("tracker")
with open(self.args["path"], "w") as config_file:
config.write(config_file)
config_file.close()
def get_config(self):
if not os.path.exists(self.args["path"]):
self.create_config()
config = configparser.ConfigParser()
config.read(self.args["path"])
return config
def get_setting(self, section, setting):
config = self.get_config()
value = config.get(section, setting)
return value
def update_states(self, section, setting, value):
if section == "automation":
self.turn_off(setting)
elif section == "boolean_on":
self.turn_on(setting)
elif section == "boolean_off":
self.turn_off(setting)
elif section == "datetime":
self.call_service("input_datetime/set_datetime",
entity_id=setting, time=value)
elif section == "number":
self.set_value(setting, value)
elif section == "select":
self.select_option(setting, value)
elif section == "text":
self.call_service("input_text/set_value",
entity_id=setting, option=value)
elif section == "tracker":
self.call_service("device_tracker/see",
dev_id=setting.split(".")[1], location_name=value)
def load_config(self, event_name, data, kwargs):
config = self.get_config()
for (setting, value) in config.items("automation"):
if value == "off":
self.update_states("automation", setting, value)
for (setting, value) in config.items("boolean"):
if self.get_state(setting) != value:
if value == "on":
self.update_states("boolean_on", setting, value)
else:
self.update_states("boolean_off", setting, value)
for (setting, value) in config.items("datetime"):
if self.get_state(setting) != value:
self.update_states("datetime", setting, value)
for (setting, value) in config.items("number"):
if self.get_state(setting) != value:
self.update_states("number", setting, value)
for (setting, value) in config.items("select"):
if self.get_state(setting) != value:
self.update_states("select", setting, value)
for (setting, value) in config.items("text"):
if self.get_state(setting) != value:
self.update_states("text", setting, value)
for (setting, value) in config.items("tracker"):
if self.get_state(setting) != value:
self.update_states("tracker", setting, value)
self.turn_on(self.args["isloaded_switch"])
self.log("States Imported Successfully")