EMHASS: An Energy Management for Home Assistant

Hi All,

I am using EMHASS for a while now, seems ok, however there a few things I am still struggling with:

  • If real PV power isn’t as the PV forecast, the system will take grid power (regardless of pricing) to charge the battery

  • If power load forecast is less then real (at night using airconditioning to cool the bedroom a little) the system will take power from the grid, because it already discharged the battery to min SOC, the next night it will be expecting more power usage.

What’s the best way to cope with these 2 scenarios? Will increasing SOCfinal to a higher number with the MPC call help in te second scenario?

For the first scenario I tried to think of an automation, but it comes so complex it seems, I am not that experienced enough I am afraid, a little help would be nice.

This is my attempt for automation of scenario 1 where the idea is to take pv power between sunrise and sunset (spring/summer scenario).

alias: Battery SOC control EMHASS real pv power
description: Automation which controls battery SOClvl
trigger:
  - platform: state
    entity_id:
      - sensor.soc_batt_forecast
      - sensor.battery_batterijpercentage
  - platform: time_pattern
    minutes: /5
condition: []
action:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            above: sensor.soc_batt_forecast
        sequence:
          - service: huawei_solar.forcible_discharge_soc
            data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: "{{states('sensor.p_batt_forecast') | int(0)|abs}}"
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            below: sensor.soc_batt_forecast
          - condition: sun
            before: sunrise
            after: sunset
        sequence:
          - service: huawei_solar.forcible_charge_soc
            data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: "{{ (states('sensor.p_batt_forecast') | int(0) | abs)}}"
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            below: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            below: 1
          - condition: sun
            after: sunrise
            before: sunset
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            above: sensor.inverter_ingangsvermogen
        sequence:
          - service: huawei_solar.forcible_charge_soc
            data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: >-
                {{ (states('sensor.inverter_ingangsvermogen') | int(0) | abs) -
                states('sensor.power_load_no_var_loads')}}
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
    default:
      - service: huawei_solar.stop_forcible_charge
        data:
          device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
mode: single

You can use real (now) values for PV and load forecasts and get them to match exactly.
Note I find you need to use “alpha”: 1, “beta”: 0, if you are injecting pv & load forecasts.

EMHASS always exactly balances and by using now values for PV & load they match the situation when MPC is run, which I do every minute.

