davidusb-geek / emhass

emhass: Energy Management for Home Assistant, is a Python module designed to optimize your home energy interfacing with Home Assistant.
MIT License
260 stars 51 forks source link

Inverter can't output the load that EMHASS seems to think it should. #220

Closed Deztak closed 1 month ago

Deztak commented 3 months ago

It seems that EMHASS is not accounting for my inverter having to supply the load and feed-in. Hence my 10kW inverter is currently outputting about 10kW but only 6kW is making it to the grid while EMHASS thinks about 10kW should be making it.

I have it setup in the Config that my max battery draw is 10kW and the max grid load is 13kW and the nominated inverter from the csv is a 10kW inverter. If I reduce the grid draw it'll fix this issue but then it will start recharging the batter early and I end up filling it while the feed-in price is still negative so I have solar going to waste and I needless paid higher prices to charge the battery.

I think this may be why I seem to be struggling to discharge the battery per the EMHASS planned discharge. I usually still have about 20-30% charge when the projection at midday was to drop it to 9% by the end of the peak feed-in period.

image

purcell-lab commented 3 months ago

I have my EMHASS forecasts (on the left) aligned with my actual readings (on the right) so I can debug these types of issues

Screenshot_20240308-160452

The EMHASS forecasts should always be in balance, if Optimal.

Grid +  PV + Battery = Load (+ deferrable loads)

It's not clear from your example above what are the four EMHASS forecasts.

Deztak commented 3 months ago

The bottom row are actuals, second bottom row is the planned. I’m re-running the option and publish every few minutes, basically when there is new pricing or Solar forecasts.

Most of the first three rows are actuals, total power is the sum of all of the power sources (actuals) and the percentages are the percentage of the total power that is being sourced (first row) and drawn (second row)

So EMHASS Grid Power is -9,679.09 W and this is just states.p_grid_forecast EMHASS PV Power is states.p_pv_forecast

I do have an output that shows the sum of the power sources from EMHASS and it was over 13,000 W … if there is an inverter power limit in the config then I’ve missed it but, I think this could be solved with an Inverter power limit as the batteries can be charge with up to 15,000 W from the PV on the DC circuit but the AC circuit is always limited to 10,000 W whether it’s powering the house or feeding the grid. When it’s recharging it will trip my 63amp circuit breaker at about 15,200 W so I could in theory power the house with 5,200 W while recharging the batteries from grid with 10,000 W … but tripping the circuit breaker too often has lead me to only allow 13,000 W that way turning on a 2,000W oven or kettle won’t trip the circuit breaker.

davidusb-geek commented 3 months ago

Use the template editor in developer tools to share your actual curl command and the actual data that you are passing to each enpoint call. Also share the details of your setup/config as asked on the issue template. Otherwise it is difficult to provide help.

Deztak commented 3 months ago

Mark helped me out via an Amber-Home Assistant Facebook group to get some rest sensors setup that pull data from Solar.Forecast as well as pushing data to EMHASS. Unfortunately I can’t seem to copy-paste from the Mobile UI in Samba or access the add-on tabs.

If I end up not being able to get to sleep then I’ll copy-paste it all here but, if the issue is the user then I’m thinking it’s in the config. I messed about with it a bit, trying to get the EMHASS outputs to be right. SolarEdge setup the batteries with a charge limit of 11,400W as this is basically the theoretical peak PV power of my setup. I do have three of their 9.7kVA batteries, with a theoretical max DC charge rate of 15,000W (so I have spare capacity in my DC circuit)

I had the charge and discharge rates set to 10,000 W but then EMHASS was feeding back to the grid while the feed-in price was forecast to be negative, so I bumped up the charge rate to 11,400 W and that solved that issue but if I bumped up the discharge rate to 11,400 W then it would predict it discharging at 11,400 W … as that’s not possible I put it back to 10,000 W but, EMHASS seems to think the inverter can push out peak PV + peak battery discharge power at the same time.

Below is a plot of the actual total power and EMHASS total power. Below that is a plot of EMHASS PV, Batt, Grid & Load with the same time period actuals. Note in the processed data for the gauge display I need to negate the actual grid power as I have +ve for drawn power for each power source.

image image
Deztak commented 3 months ago

My rest commands: Copy-pasted from stuff Mark sent me on facebook as I tried to get his code from the help docs to work and struggled a lot. I don't use SolCast

