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

Updated 2016/07/25
Added Support of Device Trackers.

  • Do not use the tracker function if you use presence detect that stores persistent data (OwnTracks, MQTT, etc.) or polling (Nmap, ASUSWRT, etc)

  • The tracker function works great with presence detection that relies on devices reporting in their location. (Locative, Hass iOS beta app, etc…).


What this will do:

This will allow you to save the state of Device_Trackers, Input_Booleans, Input_Selects, & Input_Sliders on change to a .ini file & load these setting, (states), using the API, back into Home-Assistant on start/restart automatically.


Info:

  • I created this because I am constantly tweaking/editing Home-Assistant and use a lot of Input_Components with my automatons. I found it frustrating to have to keep changing these components, or seeing my device_trackers set to “Away” after restarting Hass.

  • At first I just used the “initial:” option to set defaults, which works OK most of the time, but wanted an option to not have to edit the config every time I wanted different options than “initial:”


Disclaimer:

  • My python-fu is not the strongest.

  • I take no responsibility if this causes harm to your Hass install, your PC, or get’s your daughter pregnant.

  • The python script was written with python2 in mind & needs to be edited to work natively through python3.

  • That said, it should work with any system that has python2 installed, even when using python3 for Hass.


Highly Recommended you DO NOT try to modify this to work with anything other than Input_Boolean, Input_Select, Input_Slider, & Certain Device_Trackers.


Python Script:
hass_saved_settings.py - Updated 2016/07/25


###################################################
#      AUTOMATION EXAMPLE - LOAD SETTINGS         #
###################################################

##Load Input States from .ini - hass/saved_states

- alias: "Load Input States from Settings.ini"

  trigger:
  
    platform: event
    event_type: homeassistant_start
    
  action:
   
    - delay:
        minutes: 1
        
    - service: shell_command.load_input_settings


    ####################################################
    #      AUTOMATION EXAMPLE - SAVE SETTINGS          #
    ####################################################

    ## Save Input States to .ini - hass/saved_states

    - alias: "Save Input States to Settings.ini"

      trigger:

    ## Input Boolean

        - platform: state
          entity_id: input_boolean.your_input_boolean_01

        - platform: state
          entity_id: input_boolean.your_input_boolean_02
          
    ## Input Select

        - platform: state
          entity_id: input_select.your_input_select_01
          
        - platform: state
          entity_id: input_select.your_input_select_02
          
    ## Input Slider

        - platform: state
          entity_id: input_slider.your_input_slider_01
          
        - platform: state
          entity_id: input_slider.your_input_slider_02

## Device Trackers

        - platform: state
          entity_id: device_tracker.your_ios_device

        - platform: state
          entity_id: device_your_android_device

      action:

        service: shell_command.save_input_settings
        data_template:
            section: '{{ trigger.entity_id }}'
            settings: '{{ trigger.entity_id }}'
            value: "{{ trigger.to_state.state }}"

    #####################################
    #      SHELL_COMMAND EXAMPLE        #
    #####################################

    ## Save Input Settings

      save_input_settings: 'PYTHON_SCRIPT_LOCATION/hass_saved_settings.py -act update_settings -sec {{ section }} -set {{ settings }} -val "{{ value }}"'
      # ex.  ''/home/mike/.homeassistant/shell_scripts/hass_settings/hass_saved_settings.py -sec {{ section }} -set {{ settings }} -val "{{ value }}"'
      
      load_input_settings: 'PYTHON_SCRIPT_LOCATION/hass_saved_settings.py -act update_hass'
      # ex. '/home/mike/.homeassistant/shell_scripts/hass_settings/hass_saved_settings.py -act update_hass'

Notes:

  • The delay: time in the “LOAD SETTINGS” may need to be tweaked depending on your setup. It was needed for me to make sure everything was loaded, if run to soon then the settings were not applied. You can lower or raise the delay, or even remove it, I just set it to 1 Minute to be safe.

  • There are settings in the hass_saved_settings.py near the top that need to be configured.

path = ""         # Path to ini file. ex. "/home/mike/.homeassistant/saved_input_settings.ini"
host = ""         # Host & Port of Home-Assistant. ex. "localhost:8123"
api_key = ""    # Frontend / API Info. ex. "MyHassPassword"
  • You do not need to create the .ini file, it will be created automatically once the Save automation is triggered for the first time. (move a slider, switch a boolean, etc…)

  • Once going, you only need to edit the SAVE SETTINGS automation to track new inputs.

  • This will only load Inputs that are not set as default ( Input_Boolean != off / Input_Slider != 0 / Input_Select != “None” and != “No One”)

  • You may need to adjust the defaults for Input_Select. I have mine set as “None” and “No One”
    you can find that on line 137 of the hass_saved_settings.py.

if value != "None" and value != "No One":

  • You can rename the python script to anything you want, you’ll just need to edit the Shell_Commands.

  • Updating the python script, you may need to manually edit your .ini to add new sections or you can just delete the .ini & a new one with the correct sections will be created.


OK, I think that’s all of it… Really hope this is useful & actually works for some of you. lol

I’ll try to help & answer any questions that I can, just be gentle as I am so new to python & Home-Assistant
:slight_smile:

9 Likes

Done forget to also vote here.

Work perfectly, the only thing, I’ve got this warning in the log:

7-04-28 17:25:57 WARNING (MainThread) [homeassistant.components.automation.event] Deprecation: Automations should not listen to event 'homeassistant_start'. Use platform 'homeassistant' instead. Feature will be removed in 0.45 

So I changed change this ?

  - alias: "Load Input States from Settings.ini"
    trigger:
      platform: event
      event_type: homeassistant_start

to

  - alias: "Load Input States from Settings.ini"
    trigger:
      platform: homeassistant
      event: start

can I change the code for save my switch state?

How do I use this component?

I don’t think you need it. State saving was added awhile back for most things.

Thank you for all !
I would save a input.datetime component with this script.
How?

You would have to modify the script as it doesn’t support it atm.

Hello,
do you still have the script? its not in the page anymore
thanks

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

thanks alot!!
Cheers