EMHASS: An Energy Management for Home Assistant

if you want to control a battery (huawei), what should you focus on? SOC or power or both? How important is it? Because I see now that I’ve tried to control, I control power and SOC drops more than forecast.
It would be an advantage if you could input soc into emhass so that emhass could adjust power according to soc

I used to pass sensor.p_batt_forecast to my sonnen battery and it struggled to follow this curve so I switched to sensor.soc_batt_forecast with the below template to change the SoC to a power level that compares the current actual SoC to the forecast in 30 minutes and calculates what to apply to the battery to achieve that forecast.

{%- set third_row = state_attr('sensor.soc_batt_forecast', 'battery_scheduled_soc')[1] -%}
{%- set soc_value = third_row['soc_batt_forecast']|float(0) -%}
{%- set raw_power = ((states('sensor.sonnenbatterie_84324_state_charge_user')|float(0) - soc_value) / 100 * 9300 / 0.5 / 0.9)|round(0) -%}
{%- set limited_power = min(max(raw_power, -3300), 3300) -%}
{{ limited_power }}

My battery has a 3300 kW power limit so I have to flatten the curve if it exceeds this value.

I use this in a node red flow that passes the calculated power to the battery as a charge or discharge command.

That seems to work much better than using the sensor.p_batt_forecast value.

And the Tune method?

Hi David,

Thanks for the response. I probly should have put that with the calculation, i need to put that into a template. I cant figure this out. I would of thought using the graphs could do it. But you cant just stop it.

Im not sure how to get this data accross.

How are people following the sun with charging their EVs?

Do you put up with the constant switching with intermittent cloud or do you delay changes to charge rates or somehow average it out?

This flow has a 10 second delay before it reads the grid output then changes the the charge amps to match the available PV output.

Experimenting with Amp cut off as well. Cut off is at 4 Amps but perhaps it should be 0. That would stop the frequency of switching charging off completely but will switch wildly between 1 and higher Amps as clouds pass over. Trying to avoid negative feed-in tariff.

Interested in what other people are doing.

I run it every day just after the fit method

Something looks fishy as my house is not expected to draw much power at all. Can someone with knowledge check if it looks right. Could it be that I have had another controller for my battery at the same time emhass was running and therefore it looks like it does?

(During the day today, my battery has been standing still and intend to do the same thing tomorrow.)

logging_level: INFO
data_path: /share/
costfun: self-consumption
sensor_power_photovoltaics: sensor.input_power_with_efficiency_loss
sensor_power_load_no_var_loads: sensor.power_load_no_var_loads
set_total_pv_sell: false
set_nocharge_from_grid: false
set_nodischarge_to_grid: false
maximum_power_from_grid: 9000
number_of_deferrable_loads: 2
list_nominal_power_of_deferrable_loads:
  - nominal_power_of_deferrable_loads: 1500
  - nominal_power_of_deferrable_loads: 2220
list_operating_hours_of_each_deferrable_load:
  - operating_hours_of_each_deferrable_load: 5
  - operating_hours_of_each_deferrable_load: 2
list_start_timesteps_of_each_deferrable_load:
  - start_timesteps_of_each_deferrable_load: 0
  - start_timesteps_of_each_deferrable_load: 0
list_end_timesteps_of_each_deferrable_load:
  - end_timesteps_of_each_deferrable_load: 0
  - end_timesteps_of_each_deferrable_load: 0
list_peak_hours_periods_start_hours:
  - peak_hours_periods_start_hours: "00:00"
  - peak_hours_periods_start_hours: "10:00"
list_peak_hours_periods_end_hours:
  - peak_hours_periods_end_hours: "12:00"
  - peak_hours_periods_end_hours: "21:00"
list_treat_deferrable_load_as_semi_cont:
  - treat_deferrable_load_as_semi_cont: false
  - treat_deferrable_load_as_semi_cont: false
list_set_deferrable_load_single_constant:
  - set_deferrable_load_single_constant: false
  - 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: Huawei_Technologies_Co___Ltd___SUN2000_10KTL_USL0__240V_
list_surface_tilt:
  - surface_tilt: 18
list_surface_azimuth:
  - surface_azimuth: 230