rest_command: post_mpc_optim_solcast: url: http://homeassistant.local:5000/action/naive-mpc-optim method: POST content_type: 'application/json' payload: >- { "pv_power_forecast":{{states('sensor.solcast_24hrs_forecast')}},"load_cost_forecast":{{states('sensor.amber_gen_price_forecast')}},"prod_price_forecast":{{states('sensor.amber_prod_price_forecast')}},"prediction_horizon":{{states('sensor.solcast_24hrs_forecast')|from_json|count}},"soc_init":{{(states('sensor.med_battery_charge')|float(0)/100)|round(2)}},"soc_final":{{float(0.15)|round(2)}} } dayahead_optim: url: http://homeassistant.local:5000/action/dayahead-optim method: POST content_type: 'application/json' payload: >- {} publish_data: url: http://homeassistant.local:5000/action/publish-data method: POST content_type: 'application/json' payload: >- {}

The data passed through the 'post_mpc_optim_solcast' function looks like:

{ "pv_power_forecast": [ 3722, 4558, 5324, 6030, 6646, 7180, 7562, 7790, 7868, 7924, 7886, 7694, 7346, 6856, 6248, 5534, 4726, 3852, 3046, 2300, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "load_cost_forecast": [ 0.13, 0.11, 0.14, 0.13, 0.07, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.33, 0.35, 0.36, 0.38, 0.39, 0.39, 0.39, 0.41, 0.41, 0.45, 0.45, 0.46, 0.19, 0.19, 0.19, 0.18, 0.19, 0.19, 0.2, 0.19, 0.2, 0.19, 0.19, 0.19, 0.16 ], "prod_price_forecast": [ 0.04, 0.02, 0.04, 0.02, -0.04, -0.06, -0.07, -0.07, -0.07, -0.07, -0.07, 0.24, 0.27, 0.28, 0.29, 0.31, 0.31, 0.3, 0.32, 0.32, 0.36, 0.36, 0.37, 0.09, 0.09, 0.09, 0.08, 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.07 ], "prediction_horizon": 36, "soc_init": 0.17, "soc_final": 0.15 }

Deztak commented 3 months ago

EMHASS add-in config file: Note, I have no deferrable loads setup. Mark recommended that I try a shelly device to setup my hot water as a deferrable load. I'm still looking into this. My inverter and solar panels are not listed in the csv.

logging_level: INFO costfun: profit sensor_power_photovoltaics: sensor.solar_power_w sensor_power_load_no_var_loads: sensor.consumption_power_w set_total_pv_sell: false set_nocharge_from_grid: false set_nodischarge_to_grid: false maximum_power_from_grid: 10000 number_of_deferrable_loads: 1 list_nominal_power_of_deferrable_loads:

  • nominal_power_of_deferrable_loads: 1 list_operating_hours_of_each_deferrable_load:
  • operating_hours_of_each_deferrable_load: 0 list_start_timesteps_of_each_deferrable_load:
  • start_timesteps_of_each_deferrable_load: 0 list_end_timesteps_of_each_deferrable_load:
  • end_timesteps_of_each_deferrable_load: 0 list_peak_hours_periods_start_hours:
  • peak_hours_periods_start_hours: "00:00" list_peak_hours_periods_end_hours:
  • peak_hours_periods_end_hours: "00:00" list_treat_deferrable_load_as_semi_cont:
  • treat_deferrable_load_as_semi_cont: true list_set_deferrable_load_single_constant:
  • set_deferrable_load_single_constant: false load_peak_hours_cost: 0.1907 load_offpeak_hours_cost: 0.1419 photovoltaic_production_sell_price: 0.065 list_pv_module_model:
  • pv_module_model: CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M list_pv_inverter_model:
  • pv_inverter_model: Fronius_International_GmbHFronius_Primo_5_0_1_208_240240V_ list_surface_tilt:
  • surface_tilt: 32
  • surface_tilt: 36 list_surface_azimuth:
  • surface_azimuth: 34
  • surface_azimuth: 216 list_modules_per_string:
  • modules_per_string: 16
  • modules_per_string: 16 list_strings_per_inverter:
  • strings_per_inverter: 1
  • strings_per_inverter: 1 set_use_battery: true battery_nominal_energy_capacity: 29100 battery_discharge_power_max: 8000 battery_charge_power_max: 11399 battery_discharge_efficiency: 0.95 battery_charge_efficiency: 0.95 battery_minimum_state_of_charge: 0.12 battery_maximum_state_of_charge: 1 battery_target_state_of_charge: 0.1 weather_forecast_method: solar.forecast load_forecast_method: naive
Deztak commented 3 months ago

Note in today's plan @ 1700 I have 8,512 W in P_grid_neg and 3,813 W in P_load ... so the total power through the inverter per the plan is 12,325 W

newplot (2)

davidusb-geek commented 3 months ago

I don't see a total inverter of 12 kW. According to that graph the maximum power through your inverter is around 8 kW peak. I really don't see the issue here.

Deztak commented 3 months ago

So looking at it from a power source perspective when my SolarEdge inverter is in "Discharge to maximise export" mode it outputs all available pv and batt power to the grid. At 1700 in the plot the pv power is about 5kW and the battery power is about 8kW, so the combined power is still more than the peak output of the inverter.

And as above, from a load perspective, my inverter can't power the grid independantly of the load, so as above the inverter outputs 10kW and what isn't consumed by the load goes to the grid ... with a load forecast of 3.8kW the grid export cannot be above 6.2kW (while the forecast is 8.5kW)

purcell-lab commented 3 months ago

I suspect your issue maybe that you have a DC coupled battery, so only the one inverter is servicing both PV and battery. So whilst your settings for your PV inverter can export 10 kW, your settings also state your battery (inverter) can discharge 8 kW. However your system is only capability of exporting a total of 10 kW, in any combination of battery and PV.

I have an AC coupled battery, so in effect I have two inverters; battery inverter and a PV inverter that can function independently. So in effect my maximum export is battery inverter (15 kW) + PV inverter (15 kW). This is how EMHASS models batteries and PV inverters.

Deztak commented 3 months ago

Yes, that makes the most sense for where my setup isn't as EMHASS assumes my setup is configured.

@purcell-lab

I suspect your issue maybe that you have a DC coupled battery, so only the one inverter is servicing both PV and battery. So whilst your settings for your PV inverter can export 10 kW, your settings also state your battery (inverter) can discharge 8 kW. However your system is only capability of exporting a total of 10 kW, in any combination of battery and PV.

the EMHASS forecast only makes sense to me if you have an inverter for the batteries and another for the pv … but with only one inverter with a common DC connection bus, the inverter is the bottleneck.

davidusb-geek commented 3 months ago

Couldn't this issue be solved by a maximum power from grid settings AND a maximum power to grid setting?

purcell-lab commented 3 months ago

Couldn't this issue be solved by a maximum power from grid settings AND a maximum power to grid setting?

I don't that that work resolve the issue.

Power from grid could be upto 10 kW through the inverter to charge battery + what ever amount of household load an additional 5, 10, 15 kW. Typically the network limits single phase households to 15 kW (63 A) - 20 kW (80 A)

Power to grid would be a maximum of 10 kW (through inverter mix of battery + solar), but if household load is 2 kW then max to grid is 8 kW, if household load is 5 kW then max to grid is 5 kW, ...

I think within EMHASS DC coupled batteries sharing an inverter need to be calculated differently taking into account the constraint of only having one inverter.

Deztak commented 3 months ago

Couldn't this issue be solved by a maximum power from grid settings AND a maximum power to grid setting?

I did try this but, my inverter CAN charge the batteries with 10kW and still support about 5kW of house load before tripping the 63amp breaker. I have a calculator that goal seeks on 13kW total draw from the grid. I tried goal sealing on 14kW but have too many appliances that can draw over 1kW and I have too many breaker trips.

So the system was overcharging at higher prices and it seemed to be costing me more than the current issue as that energy could have cost nothing if the pv provided it.

I think the simple solution would be to have a ‘maximum power to grid’ along with the current ‘maximum power from grid’ rather than assuming both are the same limit. Acknowledging that you have a good mix of optional and required variables already, I don’t know if it should be an optional or required input. I am biased but, maybe it should be ‘required’?

I think I could do a work-around where:

if p_grid_forecast < 0 then: set max_from_grid = int(10000) else set max_from_grid = int(13000)

then of course I’d need to lookup the docs to see if I can include this in my optim rest command.

Deztak commented 3 months ago

On this topic, I also have another code that checks if I’m better of charging from the grid or just charging from Solar and having the house load come from the grid. Where: If p_pv > 13kW - p_load then Call script: set_charge_solar_only Else Call script: set_charge_solar_and_grid

… so I have actually achieved a total power exceeding 15kW but I had about 6kW of house load due to my massive aircon struggling with the heatwave conditions.

davidusb-geek commented 3 months ago

if p_grid_forecast < 0 then: set max_from_grid = int(10000) else set max_from_grid = int(13000)

Ok this seems like a condition that should be implemented in the code to properly support this special configuration of the same inverter for both PV and battery. Do you agree @purcell-lab ?

Well I think that this is exactly waht you meant with this:

I think within EMHASS DC coupled batteries sharing an inverter need to be calculated differently taking into account the constraint of only having one inverter.

philjohn commented 3 months ago

Couldn't this issue be solved by a maximum power from grid settings AND a maximum power to grid setting?

As Deztalk said - not for this case, but for another case where you have a limit on the amount of power you can send back to the grid, which is lower than the amount you can pull, that would be a useful change.

Deztak commented 3 months ago

I agree, I just don’t know what would be involved as I don’t know the code. From reading the API info for my inverter, it has heaps of different operating modes such as limited energy return per day and proportion of energy generated per day. It even seems to have an ability to call on a backup generator, I guess for applications where you are off grid.

The output plots have to_grid and from_grid power separated, so logically speaking the code does breakup the grid power at some point … but is this done before or after the optimisation?

How much is involved in adding it to the config? Or should it be passed to EMHASS via the CURL or REST_command? Yes, not having it in the config file may make it harder, but it’s potentially a feature for more advanced users … so maybe adding it to the config would make the initial setup that little bit more complex for the average user and thus turn them away… I don’t know any of the answers to these questions, so it’s up to the best judgement of the devs and I’ll respect the decision they make as they would also have to deal with the consequence of other complaining about these potential issues.

I am very grateful for this, the sales team lead me to believe that SolarEdge does this optimisation for us and after trying for over 12 months to get something similar coded, I never broke even over a billing cycle. Currently I am about $85 in the black in the first billing cycle with EMHASS. Thankyou Devs.

davidusb-geek commented 3 months ago

The output plots have to_grid and from_grid power separated, so logically speaking the code does breakup the grid power at some point … but is this done before or after the optimisation?

It is braked down before the optimization to convert the problem to a linear one.

How much is involved in adding it to the config? Or should it be passed to EMHASS via the CURL or REST_command? Yes, not having it in the config file may make it harder, but it’s potentially a feature for more advanced users … so maybe adding it to the config would make the initial setup that little bit more complex for the average user and thus turn them away… I don’t know any of the answers to these questions, so it’s up to the best judgement of the devs and I’ll respect the decision they make as they would also have to deal with the consequence of other complaining about these potential issues.

I've marked this as a necessary enhancement and we will add support for this in the future, as is not even a strange use case. I guess that in the future with more batteries people will have this configuration more often. We just need to add a boolean in the configuration to state that we have one single inverter for PV and batteries and based on this we need to add some conditions and constraints before the optimization.

I am very grateful for this, the sales team lead me to believe that SolarEdge does this optimisation for us and after trying for over 12 months to get something similar coded, I never broke even over a billing cycle. Currently I am about $85 in the black in the first billing cycle with EMHASS. Thankyou Devs.

Cheers, glad to hear!

Deztak commented 3 months ago

Thanks Davidusb.

With the grid in this part of NSW there is a 10kW inverter limit, anymore and we had to register it as a virtual power plant and other BS costs and delays would be added. So I hesitated ALOT as, I would have to decide on whether to have a 4kW inverter on my (then) 6.6kW array and a 6kW inverter on my 29.1kWh of batteries or put leave the old inverter and have a smaller inverter for the batteries.

None of it really worked out to my setup being any where near cost positive. Then they told me about the setup I eventually got and I went all-in … max number of the biggest batteries and added 5.7kW of panels to my Solar array.

I don’t know if they’ll be more common but, within the constraints put on me by AusGrid, I was either never getting batteries or I’d get the setup I now have.

I’m hoping that Amber will payout my bill credits in a way that I can “buy you a coffee” with that payout.

kcoffau commented 3 months ago

I setup a hard limit in HA to only allow 10KW export, even when EMHASS instructs more. Its means EMHASS is wrong for periods, but revaluates every 5 mins, so in the wash, its OK.

Agree, grid limits would be an awesome variable to add. both inbound and outbound which includes loads, solar and battery.

Deztak commented 3 months ago

I setup a hard limit in HA to only allow 10KW export, even when EMHASS instructs more. Its means EMHASS is wrong for periods, but revaluates every 5 mins, so in the wash, its OK

this follows my experience too, but I noticed that I was losing more money due to less Solar being directly exported this way and I was better off with just tolerating not fully draining the battery while prices are high.

altonius commented 1 month ago

I look forward to a DC-Coupled battery option, thanks everyone for looking into this and explaining exactly what I'm experiencing.

davidusb-geek commented 1 month ago

I setup a hard limit in HA to only allow 10KW export, even when EMHASS instructs more. Its means EMHASS is wrong for periods, but revaluates every 5 mins, so in the wash, its OK.

Agree, grid limits would be an awesome variable to add. both inbound and outbound which includes loads, solar and battery.

These grid limits were already added recently. It is now possible to set these in the configuration file:

P_from_grid_max: 9000 # The maximum power that can be supplied by the utility grid in Watts
  P_to_grid_max: 9000 # The maximum power that can be supplied to the utility grid in Watts
davidusb-geek commented 1 month ago

I will try to work very soon on adding support for hybrid inverters.

altonius commented 1 month ago

I will try to work very soon on adding support for hybrid inverters.

Happy to help out with any testing when you're close to finishing this.

davidusb-geek commented 1 month ago

I will try to work very soon on adding support for hybrid inverters.

Happy to help out with any testing when you're close to finishing this.

Hi, I've just implemented a first solution. The results seems coherent to me. I solved this by adding an additional constraint like this: $P{hybrid}=P{PV}+P{bat}^{pos}+P{bat}^{neg}\leq P{hybrid}^{nominal}$ Where $P{hybrid}^{nominal}$ is the nominal power of the hybrid inverter.

I will gladly use your help @altonius or anyone willing to provide help analyzing this. To test this you need to clone this branch https://github.com/davidusb-geek/emhass/tree/davidusb-geek/dev/hybrid_inverter_def_seq Then launch the script in: scripts\script_debug_optim.py

The input data: artificially added negative prod prices image image

The optimization results: image

The results table:

image image

Does these seem logical to you?

davidusb-geek commented 1 month ago

Hi, I've just updated this implementation as it was certainly not complete when I posted those results in my previous post. Actually I realized that a PV curtailment variable is needed to implement this. I guess that this type of behavior is internally implemented in this type of inverter. Or that the PV system and the battery are well sized to avoid curtailement.

In any case to test this I have the same inputs that in my previous post but I have now multiplied the PV forecast by 2 to force the curtailment and to check the nominal power limitation of the hybrid inverter. I again considered a period of negative prod prices. The nominal power of the tested hybrid inverter is 5 kW.

Now the constraint looks like this: $P{hybrid} = P{PV} - P{curtailment} + P{bat}^{pos} + P{bat}^{neg} \leq P{hybrid}^{nominal}$

Here are my inputs: image image

And the main results: image

With the results table:

image

As we can see we now have P_hybrid_inverter and a P_PV_curtailment variables. The curtailment effectively activates on the period of negative prod prices and the P_hybrid_inverter never exceeds the nominal power of 5 kW even when the PV production is higher than 5 kW. The system converges to a solution where no power is injected to the grid during negative prod prices.

What do you think?

For reference this is what it looks like when setting inverter_is_hybrid = False. So this is to check the behavior of curtailment, I think that it is applied properly here and again no power is injected to the grid during negative prod prices.

image

davidusb-geek commented 1 month ago

I'll wait for your feedback but I think that this solves this issue. One thing is that for now I'm using the model of the inverter defined in the configuration file to obtain the nominal power of the inverter, which is needed by the defined new constraints. This can be a problem for people using solar.forecast, soclast or passing their own PV forecast data. However the solution will be to properly define this entry in the configuration with at least an inverter model with at least similar nominal power as yours. I've developed a little app to help find the models in the database: https://emhass-pvlib-database.streamlit.app/

altonius commented 1 month ago

Let me have a go at testing. I'm going to try running this locally (instead of trying to update the EMHASS add-on) and how I go back on a command line. The calculations look correct to me. I just need to get my head around how the calculation handles the different scenarios.

Deztak commented 1 month ago

For reference this is what it looks like when setting inverter_is_hybrid = False.

I'm struggling to figure out where to put "inverter_is_hybrid = False" and I can't see anything in the docs/readme/configUI for v0.9.1

I'm using the add-in and I'm getting the feeling that's what I'm doing wrong ...

--- edit ---

apologies just found ... now confused as to how to use it :P https://github.com/davidusb-geek/emhass/tree/davidusb-geek/dev/hybrid_inverter_def_seq

--- edit 2 --- I installed HASSIO onto a separate x64 machine ... https://www.home-assistant.io/installation/generic-x86-64

Seems that there should be some sort of "docker" method but, I can't figure it all out right now ... but this looks pretty promising. Given the weather here in NSW and that about 40% of my array faces WSW I'm unlikely to have this issue again for a little while. However it does look like you have the excess solar going into the batteries rather than to the grid which is what the forecast was saying previously and thus my controller that primarily looked at the power to the grid to determine if it should set the inverter to maximise export wouldn't be dumping 10kW back to the grid during negative feed-in pricing anymore.

So based on your data plots, it looks like you've solved it.

altonius commented 1 month ago

I'm not having much luck with setting up my test environment, I'm going to go through the table and see if they all make sense.

I think @Deztak above is looking at exporting scenarios. I'm looking at my current import scenarios (per the image).

If I configure battery_charge_power_max to 5000w emhass isn't able to combine both the PV and Grid to exceed this. As I use p_batt as an input to guide my charge/discharge automations, it gets tricky, so I have to increase my charge max during the day, and then decrease it overnight when I'm only going to import from the grid.

image
Deztak commented 1 month ago

Looks like the SolarEdge UI … If so, I might have some template sensors and automations that’ll help with that.

altonius commented 1 month ago

Looks like the SolarEdge UI … If so, I might have some template sensors and automations that’ll help with that.

Cheers, I have a bunch already configured, and was trying to show a very simple view of the dc-coupled setup.  I'm always happy to learn how people have setup sensors and automations.

Deztak commented 1 month ago

The (custom) sensors are in a file so that I don't have to restart each time I make a change, as you do with changes to the config.yaml file: (note: the "sensor.powerproduction###" sensors are from the two forecast.solar integrations I'm running as I have two arrays facing very different directions) I'm very much an amateur coder, sorry if it's difficult to follow what I am doing with it.

