# 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.