list_modules_per_string:
  - modules_per_string: 23
list_strings_per_inverter:
  - strings_per_inverter: 1
set_use_battery: true
battery_nominal_energy_capacity: 10000
historic_days_to_retrieve: 14
load_negative: false
optimization_time_step: 60
battery_maximum_state_of_charge: 1
battery_target_state_of_charge: 1
battery_minimum_state_of_charge: 0.2
battery_charge_power_max: 3200
battery_discharge_power_max: 1700
method_ts_round: first
mpc: 'curl -i -H ''Content-Type: application/json'' -X POST -d ''{
  "load_cost_forecast":{{((state_attr(''sensor.nordpool_kwh_se3_sek_3_10_025'', ''raw_today'') | map(attribute=''value'') | list  + state_attr(''sensor.nordpool_kwh_se3_sek_3_10_025'', ''raw_tomorrow'') | map(attribute=''value'') | list))[now().hour:][:24] }},
  "prod_price_forecast":{{((state_attr(''sensor.nordpool_moms'', ''raw_today'') | map(attribute=''value'') | list  + state_attr(''sensor.nordpool_moms'', ''raw_tomorrow'') | map(attribute=''value'') | list))[now().hour:][:24] }},
  "prediction_horizon":{{min(24, (((state_attr(''sensor.nordpool_moms'', ''raw_today'')|map(attribute=''value'')|list + state_attr(''sensor.nordpool_moms'', ''raw_tomorrow'') | map(attribute=''value'')| list)[now().hour:][:48]|list|length)))}},
  "pv_power_forecast":{{([states(''sensor.solcast_pv_forecast_power_now'')|int(0)] + state_attr(''sensor.solcast_pv_forecast_forecast_today'', ''detailedHourly'')|selectattr(''period_start'',''gt'',utcnow()) | map(attribute=''pv_estimate'')|map(''multiply'',1000)|map(''int'')|list + state_attr(''sensor.solcast_pv_forecast_forecast_tomorrow'', ''detailedHourly'')|selectattr(''period_start'',''gt'',utcnow()) | map(attribute=''pv_estimate'')|map(''multiply'',1000)|map(''int'')|list)| tojson}},
  "delta_forecast":2
  }'' http://localhost:5000/action/naive-mpc-optim'
dayahead_optim: 'curl -i -H ''Content-Type: application/json'' -X POST -d ''{"load_cost_forecast":{{((state_attr(''sensor.nordpool_kwh_se3_sek_3_10_025'', ''raw_today'') | map(attribute=''value'') | list  + state_attr(''sensor.nordpool_kwh_se3_sek_3_10_025'', ''raw_tomorrow'') | map(attribute=''value'') | list))[now().hour:][:24] }},"prod_price_forecast":{{((state_attr(''sensor.nordpool_moms'', ''raw_today'') | map(attribute=''value'') | list  + state_attr(''sensor.nordpool_moms'', ''raw_tomorrow'') | map(attribute=''value'') | list))[now().hour:][:24] }},"prediction_horizon":{{min(24, (((state_attr(''sensor.nordpool_moms'', ''raw_today'')|map(attribute=''value'')|list + state_attr(''sensor.nordpool_moms'', ''raw_tomorrow'') | map(attribute=''value'')| list)[now().hour:][:48]|list|length)))}},"pv_power_forecast":{{([states(''sensor.solcast_pv_forecast_power_now'')|int(0)] + state_attr(''sensor.solcast_pv_forecast_forecast_today'', ''detailedHourly'')|selectattr(''period_start'',''gt'',utcnow()) | map(attribute=''pv_estimate'')|map(''multiply'',1000)|map(''int'')|list + state_attr(''sensor.solcast_pv_forecast_forecast_tomorrow'', ''detailedHourly'')|selectattr(''period_start'',''gt'',utcnow()) | map(attribute=''pv_estimate'')|map(''multiply'',1000)|map(''int'')|list)| tojson}},"delta_forecast":2 }'' http://localhost:5000/action/dayahead-optim'
##
publish_data: 'curl -i -H "Content-Type:application/json" -X POST -d ''{}'' http://localhost:5000/action/publish-data'