platform: template
sensors:
    consumption_power_w:
        unique_id: "sensor.consumption_power_w"
        friendly_name: "Consumption Power W"
        device_class: "power"
        unit_of_measurement: "W"
        value_template: >
            {{ float(states('sensor.solaredge_i1_ac_power')) - float(states('sensor.solaredge_m1_ac_power')) }}
    solar_power_w:
        unique_id: "sensor.solar_power_w"
        friendly_name: "Solar Power W"
        device_class: "power"
        unit_of_measurement: "W"
        value_template: >
            {% set blah = namespace (
                batt = float(states('sensor.battery_power_w')),
                inv = float(states('sensor.solaredge_i1_ac_power')),
                solar = 0
                ) %}
            {% if states('sun.sun') == 'above_horizon' %}
                {% if blah.inv >= float(0) %}
                    {% if blah.batt >= float(0) %}
                        {% set blah.solar = (blah.inv + blah.batt) %}
                    {% else %}
                        {% set blah.solar = (blah.inv - blah.batt) %}
                    {% endif %}
                {% else %}
                    {% set blah.solar = (blah.inv + blah.batt) %}
                {% endif %}
            {% else %}
            {   % set blah.solar = float(0) %}
            {% endif %}
            {% if blah.solar < 0 %}
                {% set blah.solar = float(0) %}
            {% endif %}
            {{ blah.solar }}
    battery_charge_limit:
        unique_id: "sensor.battery_charge_limit"
        friendly_name: "Battery Charge Limit"
        unit_of_measurement: "W"
        value_template: >
                {{ min( 11400,
                    13000 +
                    min( states('sensor.power_production_now')|float(0) + states('sensor.power_production_now_2')|float(0),
                        states('sensor.power_production_next_hour')|float(0) + states('sensor.power_production_next_hour_2')|float(0),
                        float(states('sensor.solar_power_w')) ) / 1.2 -
                        max( float(states('sensor.consumption_power_w')),
                            float(states('sensor.p_load_forecast'))
                            ) * 1.2
                        )|round(0)|int(0) }}

