Save/Load your Input_Components automatically on Start/Restart (Quick Mod)

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")