For example:

        "pv_power_forecast": {{
          ([states('sensor.solaredge_nopowerlimit')|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
        }},
        "load_power_forecast": {{
          ([states('sensor.power_load_no_var_loads')|int] +
          (states('input_text.fi_fo_buffer').split(', ')|map('multiply',1000)|map('int')|list)[1:]
          )| tojson 
        }},
        "alpha": 1, "beta": 0,

        "load_power_forecast": [2303, 1900, 2700, 1400, 1400, 600, 900, 400, 1100, 300, 900, 900, 400, 2600, 300, 400, 300, 400, 300, 300, 300, 300, 300, 300, 300, 500, 500, 1000, 1000, 900, 1000, 700, 2000, 900, 1000, 300, 2400, 800, 600, 3300, 1400, 600, 300, 300, 300, 900, 3600, 300],

image

The other method is to not try and be too accurate. I.e. only start exports when p_batt > 1000

Hi,

Thank you for this, I am looking into it, can you explain what sensor.solaredge_nopowerlimit is?

Can you retrieve hourly predicted values for the coming 24h from the Solcast service as an array?
I am looking how to do it for the Public ‘Forecast’ service. I combined 3 sensors to sum the 3 planes of my solar panels. So I can see the total predicted pv forecast the next hour and for the coming 24h, but I would need an array to add it to the MPC call.
Looking how to achieve that. How did you do this?

Any idea why this is happening?
Values get re-calculated, don’t understand why.

2024-06-08 13:00:00,163 - web_server - INFO - Passed runtime parameters: {'load_cost_forecast': [10.9865, 10.3187, 11.3013, 12.6443, 13.6927, 17.991, 20.2413, 22.8341, 24.3499, 25.3558, 22.5405], 'prod_price_forecast': [-3.182, -3.812, -2.885, -1.618, -0.629, 3.426, 5.549, 7.995, 9.425, 10.374, 7.718], 'load_power_forecast': [478, 200, 200, 100, 400, 800, 400, 500, 400, 400, 600, 500, 600, 500, 500, 400, 400, 500, 400, 200, 200, 600, 400, 400, 500, 500, 200, 200, 700, 300, 700, 200, 500, 400, 200, 200, 300, 400, 200, 200, 200, 300, 300, 200, 200, 300, 200, 500], 'prediction_horizon': 11, 'alpha': 0, 'beta': 1, 'soc_init': 0.32, 'soc_final': 0.12}
2024-06-08 13:00:00,163 - web_server - INFO -  >> Setting input data dict
2024-06-08 13:00:00,163 - web_server - INFO - Setting up needed data
2024-06-08 13:00:00,175 - web_server - INFO - Retrieve hass get data method initiated...
2024-06-08 13:00:00,381 - web_server - INFO - Passed runtime parameters: {}
2024-06-08 13:00:00,382 - web_server - INFO -  >> Setting input data dict
2024-06-08 13:00:00,382 - web_server - INFO - Setting up needed data
2024-06-08 13:00:00,383 - web_server - INFO -  >> Publishing data...
2024-06-08 13:00:00,383 - web_server - INFO - Publishing data to HASS instance
2024-06-08 13:00:00,413 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 6413.0
2024-06-08 13:00:00,418 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 400
2024-06-08 13:00:00,428 - web_server - INFO - Successfully posted to sensor.p_pv_curtailment = 0.0
2024-06-08 13:00:00,461 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 2000.0
2024-06-08 13:00:00,483 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 2500.0
2024-06-08 13:00:00,524 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = -1513.0
2024-06-08 13:00:00,539 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 40.63
2024-06-08 13:00:00,544 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2024-06-08 13:00:00,548 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 109.29
2024-06-08 13:00:00,550 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-06-08 13:00:00,555 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 10.9865
2024-06-08 13:00:00,559 - web_server - INFO - Successfully posted to sensor.unit_prod_price = -3.182
2024-06-08 13:00:00,708 - web_server - INFO - Retrieving weather forecast data using method = solar.forecast
2024-06-08 13:00:04,778 - web_server - INFO -  >> Performing naive MPC optimization...
2024-06-08 13:00:04,778 - web_server - INFO - Performing naive MPC optimization
2024-06-08 13:00:04,789 - web_server - INFO - Perform an iteration of a naive MPC controller
2024-06-08 13:00:04,931 - web_server - INFO - Status: Optimal
2024-06-08 13:00:04,931 - web_server - INFO - Total value of the Cost function = 58.57
2024-06-08 13:00:05,062 - web_server - INFO - Passed runtime parameters: {}
2024-06-08 13:00:05,062 - web_server - INFO -  >> Setting input data dict
2024-06-08 13:00:05,062 - web_server - INFO - Setting up needed data
2024-06-08 13:00:05,063 - web_server - INFO -  >> Publishing data...
2024-06-08 13:00:05,063 - web_server - INFO - Publishing data to HASS instance
2024-06-08 13:00:05,071 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 279.0
2024-06-08 13:00:05,074 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 478
2024-06-08 13:00:05,077 - web_server - INFO - Successfully posted to sensor.p_pv_curtailment = 0.0
2024-06-08 13:00:05,080 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-06-08 13:00:05,082 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2024-06-08 13:00:05,085 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 199.0
2024-06-08 13:00:05,089 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 30.56
2024-06-08 13:00:05,092 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2024-06-08 13:00:05,094 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 58.61
2024-06-08 13:00:05,096 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-06-08 13:00:05,099 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 10.9865
2024-06-08 13:00:05,101 - web_server - INFO - Successfully posted to sensor.unit_prod_price = -3.182
2024-06-08 13:37:16,572 - web_server - INFO - EMHASS server online, serving index.html...

Thanks again Mark. I finally got around to implement this (naturally the update of home assistant for this month again broke my emhass sensor history).

Question though, did you manage a way to automate this? What I was thinking of is to condition the override setup on an unsuccessful run of the automated / real sensor one.

Had a look at the feedback of my shell command. Although the log spits this is not reflected in the logs of my automation.

Do you use shell or rest commands? In case of the latter, is there a feedback loop?

Would it be possible to implement 48h forecasts or at least 36h?

solaredge_nopowerlimit is my uncurtailed now solar production value. It is the power value reported by my PV inverter.

My example above returns an array for my solcast, it you can adapt this example:
https://emhass.readthedocs.io/en/latest/forecasts.html#example-combining-multiple-solcast-configurations

1 Like

I presume you are referring to the PV and load sensors being recalculated, from when you include in your payload and what is returned for the sensor.

As I mentioned above you need to set “alpha”: 1, “beta”: 0, for this to work, you have them switched around. You also need to check method_ts_round is set to first.

1 Like

Odd that the continuity of your sensors is effected by an EMHASS upgrade, I didn’t have that issue, but I always specify all four forecasts on my optimisation call. So I don’t need to automate the switch over.

I use the REST method, which does provide a log entry if there is an error.

For my load forecast I use a straight forward fifo buffer that updates the value every thirty minutes.

alias: read_sensor_data
description: ""
trigger:
  - platform: time_pattern
    minutes: /30
condition: []
action:
  - service: input_text.set_value
    target:
      entity_id: input_text.fi_fo_buffer
    data:
      value: |
        {{ (states('input_text.fi_fo_buffer').split(', ')[1:48]  + [ max(0.3,
            ( states('sensor.apf_house_entity')|int(0)
            - states('sensor.pool_pumps_power')|int(0) 
            - states('sensor.pool_heatpump_power')|int(0)
            - states('sensor.ev_charging')|int(0) 
            - states('sensor.hws_power_2')|int(0))
            /1000)|round(1)])|join(', ') }}
mode: single

1 Like

Thanks and sorry for the confusion, it’s not the Emhass update which breaks sensor continuity but it’s the update of HA.

Will tweak around but my setup is not nearly as complex. - I only optimise the battery at the moment. Simply pushing 0.5kw * 24 does the trick

Yes I totally understand this. It should be wise to put a new parameter to activate/deactivate this option. It will be done.

3 Likes

I recently got EMHASS working and it was working well. However, after experiencing negative electricity prices in my state today, EMHASS is behaving strangely. It’s trying to export an unusually high amount of energy and is setting unrealistic targets for my 1800W deferrable load."

Can you provide the payload you injected otherwise it is hard to appreciate what is going on.

Does it say status infeasible at the bottom of the page you showed, if the result is infeasible you will get values that don’t make sense and shouldn’t be used.

This only started to happen once the grid price went to -0.02
Currently infeasible.

@markpurcell the p_deferrable_nom is reading a crazy values compared to what I injected (1800W), but now its fine after positive prices.

In saying that I do self curtail with Node Red and Home Assistant, not sure if EMHASS saw no production in my photovoltics sensor and freaked out.

  post_mpc_optim_solcast: >
    curl -i -H "Content-Type: application/json" -X POST -d '{
      "load_cost_forecast": {{ (
        [states('sensor.general_price')|float(0) | round(2)] +
        state_attr('sensor.general_forecast', 'forecasts') | map(attribute='per_kwh') | map('round', 2) | list
      )|tojson }},
      "prod_price_forecast": {{ (
        [states('sensor.feed_in_price')|float(0) | round(2)] +
        state_attr('sensor.feed_in_forecast', 'forecasts') | map(attribute='per_kwh') | map('round', 2) | list
      )|tojson }},
      "pv_power_forecast": {{ states('sensor.solcast_24hrs_forecast_watts') }}, 
      "prediction_horizon": 24,
      "num_def_loads": 1,
      "p_deferrable_nom": [1800],
      "soc_init": {{ (states('sensor.powerwall_charge')|float(0) / 100)|tojson }},
      "soc_final": 0.20,
      "def_total_hours": [2],
      "def_load_start": [0],
      "def_load_end": [95]
    }' http://localhost:5000/action/naive-mpc-optim

Template render

post_mpc_optim_solcast: >
    curl -i -H "Content-Type: application/json" -X POST -d '{
      "load_cost_forecast": [0.04, 0.28, 0.33, 0.71, 0.71, 0.73, 0.58, 0.55, 0.53, 0.52, 0.49, 0.26, 0.22, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.12, 0.11, 0.12, 0.13, 0.11, 0.11, 0.15, 0.16, 0.43, 0.52, 1.37, 12.2, 19.58, 19.51, 12.2, 1.37, 1.37, 1.3, 1.3, 0.45, 0.45, 0.36, 0.36, 0.36, 0.36, 0.45, 0.36, 0.36, 1.28],
      "prod_price_forecast": [-0.05, 0.12, 0.17, 0.3, 0.3, 0.31, 0.19, 0.15, 0.13, 0.13, 0.1, 0.1, 0.06, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.0, -0.02, -0.04, -0.03, -0.02, -0.04, -0.04, 0.0, 0.01, 0.25, 0.33, 1.11, 10.96, 17.67, 17.6, 10.96, 1.11, 1.11, 1.1, 1.1, 0.32, 0.32, 0.24, 0.24, 0.24, 0.24, 0.32, 0.24, 0.24, 1.08],
      "pv_power_forecast": [1195, 2685, 2864, 1971, 634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 1310, 2655, 3757, 4540, 5172, 5593, 5821, 5788, 5669, 5506, 5269, 4881, 4354], 
      "prediction_horizon": 24,
      "num_def_loads": 1,
      "p_deferrable_nom": [1800],
      "soc_init": 1.0,
      "soc_final": 0.20,
      "def_total_hours": [2],
      "def_load_start": [0],
      "def_load_end": [95]
    }' http://localhost:5000/action/naive-mpc-optim