yaml to implement from the automations editor:

alias: Battery Limits refresh
description: ""
trigger:
  - platform: time_pattern
    seconds: /30
condition:
  - condition: state
    entity_id: automation.emhass_publish_data_2
    attribute: current
    state: "off"
action:
  - if:
      - condition: or
        conditions:
          - condition: state
            entity_id: sensor.solaredge_i1_ac_power
            state: unavailable
          - condition: state
            entity_id: sensor.solaredge_i1_ac_power
            state: unknown
    then:
      - service: homeassistant.reload_all
        metadata: {}
        data: {}
      - delay:
          hours: 0
          minutes: 0
          seconds: 30
          milliseconds: 0
  - choose:
      - conditions:
          - condition: state
            entity_id: select.solaredge_i1_storage_command_mode
            state: Maximize Self Consumption
        sequence:
          - service: script.battery_reset
            metadata: {}
            data: {}
      - conditions:
          - condition: state
            entity_id: select.solaredge_i1_storage_command_mode
            state: Discharge to Maximize Export
        sequence:
          - service: script.battery_set_discharge_to_maximize_export
            data: {}
      - conditions:
          - condition: or
            conditions:
              - condition: state
                entity_id: select.solaredge_i1_storage_command_mode
                state: Charge from Solar Power and Grid
              - condition: state
                entity_id: select.solaredge_i1_storage_command_mode
                state: Charge from Solar Power
        sequence:
          - service: script.battery_set_charge_from_solar_power_and_grid
            metadata: {}
            data: {}