Hi Johan,
What is the content of your historic power? Looks like you’re expecting not to use anything.

That’s what I was trying to say in a previous post.

You need to exclude your pv and battery from the load. The value should be positive and reflect the net usage of your house.

I’m trying to switch from the usage prediction method “naive” to “mlforcaster”. Unfortunately, I can’t quite figure it out from the documentation, because I’m using emhass as a docker standalone. Is it enough if I change the line in the file “config_emhass.yaml”:

  • load_forecast_method: ‘naive’ # options are ‘csv’ to load a custom load forecast from a CSV file or ‘naive’ for a persistance model
    to
  • load_forecast_method: ‘mlforecaster’
    or is the specification of method=mlforcaster to be understood as an environment variable in the Docker call?

Thank you very much.
Thomas

Hey mate,

I have mine calculate the field of energy, starts with sun the any energy entering the grid that is diverted to the car.

I have mine on 15 second changes if value is less then 1000watts, and 10 second delay for greater then 1000w

You will always have a clunky value as its not hard wired, and even if you look at charge hq and other systems. They are delyed too

Hi Jeza,
I added a smoothing node (moving averages) and set to a 10 second cycle to process the flow. Seems to be ok.

  1. Calculates the available PV going to the grid
  2. Switches any output above 115W to the upper fork of the flow.
  3. Lower fork simply checks the car is home and connected and stops charging.
  4. Upper fork checks car is home and connected.
  5. Then converts the available PV to amps.
  6. Writes a timestamp and the calculated amps to a CSV file
  7. Checks that this is a different value than the last value 10 seconds ago.
  8. If not different exits the flow after passing an exit flag to the CSV file.
  9. If different, passes the value to a smoothing node which calculates the moving average value from 5 past values.
  10. This moving average value is then passed to the car’s amperage setting and if the car is already charging this changes the rate of charge dynamically.
  11. If the car is not already charging then the last two check the charging status and enables charging if not already charging.

Only reason I’m writing the values to a file is to compare the smoothed curve to the unsmoothed.

