Files
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

306 lines
9.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
```yaml
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`)
```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`)
```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 **Dashboard****Edit****Add Card****Manual**
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:
```yaml
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):
```yaml
# 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:
```yaml
- 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**:
```json
"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
```bash
ssh root@192.168.66.113
ha addons logs 5b918bf2_emhass | tail -30
ha addons restart 5b918bf2_emhass
```
### Verify NordPool prices are being passed
```bash
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
- [EMHASS Documentation](https://emhass.readthedocs.io/)
- [EMHASS GitHub](https://github.com/davidusb-geek/emhass)
- [Deye Inverter MQTT Integration](https://github.com/kbialek/deye-inverter-mqtt)
- [NordPool Integration](https://www.home-assistant.io/integrations/nordpool/)