From cf9ec6345d3f4f5f7bd362cd4b5943fcb135dae4 Mon Sep 17 00:00:00 2001 From: Trefor Southwell <48591903+springfall2008@users.noreply.github.com> Date: Sun, 14 Jan 2024 21:30:17 +0000 Subject: [PATCH 1/9] Save/Restore settings selector function --- apps/predbat/predbat.py | 105 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 7 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 918f1c33d..949817558 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -18,7 +18,7 @@ import os import yaml -THIS_VERSION = "v7.14.41" +THIS_VERSION = "v7.14.42" TIME_FORMAT = "%Y-%m-%dT%H:%M:%S%z" TIME_FORMAT_SECONDS = "%Y-%m-%dT%H:%M:%S.%f%z" TIME_FORMAT_OCTOPUS = "%Y-%m-%d %H:%M:%S%z" @@ -55,6 +55,7 @@ # Predbat update options PREDBAT_UPDATE_OPTIONS = [THIS_VERSION + " Loading..."] +PREDBAT_SAVE_RESTORE = ['save current', 'restore default'] # Configuration options inside HA CONFIG_ITEMS = [ @@ -471,6 +472,14 @@ "icon": "mdi:state-machine", "default": None, }, + { + "name": "saverestore", + "friendly_name": "Save/restore settings", + "type": "select", + "options": PREDBAT_SAVE_RESTORE, + "icon": "mdi:state-machine", + "default": '', + }, {"name": "auto_update", "friendly_name": "Predbat automatic update enable", "type": "switch", "default": False}, {"name": "load_filter_modal", "friendly_name": "Apply modal filter historical load", "type": "switch", "enable": "expert_mode", "default": True}, {"name": "iboost_enable", "friendly_name": "IBoost enable", "type": "switch", "default": False}, @@ -8728,7 +8737,7 @@ def calculate_plan(self, recompute=True): # HTML data self.publish_html_plan(pv_forecast_minute_step, load_minutes_step, self.end_record) - # Return if we recomputed or not + # Return if we recomputed or not return recompute def reset_inverter(self): @@ -8858,7 +8867,7 @@ def execute_plan(self): if (self.minutes_now < minutes_end) and ( (minutes_start - self.minutes_now) <= self.set_window_minutes or (inverter.charge_start_time_minutes - self.minutes_now) <= self.set_window_minutes ): - if ((minutes_start - self.minutes_now) > self.set_window_minutes) and (minutes_end - self.minutes_now) >= 24 * 60: + if ((minutes_start - self.minutes_now) > self.set_window_minutes) and (minutes_end - self.minutes_now) >= 24*60: self.log("Charge window would wrap, disabling until later") inverter.disable_charge_window() else: @@ -9850,6 +9859,9 @@ def fetch_config_options(self): self.car_charging_threshold = float(self.get_arg("car_charging_threshold")) / 60.0 self.car_charging_energy_scale = self.get_arg("car_charging_energy_scale") + # Update list of config options to save/restore to + self.update_save_restore_list() + @ad.app_lock def update_pred(self, scheduled=True): """ @@ -10022,6 +10034,14 @@ def select_event(self, event, data, kwargs): if item["name"] == "update": self.log("Calling update service for {}".format(value)) self.download_predbat_version(value) + elif item["name"] == "saverestore": + if value == "save current": + self.update_save_restore_list() + self.save_settings_yaml() + elif value == "restore default": + self.restore_settings_yaml(None) + else: + self.restore_settings_yaml(value) else: self.expose_config(item["name"], value, event=True) self.update_pending = True @@ -10128,6 +10148,8 @@ def expose_config(self, name, value, quiet=True, event=False): self.set_state(entity_id=entity, state=("on" if value else "off"), attributes={"friendly_name": item["friendly_name"], "icon": icon}) elif item["type"] == "select": icon = item.get("icon", "mdi:format-list-bulleted") + if value is None: + value = item.get("default", "") self.set_state(entity_id=entity, state=value, attributes={"friendly_name": item["friendly_name"], "options": item["options"], "icon": icon}) elif item["type"] == "update": summary = self.releases.get("this_body", "") @@ -10177,6 +10199,74 @@ def dashboard_item(self, entity, state, attributes): if entity not in self.dashboard_index: self.dashboard_index.append(entity) + def update_save_restore_list(self): + """ + Update list of current Predbat settings + """ + global PREDBAT_SAVE_RESTORE + self.save_restore_dir = None + for root in CONFIG_ROOTS: + if os.path.exists(root): + self.save_restore_dir = root + "/predbat_save" + if not self.save_restore_dir: + return + + if not os.path.exists(self.save_restore_dir): + os.mkdir(self.save_restore_dir) + + PREDBAT_SAVE_RESTORE = ['save current', 'restore default'] + for root, dirs, files in os.walk(self.save_restore_dir): + for name in files: + filepath = os.path.join(root, name) + if filepath.endswith('.yaml'): + PREDBAT_SAVE_RESTORE.append(name) + item = self.config_index.get("saverestore", None) + item['options'] = PREDBAT_SAVE_RESTORE + self.expose_config("saverestore", None) + + def restore_settings_yaml(self, filename): + """ + Restore settings from YAML file + """ + self.save_restore_dir = None + for root in CONFIG_ROOTS: + if os.path.exists(root): + self.save_restore_dir = root + "/predbat_save" + if not self.save_restore_dir: + return + + if not filename: + self.log("Restore settings to default") + for item in CONFIG_ITEMS: + self.log("Restore setting: {} = {}".format(item["name"], item["default"])) + self.expose_config(item["name"], item["default"], event=True) + else: + filepath = os.path.join(self.save_restore_dir, filename) + if os.path.exists(filepath): + self.log("Restore settings from {}".format(filepath)) + with open(filepath, "r") as file: + settings = yaml.safe_load(file) + for item in settings: + self.log("Restore setting: {} = {}".format(item["name"], item["value"])) + self.expose_config(item["name"], item["value"], event=True) + self.expose_config("saverestore", None) + + def save_settings_yaml(self): + """ + Save current Predbat settings + """ + if not self.save_restore_dir: + return + + filename = self.time_abs_str(self.minutes_now) + filename = filename.replace(' ', '_') + filename = filename.replace(':', '_') + filename += ".yaml" + filepath = os.path.join(self.save_restore_dir, filename) + with open(filepath, "w") as file: + yaml.dump(CONFIG_ITEMS, file) + self.log("Saved Predbat settings to {}".format(filepath)) + def save_settings(self): """ Save current predbat settings @@ -10184,7 +10274,7 @@ def save_settings(self): basename = "/predbat_restore_settings.yaml" filename = None text = "" - text += 'alias: "Restore Predbat settings from {}"\n'.format(self.time_abs_str(self.minutes_now)) + text += "alias: \"Restore Predbat settings from {}\"\n".format(self.time_abs_str(self.minutes_now)) text += "mode: single\n" text += "trigger: []\n" text += "condition: []\n" @@ -10205,7 +10295,7 @@ def save_settings(self): enable = item.get("enable", None) if entity == "select.predbat_update": - # Do not restore predbat version + # Do not restore predbat version continue if enable == try_enable and self.user_config_item_enabled(item): @@ -10230,7 +10320,7 @@ def save_settings(self): text += " target:\n" text += " entity_id: {}\n".format(entity) text += " data:\n" - text += ' option: "{}"\n'.format(value) + text += " option: \"{}\"\n".format(value) with open(filename, "w") as file: file.write(text) self.log("Wrote settings to {}".format(filename)) @@ -10738,4 +10828,5 @@ def run_time_loop_balance(self, cb_args): except Exception as e: self.log("ERROR: Exception raised {}".format(e)) self.record_status("ERROR: Exception raised {}".format(e)) - raise e + raise + From 4835dbe9044cc0be0b3a93e66eaf88546dd4666b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Sun, 14 Jan 2024 21:31:49 +0000 Subject: [PATCH 2/9] [pre-commit.ci lite] apply automatic fixes --- apps/predbat/predbat.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 949817558..372647a16 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -55,7 +55,7 @@ # Predbat update options PREDBAT_UPDATE_OPTIONS = [THIS_VERSION + " Loading..."] -PREDBAT_SAVE_RESTORE = ['save current', 'restore default'] +PREDBAT_SAVE_RESTORE = ["save current", "restore default"] # Configuration options inside HA CONFIG_ITEMS = [ @@ -478,7 +478,7 @@ "type": "select", "options": PREDBAT_SAVE_RESTORE, "icon": "mdi:state-machine", - "default": '', + "default": "", }, {"name": "auto_update", "friendly_name": "Predbat automatic update enable", "type": "switch", "default": False}, {"name": "load_filter_modal", "friendly_name": "Apply modal filter historical load", "type": "switch", "enable": "expert_mode", "default": True}, @@ -8737,7 +8737,7 @@ def calculate_plan(self, recompute=True): # HTML data self.publish_html_plan(pv_forecast_minute_step, load_minutes_step, self.end_record) - # Return if we recomputed or not + # Return if we recomputed or not return recompute def reset_inverter(self): @@ -8867,7 +8867,7 @@ def execute_plan(self): if (self.minutes_now < minutes_end) and ( (minutes_start - self.minutes_now) <= self.set_window_minutes or (inverter.charge_start_time_minutes - self.minutes_now) <= self.set_window_minutes ): - if ((minutes_start - self.minutes_now) > self.set_window_minutes) and (minutes_end - self.minutes_now) >= 24*60: + if ((minutes_start - self.minutes_now) > self.set_window_minutes) and (minutes_end - self.minutes_now) >= 24 * 60: self.log("Charge window would wrap, disabling until later") inverter.disable_charge_window() else: @@ -10210,18 +10210,18 @@ def update_save_restore_list(self): self.save_restore_dir = root + "/predbat_save" if not self.save_restore_dir: return - + if not os.path.exists(self.save_restore_dir): os.mkdir(self.save_restore_dir) - PREDBAT_SAVE_RESTORE = ['save current', 'restore default'] + PREDBAT_SAVE_RESTORE = ["save current", "restore default"] for root, dirs, files in os.walk(self.save_restore_dir): for name in files: filepath = os.path.join(root, name) - if filepath.endswith('.yaml'): + if filepath.endswith(".yaml"): PREDBAT_SAVE_RESTORE.append(name) item = self.config_index.get("saverestore", None) - item['options'] = PREDBAT_SAVE_RESTORE + item["options"] = PREDBAT_SAVE_RESTORE self.expose_config("saverestore", None) def restore_settings_yaml(self, filename): @@ -10257,10 +10257,10 @@ def save_settings_yaml(self): """ if not self.save_restore_dir: return - + filename = self.time_abs_str(self.minutes_now) - filename = filename.replace(' ', '_') - filename = filename.replace(':', '_') + filename = filename.replace(" ", "_") + filename = filename.replace(":", "_") filename += ".yaml" filepath = os.path.join(self.save_restore_dir, filename) with open(filepath, "w") as file: @@ -10274,7 +10274,7 @@ def save_settings(self): basename = "/predbat_restore_settings.yaml" filename = None text = "" - text += "alias: \"Restore Predbat settings from {}\"\n".format(self.time_abs_str(self.minutes_now)) + text += 'alias: "Restore Predbat settings from {}"\n'.format(self.time_abs_str(self.minutes_now)) text += "mode: single\n" text += "trigger: []\n" text += "condition: []\n" @@ -10295,7 +10295,7 @@ def save_settings(self): enable = item.get("enable", None) if entity == "select.predbat_update": - # Do not restore predbat version + # Do not restore predbat version continue if enable == try_enable and self.user_config_item_enabled(item): @@ -10320,7 +10320,7 @@ def save_settings(self): text += " target:\n" text += " entity_id: {}\n".format(entity) text += " data:\n" - text += " option: \"{}\"\n".format(value) + text += ' option: "{}"\n'.format(value) with open(filename, "w") as file: file.write(text) self.log("Wrote settings to {}".format(filename)) @@ -10828,5 +10828,4 @@ def run_time_loop_balance(self, cb_args): except Exception as e: self.log("ERROR: Exception raised {}".format(e)) self.record_status("ERROR: Exception raised {}".format(e)) - raise - + raise From 1b9ce256b309787af2520f108d7f8c8e9f3b366b Mon Sep 17 00:00:00 2001 From: Trefor Southwell <48591903+springfall2008@users.noreply.github.com> Date: Sun, 14 Jan 2024 21:33:18 +0000 Subject: [PATCH 3/9] Remove old save settings for automation code --- apps/predbat/predbat.py | 85 +++++++---------------------------------- 1 file changed, 13 insertions(+), 72 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 372647a16..e21336028 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -55,7 +55,7 @@ # Predbat update options PREDBAT_UPDATE_OPTIONS = [THIS_VERSION + " Loading..."] -PREDBAT_SAVE_RESTORE = ["save current", "restore default"] +PREDBAT_SAVE_RESTORE = ['save current', 'restore default'] # Configuration options inside HA CONFIG_ITEMS = [ @@ -478,7 +478,7 @@ "type": "select", "options": PREDBAT_SAVE_RESTORE, "icon": "mdi:state-machine", - "default": "", + "default": '', }, {"name": "auto_update", "friendly_name": "Predbat automatic update enable", "type": "switch", "default": False}, {"name": "load_filter_modal", "friendly_name": "Apply modal filter historical load", "type": "switch", "enable": "expert_mode", "default": True}, @@ -8737,7 +8737,7 @@ def calculate_plan(self, recompute=True): # HTML data self.publish_html_plan(pv_forecast_minute_step, load_minutes_step, self.end_record) - # Return if we recomputed or not + # Return if we recomputed or not return recompute def reset_inverter(self): @@ -8867,7 +8867,7 @@ def execute_plan(self): if (self.minutes_now < minutes_end) and ( (minutes_start - self.minutes_now) <= self.set_window_minutes or (inverter.charge_start_time_minutes - self.minutes_now) <= self.set_window_minutes ): - if ((minutes_start - self.minutes_now) > self.set_window_minutes) and (minutes_end - self.minutes_now) >= 24 * 60: + if ((minutes_start - self.minutes_now) > self.set_window_minutes) and (minutes_end - self.minutes_now) >= 24*60: self.log("Charge window would wrap, disabling until later") inverter.disable_charge_window() else: @@ -10210,18 +10210,18 @@ def update_save_restore_list(self): self.save_restore_dir = root + "/predbat_save" if not self.save_restore_dir: return - + if not os.path.exists(self.save_restore_dir): os.mkdir(self.save_restore_dir) - PREDBAT_SAVE_RESTORE = ["save current", "restore default"] + PREDBAT_SAVE_RESTORE = ['save current', 'restore default'] for root, dirs, files in os.walk(self.save_restore_dir): for name in files: filepath = os.path.join(root, name) - if filepath.endswith(".yaml"): + if filepath.endswith('.yaml'): PREDBAT_SAVE_RESTORE.append(name) item = self.config_index.get("saverestore", None) - item["options"] = PREDBAT_SAVE_RESTORE + item['options'] = PREDBAT_SAVE_RESTORE self.expose_config("saverestore", None) def restore_settings_yaml(self, filename): @@ -10257,74 +10257,16 @@ def save_settings_yaml(self): """ if not self.save_restore_dir: return - + filename = self.time_abs_str(self.minutes_now) - filename = filename.replace(" ", "_") - filename = filename.replace(":", "_") + filename = filename.replace(' ', '_') + filename = filename.replace(':', '_') filename += ".yaml" filepath = os.path.join(self.save_restore_dir, filename) with open(filepath, "w") as file: yaml.dump(CONFIG_ITEMS, file) self.log("Saved Predbat settings to {}".format(filepath)) - def save_settings(self): - """ - Save current predbat settings - """ - basename = "/predbat_restore_settings.yaml" - filename = None - text = "" - text += 'alias: "Restore Predbat settings from {}"\n'.format(self.time_abs_str(self.minutes_now)) - text += "mode: single\n" - text += "trigger: []\n" - text += "condition: []\n" - text += "action:\n" - for root in CONFIG_ROOTS: - if os.path.exists(root): - filename = root + basename - if filename: - enable_list = [None] - for item in CONFIG_ITEMS: - enable = item.get("enable", None) - if enable and enable not in enable_list: - enable_list.append(enable) - - for try_enable in enable_list: - for item in CONFIG_ITEMS: - entity = item["entity"] - enable = item.get("enable", None) - - if entity == "select.predbat_update": - # Do not restore predbat version - continue - - if enable == try_enable and self.user_config_item_enabled(item): - value = item.get("value", None) - if value is not None: - if item["type"] == "input_number": - text += " - service: input_number.set_value\n" - text += " target:\n" - text += " entity_id: {}\n".format(entity) - text += " data:\n" - text += " value: {}\n".format(value) - elif item["type"] == "switch": - if value: - text += " - service: switch.turn_on\n" - else: - text += " - service: switch.turn_off\n" - text += " target:\n" - text += " entity_id: {}\n".format(entity) - text += " data: {}\n" - elif item["type"] == "select": - text += " - service: select.select_option\n" - text += " target:\n" - text += " entity_id: {}\n".format(entity) - text += " data:\n" - text += ' option: "{}"\n'.format(value) - with open(filename, "w") as file: - file.write(text) - self.log("Wrote settings to {}".format(filename)) - def create_debug_yaml(self): """ Write out a debug info yaml @@ -10784,7 +10726,6 @@ def update_time_loop(self, cb_args): try: self.update_pred(scheduled=False) self.create_entity_list() - self.save_settings() except Exception as e: self.log("ERROR: Exception raised {}".format(e)) self.record_status("ERROR: Exception raised {}".format(e)) @@ -10815,7 +10756,6 @@ def run_time_loop(self, cb_args): self.prediction_started = False if config_changed: self.create_entity_list() - self.save_settings() self.prediction_started = False def run_time_loop_balance(self, cb_args): @@ -10828,4 +10768,5 @@ def run_time_loop_balance(self, cb_args): except Exception as e: self.log("ERROR: Exception raised {}".format(e)) self.record_status("ERROR: Exception raised {}".format(e)) - raise + raise + From 1f79c0e99190778596491ca110ddf1e54e24cab6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Sun, 14 Jan 2024 21:34:36 +0000 Subject: [PATCH 4/9] [pre-commit.ci lite] apply automatic fixes --- apps/predbat/predbat.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index e21336028..00b8b3b1a 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -55,7 +55,7 @@ # Predbat update options PREDBAT_UPDATE_OPTIONS = [THIS_VERSION + " Loading..."] -PREDBAT_SAVE_RESTORE = ['save current', 'restore default'] +PREDBAT_SAVE_RESTORE = ["save current", "restore default"] # Configuration options inside HA CONFIG_ITEMS = [ @@ -478,7 +478,7 @@ "type": "select", "options": PREDBAT_SAVE_RESTORE, "icon": "mdi:state-machine", - "default": '', + "default": "", }, {"name": "auto_update", "friendly_name": "Predbat automatic update enable", "type": "switch", "default": False}, {"name": "load_filter_modal", "friendly_name": "Apply modal filter historical load", "type": "switch", "enable": "expert_mode", "default": True}, @@ -8737,7 +8737,7 @@ def calculate_plan(self, recompute=True): # HTML data self.publish_html_plan(pv_forecast_minute_step, load_minutes_step, self.end_record) - # Return if we recomputed or not + # Return if we recomputed or not return recompute def reset_inverter(self): @@ -8867,7 +8867,7 @@ def execute_plan(self): if (self.minutes_now < minutes_end) and ( (minutes_start - self.minutes_now) <= self.set_window_minutes or (inverter.charge_start_time_minutes - self.minutes_now) <= self.set_window_minutes ): - if ((minutes_start - self.minutes_now) > self.set_window_minutes) and (minutes_end - self.minutes_now) >= 24*60: + if ((minutes_start - self.minutes_now) > self.set_window_minutes) and (minutes_end - self.minutes_now) >= 24 * 60: self.log("Charge window would wrap, disabling until later") inverter.disable_charge_window() else: @@ -10210,18 +10210,18 @@ def update_save_restore_list(self): self.save_restore_dir = root + "/predbat_save" if not self.save_restore_dir: return - + if not os.path.exists(self.save_restore_dir): os.mkdir(self.save_restore_dir) - PREDBAT_SAVE_RESTORE = ['save current', 'restore default'] + PREDBAT_SAVE_RESTORE = ["save current", "restore default"] for root, dirs, files in os.walk(self.save_restore_dir): for name in files: filepath = os.path.join(root, name) - if filepath.endswith('.yaml'): + if filepath.endswith(".yaml"): PREDBAT_SAVE_RESTORE.append(name) item = self.config_index.get("saverestore", None) - item['options'] = PREDBAT_SAVE_RESTORE + item["options"] = PREDBAT_SAVE_RESTORE self.expose_config("saverestore", None) def restore_settings_yaml(self, filename): @@ -10257,10 +10257,10 @@ def save_settings_yaml(self): """ if not self.save_restore_dir: return - + filename = self.time_abs_str(self.minutes_now) - filename = filename.replace(' ', '_') - filename = filename.replace(':', '_') + filename = filename.replace(" ", "_") + filename = filename.replace(":", "_") filename += ".yaml" filepath = os.path.join(self.save_restore_dir, filename) with open(filepath, "w") as file: @@ -10768,5 +10768,4 @@ def run_time_loop_balance(self, cb_args): except Exception as e: self.log("ERROR: Exception raised {}".format(e)) self.record_status("ERROR: Exception raised {}".format(e)) - raise - + raise From c2282e9075051f5cb2d2033d0d25b3d6e3979ebf Mon Sep 17 00:00:00 2001 From: Trefor Southwell <48591903+springfall2008@users.noreply.github.com> Date: Mon, 15 Jan 2024 08:05:52 +0000 Subject: [PATCH 5/9] Update custom-dictionary-workspace.txt --- .cspell/custom-dictionary-workspace.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.cspell/custom-dictionary-workspace.txt b/.cspell/custom-dictionary-workspace.txt index f68299160..d0ac5a092 100644 --- a/.cspell/custom-dictionary-workspace.txt +++ b/.cspell/custom-dictionary-workspace.txt @@ -98,6 +98,7 @@ rname rowspan rstart rtype +saverestore searr Selfuse socb From fffb50d135bc5abadd0a1a4af538cc850375bd47 Mon Sep 17 00:00:00 2001 From: Trefor Southwell <48591903+springfall2008@users.noreply.github.com> Date: Mon, 15 Jan 2024 09:34:04 +0000 Subject: [PATCH 6/9] Notification for save/restore and fix default restore --- apps/predbat/predbat.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 00b8b3b1a..5e00acf3d 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -68,7 +68,7 @@ "release_url": "https://github.com/springfall2008/batpred/releases/tag/" + THIS_VERSION, "entity_picture": "https://user-images.githubusercontent.com/48591903/249456079-e98a0720-d2cf-4b71-94ab-97fe09b3cee1.png", }, - {"name": "expert_mode", "friendly_name": "Expert Mode", "type": "switch", "default": True}, + {"name": "expert_mode", "friendly_name": "Expert Mode", "type": "switch", "default": False}, { "name": "pv_metric10_weight", "friendly_name": "Metric 10 Weight", @@ -10235,11 +10235,15 @@ def restore_settings_yaml(self, filename): if not self.save_restore_dir: return + self.save_settings_yaml("previous.yaml") + if not filename: self.log("Restore settings to default") for item in CONFIG_ITEMS: - self.log("Restore setting: {} = {}".format(item["name"], item["default"])) - self.expose_config(item["name"], item["default"], event=True) + if (item["value"] != item.get("default", None)) and (item["name"] != "update"): + self.log("Restore setting: {} = {} (was {})".format(item["name"], item["default"], item["value"])) + self.expose_config(item["name"], item["default"], event=True) + self.call_notify("Predbat settings restored from default") else: filepath = os.path.join(self.save_restore_dir, filename) if os.path.exists(filepath): @@ -10247,25 +10251,28 @@ def restore_settings_yaml(self, filename): with open(filepath, "r") as file: settings = yaml.safe_load(file) for item in settings: - self.log("Restore setting: {} = {}".format(item["name"], item["value"])) - self.expose_config(item["name"], item["value"], event=True) + current = self.config_index.get(item["name"], None) + if current and (current["value"] != item["value"]) and (item["name"] != "update"): + self.log("Restore setting: {} = {} (was {})".format(item["name"], item["value"], current["value"])) + self.expose_config(item["name"], item["value"], event=True) + self.call_notify("Predbat settings restored from {}".format(filename)) self.expose_config("saverestore", None) - def save_settings_yaml(self): + def save_settings_yaml(self, filename=None): """ Save current Predbat settings """ if not self.save_restore_dir: return - filename = self.time_abs_str(self.minutes_now) - filename = filename.replace(" ", "_") - filename = filename.replace(":", "_") - filename += ".yaml" + if not filename: + filename = self.now_utc.strftime("%y_%m_%d_%H_%M_%S") + filename += ".yaml" filepath = os.path.join(self.save_restore_dir, filename) with open(filepath, "w") as file: yaml.dump(CONFIG_ITEMS, file) self.log("Saved Predbat settings to {}".format(filepath)) + self.call_notify("Predbat settings saved to {}".format(filename)) def create_debug_yaml(self): """ @@ -10355,11 +10362,7 @@ def load_user_config(self, quiet=True, register=False): name = item["name"] self.config_index[name] = item - # Set the default for expert mode to False for new installs only - if name == "expert_mode": - if new_install: - item["default"] = False - elif name == "mode": + if name == "mode": if new_install: item["default"] = PREDBAT_MODE_OPTIONS[PREDBAT_MODE_MONITOR] @@ -10768,4 +10771,4 @@ def run_time_loop_balance(self, cb_args): except Exception as e: self.log("ERROR: Exception raised {}".format(e)) self.record_status("ERROR: Exception raised {}".format(e)) - raise + raise \ No newline at end of file From cae0e161398025bdfeade4dd0c30bae965c2fdd6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 09:34:46 +0000 Subject: [PATCH 7/9] [pre-commit.ci lite] apply automatic fixes --- apps/predbat/predbat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 5e00acf3d..289467dd6 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -10771,4 +10771,4 @@ def run_time_loop_balance(self, cb_args): except Exception as e: self.log("ERROR: Exception raised {}".format(e)) self.record_status("ERROR: Exception raised {}".format(e)) - raise \ No newline at end of file + raise From 7fb26f4780a424d0908597ae50527117db25502d Mon Sep 17 00:00:00 2001 From: Trefor Southwell <48591903+springfall2008@users.noreply.github.com> Date: Mon, 15 Jan 2024 09:42:09 +0000 Subject: [PATCH 8/9] Update customisation.md - document save/restore --- docs/customisation.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/customisation.md b/docs/customisation.md index 52a57159e..79d571f63 100644 --- a/docs/customisation.md +++ b/docs/customisation.md @@ -6,6 +6,22 @@ See [Displaying output data](output-data.md#displayng-output-data) for information on how to view and edit these entities within Home Assistant. +## Saving and restoring Predbat settings + +The selector **select.predbat_saverestore** can be used to save you current settings to a yaml file (kept in /config/predbat_save/) and to +restore the settings from one of these files. + +Selecting **save current** will cause the settings to be save to a date/time stamped file. You can rename this file yourself in the HA filesystem +to give it a more human readable name or delete it if you no longer want it. This is normally best done in the SSH window or via a Samba mount. + +Selecting **restore default** will put all your settings back to the Predbat defaults. +Before the the restore the current settings will be saved as **previous.yaml** should you have made a mistake you can restore them quickly again. + +Selecting any of the .yaml files you have created will restore your settings from this file. +Before the the restore the current settings will be saved as **previous.yaml** should you have made a mistake you can restore them quickly again. + +![image](https://github.com/springfall2008/batpred/assets/48591903/209442c1-bd4d-4812-84e2-c5a81794bd1d) + ## Predbat mode The mode that Predbat operates in will change the operation, this can be configured with **select.predbat_mode** drop down menu as follows: @@ -22,6 +38,8 @@ This is useful if you want to over-ride what predbat is planning to do (e.g. you _NOTE: Changing the Predbat mode or the read only switch will cause Predbat to reset the inverter settings to default, this will disable both charge and discharge, reset charge and discharge rates to full power and reset the reserve to the default setting_ +![image](https://github.com/springfall2008/batpred/assets/48591903/43faa962-6b8a-495a-88f8-f762aa1d55b8) + ### Predbat Monitor mode In **monitor** mode Predbat will not control charging or discharging, inverter balancing will take place if enabled, the plan will show From e2fdf479fe84a8bc22e6a30497a5c3f141802909 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 09:42:54 +0000 Subject: [PATCH 9/9] [pre-commit.ci lite] apply automatic fixes --- docs/customisation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/customisation.md b/docs/customisation.md index 79d571f63..a5c127e6f 100644 --- a/docs/customisation.md +++ b/docs/customisation.md @@ -8,16 +8,16 @@ Home Assistant. ## Saving and restoring Predbat settings -The selector **select.predbat_saverestore** can be used to save you current settings to a yaml file (kept in /config/predbat_save/) and to +The selector **select.predbat_saverestore** can be used to save you current settings to a yaml file (kept in /config/predbat_save/) and to restore the settings from one of these files. Selecting **save current** will cause the settings to be save to a date/time stamped file. You can rename this file yourself in the HA filesystem to give it a more human readable name or delete it if you no longer want it. This is normally best done in the SSH window or via a Samba mount. -Selecting **restore default** will put all your settings back to the Predbat defaults. +Selecting **restore default** will put all your settings back to the Predbat defaults. Before the the restore the current settings will be saved as **previous.yaml** should you have made a mistake you can restore them quickly again. -Selecting any of the .yaml files you have created will restore your settings from this file. +Selecting any of the .yaml files you have created will restore your settings from this file. Before the the restore the current settings will be saved as **previous.yaml** should you have made a mistake you can restore them quickly again. ![image](https://github.com/springfall2008/batpred/assets/48591903/209442c1-bd4d-4812-84e2-c5a81794bd1d)