[
    {
        "id": "f87a2e360c2f8cba",
        "type": "poll-state",
        "z": "65840aa926d9c567",
        "name": "Follow Sun",
        "server": "afc27684.cf6ed8",
        "version": 3,
        "exposeAsEntityConfig": "6d4bf5e5550a42e6",
        "updateInterval": "10",
        "updateIntervalType": "num",
        "updateIntervalUnits": "seconds",
        "outputInitially": false,
        "outputOnChanged": false,
        "entityId": "sensor.sonnenbatterie_84324_consumption_w",
        "stateType": "str",
        "ifState": "",
        "ifStateType": "str",
        "ifStateOperator": "is",
        "outputs": 1,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "data",
                "propertyType": "msg",
                "value": "",
                "valueType": "entity"
            },
            {
                "property": "topic",
                "propertyType": "msg",
                "value": "",
                "valueType": "triggerId"
            }
        ],
        "x": 120,
        "y": 2740,
        "wires": [
            [
                "7266cd2c4c8e1e7c"
            ]
        ]
    },
    {
        "id": "7266cd2c4c8e1e7c",
        "type": "api-render-template",
        "z": "65840aa926d9c567",
        "name": "Unused PV",
        "server": "afc27684.cf6ed8",
        "version": 0,
        "template": "{{states('sensor.sonnenbatterie_84324_production_w') | int(0) \n- (states('sensor.house_power_consumption_less_deferrables') | int(0) \n+ states('sensor.garage_power_point_power') | int(0)\n- states('sensor.sonnenbatterie_84324_state_battery_inout') | int(0))}}",
        "resultsLocation": "payload",
        "resultsLocationType": "msg",
        "templateLocation": "",
        "templateLocationType": "none",
        "x": 270,
        "y": 2740,
        "wires": [
            [
                "52a6e2127d3cece5"
            ]
        ]
    },
    {
        "id": "52a6e2127d3cece5",
        "type": "switch",
        "z": "65840aa926d9c567",
        "name": "charge",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "gt",
                "v": "115",
                "vt": "num"
            },
            {
                "t": "lte",
                "v": "115",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 2,
        "x": 410,
        "y": 2740,
        "wires": [
            [
                "b1807955eff74bd2"
            ],
            [
                "b2fb6d6b52ad07bb"
            ]
        ]
    },
    {
        "id": "b2fb6d6b52ad07bb",
        "type": "api-current-state",
        "z": "65840aa926d9c567",
        "name": "Tesla at home",
        "server": "afc27684.cf6ed8",
        "version": 3,
        "outputs": 2,
        "halt_if": "home",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "device_tracker.ynot_location_tracker",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "data",
                "propertyType": "msg",
                "value": "",
                "valueType": "entity"
            }
        ],
        "for": "0",
        "forType": "num",
        "forUnits": "minutes",
        "override_topic": false,
        "state_location": "payload",
        "override_payload": "msg",
        "entity_location": "data",
        "override_data": "msg",
        "x": 600,
        "y": 2780,
        "wires": [
            [
                "45136e49d6f69ff8"
            ],
            []
        ]
    },
    {
        "id": "b1807955eff74bd2",
        "type": "api-current-state",
        "z": "65840aa926d9c567",
        "name": "Tesla at home",
        "server": "afc27684.cf6ed8",
        "version": 3,
        "outputs": 2,
        "halt_if": "home",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "device_tracker.ynot_location_tracker",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "data",
                "propertyType": "msg",
                "value": "",
                "valueType": "entity"
            }
        ],
        "for": "0",
        "forType": "num",
        "forUnits": "minutes",
        "override_topic": false,
        "state_location": "payload",
        "override_payload": "msg",
        "entity_location": "data",
        "override_data": "msg",
        "x": 600,
        "y": 2700,
        "wires": [
            [
                "7d05539153da05b6"
            ],
            []
        ]
    },
    {
        "id": "45136e49d6f69ff8",
        "type": "api-current-state",
        "z": "65840aa926d9c567",
        "name": "Tesla Connected",
        "server": "afc27684.cf6ed8",
        "version": 3,
        "outputs": 2,
        "halt_if": "on",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "binary_sensor.ynot_charger",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "data",
                "propertyType": "msg",
                "value": "",
                "valueType": "entity"
            }
        ],
        "for": "0",
        "forType": "num",
        "forUnits": "minutes",
        "override_topic": false,
        "state_location": "payload",
        "override_payload": "msg",
        "entity_location": "data",
        "override_data": "msg",
        "x": 800,
        "y": 2780,
        "wires": [
            [
                "f2115ff7a460c515"
            ],
            []
        ]
    },
    {
        "id": "7d05539153da05b6",
        "type": "api-current-state",
        "z": "65840aa926d9c567",
        "name": "Tesla Connected",
        "server": "afc27684.cf6ed8",
        "version": 3,
        "outputs": 2,
        "halt_if": "on",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "binary_sensor.ynot_charger",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "data",
                "propertyType": "msg",
                "value": "",
                "valueType": "entity"
            }
        ],
        "for": "0",
        "forType": "num",
        "forUnits": "minutes",
        "override_topic": false,
        "state_location": "payload",
        "override_payload": "msg",
        "entity_location": "data",
        "override_data": "msg",
        "x": 810,
        "y": 2700,
        "wires": [
            [
                "1ebea512a66e8501"
            ],
            []
        ]
    },
    {
        "id": "f2115ff7a460c515",
        "type": "function",
        "z": "65840aa926d9c567",
        "name": "Send Once",
        "func": "var msg1 = {payload: 0};\nvar msg2 = {payload: 'exit'};\nvar chargeW = flow.get('wattcharge');\n\nif (msg1.payload === chargeW)\n{\n    flow.set('wattcharge', msg1.payload);\n    return [null, msg2];\n}\nelse\n{\n    flow.set('wattcharge',msg1.payload);\n    return [msg1, null];\n}",
        "outputs": 2,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 990,
        "y": 2780,
        "wires": [
            [
                "5fb0e44813bbd5fb"
            ],
            []
        ]
    },
    {
        "id": "1ebea512a66e8501",
        "type": "api-render-template",
        "z": "65840aa926d9c567",
        "name": "AMPS",
        "server": "afc27684.cf6ed8",
        "version": 0,
        "template": "{{min(\nstate_attr('input_number.ev_amps','max'),\n(states('sensor.sonnenbatterie_84324_production_w') | int(0) \n- (states('sensor.house_power_consumption_less_deferrables') | int(0) \n+ states('sensor.garage_power_point_power') | int(0)\n- states('sensor.sonnenbatterie_84324_state_battery_inout') | int(0)))\n/ (state_attr('sensor.ynot_charger_power','charger_phases')|int(1)*3/2)|int(1)     \n/ max(220,state_attr('sensor.ynot_charger_power','charger_volts')|int(230))\n)|round(0)}}",
        "resultsLocation": "payload",
        "resultsLocationType": "msg",
        "templateLocation": "",
        "templateLocationType": "none",
        "x": 980,
        "y": 2700,
        "wires": [
            [
                "8ca208bf7da5f3ef",
                "2136624591dcee0a"
            ]
        ]
    },
    {
        "id": "5fb0e44813bbd5fb",
        "type": "api-call-service",
        "z": "65840aa926d9c567",
        "name": "Stop charging",
        "server": "afc27684.cf6ed8",
        "version": 5,
        "debugenabled": false,
        "domain": "switch",
        "service": "turn_off",
        "areaId": [],
        "deviceId": [],
        "entityId": [
            "switch.ynot_charger"
        ],
        "data": "",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 1180,
        "y": 2780,
        "wires": [
            [
                "a7d0fb192336aecc"
            ]
        ]
    },
    {
        "id": "8ca208bf7da5f3ef",
        "type": "function",
        "z": "65840aa926d9c567",
        "name": "Step Change",
        "func": "var msg1 = {payload: parseFloat(msg.payload)};\nvar msg2 = {payload: 'exit'};\nvar chargeW = flow.get('wattcharge') || 0;\n\nif(msg1.payload === chargeW)\n{\n    flow.set('wattcharge', msg1.payload);\n    return [null, msg2];\n}\nelse {\n    flow.set('wattcharge', msg1.payload);\n    return [msg1,null];\n}",
        "outputs": 2,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1170,
        "y": 2700,
        "wires": [
            [
                "42a1bae8c4a0c421"
            ],
            [
                "6abb8d9afa47c59f"
            ]
        ]
    },
    {
        "id": "2136624591dcee0a",
        "type": "function",
        "z": "65840aa926d9c567",
        "name": "mod",
        "func": "{\n    var timestamp = new Date().toISOString();\n    msg.payload = timestamp + \", \" + String(msg.payload) + \", \";\n\n    return msg;\n}",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1130,
        "y": 2640,
        "wires": [
            [
                "83511f61b092055f"
            ]
        ]
    },
    {
        "id": "a7d0fb192336aecc",
        "type": "api-call-service",
        "z": "65840aa926d9c567",
        "name": "update",
        "server": "afc27684.cf6ed8",
        "version": 5,
        "debugenabled": false,
        "domain": "button",
        "service": "press",
        "areaId": [],
        "deviceId": [],
        "entityId": [
            "button.ynot_force_data_update"
        ],
        "data": "",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 1370,
        "y": 2780,
        "wires": [
            []
        ]
    },
    {
        "id": "42a1bae8c4a0c421",
        "type": "smooth",
        "z": "65840aa926d9c567",
        "name": "Smooth A",
        "property": "payload",
        "action": "mean",
        "count": "5",
        "round": "0",
        "mult": "single",
        "reduce": false,
        "x": 1320,
        "y": 2700,
        "wires": [
            [
                "6abb8d9afa47c59f"
            ]
        ]
    },
    {
        "id": "6abb8d9afa47c59f",
        "type": "file",
        "z": "65840aa926d9c567",
        "name": "write log",
        "filename": "/share/followsun.csv",
        "filenameType": "str",
        "appendNewline": true,
        "createDir": true,
        "overwriteFile": "false",
        "encoding": "none",
        "x": 1440,
        "y": 2640,
        "wires": [
            []
        ]
    },
    {
        "id": "83511f61b092055f",
        "type": "file",
        "z": "65840aa926d9c567",
        "name": "write log",
        "filename": "/share/followsun.csv",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "false",
        "encoding": "none",
        "x": 1280,
        "y": 2620,
        "wires": [
            []
        ]
    },
    {
        "id": "afc27684.cf6ed8",
        "type": "server",
        "name": "Home Assistant",
        "version": 5,
        "addon": true,
        "rejectUnauthorizedCerts": true,
        "ha_boolean": "y|yes|true|on|home|open",
        "connectionDelay": true,
        "cacheJson": true,
        "heartbeat": false,
        "heartbeatInterval": 30,
        "areaSelector": "friendlyName",
        "deviceSelector": "friendlyName",
        "entitySelector": "friendlyName",
        "statusSeparator": "at: ",
        "statusYear": "hidden",
        "statusMonth": "short",
        "statusDay": "numeric",
        "statusHourCycle": "h23",
        "statusTimeFormat": "h:m",
        "enableGlobalContextStore": true
    },
    {
        "id": "6d4bf5e5550a42e6",
        "type": "ha-entity-config",
        "server": "afc27684.cf6ed8",
        "deviceConfig": "",
        "name": "follow sun",
        "version": "6",
        "entityType": "switch",
        "haConfig": [
            {
                "property": "name",
                "value": "follow sun"
            },
            {
                "property": "icon",
                "value": "mdi:sun-clock"
            },
            {
                "property": "entity_picture",
                "value": ""
            },
            {
                "property": "entity_category",
                "value": ""
            },
            {
                "property": "device_class",
                "value": ""
            }
        ],
        "resend": false,
        "debugEnabled": false
    }
]