The logs

2024-06-11 15:33:00,362 - web_server - INFO - Passed runtime parameters: {'load_cost_forecast': [0.04, 0.28, 0.32, 0.72, 0.59, 0.66, 0.56, 0.55, 0.52, 0.51, 0.46, 0.25, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13, 0.12, 0.12, 0.12, 0.11, 0.11, 0.11, 0.12, 0.16, 0.36, 0.5, 12.2, 19.51, 19.58, 19.58, 19.39, 12.2, 12.2, 19.32, 12.14, 1.3, 1.3, 0.45, 0.45, 0.36, 0.45, 1.28, 0.36, 0.37, 1.33], 'prod_price_forecast': [-0.05, 0.12, 0.15, 0.31, 0.2, 0.26, 0.16, 0.15, 0.13, 0.12, 0.07, 0.09, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.0, -0.02, -0.02, -0.03, -0.02, -0.03, -0.03, -0.03, -0.02, 0.01, 0.19, 0.32, 10.96, 17.6, 17.67, 17.67, 17.49, 10.96, 10.96, 17.48, 10.95, 1.1, 1.1, 0.32, 0.32, 0.24, 0.32, 1.08, 0.24, 0.25, 1.12], 'pv_power_forecast': [1195, 2685, 2864, 1971, 634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 1310, 2655, 3757, 4540, 5172, 5593, 5821, 5788, 5669, 5506, 5269, 4881, 4354], 'prediction_horizon': 24, 'num_def_loads': 1, 'p_deferrable_nom': [1800], 'soc_init': 0.99, 'soc_final': 0.2, 'def_total_hours': [2], 'def_load_start': [0], 'def_load_end': [95]}
2024-06-11 15:33:00,362 - web_server - INFO -  >> Setting input data dict
2024-06-11 15:33:00,362 - web_server - INFO - Setting up needed data
2024-06-11 15:33:00,364 - web_server - INFO - Retrieve hass get data method initiated...
2024-06-11 15:33:00,691 - web_server - INFO - Retrieving weather forecast data using method = list
2024-06-11 15:33:00,692 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2024-06-11 15:33:00,692 - web_server - INFO - Retrieve hass get data method initiated...
2024-06-11 15:33:01,319 - web_server - INFO -  >> Performing naive MPC optimization...
2024-06-11 15:33:01,319 - web_server - INFO - Performing naive MPC optimization
2024-06-11 15:33:01,329 - web_server - INFO - Perform an iteration of a naive MPC controller
2024-06-11 15:33:01,391 - web_server - DEBUG - Deferrable load 0: Proposed optimization window: 0 --> 0
2024-06-11 15:33:01,391 - web_server - DEBUG - Deferrable load 0: Validated optimization window: 0 --> 0
2024-06-11 15:33:01,401 - web_server - WARNING - Solver default unknown, using default
Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Dec 15 2019 

