EMHASS: An Energy Management for Home Assistant

Nice feature that json testing.
I’m almost sure that this is the solution, adding the tojson function:

{{ \"load_cost_forecast\":{{((state_attr('sensor.nordpool', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] | tojson }},\"prod_price_forecast\":{{((state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] | tojson}} }}

Thanks @davidusb !

This is the output via Developer Tools / Templates:

curl -i -H \"Content-Type: application/json\" -X POST -d '{\"load_cost_forecast\":[0.083, 0.086, 0.077, 0.077, 0.069, 0.064, 0.057, 0.051, 0.055, 0.061, 0.066, 0.076, 0.074, 0.077, 0.079, 0.077, 0.074, 0.07, 0.078, 0.084, 0.094, 0.109, 0.105, 0.093],\"prod_price_forecast\":[0.083, 0.086, 0.077, 0.077, 0.069, 0.064, 0.057, 0.051, 0.055, 0.061, 0.066, 0.076, 0.074, 0.077, 0.079, 0.077, 0.074, 0.07, 0.078, 0.084, 0.094, 0.109, 0.105, 0.093]}' http://localhost:5000/action/dayahead-optim

using this shell_command:

curl -i -H \"Content-Type: application/json\" -X POST -d '{\"load_cost_forecast\":{{((state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] }},\"prod_price_forecast\":{{((state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24]}}}' http://localhost:5000/action/dayahead-optim

If I am adding the | tojson formatting like this:

curl -i -H \"Content-Type: application/json\" -X POST -d '{\"load_cost_forecast\":{{((state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] | tojson }},\"prod_price_forecast\":{{((state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] | tojson }}}' http://localhost:5000/action/dayahead-optim

I am still getting following error:

Are you sure of your sensor name.
It is not like this?:

{\"load_cost_forecast\":{{((state_attr('sensor.nordpool', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] | tojson }},\"prod_price_forecast\":{{((state_attr('sensor.nordpool', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] | tojson }}}

Looks like an issue with the curl command itself. Data in Template/Developer sections looks fine and jsonlint checker is cool with this.

I’ve found a small typo that there was a space between Content-Type and : application/json that was not working out.

Command rectified to this now:

curl -i -H \"Content-Type:application/json\" -X POST -d '{"load_cost_forecast":{{((state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] | tojson }},"prod_price_forecast":{{((state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] | tojson }}}' http://localhost:5000/action/dayahead-optim

but getting issue now with bad request, invalid header…

Ah. Darn. Raspberry Pi 4 (32-bit) rpi4…

Yes! They were supported until recently, but we upgraded to fully support Python 3.11. Since then the support was broken, still searching for a solution.

1 Like

Answering my own question here. Moved away from shell_command towards rest at this works now:

Code:

rest_command:
  dayahead_optim_rest:
    url: http://localhost:5000/action/dayahead-optim
    method: POST
    content_type: "application/json"
    payload: >-
      {
        "load_cost_forecast": {{
        ((state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_today') | map(attribute='value') | list + state_attr('sensor.nordpool_kwh_be_eur_3_10_021', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:48]
        }}
      }

Have an issue now that EMHASS is expecting 48 values and nordpool is also delivering 26.

2024-02-10 22:53:37,144 - web_server - ERROR - Passed type is <class 'list'> and length is 26

And I moved away from rest_command to Node-Red Render Template Node:

Followed by Change Node

And then http Request Node

Full Flow with error handling (or error recording at least):

Are there any gotchas upgrading from EMHASS 0.4.2 to 0.6.5 when running MPC model in an amber configuration?

The main issue most people had problems with was that a new functionality requiring a list of configurations parameters was added: the deferrable load start and end hours. By default there are only two items on each list coming from the default configuration file. So if the user has a number of deferrables other than two then you need to update those lists in the configuration otherwise there will be errors when starting the add-on.
So update and verify your configuration before resting. Do a backup to come back to your previous working version to be sure.

3 Likes

I’m getting the following error in the log after upgrading to 0.6.5:

The error didn’t start until this morning. Was working without error last night.
Although its posting data ok and the MPC template output looks ok:
I haven’t modifies my configuration from 0.4.2.

2024-02-12 07:28:09,486 - web_server - INFO - Launching the emhass webserver at: http://0.0.0.0:5000
2024-02-12 07:28:09,486 - web_server - INFO - Home Assistant data fetch will be performed using url: http://supervisor/core/api
2024-02-12 07:28:09,486 - web_server - INFO - The data path is: /share
2024-02-12 07:28:09,488 - web_server - INFO - Using core emhass version: 0.7.6
waitress   INFO  Serving on http://0.0.0.0:5000
2024-02-12 07:28:28,845 - web_server - INFO - Setting up needed data
2024-02-12 07:28:28,915 - web_server - INFO - Retrieve hass get data method initiated...
2024-02-12 07:28:32,618 - web_server - INFO - Retrieving weather forecast data using method = list
2024-02-12 07:28:32,620 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2024-02-12 07:28:32,620 - web_server - INFO - Retrieve hass get data method initiated...
2024-02-12 07:28:32,628 - web_server - ERROR - The retrieved JSON is empty, check that correct day or variable names are passed
2024-02-12 07:28:32,628 - web_server - ERROR - Either the names of the passed variables are not correct or days_to_retrieve is larger than the recorded history of your sensor (check your recorder settings)
2024-02-12 07:28:32,628 - web_server - ERROR - Exception on /action/naive-mpc-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 1463, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 872, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 870, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 855, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/web_server.py", line 50, in action_call
    input_data_dict = set_input_data_dict(config_path, str(data_path), costfun,
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/command_line.py", line 120, in set_input_data_dict
    P_load_forecast = fcst.get_load_forecast(method=optim_conf['load_forecast_method'], set_mix_forecast=True, df_now=df_input_data)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/forecast.py", line 589, in get_load_forecast
    rh.get_data(days_list, var_list)
  File "/usr/local/lib/python3.11/dist-packages/emhass/retrieve_hass.py", line 150, in get_data
    self.df_final = pd.concat([self.df_final, df_day], axis=0)
                                              ^^^^^^
UnboundLocalError: cannot access local variable 'df_day' where it is not associated with a value
2024-02-12 07:28:32,672 - web_server - INFO - Setting up needed data
2024-02-12 07:28:32,674 - web_server - INFO -  >> Publishing data...
2024-02-12 07:28:32,674 - web_server - INFO - Publishing data to HASS instance
2024-02-12 07:28:32,690 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 143
2024-02-12 07:28:32,698 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 467.89
2024-02-12 07:28:32,706 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-02-12 07:28:32,714 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2024-02-12 07:28:32,724 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 324.89
2024-02-12 07:28:32,733 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 22.0
2024-02-12 07:28:32,742 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2024-02-12 07:28:32,751 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 6.53
2024-02-12 07:28:32,759 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-02-12 07:28:32,768 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.26
2024-02-12 07:28:32,779 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.16
{
  "prod_price_forecast": [0.09, 0.07, 0.05, 0.05, 0.04, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.32, 0.33, 0.34, 0.36, 0.36, 0.36, 0.37, 0.43, 0.59, 0.65, 0.75, 1.09, 0.77, 0.4, 0.32, 0.3, 0.15, 0.15, 0.18, 0.18, 0.15, 0.15, 0.15, 0.12, 0.12, 0.1, 0.09, 0.09],
  "load_cost_forecast": [0.19, 0.17, 0.15, 0.15, 0.13, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.14, 0.41, 0.42, 0.43, 0.45, 0.45, 0.46, 0.46, 0.53, 0.7, 0.77, 0.88, 1.26, 0.94, 0.54, 0.44, 0.43, 0.26, 0.25, 0.29, 0.28, 0.26, 0.25, 0.26, 0.22, 0.22, 0.2, 0.2, 0.19],
  "pv_power_forecast": [800, 993, 1501, 2032, 2498, 2900, 3252, 3536, 3594, 3658, 3736, 3737, 3669, 3595, 3569, 3524, 3341, 3046, 2638, 2176, 1579, 1065, 574, 153, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 110, 503, 987, 1519, 2039, 2501, 2911, 3252, 3532, 3737, 3819, 3940, 3939, 3872, 3732, 3601, 3382, 2971, 2585, 2232, 1807, 1351, 903, 468, 116, 14, 0, 0, 0, 0, 0, 0, 0, 0],
  "prediction_horizon": 41,
  "num_def_loads": 2,
  "def_total_hours": [2,0],
  "P_deferrable_nom": [1300, 1610],
  "treat_def_as_semi_cont": [1, 0],
  "set_def_constant": [0, 0],
  "soc_init": 0.22,
  "soc_final": 0.27,
  "alpha": 0,
  "beta": 1
}

Dayahead also produces an error:

2024-02-12 07:43:40,354 - web_server - INFO - Setting up needed data
2024-02-12 07:43:40,355 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 48
2024-02-12 07:43:40,355 - web_server - ERROR - Passed type is <class 'list'> and length is 43
2024-02-12 07:43:40,355 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 48
2024-02-12 07:43:40,355 - web_server - ERROR - Passed type is <class 'list'> and length is 43
2024-02-12 07:43:40,357 - web_server - INFO - Retrieving weather forecast data using method = list
2024-02-12 07:43:40,358 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2024-02-12 07:43:40,358 - web_server - INFO - Retrieve hass get data method initiated...
2024-02-12 07:43:40,365 - web_server - ERROR - The retrieved JSON is empty, check that correct day or variable names are passed
2024-02-12 07:43:40,365 - web_server - ERROR - Either the names of the passed variables are not correct or days_to_retrieve is larger than the recorded history of your sensor (check your recorder settings)
2024-02-12 07:43:40,365 - web_server - ERROR - Exception on /action/dayahead-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 1463, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 872, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 870, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 855, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/web_server.py", line 50, in action_call
    input_data_dict = set_input_data_dict(config_path, str(data_path), costfun,
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/command_line.py", line 91, in set_input_data_dict
    P_load_forecast = fcst.get_load_forecast(method=optim_conf['load_forecast_method'])
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/forecast.py", line 589, in get_load_forecast
    rh.get_data(days_list, var_list)
  File "/usr/local/lib/python3.11/dist-packages/emhass/retrieve_hass.py", line 150, in get_data
    self.df_final = pd.concat([self.df_final, df_day], axis=0)
                                              ^^^^^^
UnboundLocalError: cannot access local variable 'df_day' where it is not associated with a value

and the length is only 43 but this template has not changed from functioning 0.4.2?

Try and include a synthetic load_forecast 48x 0.5 is fine, as that will work around the 2 day constraint.

So you think it’s missing recorder data? Normally dayahead works when recorder data is missing but this time the list length is causing an error as they are less than 48 elements long?

Just trying to rule out as many possibilities as we can.

That fixed MPC. Thank you very much.
Now to figure out what’s wrong with dayahead or does it use history data now,
or does dayahead need a prediction_horizon calculation now?
Never had to before?

2024-02-12 10:03:33,117 - web_server - INFO - Setting up needed data
2024-02-12 10:03:33,118 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 48
2024-02-12 10:03:33,118 - web_server - ERROR - Passed type is <class 'list'> and length is 38
2024-02-12 10:03:33,118 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 48
2024-02-12 10:03:33,118 - web_server - ERROR - Passed type is <class 'list'> and length is 38
2024-02-12 10:03:33,119 - web_server - INFO - Retrieving weather forecast data using method = list
2024-02-12 10:03:33,119 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2024-02-12 10:03:33,120 - web_server - INFO - Retrieve hass get data method initiated...
2024-02-12 10:03:33,127 - web_server - ERROR - The retrieved JSON is empty, check that correct day or variable names are passed
2024-02-12 10:03:33,127 - web_server - ERROR - Either the names of the passed variables are not correct or days_to_retrieve is larger than the recorded history of your sensor (check your recorder settings)
2024-02-12 10:03:33,127 - web_server - ERROR - Exception on /action/dayahead-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 1463, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 872, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 870, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 855, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/web_server.py", line 50, in action_call
    input_data_dict = set_input_data_dict(config_path, str(data_path), costfun,
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/command_line.py", line 91, in set_input_data_dict
    P_load_forecast = fcst.get_load_forecast(method=optim_conf['load_forecast_method'])
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/forecast.py", line 589, in get_load_forecast
    rh.get_data(days_list, var_list)
  File "/usr/local/lib/python3.11/dist-packages/emhass/retrieve_hass.py", line 150, in get_data
    self.df_final = pd.concat([self.df_final, df_day], axis=0)
                                              ^^^^^^
UnboundLocalError: cannot access local variable 'df_day' where it is not associated with a value
{
  "load_cost_forecast": {{
    ([states('sensor.cecil_st_general_price')|float(0)] + 
    state_attr('sensor.cecil_st_general_forecast', 'forecasts') |map(attribute='per_kwh')|list) 
    | tojson 
  }},
  "prod_price_forecast": {{
    ([states('sensor.cecil_st_feed_in_price')|float(0)] +
    (state_attr('sensor.cecil_st_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list))
    | tojson 
  }},
  "pv_power_forecast": {{
    ([states('sensor.sonnenbatterie_84324_production_w')|int(0)] +
    state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list +
    state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list
    )| tojson
  }},
  "num_def_loads": 2,
  "def_total_hours": [3, 1],
  "P_deferrable_nom":  [1300, 3450],
  "treat_def_as_semi_cont": [1, 0]  
}

Nether adding a prediction_horizon nor load_power_forecast fixed dayahead.

2024-02-12 10:46:01,123 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 48
2024-02-12 10:46:01,123 - web_server - ERROR - Passed type is <class 'list'> and length is 37
2024-02-12 10:46:01,124 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 48

Looks like you might need to pad out all forecasts to 48 elements. Not sure if this is a new requirement for day ahead.

0.6.5 which just dropped allows you to now enter your forecasts directly from the EMHASS web UI, so that could speed testing up for you.

1 Like

I’ve got one question how you guys handle MPC optimization tasks.

I’m running MPC on a 5 min basis. Lets assume I have two deferrable loads which may run in parallel but only with the best result (dishwasher and washing machine) else the can run sequentiell like this:

My logic today, once the p_deferrableX sensors > 0.1 I start the dishwasher/washing machine. This works pretty good but to handle the request itself and make EMHASS calculate the runtime I set def_total_hours to the needed value (e.g. 3h). Once the automation is ongoing I set the def_total_hours for this load to 0 again otherwise it might be rescheduled to a later point in time.
And this is the problem, with the next iteration of MPC the second deferrable load will be moved to the next available slot while the first deferrable load is still running.

image

How do you handle such a situation? Do you pause MPC and only publish until the loads are finished? Do you reduce the hours by one timeframe after it passes by?

This is how I calc the hours to run:

template:
  - sensor:
    - name: p_deferrable1_def_total_hours
        unique_id: 7a126cd6-d49c-40a9-867a-5f7c1d08cbdb
        state: |-
          {{
            is_state('automation.p_deferrable1_dishwasher','on') | int
            *
            is_state('input_boolean.p_deferrable1_todo_start','on') | int
            *
            3
          }}

I think there is nothing to let EMHASS know that the load is already running or did I missed something?

Hi,
For my electric car, I calculate the remaining hours based on the percentage battery, the max amps, kwh’s total battery etc. But for a dishwasher it could be more difficult, you could perhaps check if it’s already running to not start it again (and use the total kw’s divided by the runtime as load).

I do similar with my EV charging and pool pump. I continuously update def_total_hours to reflect how many hours I want the activity to continue for.

With EV it is based on state of charge / charging rate = total hours that need to be scheduled for the future.

For pool pump I use: required run hours - actual run hours.

For something like a dishwasher could you start a countdown timer when it starts for say three hours and then this gives your decreasing def_total_hours. You need to ensure that EMHASS doesn’t schedule multiple startups at different times of the day, but I believe a similar issue was recently fixed.

4 Likes