mode: single

This is the script that changes the battery setting ... note, if there is more solar the batteries can consume then I go to 'Charge from Solar Only' mode

alias: Battery - Charge from Solar Power and Grid
sequence:
  - if:
      - condition: or
        conditions:
          - condition: numeric_state
            entity_id: sensor.solar_power_w
            above: sensor.battery_charge_limit
    then:
      - if:
          - condition: not
            conditions:
              - condition: state
                entity_id: select.solaredge_i1_storage_command_mode
                state: Charge from Solar Power
        then:
          - service: select.select_option
            data:
              option: Charge from Solar Power
            target:
              entity_id: select.solaredge_i1_storage_command_mode
      - if:
          - condition: numeric_state
            entity_id: number.solaredge_i1_storage_charge_limit
            below: 11400
        then:
          - service: number.set_value
            data:
              value: "11400"
            target:
              entity_id: number.solaredge_i1_storage_charge_limit
    else:
      - if:
          - condition: numeric_state
            entity_id: sensor.battery_charge_limit
            below: 11400
        then:
          - service: number.set_value
            data:
              value: "{{int(states('sensor.battery_charge_limit'))}}"
            target:
              entity_id: number.solaredge_i1_storage_charge_limit
        else:
          - service: number.set_value
            data:
              value: "11400"
            target:
              entity_id: number.solaredge_i1_storage_charge_limit
      - if:
          - condition: not
            conditions:
              - condition: state
                entity_id: select.solaredge_i1_storage_command_mode
                state: Charge from Solar Power and Grid
        then:
          - service: select.select_option
            data:
              option: Charge from Solar Power and Grid
            target:
              entity_id: select.solaredge_i1_storage_command_mode
  - if:
      - condition: and
        conditions:
          - condition: numeric_state
            entity_id: number.solaredge_i1_site_limit
            below: 10000
    then:
      - service: number.set_value
        data:
          value: "10000"
        target:
          entity_id:
            - number.solaredge_i1_site_limit
  - if:
      - condition: numeric_state
        entity_id: number.solaredge_i1_storage_discharge_limit
        below: 11400
    then:
      - service: number.set_value
        data:
          value: "11400"
        target:
          entity_id: number.solaredge_i1_storage_discharge_limit