command line - /usr/local/lib/python3.11/dist-packages/pulp/solverdir/cbc/linux/64/cbc /tmp/9e44a74fa299472c8547dea7a970ba30-pulp.mps -max -timeMode elapsed -branch -printingOptions all -solution /tmp/9e44a74fa299472c8547dea7a970ba30-pulp.sol (default strategy 1)
At line 2 NAME          MODEL
At line 3 ROWS
At line 435 COLUMNS
At line 2777 RHS
At line 3208 BOUNDS
At line 3497 ENDATA
Problem MODEL has 430 rows, 264 columns and 2030 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Problem is infeasible - 0.00 seconds
Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.00   (Wallclock seconds):       0.00

2024-06-11 15:33:01,414 - web_server - INFO - Status: Infeasible
2024-06-11 15:33:01,414 - web_server - INFO - Total value of the Cost function = -1.03
2024-06-11 15:33:01,594 - web_server - INFO - Passed runtime parameters: {}
2024-06-11 15:33:01,594 - web_server - INFO -  >> Setting input data dict
2024-06-11 15:33:01,594 - web_server - INFO - Setting up needed data
2024-06-11 15:33:01,595 - web_server - INFO -  >> Publishing data...
2024-06-11 15:33:01,596 - web_server - INFO - Publishing data to HASS instance
2024-06-11 15:33:01,605 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 827.24
2024-06-11 15:33:01,612 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 1068.03
2024-06-11 15:33:01,618 - web_server - INFO - Successfully posted to sensor.p_pv_curtailment = 0.0
2024-06-11 15:33:01,625 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = -240.78
2024-06-11 15:33:01,632 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2024-06-11 15:33:01,638 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 99.0
2024-06-11 15:33:01,645 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2024-06-11 15:33:01,651 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 0.89
2024-06-11 15:33:01,656 - web_server - INFO - Successfully posted to sensor.optim_status = Infeasible
2024-06-11 15:33:01,663 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.04
2024-06-11 15:33:01,670 - web_server - INFO - Successfully posted to sensor.unit_prod_price = -0.05

