EMHASS: An Energy Management for Home Assistant

There seems to be a gap in the start time for amber data in this graph. Simthing wrong with the time?

Your logs donā€™t show your MPC optim being called.

There should be a line:

INFO - Perform an iteration of a naive MPC controller

Iā€™m calling it from node-red. Iā€™ll go back to automations.yaml see if that works

- alias: EMHASS day-ahead optimization
  trigger:
  - minutes: /1
    platform: time_pattern
  action:
  - service: shell_command.post_mpc_optim_solcast
- alias: EMHASS publish data
  trigger:
  - minutes: /1
    platform: time_pattern
  action:
  - service: shell_command.publish_data

no change

2023-07-17 07:31:00,109 - web_server - INFO - Setting up needed data
2023-07-17 07:31:00,111 - web_server - INFO -  >> Publishing data...
2023-07-17 07:31:00,111 - web_server - INFO - Publishing data to HASS instance
2023-07-17 07:31:00,125 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 23.88
2023-07-17 07:31:00,136 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 563.62
2023-07-17 07:31:00,145 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2023-07-17 07:31:00,156 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2023-07-17 07:31:00,165 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 10.0
2023-07-17 07:31:00,174 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 539.73
2023-07-17 07:31:00,188 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -1.68
2023-07-17 07:31:00,198 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.1419
2023-07-17 07:31:00,209 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.065

I would recommend turning off your automations as they are not working correctly and just focus on getting either your day ahead optimisation functional, in the first instance and then your MPC optimisation functional.

You can call them individually from the developer tools services menu.

Confirm the results are correct in the logs and the :5000 interface before proceeding.

yep working on it. Breaking down the shell commans into its separate sections and looking at output. Trying to call from command line.

1 Like

One question if I may. For solcast do you call update_forecasts or update_actual_forecasts? THe former makes one call to solcast while the latter makes two.

THakns
Rob

I use auto polling as I have the original 50 API calls.

From the look of GitHub - oziee/ha-solcast-solar: Solcast Integration for Home Assistant

I would suggest update_forecasts would be sufficient.

1 Like

I had emhass in profit mode, but its costing me money in the morning , the ideal behaviour id like it for it to only discharge to the grid when i can generate a significant profit, right now ill be charging at 20c and discharging at 25c, but often the fit drops below the charging price as the day goes on so i end up loosing money.

Ive changed to to cost to see what happens but it wants to do some weird things, like charging my battery in the evening peak and discharging in the middle of the night.

I dont want to disable grid charging as id like my battery to top it self up on days with crap solar production like today.
Any ideas on what i can adjust to improve performance?

I think Iā€™m on the same boat

image

I donā€™t think the ā€˜costā€™ optimization is relevant in Australia. I havenā€™t been able to understand the use case, I think it is just trying to optimize the cost of grid imports, without regard to solar. Like you I seem to get funny results when I try.

https://emhass.readthedocs.io/en/latest/lpems.html#household-ems-with-lp

EMHASS itself doesnā€™t thresholds on buy/ sell values, but I generally find a healthy spread.

However if you wanted to limit battery exports to the grid above a certain price then you could achieve this in your battery automation.

Something like:

export_price < threshold

then

battery_export = p_load_forecast - p_pv_forecast

else

battery_export = p_batt_forecast

I regularly see a good margin between the highest buy cost of the day and the lowest sell price. e.g. 31c sell vs 21c buy for today

Here is a better example showing a full 24 hours.

This evening buy at 14c sell at 31c, but overnight buy at 15c and sell in the morning at 20c.

Does the second sell represent value?

I note that later in the day (12:00) the buy price drops to 8c so selling at 20c makes sense, but does it make sense to buy overnight at 15c?

My problem is the sell price rarely seems to match what the prediction says, so i end up buying at 20c with the expectation to sell at 32c but by the time the morning peak comes around the actual sell price is has fallen significantly.

I could maybe get around this by putting a scaler on the fit forecast price.

1 Like

I thinkā€¦ just like today in VICā€¦ when it comes to sell timeā€¦ the original sell prices did not hold well. its like the difference of about 5cā€¦ is it worth itā€¦ very subjective.

Its just my second month in Amberā€¦ so I donā€™t have many experience

The Amber API does have a feed_in range_min value, that comes and goes. I have done some experimentation using feed_in forecast for the next 2 hours and range_min for the longer term forecasts.

The rang_min value isnā€™t always present so it can be a challenge to calculate the EMHASS persistence.

