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>
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
# Contains real HA long-lived token — use config_emhass.yaml as reference
|
||||||
|
config.json
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# Smart Home Project — HA + Domoticz Migration
|
||||||
|
|
||||||
|
## Systems
|
||||||
|
|
||||||
|
### Home Assistant (primary, growing)
|
||||||
|
- URL: http://192.168.66.113:8123
|
||||||
|
- MCP: connected via hass-mcp
|
||||||
|
- Entity naming: snake_case
|
||||||
|
- Prefer native HA constructs over Jinja2 templates
|
||||||
|
- Always confirm before deleting automations or entities
|
||||||
|
|
||||||
|
### Domoticz (legacy, stable)
|
||||||
|
- URL: http://192.168.66.157:8080
|
||||||
|
- API: no auth required (trusted IP)
|
||||||
|
- API endpoint: http://192.168.66.157:8080/json.htm
|
||||||
|
- Full access granted — changes allowed when explicitly requested
|
||||||
|
|
||||||
|
## Migration Strategy
|
||||||
|
- Pace: slow, step by step — nothing is broken, no rush
|
||||||
|
- Approach: replicate one device/automation at a time in HA
|
||||||
|
- Before migrating anything: query Domoticz API to understand current state
|
||||||
|
- After migrating: verify HA entity works before suggesting Domoticz removal
|
||||||
|
- Keep a running log in `migration_log.md` in this directory
|
||||||
|
|
||||||
|
## Workflow Rules
|
||||||
|
- Always check both systems before suggesting changes
|
||||||
|
- Prefer additive changes (add to HA) over removing from Domoticz
|
||||||
|
- When creating automations in HA, follow existing snake_case naming
|
||||||
|
- Ask before any bulk operations
|
||||||
|
- Never delete from Domoticz without explicit confirmation, even with full access
|
||||||
|
|
||||||
|
|
||||||
|
## Energy System
|
||||||
|
|
||||||
|
### Inverter
|
||||||
|
- Model: Deye SUN-12K-SG04LP3-EU
|
||||||
|
- Integration: deye-inverter-mqtt (Docker: ghcr.io/kbialek/deye-inverter-mqtt)
|
||||||
|
- Data arrives via MQTT → HA sensors
|
||||||
|
|
||||||
|
### Battery
|
||||||
|
- Capacity: 32 kWh
|
||||||
|
- Connected to Deye inverter
|
||||||
|
|
||||||
|
### EV Charger
|
||||||
|
- Brand: OpenEVSE
|
||||||
|
- Integration: OpenEVSE HA integration
|
||||||
|
|
||||||
|
### Spot Prices
|
||||||
|
- Integration: NordPool, zone: LV
|
||||||
|
- Currency: EUR/MWh
|
||||||
|
|
||||||
|
### EMHASS
|
||||||
|
- Add-on URL: http://192.168.66.113:5000
|
||||||
|
- Config file: /config/emhass/config_emhass.yaml
|
||||||
|
- Goal: minimize electricity bill via solar self-consumption,
|
||||||
|
battery charge/discharge, and EV charging schedule optimization
|
||||||
|
- Do not write config_emhass.yaml until sensor discovery is complete
|
||||||
|
and all critical entity IDs are confirmed
|
||||||
@@ -0,0 +1,306 @@
|
|||||||
|
# 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:00–05:00, 12:00–14:00)?
|
||||||
|
2. Did battery discharge during peak hours (19:00–22: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/)
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# EMHASS v0.17.1 — reference copy of config.json in YAML form
|
||||||
|
# The actual file deployed to HA is config.json (at /addon_configs/5b918bf2_emhass/config.json)
|
||||||
|
# This YAML is for human readability only.
|
||||||
|
#
|
||||||
|
# System: Deye SUN-12K-SG04LP3-EU + 32 kWh LiFePO4 battery
|
||||||
|
# Location: Latvia, NordPool LV zone
|
||||||
|
# Strategy: profit (minimize grid cost), self-consumption, no grid export
|
||||||
|
|
||||||
|
hass_url: http://192.168.66.113:8123
|
||||||
|
long_lived_token: "<HA long-lived access token>"
|
||||||
|
|
||||||
|
costfun: profit
|
||||||
|
optimization_time_step: 30 # minutes
|
||||||
|
historic_days_to_retrieve: 10
|
||||||
|
method_ts_round: nearest
|
||||||
|
|
||||||
|
# ── Sensors ──────────────────────────────────────────────────────────────────
|
||||||
|
sensor_power_photovoltaics: sensor.deye_inverter_mqtt_dc_total_power
|
||||||
|
sensor_power_load_no_var_loads: sensor.deye_inverter_mqtt_total_load_power
|
||||||
|
sensor_replace_zero:
|
||||||
|
- sensor.deye_inverter_mqtt_dc_total_power
|
||||||
|
sensor_linear_interp:
|
||||||
|
- sensor.deye_inverter_mqtt_dc_total_power
|
||||||
|
- sensor.deye_inverter_mqtt_total_load_power
|
||||||
|
|
||||||
|
# ── Grid ─────────────────────────────────────────────────────────────────────
|
||||||
|
maximum_power_from_grid: 16090 # W — contract limit
|
||||||
|
maximum_power_to_grid: 0 # W — no export (self-consumption only)
|
||||||
|
set_total_pv_sell: false
|
||||||
|
set_nodischarge_to_grid: true # battery never exports to grid
|
||||||
|
set_nocharge_from_grid: false # allow grid→battery during cheap hours
|
||||||
|
|
||||||
|
# ── Electricity pricing ───────────────────────────────────────────────────────
|
||||||
|
# Dynamic NordPool pricing via automation (14:30 daily).
|
||||||
|
# NordPool prices (passed as list) already include distribution + VAT.
|
||||||
|
load_cost_forecast_method: list
|
||||||
|
photovoltaic_production_sell_price: 0.0 # no feed-in tariff
|
||||||
|
|
||||||
|
# ── Inverter ─────────────────────────────────────────────────────────────────
|
||||||
|
inverter_is_hybrid: true
|
||||||
|
inverter_ac_output_max: 12000 # W — Deye SUN-12K
|
||||||
|
inverter_ac_input_max: 12000 # W
|
||||||
|
|
||||||
|
# ── Battery ───────────────────────────────────────────────────────────────────
|
||||||
|
set_use_battery: true
|
||||||
|
battery_nominal_energy_capacity: 32000 # Wh (32 kWh)
|
||||||
|
battery_discharge_power_max: 11000 # W
|
||||||
|
battery_charge_power_max: 11000 # W
|
||||||
|
battery_discharge_efficiency: 0.96
|
||||||
|
battery_charge_efficiency: 0.96
|
||||||
|
battery_minimum_state_of_charge: 0.1 # fraction (= 10%)
|
||||||
|
battery_maximum_state_of_charge: 1.0 # fraction (= 100%)
|
||||||
|
battery_target_state_of_charge: 0.6 # fraction — end-of-day target
|
||||||
|
|
||||||
|
# ── Deferrable loads ──────────────────────────────────────────────────────────
|
||||||
|
# Add EV here when OpenEVSE is integrated
|
||||||
|
number_of_deferrable_loads: 0
|
||||||
|
nominal_power_of_deferrable_loads: []
|
||||||
|
operating_hours_of_each_deferrable_load: []
|
||||||
|
treat_deferrable_load_as_semi_cont: []
|
||||||
|
set_deferrable_load_single_constant: []
|
||||||
|
start_timesteps_of_each_deferrable_load: []
|
||||||
|
end_timesteps_of_each_deferrable_load: []
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# EMHASS Dashboard Card
|
||||||
|
# Add this to your dashboard (Dashboard → Edit → Add Card → Manual)
|
||||||
|
|
||||||
|
type: entities
|
||||||
|
title: EMHASS Energy Status
|
||||||
|
show_header_toggle: false
|
||||||
|
entities:
|
||||||
|
# Current Status
|
||||||
|
- type: section
|
||||||
|
label: Current Status
|
||||||
|
- entity: sensor.current_hour_price
|
||||||
|
name: Current Price
|
||||||
|
icon: mdi:cash
|
||||||
|
secondary_info: "{{ state_attr('sensor.nordpool_kwh_lv_eur_3_10_021', 'low_price') }}"
|
||||||
|
- entity: sensor.battery_power_state
|
||||||
|
name: Battery State
|
||||||
|
icon: >
|
||||||
|
{% if is_state('sensor.battery_power_state', 'charging') %}mdi:battery-charging
|
||||||
|
{% elif is_state('sensor.battery_power_state', 'discharging') %}mdi:battery-minus
|
||||||
|
{% else %}mdi:battery{% endif %}
|
||||||
|
- entity: sensor.deye_inverter_mqtt_battery_soc
|
||||||
|
name: Battery SOC
|
||||||
|
icon: mdi:battery-{{ (states('sensor.deye_inverter_mqtt_battery_soc') | float(0) / 10) | round(0) | int }}0
|
||||||
|
- entity: sensor.deye_inverter_mqtt_battery_power
|
||||||
|
name: Battery Power
|
||||||
|
secondary_info: "Target: {{ states('sensor.soc_batt_forecast') }}%"
|
||||||
|
|
||||||
|
# Forecast Comparison
|
||||||
|
- type: section
|
||||||
|
label: Forecast vs Reality
|
||||||
|
- entity: sensor.battery_soc_forecast_error
|
||||||
|
name: SOC Forecast Error
|
||||||
|
icon: >
|
||||||
|
{% set err = states('sensor.battery_soc_forecast_error') | float(0) %}
|
||||||
|
{% if err | abs < 5 %}mdi:check-circle
|
||||||
|
{% elif err | abs < 10 %}mdi:alert-circle
|
||||||
|
{% else %}mdi:alert-octagon{% endif %}
|
||||||
|
- entity: sensor.soc_batt_forecast
|
||||||
|
name: Target SOC (Forecast)
|
||||||
|
icon: mdi:target
|
||||||
|
|
||||||
|
# Daily Totals
|
||||||
|
- type: section
|
||||||
|
label: Today
|
||||||
|
- entity: sensor.deye_inverter_mqtt_daily_production
|
||||||
|
name: PV Production
|
||||||
|
icon: mdi:solar-power
|
||||||
|
- entity: sensor.deye_inverter_mqtt_daily_energy_bought
|
||||||
|
name: Grid Import
|
||||||
|
icon: mdi:transmission-tower-import
|
||||||
|
- entity: sensor.deye_inverter_mqtt_daily_energy_sold
|
||||||
|
name: Grid Export
|
||||||
|
icon: mdi:transmission-tower-export
|
||||||
|
- entity: sensor.deye_inverter_mqtt_daily_battery_charge
|
||||||
|
name: Battery Charged
|
||||||
|
icon: mdi:battery-charging
|
||||||
|
- entity: sensor.deye_inverter_mqtt_daily_battery_discharge
|
||||||
|
name: Battery Discharged
|
||||||
|
icon: mdi:battery-minus
|
||||||
|
- entity: sensor.deye_inverter_mqtt_daily_load_consumption
|
||||||
|
name: Load Consumption
|
||||||
|
icon: mdi:home-lightning-bolt
|
||||||
|
|
||||||
|
---
|
||||||
|
# Alternative: Compact History Graph
|
||||||
|
type: history-graph
|
||||||
|
title: Battery SOC: Actual vs Forecast
|
||||||
|
entities:
|
||||||
|
- entity: sensor.deye_inverter_mqtt_battery_soc
|
||||||
|
name: Actual
|
||||||
|
color: "#4CAF50"
|
||||||
|
- entity: sensor.soc_batt_forecast
|
||||||
|
name: Forecast
|
||||||
|
color: "#FF9800"
|
||||||
|
hours_to_show: 48
|
||||||
|
refresh_interval: 300
|
||||||
|
|
||||||
|
---
|
||||||
|
# Price Timeline Card
|
||||||
|
type: entities
|
||||||
|
title: Price Timeline
|
||||||
|
entities:
|
||||||
|
- type: custom:timeline-card
|
||||||
|
entities:
|
||||||
|
- entity: sensor.nordpool_kwh_lv_eur_3_10_021
|
||||||
|
name: NordPool Price
|
||||||
|
title: Spot Price Timeline
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
# Migration Log — HA + Domoticz
|
||||||
|
|
||||||
|
## 2026-04-06 — EMHASS Initial Configuration
|
||||||
|
|
||||||
|
### Discovery completed
|
||||||
|
- All critical Deye inverter sensors confirmed working via MQTT
|
||||||
|
- Sign conventions verified:
|
||||||
|
- `battery_power`: positive = discharging, negative = charging
|
||||||
|
- `total_grid_power`: positive = import, negative = export
|
||||||
|
- Formula: `grid + pv = load + (-battery)` ✓
|
||||||
|
|
||||||
|
### Sensor decisions
|
||||||
|
| Role | Sensor chosen | Notes |
|
||||||
|
|------|--------------|-------|
|
||||||
|
| PV power | `sensor.deye_inverter_mqtt_dc_total_power` | DC total (PV1+PV2) |
|
||||||
|
| House load | `sensor.load_power_no_var_loads` | Template sensor, ready for EV subtraction later |
|
||||||
|
| Grid power | `sensor.deye_inverter_mqtt_total_grid_power` | Signed, +import/-export |
|
||||||
|
| Battery SOC | `sensor.deye_inverter_mqtt_battery_soc` | Direct from inverter |
|
||||||
|
| Battery power | `sensor.deye_inverter_mqtt_battery_power` | Signed, matches EMHASS convention |
|
||||||
|
| Spot price | `sensor.nordpool_kwh_lv_eur_3_10_021` | LV zone, 15-min resolution, has today/tomorrow arrays |
|
||||||
|
|
||||||
|
### Legacy sensors to clean up (not used in EMHASS)
|
||||||
|
- `sensor.deye_pv1_power`, `sensor.deye_pv1_voltage`, `sensor.deye_pv1_current`
|
||||||
|
- `sensor.deye_pv2_power`, `sensor.deye_pv2_voltage`, `sensor.deye_pv2_current`
|
||||||
|
- `sensor.deye_total_pv_power`, `sensor.deye_pv_day_energy`, `sensor.deye_total_pv_energy`
|
||||||
|
- `sensor.total_ev_power`, `sensor.total_ev_energy` (CT clamp readings, not OpenEVSE integration)
|
||||||
|
- `sensor.deye` (utility meter, check if still needed)
|
||||||
|
|
||||||
|
### EMHASS config written
|
||||||
|
- File: `config_emhass.yaml` in this repo
|
||||||
|
- Deploy to HA at: `/config/emhass/config_emhass.yaml`
|
||||||
|
- Version targeted: v0.17.1
|
||||||
|
- Mode: self-consumption, no grid export, no EV (to be added later)
|
||||||
|
- Key parameters: 32 kWh battery, 11 kW charge/discharge, 16090 W grid limit, 10% min SOC
|
||||||
|
|
||||||
|
### MCP setup
|
||||||
|
- Fixed hass-mcp env var (was `HATOKEN`, needed `HA_TOKEN`)
|
||||||
|
- Installed `uv`/`uvx` to `~/.local/bin` (required by hass-mcp)
|
||||||
|
- Config stored in `~/.claude.json` (local scope, this project)
|
||||||
|
|
||||||
|
### Completed — 2026-04-06
|
||||||
|
|
||||||
|
#### Config deployment
|
||||||
|
- Deployed `config.json` to `/addon_configs/5b918bf2_emhass/config.json`
|
||||||
|
- Had to find correct path (newer HA OS uses `/addon_configs/{slug}/` not `/homeassistant/`)
|
||||||
|
- Fixed sensor: switched to `sensor.deye_inverter_mqtt_total_load_power` (has history, unlike `load_power_no_var_loads`)
|
||||||
|
|
||||||
|
#### NordPool integration
|
||||||
|
- EMHASS v0.17 has no native NordPool sensor support
|
||||||
|
- Solution: `load_cost_forecast_method: "list"` + pass price array at runtime
|
||||||
|
- Automation builds 48-value list from NordPool `tomorrow` attribute (resampled from 15-min to 30-min)
|
||||||
|
- Fixed cost added: 0.1437 €/kWh (distribution + VAT)
|
||||||
|
|
||||||
|
#### Files updated on HA
|
||||||
|
- `/addon_configs/5b918bf2_emhass/config.json` — EMHASS config
|
||||||
|
- `/homeassistant/configuration.yaml` — added `rest_command` for EMHASS API calls
|
||||||
|
- `/homeassistant/automations.yaml` — added `emhass_dayahead_optimization` automation
|
||||||
|
|
||||||
|
#### Daily automation
|
||||||
|
- Triggers at 14:30 EET/EEST
|
||||||
|
- Waits up to 60min for `tomorrow_valid == true`
|
||||||
|
- Resamples NordPool prices, adds fixed cost, POSTs to EMHASS
|
||||||
|
- Runs `dayahead-optim` → `publish-data`
|
||||||
|
|
||||||
|
#### Verified working
|
||||||
|
- `sensor.p_pv_forecast` — PV forecast (W)
|
||||||
|
- `sensor.p_load_forecast` — Load forecast (W)
|
||||||
|
- `sensor.p_grid_forecast` — Grid import forecast (W)
|
||||||
|
- `sensor.soc_batt_forecast` — Target end-of-day SOC (%)
|
||||||
|
- `sensor.unit_load_cost` — First-hour price from NordPool
|
||||||
|
|
||||||
|
### Remaining / Future
|
||||||
|
|
||||||
|
1. **Switch load sensor** — after `sensor.load_power_no_var_loads` accumulates 24h+ history, switch back for more accurate EV separation
|
||||||
|
2. **OpenEVSE integration** — when charger is connected, add `number_of_deferrable_loads: 1` for smart EV charging
|
||||||
|
3. **Legacy sensor cleanup** — remove unused `sensor.deye_*` duplicates from old configuration
|
||||||
Reference in New Issue
Block a user