Not a solution, but I experienced the same issue when prices went negative, so I went back to 0.9.1.
I did not dive into the issue, but from a quick scan it seemed to do with the PV_curtailment, but again I did really went deep into this as I first want to setup pv_power_forecast properly and try again.

Think you are onto something.

Now the neg prices have purged the forcast is “optimal” again

2024-06-11 15:54:00,366 - web_server - INFO - Passed runtime parameters: {'load_cost_forecast': [0.1, 0.28, 0.33, 0.71, 0.71, 0.73, 0.58, 0.55, 0.53, 0.52, 0.49, 0.26, 0.22, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.12, 0.11, 0.12, 0.13, 0.11, 0.11, 0.15, 0.16, 0.43, 0.52, 1.37, 12.2, 19.58, 19.51, 12.2, 1.37, 1.37, 1.3, 1.3, 0.45, 0.45, 0.36, 0.36, 0.36, 0.36, 0.45, 0.36, 0.36, 1.28], 'prod_price_forecast': [0.0, 0.12, 0.17, 0.3, 0.3, 0.31, 0.19, 0.15, 0.13, 0.13, 0.1, 0.1, 0.06, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.0, -0.02, -0.04, -0.03, -0.02, -0.04, -0.04, 0.0, 0.01, 0.25, 0.33, 1.11, 10.96, 17.67, 17.6, 10.96, 1.11, 1.11, 1.1, 1.1, 0.32, 0.32, 0.24, 0.24, 0.24, 0.24, 0.32, 0.24, 0.24, 1.08], 'pv_power_forecast': [1195, 2685, 2864, 1971, 634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 1310, 2655, 3757, 4540, 5172, 5593, 5821, 5788, 5669, 5506, 5269, 4881, 4354], 'prediction_horizon': 24, 'num_def_loads': 1, 'p_deferrable_nom': [1800], 'soc_init': 1.0, 'soc_final': 0.2, 'def_total_hours': [2], 'def_load_start': [0], 'def_load_end': [95]}
2024-06-11 15:54:00,366 - web_server - INFO -  >> Setting input data dict
2024-06-11 15:54:00,366 - web_server - INFO - Setting up needed data
2024-06-11 15:54:00,369 - web_server - INFO - Retrieve hass get data method initiated...
2024-06-11 15:54:00,714 - web_server - INFO - Retrieving weather forecast data using method = list
2024-06-11 15:54:00,715 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2024-06-11 15:54:00,716 - web_server - INFO - Retrieve hass get data method initiated...
2024-06-11 15:54:01,025 - web_server - INFO -  >> Performing naive MPC optimization...
2024-06-11 15:54:01,025 - web_server - INFO - Performing naive MPC optimization
2024-06-11 15:54:01,035 - web_server - INFO - Perform an iteration of a naive MPC controller
2024-06-11 15:54:01,097 - web_server - DEBUG - Deferrable load 0: Proposed optimization window: 0 --> 0
2024-06-11 15:54:01,097 - web_server - DEBUG - Deferrable load 0: Validated optimization window: 0 --> 0
2024-06-11 15:54:01,107 - web_server - WARNING - Solver default unknown, using default
Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Dec 15 2019 

