Files
ha-claude/README.md
T
Gints KiršteinsandClaude Sonnet 4.6 87f078ba72 Initial commit — EMHASS + Deye + NordPool setup
- EMHASS config for Deye SUN-12K + 32 kWh battery, NordPool LV
- Day-ahead optimization automation (14:30 daily) with real battery SOC init
- Forecast vs reality template sensors and dashboard card
- Migration log from Domoticz

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:09:45 +03:00

9.9 KiB
Raw Blame History

EMHASS Energy Management — Deye + NordPool Setup

Energy Management for Home Assistant (EMHASS) configured for:

  • Deye SUN-12K-SG04LP3-EU hybrid inverter
  • 32 kWh LiFePO4 battery
  • NordPool LV spot prices
  • Self-consumption optimization with price arbitrage

System Overview

┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│   Deye Inverter │      │  Home Assistant │      │    NordPool     │
│   (MQTT → HA)   │─────▶│    Sensors      │◀─────│   Spot Prices   │
│                 │      │                 │      │   (LV zone)     │
└─────────────────┘      └────────┬────────┘      └─────────────────┘
                                  │
                                  ▼
                         ┌─────────────────┐
                         │     EMHASS      │
                         │   (add-on)      │
                         │                 │
                         │ • Day-ahead     │
                         │   optimization  │
                         │ • Battery       │
                         │   scheduling    │
                         │ • Price         │
                         │   arbitrage     │
                         └────────┬────────┘
                                  │
                                  ▼
                         ┌─────────────────┐
                         │ Forecast Sensors │
                         │ • p_pv_forecast  │
                         │ • p_load_forecast │
                         │ • p_grid_forecast│
                         │ • soc_batt_forecast│
                         └─────────────────┘

Daily Workflow

1. NordPool Price Publication (~14:30 EET/EEST)

NordPool publishes next-day spot prices for the LV zone. The sensor.nordpool_kwh_lv_eur_3_10_021 sensor receives:

  • today — 96 values (15-min resolution) for current day
  • tomorrow — 96 values for next day (once published, typically by 14:30)
  • tomorrow_valid — becomes true when prices are available

2. EMHASS Automation (14:30 daily)

trigger: 14:30
  
wait: tomorrow_valid == true (timeout 60min)
  
build: 48-value price list (30-min resolution)
       = NordPool 15-min prices resampled to 30-min steps
       (prices already include distribution + VAT — no offset added)
read: battery_soc_init = sensor.deye_inverter_mqtt_battery_soc / 100
  
POST: /action/dayahead-optim with price list + battery_soc_init
  
wait: 15 seconds
  
POST: /action/publish-data
  
result: Forecast sensors updated with tomorrow's plan

3. What EMHASS Optimizes

With costfun: profit and set_nodischarge_to_grid: true:

  • Discharge battery to cover load during expensive hours (sell to yourself)
  • Charge battery from grid during cheap hours (price arbitrage)
  • Never export to grid (maximum_power_to_grid: 0)
  • Maintain SOC between 10%100%, target 60% end-of-day

Configuration Files

EMHASS Config (/addon_configs/5b918bf2_emhass/config.json)

{
  "hass_url": "http://192.168.66.113:8123",
  "long_lived_token": "<HA long-lived access token>",
  
  "costfun": "profit",
  "optimization_time_step": 30,
  "historic_days_to_retrieve": 10,
  
  "sensor_power_photovoltaics": "sensor.deye_inverter_mqtt_dc_total_power",
  "sensor_power_load_no_var_loads": "sensor.deye_inverter_mqtt_total_load_power",
  
  "maximum_power_from_grid": 16090,
  "maximum_power_to_grid": 0,
  
  "load_cost_forecast_method": "list",
  
  "set_use_battery": true,
  "battery_nominal_energy_capacity": 32000,
  "battery_charge_power_max": 11000,
  "battery_discharge_power_max": 11000,
  "battery_charge_efficiency": 0.96,
  "battery_discharge_efficiency": 0.96,
  "battery_minimum_state_of_charge": 0.1,
  "battery_maximum_state_of_charge": 1.0,
  "battery_target_state_of_charge": 0.6,
  
  "number_of_deferrable_loads": 0
}

HA Configuration (/config/configuration.yaml)

rest_command:
  emhass_dayahead_optim:
    url: http://192.168.66.113:5000/action/dayahead-optim
    method: POST
    content_type: application/json
    body: "{{ body }}"
  emhass_publish_data:
    url: http://192.168.66.113:5000/action/publish-data
    method: POST
    content_type: application/json

Automation (/config/automations.yaml)

