diff --git a/apps/predbat/axle.py b/apps/predbat/axle.py index e3357d790..2d93dda03 100644 --- a/apps/predbat/axle.py +++ b/apps/predbat/axle.py @@ -29,10 +29,14 @@ class AxleAPI(ComponentBase): def initialize(self, api_key, pence_per_kwh, automatic): """Initialize the AxleAPI component""" + if not isinstance(api_key, str) or not api_key: + self.log("Error: AxleAPI: axle_api_key is missing or invalid, you must set it to a string (not a list or number). Axle Energy integration will not function correctly.") + api_key = None self.api_key = api_key self.pence_per_kwh = pence_per_kwh self.automatic = automatic self.failures_total = 0 + self.history_loaded = False self.event_history = [] # List of past events self.current_event = { # Current event "start_time": None, @@ -40,7 +44,7 @@ def initialize(self, api_key, pence_per_kwh, automatic): "import_export": None, "pence_per_kwh": None, } - self.updated_at: None # Last updated moved out to separate attribute to not pollute triggering on change of current_event + self.updated_at = None # Last updated moved out to separate attribute to not pollute triggering on change of current_event def load_event_history(self): """ @@ -185,6 +189,11 @@ async def fetch_axle_event(self): """ Fetch the latest VPP event from Axle Energy API """ + if not self.api_key: + self.log("Error: AxleAPI: Cannot fetch event - axle_api_key is not set or invalid. Please check your apps.yaml configuration.") + self.failures_total += 1 + return + self.log("AxleAPI: Fetching latest VPP event data") url = "https://api.axle.energy/vpp/home-assistant/event" diff --git a/apps/predbat/tests/test_axle.py b/apps/predbat/tests/test_axle.py index 44982d967..4ee595730 100644 --- a/apps/predbat/tests/test_axle.py +++ b/apps/predbat/tests/test_axle.py @@ -114,6 +114,7 @@ def test_axle(my_predbat=None): # Sub-test registry - each entry is (key, function, description) sub_tests = [ ("initialization", _test_axle_initialization, "Axle API initialization"), + ("list_api_key", _test_axle_list_api_key_validation, "List API key validation and error logging"), ("active_event", _test_axle_fetch_with_active_event, "Fetch with active event"), ("duplicate_event", _test_axle_duplicate_event_detection, "Duplicate event detection"), ("notify_config", _test_axle_fetch_with_notify_config, "Notification config control"), @@ -174,6 +175,7 @@ def _test_axle_initialization(my_predbat=None): assert axle.pence_per_kwh == 150, "Pence per kWh not set correctly" assert axle.failures_total == 0, "Failures should be 0 on init" assert axle.last_updated_timestamp is None, "Last updated should be None on init" + assert axle.updated_at is None, "updated_at should be None on init" assert axle.current_event["start_time"] is None, "Current event should be None on init" assert axle.event_history == [], "Event history should be empty on init" assert axle.history_loaded is False, "History should not be loaded on init" @@ -182,6 +184,26 @@ def _test_axle_initialization(my_predbat=None): return False +def _test_axle_list_api_key_validation(my_predbat=None): + """Test that a list-type API key (incorrect YAML format) is handled with clear error logging""" + print("Test: Axle API list API key validation") + + # Case 1: api_key is a non-empty list (most common misconfiguration) + axle = MockAxleAPI() + axle.initialize(api_key=["correct_key_as_list"], pence_per_kwh=100, automatic=False) + + assert axle.api_key is None, "Should failed to allow a list as an API key" + + # Case 2: api_key is an empty list + axle2 = MockAxleAPI() + axle2.initialize(api_key=[], pence_per_kwh=100, automatic=False) + + assert axle2.api_key is None, "Empty list should result in None api_key" + + print(" ✓ List API key validation works correctly") + return False + + def _test_axle_fetch_with_active_event(my_predbat=None): """Test fetching an active VPP event from API""" print("Test: Axle API fetch with active event")