From 7a79d03953407b7daa1f7f38fc95c8e312efc8f8 Mon Sep 17 00:00:00 2001 From: nebhead Date: Sun, 9 Jun 2024 14:19:39 -0700 Subject: [PATCH] Added Dashboard Configuration Capability Added dashboard configuration capability defined in the ./dashboard folder with a json file defining configuration for each. This will get built on boot and loaded dynamically. Default dashboard now has the option to set the maximum temperature to display for both the primary and the food gauges. This can be configured by clicking on the gear icon. --- app.py | 22 ++++++++++++ common/common.py | 54 ++++++++++++++++------------ dashboard/default.json | 47 +++++++++++++++++++++++- static/js/dash_default.js | 40 ++++++++++++++------- templates/_macro_dash_default.html | 46 +++++++++++++++++++++++- templates/_macro_generic_config.html | 27 ++++++++++++++ templates/dash_default.html | 32 ++++++++--------- updater/post-update-message.html | 3 ++ 8 files changed, 218 insertions(+), 53 deletions(-) create mode 100644 templates/_macro_generic_config.html diff --git a/app.py b/app.py index c7257a37..3b4289fe 100755 --- a/app.py +++ b/app.py @@ -98,6 +98,28 @@ def dash(): page_theme=settings['globals']['page_theme'], grill_name=settings['globals']['grill_name']) +@app.route('/dashconfig', methods=['POST','GET']) +def dash_config(): + global settings + current = settings['dashboard']['current'] + dash_data = settings['dashboard']['dashboards'].get(current, {}) + meta_data_filename = dash_data.get('metadata', None) + dash_metadata = read_generic_json(f'./dashboard/{meta_data_filename}') + + if request.method == 'GET': + render_string = "{% from '_macro_dash_default.html' import render_config_card %}{{ render_config_card(dash_metadata, dash_data) }}" + return render_template_string(render_string, dash_metadata=dash_metadata, dash_data=dash_data) + elif request.method == 'POST': + dash_config_request = request.form + for key, value in dash_config_request.items(): + if 'dashConfig_' in key: + dash_data['config'][key.replace('dashConfig_','')] = value + settings['dashboard']['dashboards'][current]['config'] = dash_data['config'] + write_settings(settings) + return redirect('/dash') + + return 'Bad Request' + @app.route('/hopperlevel') def hopper_level(): pelletdb = read_pellet_db() diff --git a/common/common.py b/common/common.py index 59567969..57ca6a6e 100644 --- a/common/common.py +++ b/common/common.py @@ -272,29 +272,7 @@ def default_settings(): 'auto_power_off' : False # Power off the system after shutdown (False = disabled) } - settings['dashboard'] = { - 'current' : 'Default', - 'dashboards' : { - 'Default' : { - 'name' : 'Default', - 'friendly_name' : 'Default Dashboard', - 'html_name' : 'dash_default.html', - 'custom' : { - 'hidden_cards' : [] - }, - 'config' : {} - }, - 'Basic' : { - 'name' : 'Basic', - 'friendly_name' : 'Basic Dashboard', - 'html_name' : 'dash_basic.html', - 'custom' : { - 'hidden_cards' : [] - }, - 'config' : {} - } - } - } + settings['dashboard'] = _default_dashboard() settings['notify_services'] = default_notify_services() @@ -312,6 +290,36 @@ def default_settings(): return settings +def _default_dashboard(): + ''' + Generate default dashboard settings by getting metadata from each json file in the /dashboard folder + ''' + dash_data = { + 'current' : 'Default', + 'dashboards' : {} + } + # Define the folder path + folder_path = './dashboard' + + # Loop through files in the folder + for filename in os.listdir(folder_path): + # Check if the file is a JSON file + if filename.endswith('.json'): + dash_metadata = read_generic_json(os.path.join(folder_path, filename)) + dash_data['dashboards'][dash_metadata['name']] = { + 'name' : dash_metadata['name'], + 'friendly_name' : dash_metadata['friendly_name'], + 'html_name' : dash_metadata['html_name'], + 'metadata' : filename, + 'custom' : dash_metadata['custom'], + 'config' : {} + } + for item in dash_metadata['config']: + dash_data['dashboards'][dash_metadata['name']]['config'][item['name']] = item['default'] + + return dash_data + + def _default_controller_config(): controller_metadata = read_generic_json('./controller/controllers.json') config = {} diff --git a/dashboard/default.json b/dashboard/default.json index 45e973c9..d935ff1a 100644 --- a/dashboard/default.json +++ b/dashboard/default.json @@ -12,5 +12,50 @@ "custom" : { "hidden_cards" : [] }, - "config" : {} + "config" : [ + { + "name": "max_primary_temp_F", + "friendly_name": "Max Primary Probe Display Temp F", + "description": "This is the maximum primary probe (grill probe) display temperature (F). The primary gauge will max out at this temperature.", + "hidden": false, + "type": "float", + "min": 0, + "max": 10000, + "step": 1, + "default": 600 + }, + { + "name": "max_food_temp_F", + "friendly_name": "Max Food Probe Display Temp F", + "description": "This is the maximum food probe display temperature (F). The food gauges will max out at this temperature.", + "hidden": false, + "type": "float", + "min": 0, + "max": 10000, + "step": 1, + "default": 300 + }, + { + "name": "max_primary_temp_C", + "friendly_name": "Max Primary Probe Display Temp C", + "description": "This is the maximum primary probe (grill probe) display temperature (C). The primary gauge will max out at this temperature.", + "hidden": false, + "type": "float", + "min": 0, + "max": 10000, + "step": 1, + "default": 300 + }, + { + "name": "max_food_temp_C", + "friendly_name": "Max Food Probe Display Temp C", + "description": "This is the maximum food probe display temperature (C). The food gauges will max out at this temperature.", + "hidden": false, + "type": "float", + "min": 0, + "max": 10000, + "step": 1, + "default": 150 + } + ] } \ No newline at end of file diff --git a/static/js/dash_default.js b/static/js/dash_default.js index bb7ce54d..000a3236 100644 --- a/static/js/dash_default.js +++ b/static/js/dash_default.js @@ -12,21 +12,33 @@ var probes = []; // List of probe keys var primary = ''; // Primary key var probeGauges = {}; // List of probe gauges var probesReady = false; // Pre-initialized state -// Set max temperatures for units specified -if (units == 'F') { - var maxTempPrimary = 600; - var maxTempFood = 300; -} else { - var maxTempPrimary = 300; - var maxTempFood = 150; -} + var last_fan_status = null; var last_auger_status = null; var last_igniter_status = null; var last_pmode_status = null; var last_lid_open_status = false; var display_mode = null; -var dashDataStruct = {}; +if (typeof dashDataStruct == 'undefined') { + var dashDataStruct = {}; + console.log('DEBUG: dashDataStruct undefined'); + // Set max temperatures for units specified + if (units == 'F') { + var maxTempPrimary = 600; + var maxTempFood = 300; + } else { + var maxTempPrimary = 300; + var maxTempFood = 150; + }; +} else { + if (units == 'F') { + var maxTempPrimary = dashDataStruct.config.max_primary_temp_F; + var maxTempFood = dashDataStruct.config.max_food_temp_F; + } else { + var maxTempPrimary = dashDataStruct.config.max_primary_temp_C; + var maxTempFood = dashDataStruct.config.max_food_temp_C; + }; +}; // Credits to https://github.com/naikus for SVG-Gauge (https://github.com/naikus/svg-gauge) MIT License Copyright (c) 2016 Aniket Naik var Gauge = window.Gauge; @@ -69,10 +81,10 @@ function initProbeGauge(key) { value: 0, // Custom dial colors (Optional) color: function(value) { - if(value <= maxTemp) { + if(value <= maxTemp * 0.90) { return "#3498db"; // default color }else { - return "#ef4655"; // if exceeds max value, RED + return "#ef4655"; // if is temperature is greater than 10% of max value, RED }; } }); @@ -534,8 +546,12 @@ function setPmode(pmode) { // Show the Dashboard Settings Modal/Dialog when clicked function dashSettings() { + dashLoadConfig(); $("#dashSettingsModal").modal('show'); - //dashData(); +}; + +function dashLoadConfig() { + $("#dash_config_card").load("/dashconfig"); }; // Get dashboard data structure diff --git a/templates/_macro_dash_default.html b/templates/_macro_dash_default.html index fb2a663d..9a7aae66 100755 --- a/templates/_macro_dash_default.html +++ b/templates/_macro_dash_default.html @@ -236,4 +236,48 @@

