emhass 0.11.4__py3-none-any.whl → 0.15.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,6 +18,13 @@
18
18
  </br></br>
19
19
  <button type="button" id="regressor-model-fit" class="button button1">ML regressor model fit</button>
20
20
  <button type="button" id="regressor-model-predict" class="button button2">ML regressor model predict</button>
21
+ </br></br>
22
+ <div id="export-influxdb-section" style="display: none;">
23
+ <h4>Export InfluxDB data to CSV for ML training</h4>
24
+ <p style="font-size: 0.9em; color: #666; margin-top: -10px;">Export historical sensor data from InfluxDB to train ML regressor models</p>
25
+ <button type="button" id="export-influxdb-to-csv" class="button button1">Export InfluxDB to CSV</button>
26
+ </br></br>
27
+ </div>
21
28
  <!-- -->
22
29
  <!--dynamic runtime parameter input (list and box) elements section -->
23
30
  <h4>Input Runtime Parameters</h4>
@@ -29,13 +29,17 @@
29
29
  <div id="Solar System (PV)" class="section-card">
30
30
  <div class="section-card-header">
31
31
  <h4>Solar System (PV)</h4>
32
+ <label class="switch" for="set_use_pv"> <!-- switch connected to set_use_pv -->
33
+ <input id="set_use_pv" type="checkbox">
34
+ <span class="slider"></span>
35
+ </label>
32
36
  </div>
33
37
  <div class="section-body"> </div> <!-- parameters will get generated here -->
34
38
  </div>
35
39
  <div id="Battery" class="section-card">
36
40
  <div class="section-card-header">
37
41
  <h4>Battery</h4>
38
- <label class="switch"> <!-- switch connected to set_use_battery -->
42
+ <label class="switch" for="set_use_battery"> <!-- switch connected to set_use_battery -->
39
43
  <input id="set_use_battery" type="checkbox">
40
44
  <span class="slider"></span>
41
45
  </label>
@@ -19,11 +19,11 @@
19
19
  //on page reload
20
20
  window.onload = async function () {
21
21
  ///fetch configuration parameters from definitions json file
22
- param_definitions = await getParamDefinitions();
22
+ let param_definitions = await getParamDefinitions();
23
23
  //obtain configuration from emhass (pull)
24
- config = await obtainConfig();
24
+ let config = await obtainConfig();
25
25
  //obtain configuration_list.html html as a template to dynamically to render parameters in a list view (parameters as input items)
26
- list_html = await getListHTML();
26
+ let list_html = await getListHTML();
27
27
  //load list parameter page (default)
28
28
  loadConfigurationListView(param_definitions, config, list_html);
29
29
 
@@ -70,14 +70,14 @@ async function obtainConfig() {
70
70
  const response = await fetch(`get-config`, {
71
71
  method: "GET",
72
72
  });
73
- response_status = await response.status; //return status
73
+ let response_status = response.status; //return status
74
74
  //if request failed
75
75
  if (response_status !== 200 && response_status !== 201) {
76
76
  showChangeStatus(response_status, await response.json());
77
77
  return {};
78
78
  }
79
79
  //else extract json rom data
80
- blob = await response.blob(); //get data blob
80
+ let blob = await response.blob(); //get data blob
81
81
  config = await new Response(blob).json(); //obtain json from blob
82
82
  showChangeStatus(response_status, {});
83
83
  return config;
@@ -90,13 +90,13 @@ async function ObtainDefaultConfig() {
90
90
  method: "GET",
91
91
  });
92
92
  //if request failed
93
- response_status = await response.status; //return status
93
+ let response_status = response.status; //return status
94
94
  if (response_status !== 200 && response_status !== 201) {
95
95
  showChangeStatus(response_status, await response.json());
96
96
  return {};
97
97
  }
98
98
  //else extract json rom data
99
- blob = await response.blob(); //get data blob
99
+ let blob = await response.blob(); //get data blob
100
100
  config = await new Response(blob).json(); //obtain json from blob
101
101
  showChangeStatus(response_status, {});
102
102
  return config;
@@ -109,9 +109,9 @@ async function getListHTML() {
109
109
  errorAlert("Unable to obtain configuration_list.html file");
110
110
  return {};
111
111
  }
112
- blob = await response.blob(); //get data blob
113
- htmlTemplateData = await new Response(blob).text(); //obtain html from blob
114
- return await htmlTemplateData;
112
+ let blob = await response.blob(); //get data blob
113
+ let htmlTemplateData = await new Response(blob).text(); //obtain html from blob
114
+ return htmlTemplateData;
115
115
  }