command line - /usr/local/lib/python3.11/dist-packages/pulp/solverdir/cbc/linux/64/cbc /tmp/ad3fe9aac6f4486b95f2b4d3f336dea7-pulp.mps -max -timeMode elapsed -branch -printingOptions all -solution /tmp/ad3fe9aac6f4486b95f2b4d3f336dea7-pulp.sol (default strategy 1)
At line 2 NAME          MODEL
At line 3 ROWS
At line 435 COLUMNS
At line 2776 RHS
At line 3207 BOUNDS
At line 3496 ENDATA
Problem MODEL has 430 rows, 264 columns and 2030 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Continuous objective value is -1.89629 - 0.00 seconds
Cgl0003I 0 fixed, 0 tightened bounds, 26 strengthened rows, 48 substitutions
Cgl0004I processed model has 256 rows, 191 columns (95 integer (95 of which binary)) and 1677 elements
Cbc0038I Initial state - 21 integers unsatisfied sum - 3.6961
Cbc0038I Pass   1: suminf.    2.69194 (19) obj. 2.33936 iterations 36
Cbc0038I Solution found of 2.33936
Cbc0038I Relaxing continuous gives 2.18671
Cbc0038I Before mini branch and bound, 68 integers at bound fixed and 61 continuous
Cbc0038I Full problem 256 rows 191 columns, reduced to 10 rows 13 columns
Cbc0038I Mini branch and bound improved solution from 2.18671 to 1.89629 (0.01 seconds)
Cbc0038I After 0.01 seconds - Feasibility pump exiting with objective of 1.89629 - took 0.00 seconds
Cbc0012I Integer solution of 1.8962861 found by feasibility pump after 0 iterations and 0 nodes (0.01 seconds)
Cbc0001I Search completed - best objective 1.896286097077288, took 0 iterations and 0 nodes (0.01 seconds)
Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost
Cuts at root node changed objective from 1.89629 to 1.89629
Probing was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
Gomory was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
Knapsack was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
Clique was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
MixedIntegerRounding2 was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
FlowCover was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
TwoMirCuts was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
ZeroHalf was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)

Result - Optimal solution found

Objective value:                -1.89628610
Enumerated nodes:               0
Total iterations:               0
Time (CPU seconds):             0.02
Time (Wallclock seconds):       0.02

Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.02   (Wallclock seconds):       0.02

2024-06-11 15:54:01,139 - web_server - INFO - Status: Optimal
2024-06-11 15:54:01,139 - web_server - INFO - Total value of the Cost function = -1.90

Ah, like I experienced also. Maybe you can try and go back to 0.9.1 as well and see what you get then. Just to be sure that your solution is always ‘optimal’, even with negative prices.

Why is your def_load_end [95], when your prediction_horizon is 24?

If you want to disable def_load_end can you can just make it 0?

If you define your solver in the config you won’t get these extra debug messages:

Have made is 0 and matched the horizon prediction but I don’t understand the high deferrable load numbers when the power price went negative.

I’m literally feeding it 1800 for the load.

But once grid prices went back to positive numbers the issue went away.