mode: single
davidusb-geek commented 1 month ago

Let me have a go at testing. I'm going to try running this locally (instead of trying to update the EMHASS add-on) and how I go back on a command line.

Sorry I didn't gave much further explanation. This is not released on any add-on version, so you will only find the base code on a development git branch. There is a script that you can use on that branch. In a machine with Python installed the steps are: clone the repo, set an environment, switch to dev branch, launch the script...

git clone https://github.com/davidusb-geek/emhass.git
cd emhass
python -m venv .venv
source .venv/bin/activate
python setup.py install
git checkout davidusb-geek/dev/hybrid_inverter_def_seq
python scripts/script_debug_optim.py
davidusb-geek commented 1 month ago

I'm struggling to figure out where to put "inverter_is_hybrid = False" and I can't see anything in the docs/readme/configUI for v0.9.1

So not yet published/released nor documented, just a dev base code for now. I set that option manually in the said script.

Deztak commented 1 month ago

Let me have a go at testing. I'm going to try running this locally (instead of trying to update the EMHASS add-on) and how I go back on a command line.

Sorry I didn't gave much further explanation. This is not released on any add-on version, so you will only find the base code on a development git branch. There is a script that you can use on that branch. In a machine with Python installed the steps are: clone the repo, set an environment, switch to dev branch, launch the script...

