## 🎯 Hauptänderungen ### Version 3.4.0 - SOC-Drift & Charging Capacity - ✨ Sicherheitspuffer (20-50% konfigurierbar) für untertägige SOC-Schwankungen - ✨ Monatliche automatische Batterie-Kalibrierung - 🐛 SOC-Plausibilitäts-Check (filtert 65535% Spikes beim Modus-Wechsel) - 🐛 Zeitabhängige API-Abfrage (vor/nach 14:00 Uhr) ### Neue Features - 🔋 **Safety Buffer**: Kompensiert SOC-Drift und Eigenverbrauch - 🔋 **Auto-Calibration**: Monatlicher Vollzyklus für SOC-Genauigkeit - 🔋 **Spike Protection**: 4-fach Schutz gegen ungültige SOC-Werte - 🔋 **Smart API**: Verhindert HTTP 500 Errors bei fehlenden Tomorrow-Preisen ### Dokumentation - 📚 SOC_CALIBRATION_GUIDE.md - Umfassender Kalibrierungs-Guide - 📚 FIX_CHARGING_CAPACITY.md - Sicherheitspuffer-Dokumentation - 📚 FIX_SOC_SPIKE_PROBLEM.md - Spike-Protection-Lösung - 📚 FIX_API_TIMING.md - Zeitabhängige API-Abfrage - 📚 DIAGNOSE_LADE_PROBLEM.md - Debug-Guide ### Neue Dateien - battery_calibration_automation.yaml - 4 Automations für Kalibrierung - battery_calibration_input_helper.yaml - Input Helper Config - battery_optimizer_input_helper_safety_buffer.yaml - Puffer Config - debug_schedule.py - Umfassendes Debug-Script ### Scripts - battery_charging_optimizer.py v3.4.0 - hastrom_flex_extended.py v1.1.0 - debug_schedule.py v1.0.0 ### Fixes - 🐛 SOC springt auf 65535% beim ESS-Modus-Wechsel → Debounce + Plausibilitäts-Check - 🐛 API-HTTP-500 vor 14:00 → Zeitabhängige Abfrage - 🐛 Batterie nicht bis 100% geladen → Sicherheitspuffer - 🐛 SOC driftet ohne Vollzyklen → Automatische Kalibrierung ## 🚀 Installation 1. Input Helper erstellen (siehe battery_optimizer_input_helper_safety_buffer.yaml) 2. Automations installieren (siehe battery_calibration_automation.yaml) 3. Scripts aktualisieren (battery_charging_optimizer.py v3.4.0) 4. PyScript neu laden ## 📊 Verbesserungen - Präzisere Ladeplanung durch Sicherheitspuffer - Robustheit gegen SOC-Drift - Keine API-Fehler mehr vor 14:00 - Hardware-Stopp bei 100% wird respektiert - Bessere Batterie-Gesundheit durch regelmäßige Kalibrierung 🤖 Generated with Claude Code (claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
387 lines
11 KiB
Markdown
387 lines
11 KiB
Markdown
# PyScript Battery Optimizer - Diagnostic Report
|
|
|
|
**Date**: 2025-11-20
|
|
**Files Analyzed**:
|
|
- `/config/pyscript/battery_charging_optimizer.py` (v3.2.0)
|
|
- `/config/pyscript/hastrom_flex_extended.py` (v2.0)
|
|
|
|
## Syntax Check Results
|
|
|
|
✅ **Both files have valid Python syntax** - No compilation errors detected
|
|
|
|
## Potential Runtime Issues Found
|
|
|
|
### 1. CRITICAL: Missing Import in hastrom_flex_extended.py
|
|
|
|
**Issue**: The script uses `task.executor()` but doesn't import the PyScript-specific modules that provide this functionality.
|
|
|
|
**Location**: Line 37 in `hastrom_flex_extended.py`
|
|
```python
|
|
response = task.executor(requests.get, url)
|
|
```
|
|
|
|
**Problem**: In PyScript, `task` is a built-in PyScript object, but if the PyScript integration isn't loading properly or if there's an initialization issue, this will fail with `NameError: name 'task' is not defined`.
|
|
|
|
**Expected Error**:
|
|
```
|
|
NameError: name 'task' is not defined
|
|
```
|
|
|
|
**Solution**: This should work in PyScript environment, but verify PyScript is properly loaded.
|
|
|
|
---
|
|
|
|
### 2. Timezone Import Compatibility
|
|
|
|
**Issue**: Both files use `from zoneinfo import ZoneInfo`
|
|
|
|
**Location**:
|
|
- Line 11 in `battery_charging_optimizer.py`
|
|
- Line 4 in `hastrom_flex_extended.py`
|
|
|
|
**Problem**: `zoneinfo` is part of Python 3.9+ standard library. Home Assistant should have this, but PyScript might have restrictions.
|
|
|
|
**Expected Error** (if zoneinfo not available):
|
|
```
|
|
ModuleNotFoundError: No module named 'zoneinfo'
|
|
```
|
|
|
|
**Alternative**: Use PyScript's built-in timezone handling or `pytz` library if available.
|
|
|
|
---
|
|
|
|
### 3. State Access Pattern Issues
|
|
|
|
**Issue**: Direct state access using dot notation and dictionary methods mixed
|
|
|
|
**Locations**:
|
|
- Line 33: `state.get('input_boolean.battery_optimizer_enabled')`
|
|
- Line 35: `input_text.battery_optimizer_status = "Deaktiviert"`
|
|
- Line 66: `state.get('sensor.esssoc')`
|
|
|
|
**Problem**: PyScript has specific patterns for accessing and setting states. The mixing of:
|
|
- `state.get()` (dictionary-style)
|
|
- `input_text.battery_optimizer_status =` (attribute-style)
|
|
|
|
This should work, but if there's a timing issue or entity doesn't exist, it will fail silently or raise AttributeError.
|
|
|
|
**Expected Errors**:
|
|
```
|
|
AttributeError: 'state' object has no attribute 'input_text'
|
|
```
|
|
or
|
|
```
|
|
TypeError: 'NoneType' object is not subscriptable
|
|
```
|
|
|
|
---
|
|
|
|
### 4. Datetime Comparison with ISO Strings
|
|
|
|
**Issue**: Comparing datetime objects with ISO strings from stored schedule
|
|
|
|
**Location**: Lines 590-605 in `battery_charging_optimizer.py`
|
|
```python
|
|
for entry in schedule:
|
|
entry_dt = datetime.fromisoformat(entry['datetime'])
|
|
# ...
|
|
if entry_date == current_date and entry_hour == current_hour:
|
|
```
|
|
|
|
**Problem**: The schedule stores datetime as ISO string (line 391), then loads it back. If the stored format doesn't match exactly what `fromisoformat()` expects, this will fail.
|
|
|
|
**Expected Error**:
|
|
```
|
|
ValueError: Invalid isoformat string: '...'
|
|
```
|
|
|
|
---
|
|
|
|
### 5. Service Decorator Registration
|
|
|
|
**Issue**: Services defined with `@service` decorator
|
|
|
|
**Locations**:
|
|
- Line 22: `@service` for `calculate_charging_schedule()`
|
|
- Line 556: `@service` for `execute_charging_schedule()`
|
|
- Line 15: `@service` for `getprices_extended()`
|
|
|
|
**Problem**: If PyScript isn't fully initialized or there's a registration conflict, services won't be available.
|
|
|
|
**Expected Behavior**: Services should appear as:
|
|
- `pyscript.calculate_charging_schedule`
|
|
- `pyscript.execute_charging_schedule`
|
|
- `pyscript.getprices_extended`
|
|
|
|
**Check Command** (in HA Developer Tools → Services):
|
|
Search for services starting with `pyscript.`
|
|
|
|
---
|
|
|
|
### 6. Time Trigger Cron Syntax
|
|
|
|
**Issue**: Multiple cron triggers defined
|
|
|
|
**Locations in battery_charging_optimizer.py**:
|
|
- Line 646: `@time_trigger("cron(5 14 * * *)")` - Daily at 14:05
|
|
- Line 653: `@time_trigger("cron(5 * * * *)")` - Hourly at xx:05
|
|
- Line 659: `@time_trigger("cron(5 0 * * *)")` - Midnight at 00:05
|
|
|
|
**Locations in hastrom_flex_extended.py**:
|
|
- Line 151: `@time_trigger("cron(0 * * * *)")` - Hourly
|
|
- Line 156: `@time_trigger("cron(5 14 * * *)")` - Daily at 14:05
|
|
- Line 162: `@time_trigger("cron(5 0 * * *)")` - Midnight
|
|
|
|
**Problem**: PyScript cron syntax might differ from standard cron. Some implementations use different formats.
|
|
|
|
**Expected Error** (if syntax wrong):
|
|
```
|
|
ValueError: Invalid cron expression
|
|
```
|
|
|
|
**Verify**: Check PyScript documentation for correct cron syntax.
|
|
|
|
---
|
|
|
|
### 7. Attribute Access on State Objects
|
|
|
|
**Issue**: Accessing attributes from state objects
|
|
|
|
**Location**: Lines 114-141 in `battery_charging_optimizer.py`
|
|
```python
|
|
prices_attr_ext = state.getattr(price_entity_ext)
|
|
prices_today = prices_attr.get('prices_today', [])
|
|
```
|
|
|
|
**Problem**: `state.getattr()` might return `None` if entity doesn't exist, then `.get()` on `None` will fail.
|
|
|
|
**Expected Error**:
|
|
```
|
|
AttributeError: 'NoneType' object has no attribute 'get'
|
|
```
|
|
|
|
**Better Pattern**:
|
|
```python
|
|
prices_attr_ext = state.getattr(price_entity_ext) or {}
|
|
```
|
|
|
|
---
|
|
|
|
### 8. State.set() with Attributes
|
|
|
|
**Issue**: Setting state with complex attribute structures
|
|
|
|
**Location**: Lines 484-500 in `battery_charging_optimizer.py`
|
|
```python
|
|
state.set(
|
|
'pyscript.battery_charging_schedule',
|
|
value='active',
|
|
new_attributes={
|
|
'schedule': schedule, # This could be very large
|
|
'last_update': get_local_now().isoformat(),
|
|
...
|
|
}
|
|
)
|
|
```
|
|
|
|
**Problem**:
|
|
1. Large schedule arrays might exceed PyScript state size limits
|
|
2. ISO format string from datetime might not match expected format
|
|
3. Datetime objects in schedule must be serializable
|
|
|
|
**Expected Errors**:
|
|
```
|
|
ValueError: State attributes too large
|
|
```
|
|
or
|
|
```
|
|
TypeError: Object of type datetime is not JSON serializable
|
|
```
|
|
|
|
---
|
|
|
|
## Most Likely Issues Based on "Not Working" Symptom
|
|
|
|
### Primary Suspects:
|
|
|
|
**1. PyScript Not Loading Files**
|
|
- PyScript might not be finding the files at `/config/pyscript/`
|
|
- File permissions issue
|
|
- PyScript integration disabled or in error state
|
|
|
|
**Check**: Look in HA UI → Settings → Devices & Services → PyScript
|
|
|
|
---
|
|
|
|
**2. Entity Dependencies Missing**
|
|
- Required entities don't exist or are unavailable:
|
|
- `sensor.hastrom_flex_pro_ext` (created by hastrom script)
|
|
- `sensor.esssoc` (from OpenEMS)
|
|
- `input_boolean.battery_optimizer_enabled`
|
|
- Various input_number helpers
|
|
|
|
**Check**: Developer Tools → States, search for these entities
|
|
|
|
---
|
|
|
|
**3. Timezone Module Import Failure**
|
|
- If `zoneinfo` import fails, entire script won't load
|
|
- PyScript would show error on startup
|
|
|
|
**Check**: Home Assistant logs for `ModuleNotFoundError`
|
|
|
|
---
|
|
|
|
**4. Service Not Calling Other Service**
|
|
- Line 650: `pyscript.calculate_charging_schedule()`
|
|
- This calls the service from within PyScript
|
|
|
|
**Problem**: Service-to-service calls in PyScript require specific syntax
|
|
**Correct Syntax**: `task.unique("calc")` or use the decorated function directly
|
|
|
|
---
|
|
|
|
**5. Schedule State Not Persisting**
|
|
- State created by one script not accessible to other
|
|
- State lost on Home Assistant restart
|
|
- Wrong entity ID format
|
|
|
|
---
|
|
|
|
## Recommended Diagnostic Steps
|
|
|
|
### Step 1: Check PyScript Status
|
|
```yaml
|
|
# In Home Assistant Developer Tools → Services:
|
|
service: pyscript.reload
|
|
```
|
|
Look for errors in logs immediately after reload.
|
|
|
|
### Step 2: Verify Entity Existence
|
|
Check if these entities exist:
|
|
- `sensor.hastrom_flex_pro_ext`
|
|
- `sensor.hastrom_flex_ext`
|
|
- `pyscript.battery_charging_schedule`
|
|
- `sensor.esssoc`
|
|
- `input_boolean.battery_optimizer_enabled`
|
|
|
|
### Step 3: Manual Service Call
|
|
Try calling services manually:
|
|
```yaml
|
|
service: pyscript.getprices_extended
|
|
```
|
|
|
|
Then:
|
|
```yaml
|
|
service: pyscript.calculate_charging_schedule
|
|
```
|
|
|
|
Watch for errors in Home Assistant logs (Settings → System → Logs)
|
|
|
|
### Step 4: Check Home Assistant Logs
|
|
Look for these specific error patterns:
|
|
- `ModuleNotFoundError: No module named 'zoneinfo'`
|
|
- `NameError: name 'task' is not defined`
|
|
- `AttributeError:` (various)
|
|
- `Traceback` lines mentioning `pyscript` or your script names
|
|
|
|
### Step 5: Verify File Locations
|
|
Ensure files are at:
|
|
- `/config/pyscript/battery_charging_optimizer.py`
|
|
- `/config/pyscript/hastrom_flex_extended.py`
|
|
|
|
Not:
|
|
- `/config/pyscripts/` (note the 's')
|
|
- Any other location
|
|
|
|
---
|
|
|
|
## Quick Fix Attempts
|
|
|
|
### Fix 1: Add Error Handling to getprices_extended
|
|
In `hastrom_flex_extended.py`, line 37, add try-catch:
|
|
```python
|
|
try:
|
|
response = task.executor(requests.get, url)
|
|
data = response.json()
|
|
except Exception as e:
|
|
log.error(f"API call failed: {e}")
|
|
log.error(f"Exception type: {type(e).__name__}")
|
|
return
|
|
```
|
|
|
|
### Fix 2: Add Null Checks for State Access
|
|
In `battery_charging_optimizer.py`, line 115-125:
|
|
```python
|
|
prices_attr_ext = state.getattr(price_entity_ext) or {}
|
|
prices_attr_old = state.getattr(price_entity_old) or {}
|
|
|
|
if prices_attr_ext.get('prices_today'):
|
|
# ... use extended
|
|
```
|
|
|
|
### Fix 3: Alternative Timezone Import
|
|
At top of both files, try:
|
|
```python
|
|
try:
|
|
from zoneinfo import ZoneInfo
|
|
except ImportError:
|
|
from datetime import timezone, timedelta
|
|
# Fallback: create Europe/Berlin manually
|
|
TIMEZONE = timezone(timedelta(hours=1)) # CET
|
|
```
|
|
|
|
---
|
|
|
|
## Expected Log Entries If Working
|
|
|
|
You should see these log messages if scripts are working:
|
|
|
|
**From hastrom_flex_extended.py:**
|
|
```
|
|
Lade Preise für 20251120 und 20251121 (lokale Zeit: ...)
|
|
✓ API-Abfrage erfolgreich: 48 Datenpunkte
|
|
📊 haStrom FLEX PRO Extended - Preise aktualisiert:
|
|
├─ Heute: 24 Stunden
|
|
└─ Morgen: 24 Stunden (verfügbar: True)
|
|
```
|
|
|
|
**From battery_charging_optimizer.py:**
|
|
```
|
|
=== Batterie-Optimierung gestartet (v3.2 - FIXED Timezones) ===
|
|
Konfiguration geladen: SOC 20-100%, Max 5000W
|
|
Strompreise geladen: 48 Stunden (Tomorrow: True)
|
|
PV-Prognose: Heute X.X kWh, Morgen X.X kWh
|
|
Aktueller SOC: XX%
|
|
🎯 Benötigte Ladestunden: X (bei 5000W pro Stunde)
|
|
✓ Top X günstigste Stunden ausgewählt:
|
|
✓ Ladeplan gespeichert: XX Stunden, X Ladungen
|
|
=== Optimierung abgeschlossen ===
|
|
```
|
|
|
|
---
|
|
|
|
## Conclusion
|
|
|
|
Without access to live Home Assistant logs, the most likely issues are:
|
|
|
|
1. **zoneinfo import failure** - Python environment in PyScript might not have it
|
|
2. **Entity dependencies missing** - Required sensors/helpers don't exist
|
|
3. **PyScript not loading scripts** - File location or permission issue
|
|
4. **State access returning None** - Entities not ready when script runs
|
|
|
|
**RECOMMENDED ACTION**: Access Home Assistant logs via:
|
|
- Settings → System → Logs (Web UI)
|
|
- Or download logs via: Settings → System → Advanced → Download Logs
|
|
- Or SSH into HA and check: `/config/home-assistant.log`
|
|
|
|
Look specifically for errors containing:
|
|
- `battery_charging_optimizer`
|
|
- `hastrom_flex_extended`
|
|
- `pyscript`
|
|
- `ModuleNotFoundError`
|
|
- `NameError`
|
|
- `AttributeError`
|
|
|
|
The actual error message will pinpoint the exact issue.
|