116
116
 
117
117
  //load list configuration view
@@ -121,13 +121,13 @@ function loadConfigurationListView(param_definitions, config, list_html) {
121
121
  }
122
122
 
123
123
  //list parameters used in the section headers
124
- header_input_list = ["set_use_battery", "number_of_deferrable_loads"];
124
+ let header_input_list = ["set_use_battery", "set_use_pv", "number_of_deferrable_loads"];
125
125
 
126
126
  //get the main container and append list template html
127
127
  document.getElementById("configuration-container").innerHTML = list_html;
128
128
 
129
- //loop though configuration sections ('Local','System','Tariff','Solar System (PV)') in definitions file
130
- for (var section in param_definitions) {
129
+ //loop through configuration sections ('Local','System','Tariff','Solar System (PV)') in definitions file
130
+ for (let section in param_definitions) {
131
131
  // build each section by adding parameters with their corresponding input elements
132
132
  buildParamContainers(
133
133
  section,
@@ -138,12 +138,12 @@ function loadConfigurationListView(param_definitions, config, list_html) {
138
138
 
139
139
  //after sections have been built, add event listeners for section header inputs
140
140
  //loop though headers
141
- for (header_input_param of header_input_list) {
141
+ for (let header_input_param of header_input_list) {
142
142
  if (param_definitions[section].hasOwnProperty(header_input_param)) {
143
143
  //grab default from definitions file
144
- value = param_definitions[section][header_input_param]["default_value"];
144
+ let value = param_definitions[section][header_input_param]["default_value"];
145
145
  //find input element (using the parameter name as the input element ID)
146
- header_input_element = document.getElementById(header_input_param);
146
+ let header_input_element = document.getElementById(header_input_param);
147
147
  if (header_input_element !== null) {
148
148
  //add event listener to element (trigger on input change)
149
149
  header_input_element.addEventListener("input", (e) =>
@@ -164,6 +164,74 @@ function loadConfigurationListView(param_definitions, config, list_html) {
164
164
  }
165
165
  }
166
166
  }
167
+
168
+ // Dynamic hiding for InfluxDB options
169
+ const use_influx_param = "use_influxdb";
170
+ const influx_related_params = [
171
+ "influxdb_host",
172
+ "influxdb_port",
173
+ "influxdb_username",
174
+ "influxdb_password",
175
+ "influxdb_database",
176
+ "influxdb_measurement",
177
+ "influxdb_retention_policy",
178
+ "influxdb_use_ssl",
179
+ "influxdb_verify_ssl"
180
+ ];
181
+
182
+ const influx_toggle_div = document.getElementById(use_influx_param);
183
+ if (influx_toggle_div) {
184
+ // The actual input is inside the div with the ID
185
+ const influx_input = influx_toggle_div.querySelector("input");
186
+ if (influx_input) {
187
+ const toggleInfluxVisibility = () => {
188
+ const isChecked = influx_input.checked;
189
+ influx_related_params.forEach(paramId => {
190
+ const paramDiv = document.getElementById(paramId);
191
+ if (paramDiv) {
192
+ paramDiv.style.display = isChecked ? "" : "none";
193
+ }
194
+ });
195
+ };
196
+
197
+ // Add listener and set initial state
198
+ influx_input.addEventListener("change", toggleInfluxVisibility);
199
+ toggleInfluxVisibility();
200
+ }
201
+ }
202
+
203
+ // ML Forecaster Visibility Logic
204
+ const forecast_method_param = "load_forecast_method";
205
+ const ml_related_params = [
206
+ "model_type",
207
+ "var_model",
208
+ "sklearn_model",
209
+ "regression_model",
210
+ "num_lags",
211
+ "split_date_delta",
212
+ "n_trials",
213
+ "perform_backtest"
214
+ ];
215
+
216
+ const forecast_method_div = document.getElementById(forecast_method_param);
217
+ if (forecast_method_div) {
218
+ const method_select = forecast_method_div.querySelector("select, input");
219
+ if (method_select) {
220
+ const toggleMLVisibility = () => {
221
+ const isML = method_select.value === "mlforecaster";
222
+ ml_related_params.forEach(paramId => {
223
+ const paramDiv = document.getElementById(paramId);
224
+ if (paramDiv) {
225
+ paramDiv.style.display = isML ? "" : "none";
226
+ }
227
+ });
228
+ };
229
+ // Add listener and set initial state
230
+ method_select.addEventListener("change", toggleMLVisibility);
231
+ method_select.addEventListener("input", toggleMLVisibility); // Handle both select and text input types
232
+ toggleMLVisibility();
233
+ }
234
+ }
167
235
  }
168
236
 
169
237
  //build sections body, containing parameter/param containers (containing parameter/param inputs)
@@ -174,9 +242,9 @@ function buildParamContainers(
174
242
  header_input_list
175
243
  ) {
176
244
  //get the section container element
177
- SectionContainer = document.getElementById(section);
245
+ let SectionContainer = document.getElementById(section);
178
246
  //get the body container inside the section (where the parameters will be appended)
179
- SectionParamElement = SectionContainer.getElementsByClassName("section-body");
247
+ let SectionParamElement = SectionContainer.getElementsByClassName("section-body");
180
248
  if (SectionContainer == null || SectionParamElement.length == 0) {
181
249
  console.error("Unable to find Section container or Section Body");
182
250
  return 0;
@@ -217,7 +285,7 @@ function buildParamContainers(
217
285
  }
218
286
 
219
287
  //if parameter type == array.* and not in "Deferrable Loads" section, append plus and minus buttons in param div
220
- array_buttons = "";
288
+ let array_buttons = "";
221
289
  if (
222
290
  parameter_definition_object["input"].search("array.") > -1 &&
223
291
  section != "Deferrable Loads"
@@ -265,7 +333,7 @@ function buildParamContainers(
265
333
  });
266
334
 
267
335
  //check initial checkbox state, check "value" of input and match to "checked" value
268
- let checkbox = document.querySelectorAll("input[type='checkbox']");
336
+ let checkbox = SectionContainer.querySelectorAll("input[type='checkbox']");
269
337
  checkbox.forEach(function (answer) {
270
338
  let value = answer.value === "true";
271
339
  answer.checked = value;
@@ -305,7 +373,7 @@ function buildParamContainers(
305
373
  }
306
374
 
307
375
  //obtain required param inputs, add event listeners
308
- requirement_inputs =
376
+ let requirement_inputs =
309
377
  requirement_element.getElementsByClassName("param_input");
310
378
  //grab required value
311
379
  const requirement_value = Object.values(
@@ -334,10 +402,11 @@ function buildParamElement(
334
402
  parameter_definition_name,
335
403
  config
336
404
  ) {
337
- var type = "";
338
- var inputs = "";
339
- var type_specific_html = "";
340
- var type_specific_html_end = "";
405
+ let type = "";
406
+ let inputs = "";
407
+ let type_specific_html = "";
408
+ let type_specific_html_end = "";
409
+ let placeholder = ""
341
410
 
342
411
  //switch statement to adjust generated html according to the parameter data type (definitions in definitions file)
343
412
  switch (parameter_definition_object["input"]) {
@@ -345,12 +414,12 @@ function buildParamElement(
345
414
  //number
346
415
  case "int":
347
416
  type = "number";
348
- placeholder = parseInt(parameter_definition_object["default_value"]);
417
+ placeholder = Number.parseInt(parameter_definition_object["default_value"]);
349
418
  break;
350
419
  case "array.float":
351
420
  case "float":
352
421
  type = "number";
353
- placeholder = parseFloat(parameter_definition_object["default_value"]);
422
+ placeholder = Number.parseFloat(parameter_definition_object["default_value"]);
354
423
  break;
355
424
  //text (string)
356
425
  case "array.string":
@@ -384,9 +453,8 @@ function buildParamElement(
384
453
 
385
454
  //check default values saved in param definitions
386
455
  //definitions default value is used if none is found in the configs, or an array element has been added in the ui (deferrable load number increase or plus button pressed)
387
- value = parameter_definition_object["default_value"];
388
456
  //check if a param value is saved in the config file (if so overwrite definition default)
389
- value = checkConfigParam(value, config, parameter_definition_name);
457
+ let value = checkConfigParam(placeholder, config, parameter_definition_name);
390
458
 
391
459
  //generate and return param input html,
392
460
  //check if param value is not an object, if so assume its a single value.
@@ -395,7 +463,7 @@ function buildParamElement(
395
463
  if (parameter_definition_object["input"] == "select") {
396
464
  let inputs = `<select class="param_input">`;
397
465
  for (const options of parameter_definition_object["select_options"]) {
398
- selected = ""
466
+ let selected = ""
399
467
  //if item in select is the same as the config value, then append "selected" tag
400
468
  if (options==value) {selected = `selected="selected"`}
401
469
  inputs += `<option ${selected}>${options}</option>`;
@@ -416,8 +484,8 @@ function buildParamElement(
416
484
  else {
417
485
  //for items such as load_peak_hour_periods (object of objects with arrays)
418
486
  if (typeof Object.values(value)[0] === "object") {
419
- for (param of Object.values(value)) {
420
- for (items of Object.values(param)) {
487
+ for (let param of Object.values(value)) {
488
+ for (let items of Object.values(param)) {
421
489
  inputs += `<input class="param_input" type="${type}" placeholder=${Object.values(items)[0]} value=${
422
490
  Object.values(items)[0]
423
491
  }>`;
@@ -429,7 +497,7 @@ function buildParamElement(
429
497
  // array of values
430
498
  else {
431
499
  let inputs = "";
432
- for (param of value) {
500
+ for (let param of value) {
433
501
  inputs += `
434
502
  ${type_specific_html}
435
503
  <input class="param_input" type="${type}" placeholder=${parameter_definition_object["default_value"]} value=${param}>
@@ -448,14 +516,14 @@ function plusElements(
448
516
  section,
449
517
  config
450
518
  ) {
451
- param_element = document.getElementById(parameter_definition_name);
519
+ let param_element = document.getElementById(parameter_definition_name);
452
520
  if (param_element == null) {
453
521
  console.log(
454
522
  "Unable to find " + parameter_definition_name + " param div container"
455
523
  );
456
524
  return 1;
457
525
  }
458
- param_input_container =
526
+ let param_input_container =
459
527
  param_element.getElementsByClassName("param-input")[0];
460
528
  // Add a copy of the param element
461
529
  param_input_container.innerHTML += buildParamElement(
@@ -467,14 +535,15 @@ function plusElements(
467
535
 
468
536
  //Remove param inputs in param div container (minimum 1)
469
537
  function minusElements(param) {
470
- param_element = document.getElementById(param);
538
+ let param_element = document.getElementById(param);
539
+ let param_input
471
540
  if (param_element == null) {
472
541
  console.log(
473
542
  "Unable to find " + parameter_definition_name + " param div container"
474
543
  );
475
544
  return 1;
476
545
  }
477
- param_input_list = param_element.getElementsByTagName("input");
546
+ let param_input_list = param_element.getElementsByTagName("input");
478
547
  if (param_input_list.length == 0) {
479
548
  console.log(
480
549
  "Unable to find " + parameter_definition_name + " param input/s"
@@ -493,7 +562,7 @@ function minusElements(param) {
493
562
  //if param is "load_peak_hour_periods", remove both start and end param inputs as well as the line brake tag separating the inputs
494
563
  if (param == "load_peak_hour_periods") {
495
564
  if (param_input_list.length > 2) {
496
- brs = document.getElementById(param).getElementsByTagName("br");
565
+ let brs = document.getElementById(param).getElementsByTagName("br");
497
566
  param_input_list[param_input_list.length - 1].remove();
498
567
  param_input_list[param_input_list.length - 1].remove();
499
568
  brs[brs.length - 1].remove();
@@ -511,6 +580,7 @@ function checkRequirements(
511
580
  param_element,
512
581
  requirement_value
513
582
  ) {
583
+ let requirement_element_value
514
584
  //get current value of required element
515
585
  if (requirement_element.type == "checkbox") {
516
586
  requirement_element_value = requirement_element.checked;
@@ -522,22 +592,22 @@ function checkRequirements(
522
592
  if (!param_element.classList.contains("requirement-disable")) {
523
593
  param_element.classList.add("requirement-disable");
524
594
  }
525
- } else {
526
- if (param_element.classList.contains("requirement-disable")) {
595
+ } else if (param_element.classList.contains("requirement-disable")) {
527
596
  param_element.classList.remove("requirement-disable");
528
- }
529
597
  }
530
598
  }
531
599
 
532
600
  //on header input change, execute accordingly
533
601
  function headerElement(element, param_definitions, config) {
534
602
  //obtain section body element
535
- section_card = element.closest(".section-card");
603
+ let section_card = element.closest(".section-card");
604
+ let param_list
605
+ let difference
536
606
  if (section_card == null) {
537
607
  console.log("Unable to obtain section-card");
538
608
  return 1;
539
609
  }
540
- param_container = section_card.getElementsByClassName("section-body");
610
+ let param_container = section_card.getElementsByClassName("section-body");
541
611
  if (param_container.length > 0) {
542
612
  param_container = section_card.getElementsByClassName("section-body")[0];
543
613
  } else {
@@ -559,6 +629,19 @@ function headerElement(element, param_definitions, config) {
559
629
  }
560
630
  break;
561
631
 
632
+ //if set_use_pv, add or remove PV section (inc. related params)
633
+ case "set_use_pv":
634
+ if (element.checked) {
635
+ param_container.innerHTML = "";
636
+ buildParamContainers("Solar System (PV)", param_definitions["Solar System (PV)"], config, [
637
+ "set_use_pv",
638
+ ]);
639
+ element.checked = true;
640
+ } else {
641
+ param_container.innerHTML = "";
642
+ }
643
+ break;
644
+
562
645
  //if number_of_deferrable_loads, the number of inputs in the "Deferrable Loads" section should add up to number_of_deferrable_loads value in header
563
646
  case "number_of_deferrable_loads":
564
647
  //get a list of param in section
@@ -571,7 +654,7 @@ function headerElement(element, param_definitions, config) {
571
654
  }
572
655
  //calculate how much off the fist parameters input elements amount to is, compering to the number_of_deferrable_loads value
573
656
  difference =
574
- parseInt(element.value) -
657
+ Number.parseInt(element.value) -
575
658
  param_container.firstElementChild.querySelectorAll("input").length;
576
659
  //add elements based on how many elements are missing
577
660
  if (difference > 0) {
@@ -608,22 +691,24 @@ function checkConfigParam(value, config, parameter_definition_name) {
608
691
  //send all parameter input values to EMHASS, to save to config.json and param.pkl
609
692
  async function saveConfiguration(param_definitions) {
610
693
  //start wth none
611
- config = {};
694
+ let config = {};
695
+ let param_inputs
696
+ let param_element
612
697
 
613
698
  //if section-cards (config sections/list) exists
614
- config_card = document.getElementsByClassName("section-card");
699
+ let config_card = document.getElementsByClassName("section-card");
615
700
  //check if page is in list or box view
616
- config_box_element = document.getElementById("config-box");
701
+ let config_box_element = document.getElementById("config-box");
617
702
 
618
703
  //if true, in list view
619
704
  if (Boolean(config_card.length)) {
620
705
  //retrieve params and their input/s by looping though param_definitions list
621
706
  //loop through the sections
622
- for (var [section_name, section_object] of Object.entries(
707
+ for (const [, section_object] of Object.entries(
623
708
  param_definitions
624
709
  )) {
625
710
  //loop through parameters
626
- for (var [
711
+ for (let [
627
712
  parameter_definition_name,
628
713
  parameter_definition_object,
629
714
  ] of Object.entries(section_object)) {
@@ -637,7 +722,6 @@ async function saveConfiguration(param_definitions) {
637
722
  parameter_definition_name +
638
723
  " param div container element, skipping this param"
639
724
  );
640
- continue;
641
725
  }
642
726
  //extract input/s and their value/s from param container div
643
727
  else {
@@ -649,10 +733,10 @@ async function saveConfiguration(param_definitions) {
649
733
  }
650
734
 
651
735
  // loop though param_inputs, extract the element/s values
652
- for (var input of param_inputs) {
736
+ for (let input of param_inputs) {
653
737
  switch (input.type) {
654
738
  case "number":
655
- param_values.push(parseFloat(input.value));
739
+ param_values.push(Number.parseFloat(input.value));
656
740
  break;
657
741
  case "checkbox":
658
742
  param_values.push(input.checked);
@@ -737,20 +821,20 @@ async function ToggleView(param_definitions, list_html, default_reset) {
737
821
  config = {};
738
822
 
739
823
  //find out if list or box view is active
740
- configuration_container = document.getElementById("configuration-container");
824
+ let configuration_container = document.getElementById("configuration-container");
741
825
  if (configuration_container == null) {
742
826
  errorAlert("Unable to find Configuration Container element");
743
827
  }
744
828
  //get yaml button
745
- yaml_button = document.getElementById("yaml");
829
+ let yaml_button = document.getElementById("yaml");
746
830
  if (yaml_button == null) {
747
831
  console.log("Unable to obtain yaml button");
748
832
  }
749
833
 
750
834
  // if section-cards (config sections/list) exists
751
- config_card = configuration_container.getElementsByClassName("section-card");
835
+ let config_card = configuration_container.getElementsByClassName("section-card");
752
836
  //selected view (0 = box)
753
- selected_view = Boolean(config_card.length);
837
+ let selected_view = Boolean(config_card.length);
754
838
 
755
839
  //if default_reset is passed do not switch views, instead reinitialize view with default config as values
756
840
  if (default_reset) {
@@ -788,7 +872,7 @@ async function ToggleView(param_definitions, list_html, default_reset) {
788
872
  //load box (json textarea) view
789
873
  async function loadConfigurationBoxPage(config) {
790
874
  //get configuration container element
791
- configuration_container = document.getElementById("configuration-container");
875
+ let configuration_container = document.getElementById("configuration-container");
792
876
  if (configuration_container == null) {
793
877
  errorAlert("Unable to find Configuration Container element");
794
878
  }
@@ -806,7 +890,7 @@ async function loadConfigurationBoxPage(config) {
806
890
 
807
891
  //function in control of status icons and alert box from a fetch request
808
892
  async function showChangeStatus(status, logJson) {
809
- var loading = document.getElementById("loader"); //element showing statuses
893
+ let loading = document.getElementById("loader"); //element showing statuses
810
894
  if (loading === null) {
811
895
  console.log("unable to find loader element");
812
896
  return 1;
@@ -847,7 +931,7 @@ async function errorAlert(text) {
847
931
  //convert yaml box into json box
848
932
  async function yamlToJson() {
849
933
  //get box element
850
- config_box_element = document.getElementById("config-box");
934
+ let config_box_element = document.getElementById("config-box");
851
935
  if (config_box_element == null) {
852
936
  errorAlert("Unable to obtain config box");
853
937
  } else {
@@ -858,10 +942,10 @@ async function yamlToJson() {
858
942
  },
859
943
  body: config_box_element.value,
860
944
  });
861
- response_status = await response.status; //return status
945
+ let response_status = response.status; //return status
862
946
  if (response_status == 201) {
863
947
  showChangeStatus(response_status, {});
864
- blob = await response.blob(); //get data blob
948
+ let blob = await response.blob(); //get data blob
865
949
  config = await new Response(blob).json(); //obtain json from blob
866
950
  config_box_element.value = JSON.stringify(config, null, 2);
867
951
  } else {
@@ -869,4 +953,4 @@ async function yamlToJson() {
869
953
  }
870
954
  }
871
955
  return 0;
872
- }
956
+ }