image

and then a few minutes later I have a full set of range_min

Move the shell commands to node-red. Working find in node-red.
Thanks very much for your help.

1 Like

I suppose you can establish the POST end points in node red directly so that would give you more control than the curl shell commands.

Yes and it separates the different components of the POST. Makes it a little clearer than trying to compose one long string. I can process returned error messages as well. If not 201 send a message to my phone so I can investigate. Iā€™ve got that set up with all the commands going to the battery as well.

2 Likes

Please share your node red flow

[{"id":"7e7a97b8e68d3389","type":"function","z":"65840aa926d9c567","name":"POST return != 201","func":"var status = msg.statusCode\nif(status != 201)\n{\n    return msg\n}\nelse\nreturn","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1490,"y":460,"wires":[["0599d210da9c7483"]]},{"id":"80bd09881d89d374","type":"http request","z":"65840aa926d9c567","name":"POST MPC","method":"POST","ret":"txt","paytoqs":"ignore","url":"http://192.168.99.17:5000/action/naive-mpc-optim","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":790,"y":780,"wires":[["459be90396eb63a0","7e7a97b8e68d3389","62d9e74bace8efe8"]]},{"id":"0599d210da9c7483","type":"api-call-service","z":"65840aa926d9c567","name":"Notify Robert's iPhones","server":"afc27684.cf6ed8","version":5,"debugenabled":false,"domain":"notify","service":"mobile_app_robsiphone","areaId":[],"deviceId":[],"entityId":[],"data":"{\"title\":\"EMHASS POST to battery failed\",\"message\":\"error: '{{statusCode}}' URL: '{{responseUrl}}'\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1510,"y":520,"wires":[[]]},{"id":"035211769c9ed7a4","type":"function","z":"65840aa926d9c567","name":"POST Params","func":"var payload = msg.payload\nmsg.headers = {}\nmsg.headers[\"Content-Type\"] = \"application/json\"\nmsg.url = \"http://192.168.99.17:5000/action/naive-mpc-optim\"\nmsg.payload = payload\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":620,"y":780,"wires":[["80bd09881d89d374"]]},{"id":"459be90396eb63a0","type":"debug","z":"65840aa926d9c567","name":"debug MPC POST","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1510,"y":720,"wires":[]},{"id":"62d9e74bace8efe8","type":"change","z":"65840aa926d9c567","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"http://192.168.99.17:5000/action/publish-data","tot":"str"},{"t":"set","p":"method","pt":"msg","to":"POST","tot":"str"},{"t":"set","p":"headers","pt":"msg","to":"Content-Type: application/json","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"{}","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1000,"y":780,"wires":[["bec2a54eea11d3e8"]]},{"id":"cc56cc8594ded18c","type":"api-render-template","z":"65840aa926d9c567","name":"MPC Array","server":"afc27684.cf6ed8","version":0,"template":"{\"load_cost_forecast\":{{(\n        ([states('sensor.cecil_st_general_price')|float(0)] +\n        state_attr('sensor.cecil_st_general_forecast', 'forecasts') |map(attribute='per_kwh')|list)[:48])\n        }}, \"prod_price_forecast\":{{(\n        ([states('sensor.cecil_st_feed_in_price')|float(0)] +\n        state_attr('sensor.cecil_st_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list)[:48]) \n        }},\"pv_power_forecast\":{{([states('sensor.sonnenbatterie_84324_production_w')|int(0)] +\n        state_attr('sensor.forecast_today', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',2000)|map('int')|list +\n        state_attr('sensor.forecast_tomorrow', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',2000)|map('int')|list\n        )| tojson\n        }}, \"prediction_horizon\":{{min(48, (state_attr('sensor.cecil_st_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length)+1)\n        }},\"soc_init\":{{(states('sensor.sonnenbatterie_84324_state_charge_user')|float(0))/100\n        }},\"soc_final\":0.05,\"def_total_hours\":[2]}","resultsLocation":"payload","resultsLocationType":"msg","templateLocation":"","templateLocationType":"none","x":450,"y":780,"wires":[["035211769c9ed7a4"]]},{"id":"bec2a54eea11d3e8","type":"http request","z":"65840aa926d9c567","name":"POST Publish data","method":"use","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":1210,"y":780,"wires":[["459be90396eb63a0"]]},{"id":"be01d6d98c163e23","type":"inject","z":"65840aa926d9c567","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":310,"y":780,"wires":[["cc56cc8594ded18c"]]},{"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}]
3 Likes