## 🎯 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>
11 KiB
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
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
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:
@serviceforcalculate_charging_schedule() - Line 556:
@serviceforexecute_charging_schedule() - Line 15:
@serviceforgetprices_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_schedulepyscript.execute_charging_schedulepyscript.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
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:
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
state.set(
'pyscript.battery_charging_schedule',
value='active',
new_attributes={
'schedule': schedule, # This could be very large
'last_update': get_local_now().isoformat(),
...
}
)
Problem:
- Large schedule arrays might exceed PyScript state size limits
- ISO format string from datetime might not match expected format
- 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
zoneinfoimport 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
# 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_extsensor.hastrom_flex_extpyscript.battery_charging_schedulesensor.esssocinput_boolean.battery_optimizer_enabled
Step 3: Manual Service Call
Try calling services manually:
service: pyscript.getprices_extended
Then:
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 definedAttributeError:(various)Tracebacklines mentioningpyscriptor 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:
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:
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:
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:
- zoneinfo import failure - Python environment in PyScript might not have it
- Entity dependencies missing - Required sensors/helpers don't exist
- PyScript not loading scripts - File location or permission issue
- 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_optimizerhastrom_flex_extendedpyscriptModuleNotFoundErrorNameErrorAttributeError
The actual error message will pinpoint the exact issue.