I wrote my own automation to vary the Tesla’s charging amps based on the amount of excess PV I have.
Yes it can jump up and down if the sun ducks in and out of the clouds

1 Like

Yes this is enough for the optimization to try to use the MLForecaster.
However you need to fit a model first, otherwise the call to any optimization routine will fail.
Set an automation to fit your model once a day for example.
You can optionally tune your model in search of better forecasting results.

2 Likes

I usually let EMHASS handling the optimisation, including following the sun.

In my plan for tomorrow you can see EMHASS follows the sun until about 11am as that is optimal. After 11am the price is so low that it makes sense to import additional EV charging from the grid (as well as battery charging at the same time from super low prices).

Then during the day I run high frequency MPC (every minute) to recalculate the plan, but also determine the exact values for EV charging power. To get exactly the correct value (to the nearest W) for EV charging power at that instant you also need to supply now values for power_load_no_vars and pv_generation, which I supply as the first values in my PV and load forecast payload. EMHASS then calculates
EV load = pv_now + battery_now + grid_now - load_now

This had the effect of reducing EV load if I turn on the kettle or a cloud passes overhead.

My EV charging automation then takes the required power level and converts that to the required charging_amps which is passed to the vehicle via API REST call.

2 Likes

So you’re not using the Tesla HACS to control charging? You’ve moved to API call?

I have the same basic model. 60 second MPC call. Pass the now PV production as the first element in pv_power_forecast payload.

But I don’t pass a load forecast payload with power_load_no_vars. The system is still using the 2 day history data.

How do you create a load forecast? Are you using the machine learning forecaster?

Must have a look at that sometime. Only keep 10 days of history in the default mysql database. I wonder if it’s worth moving to mariadb.

Hi mark,

You use the tesla intergration? how did you create the calls? since they have changed the web browser to tesla one pro. I have had this question pop up from one of my installs.

I cant seem to find a solution to control the equipment?

Is it possible to implement that you can give emhass the value for the actual SOC of the battery? Then EMHASS would be able to compensate charging vs discharging power so it follows the forecast better. For example, with my installation (Huawei Luna2000), there will be lots of code and complexity to get the control right. Especially for me who is not an expert in coding.
I might be wrong but I think it will be easier then. If there isn’t anyone here who got a control working correctly for Huawei with a Luna2000 battery?

With the EMHASS MPC controller you have a soc_init value which does exactly this.
https://emhass.readthedocs.io/en/latest/intro.html#a-naive-model-predictive-controller