HH:MM:SS -{% endmacro %} \ No newline at end of file +{% endmacro %} + +{% macro render_config_card(dash_metadata, dash_data) %} +{% from '_macro_generic_config.html' import config_input_float_int, config_input_list, config_input_string%} +
+
+
+ Default Dashboard Configuration Settings +
+
+ + + + + + + + + + + {% for item in dash_metadata['config'] %} + + + + + + {% endfor %} + +
SettingOptionsDescription
{{ item['friendly_name'] }} + {% if item['type'] == 'float' or item['type'] == 'int' %} + {{ config_input_float_int('dashConfigItem', 'dashConfig', item['name'], dash_data['config'][item['name']], item['min'], item['max'], item['step']) }} + {% elif item['type'] == 'list' %} + {{ config_input_list('dashConfigItem', 'dashConfig', item['name'], dash_data['config'][item['name']], item['list_values'], item['list_labels']) }} + {% elif item['type'] == 'string' %} + {{ config_input_string('dashConfigItem', 'dashConfig', item['name'], dash_data['config'][item['name']]) }} + {% endif %} + {{ item.description }}
+
+ +
+
+{% endmacro %} diff --git a/templates/_macro_generic_config.html b/templates/_macro_generic_config.html new file mode 100644 index 00000000..7937e291 --- /dev/null +++ b/templates/_macro_generic_config.html @@ -0,0 +1,27 @@ +{% macro config_input_float_int(classname, id_prefix, label, default, min, max, step) %} + +{% endmacro %} + +{% macro config_input_list(classname, id_prefix, label, default, list_values, list_labels) %} + +{% endmacro %} + +{% macro config_input_string(classname, id_prefix, label, default) %} + +{% endmacro %} + diff --git a/templates/dash_default.html b/templates/dash_default.html index 6fbe9c4f..fa9028c3 100755 --- a/templates/dash_default.html +++ b/templates/dash_default.html @@ -90,7 +90,7 @@