Located at the end of automations.yaml — see the file for the full Jinja2 template that:

  1. Reads sensor.nordpool_kwh_lv_eur_3_10_021 tomorrow attribute
  2. Resamples from 96 values (15-min) to 48 values (30-min)
  3. Reads real battery SOC and converts to fraction (battery_soc_init)
  4. Passes both to EMHASS via load_cost_forecast + battery_soc_init parameters

Note: NordPool prices already include distribution + VAT — no fixed offset is added.


Key Sensors

Role Entity ID Notes
PV Power sensor.deye_inverter_mqtt_dc_total_power DC total from strings
Load Power sensor.deye_inverter_mqtt_total_load_power House consumption
Grid Power sensor.deye_inverter_mqtt_total_grid_power +import / -export
Battery SOC sensor.deye_inverter_mqtt_battery_soc %
Battery Power sensor.deye_inverter_mqtt_battery_power +discharge / -charge
NordPool sensor.nordpool_kwh_lv_eur_3_10_021 Spot price EUR/kWh
PV Forecast sensor.p_pv_forecast EMHASS output
Load Forecast sensor.p_load_forecast EMHASS output
Grid Forecast sensor.p_grid_forecast EMHASS output
SOC Forecast sensor.soc_batt_forecast EMHASS output — planned end-of-day SOC (always = target 60%)

Sign Conventions

Sensor Positive Negative
battery_power Discharging to load Charging from PV/grid
total_grid_power Importing from grid Exporting to grid
inverter_l*_power Export to grid Import from grid

Comparison: Forecast vs Reality

Template Sensors Created

Sensor Description
sensor.battery_soc_forecast_error Actual SOC - Forecast SOC (%)
sensor.current_hour_price Current hour's electricity price (€/kWh)

Monitoring Dashboard

Add the dashboard card from dashboard_card.yaml:

  1. Go to DashboardEditAdd CardManual
  2. Paste the YAML content

Checking Performance

Daily comparison questions:

  1. Did battery charge during cheap hours (00:0005:00, 12:0014:00)?
  2. Did battery discharge during peak hours (19:0022:00)?
  3. Is sensor.battery_soc_forecast_error within ±5%?

If error > 10%:

  • Check if Deye inverter is overriding EMHASS decisions
  • Consider adding enforcement automation (see below)

History Graph

Compare actual vs forecast over time:

type: history-graph
entities:
  - entity: sensor.deye_inverter_mqtt_battery_soc
    name: Actual SOC
  - entity: sensor.soc_batt_forecast
    name: Forecast SOC
hours_to_show: 48

Adding EV Charging (OpenEVSE)

When the EV charger is integrated:

  1. Create a sensor for EV power (or use OpenEVSE integration):

    # In configuration.yaml
    sensor:
      - platform: template
        sensors:
          ev_charger_power:
            friendly_name: "EV Charger Power"
            value_template: "{{ states('sensor.openevse_current_power') | float(0) * 230 }}"
            unit_of_measurement: "W"
    
  2. Create a template sensor that subtracts EV from total load:

      - platform: template
        sensors:
          load_power_no_var_loads:
            friendly_name: "Load Power (no EV)"
            value_template: "{{ states('sensor.deye_inverter_mqtt_total_load_power') | float - states('sensor.ev_charger_power') | float(0) }}"
            unit_of_measurement: "W"
    
  3. Update EMHASS config:

    "sensor_power_load_no_var_loads": "sensor.load_power_no_var_loads",
    "number_of_deferrable_loads": 1,
    "nominal_power_of_deferrable_loads": [7400],
    "operating_hours_of_each_deferrable_load": [6]
    
  4. Restart EMHASS


Troubleshooting

EMHASS logs show "config.json does not exist"

The config file must be at:

/addon_configs/5b918bf2_emhass/config.json

Not at /homeassistant/config.json or /config/config.json.

"Shape of passed values is (X, 1), indices imply (48, 1)"

Load sensor has insufficient history. EMHASS needs ≥48 data points (24h at 30-min resolution). Either:

  • Wait for more history to accumulate
  • Switch to sensor.deye_inverter_mqtt_total_load_power (has months of history)

Check EMHASS status via SSH

ssh root@192.168.66.113
ha addons logs 5b918bf2_emhass | tail -30
ha addons restart 5b918bf2_emhass

Verify NordPool prices are being passed

curl -s -X POST http://192.168.66.113:5000/action/dayahead-optim \
  -H "Content-Type: application/json" \
  -d '{"load_cost_forecast": [0.20, 0.19, ...]}' 

Check logs for: Passed runtime parameters: {'load_cost_forecast': [...]}


Files in This Repository

File Purpose
config.json EMHASS configuration (deploy to HA)
config_emhass.yaml Human-readable reference (same config)
migration_log.md Migration notes from Domoticz
README.md This file

References