git clone https://github.com/davidusb-geek/emhass.git
cd emhass
python -m venv .venv
source .venv/bin/activate
python setup.py install
git checkout davidusb-geek/dev/hybrid_inverter_def_seq
python scripts/script_debug_optim.py

Parlez vous Anglais?

altonius commented 1 month ago

yay, the above has got me running the script in WSL, rather than in an add-on. What's the best way to plug in my own data? do I need to configure the config file(s) to point to my HA and configure my battery / pv setup? or can I just run the script with data like I do to the API endpoint?

davidusb-geek commented 1 month ago

Parlez vous Anglais?

Oui c'était bien de l'anglais ;-)

davidusb-geek commented 1 month ago

yay, the above has got me running the script in WSL, rather than in an add-on. What's the best way to plug in my own data? do I need to configure the config file(s) to point to my HA and configure my battery / pv setup? or can I just run the script with data like I do to the API endpoint?

Great!

The best way that I can think is to pass the data as lists directly. So you need to replace the whole first part of the script, from line 33 to line 70, with something like this (I haven't tested this):

with open(emhass_conf['config_path'], 'r') as file:
    params = yaml.load(file, Loader=yaml.FullLoader)
params.update({
    'params_secrets': {
        'hass_url': 'http://supervisor/core/api',
        'long_lived_token': '${SUPERVISOR_TOKEN}',
        'time_zone': 'Europe/Paris',
        'lat': 45.83,
        'lon': 6.86,
        'alt': 4807.8
    }
    })
runtimeparams = {
    'pv_power_forecast':[i+1 for i in range(48)],
    'load_power_forecast':[i+1 for i in range(48)],
    'load_cost_forecast':[i+1 for i in range(48)],
    'prod_price_forecast':[i+1 for i in range(48)]
}
runtimeparams_json = json.dumps(runtimeparams)
params['passed_data'] = runtimeparams
params_json = json.dumps(params)
retrieve_hass_conf, optim_conf, plant_conf = utils.get_yaml_parse(
    emhass_conf, use_secrets=False, params=params_json)
set_type = "dayahead-optim"
params, retrieve_hass_conf, optim_conf, plant_conf = utils.treat_runtimeparams(
    runtimeparams_json, params_json, retrieve_hass_conf, 
    optim_conf, plant_conf, set_type, logger)
rh = RetrieveHass(
    retrieve_hass_conf['hass_url'], retrieve_hass_conf['long_lived_token'], 
    retrieve_hass_conf['freq'], retrieve_hass_conf['time_zone'],
    params, emhass_conf, logger)
if self.get_data_from_file:
    with open((emhass_conf['data_path'] / 'test_df_final.pkl'), 'rb') as inp:
        rh.df_final, days_list, var_list = pickle.load(inp)
    retrieve_hass_conf['var_load'] = str(self.var_list[0])
    retrieve_hass_conf['var_PV'] = str(self.var_list[1])
    retrieve_hass_conf['var_interp'] = [retrieve_hass_conf['var_PV'], retrieve_hass_conf['var_load']]
    retrieve_hass_conf['var_replace_zero'] = [retrieve_hass_conf['var_PV']]
else:
    days_list = utils.get_days_list(retrieve_hass_conf['days_to_retrieve'])
    var_list = [retrieve_hass_conf['var_load'], retrieve_hass_conf['var_PV']]
    rh.get_data(days_list, var_list, minimal_response=False, significant_changes_only=False)
rh.prepare_data(
    retrieve_hass_conf['var_load'], load_negative = retrieve_hass_conf['load_negative'],
    set_zero_min = retrieve_hass_conf['set_zero_min'], 
    var_replace_zero = retrieve_hass_conf['var_replace_zero'], 
    var_interp = retrieve_hass_conf['var_interp'])
df_input_data = rh.df_final.copy()
fcst = Forecast(
    retrieve_hass_conf, optim_conf, plant_conf, 
    params_json, emhass_conf, logger, get_data_from_file=True)

P_PV_forecast = fcst.get_weather_forecast(method='list')
df_input_data.index = P_PV_forecast.index
df_input_data.index.freq = rh.df_final.index.freq
P_load_forecast = fcst.get_load_forecast(method='list')
df_input_data = pd.concat([P_PV_forecast, P_load_forecast], axis=1)
df_input_data.columns = ['P_PV_forecast', 'P_load_forecast']

df_input_data = fcst.get_load_cost_forecast(df_input_data, method='list')
df_input_data = fcst.get_prod_price_forecast(df_input_data, method='list')

So in the dictionary runtimeparams you can manually place your own data. For example:

runtimeparams = {
    'pv_power_forecast':[1, 2, 3, 4, 5, 6, 7, 8, 9],
    'load_power_forecast':[1, 2, 3, 4, 5, 6, 7, 8, 9],
    'load_cost_forecast':[1, 2, 3, 4, 5, 6, 7, 8, 9],
    'prod_price_forecast':[1, 2, 3, 4, 5, 6, 7, 8, 9]
}
Deztak commented 1 month ago

I feel like I may need to use the pip command to allow me to import a GitHub module that is commonly shortened to “git” in a similar way to how pandas is commonly “import pandas as pd” … when I have time I might hit stack overflow to try and fill in the gaps.

altonius commented 1 month ago

i've been able to start modifying the file, had to add a couple of imports+ remove a few self. references but that's about as far as I can get. I've uploaded where I got upto here, it has a days worth of data that i'm attempting to play with

davidusb-geek commented 1 month ago

Ok this is included in the just released new version. Closing this for now but reopen if eneded.