diff --git a/pycheckwatt/__init__.py b/pycheckwatt/__init__.py index 9c45404..77fb534 100644 --- a/pycheckwatt/__init__.py +++ b/pycheckwatt/__init__.py @@ -143,7 +143,7 @@ def _extract_content_and_logbook(self, input_string): def _extract_fcr_d_state(self): pattern = re.compile( - r"\[ FCR-D (ACTIVATED|DEACTIVATE|FAIL ACTIVATION) \] (\S+) --(\d+)-- ((\d+,\d+)/(\d+,\d+)/(\d+,\d+) %) \((\d+) kW\) (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})" # noqa: E501 + r"\[ FCR-D (ACTIVATED|DEACTIVATE|FAIL ACTIVATION) \] (?:(?:\d+x)?\s?(\S+) --(\d+)-- | (?:(?:UP|DOWN) (?:\d+,\d+) Hz ))((?:(\d+,\d+)\/(\d+,\d+)\/)?(\d+,\d+|[A-Z]+) %)\s+\((\d+,\d+\/\d+,\d+|\d+\/\d+|\d+) kW\)\s*-?\s*.*?(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})" # noqa: E501 ) for entry in self.logbook_entries: match = pattern.search(entry) diff --git a/tests/unit/test_checkwatt_manager.py b/tests/unit/test_checkwatt_manager.py index e7c8710..ed00255 100644 --- a/tests/unit/test_checkwatt_manager.py +++ b/tests/unit/test_checkwatt_manager.py @@ -216,10 +216,10 @@ async def test_fcrd_properties_after_data_load(self, authenticated_manager): # FCR-D state properties should be populated from logbook assert manager.fcrd_state == "ACTIVATED" - assert manager.fcrd_power == "7" - assert manager.fcrd_timestamp == "2024-07-07 00:08:19" - assert manager.fcrd_percentage_up == "97,7" - assert manager.fcrd_percentage_down == "99,3" + assert manager.fcrd_power == "10,0/10,0" + assert manager.fcrd_timestamp == "2025-01-01 00:04:45" + assert manager.fcrd_percentage_up == "96,5" + assert manager.fcrd_percentage_down == "106,3" def test_properties_fail_without_data(self): """Test that properties fail appropriately when data isn't loaded.""" @@ -535,3 +535,66 @@ async def test_ems_settings_property_requires_get_ems_settings(self): await manager.get_ems_settings() assert manager.ems_settings == "Currently optimized (CO)" + + +class TestFCRDStateExtraction: + """Test FCR-D state extraction from logbook entries.""" + + def setup_method(self): + """Set up test fixtures.""" + self.manager = CheckwattManager("test_user", "test_pass") + + def test_fail_activation_with_retry_count_and_complex_power(self): + """Test parsing of FAIL ACTIVATION entries with retry count and complex power format.""" + log_entry = "[ FCR-D FAIL ACTIVATION ] 54x test@example.com --12345-- 85,9/0,6/97,0 % (10,0/10,0 kW) 2025-04-24 00:02:57 API-BACKEND" + + self.manager.logbook_entries = [log_entry] + self.manager._extract_fcr_d_state() + + assert self.manager.fcrd_state == "FAIL ACTIVATION" + assert self.manager.fcrd_percentage_up == "85,9" + assert self.manager.fcrd_percentage_response == "0,6" + assert self.manager.fcrd_percentage_down == "97,0" + assert self.manager.fcrd_power == "10,0/10,0" + assert self.manager.fcrd_timestamp == "2025-04-24 00:02:57" + + def test_activated_with_complex_power_format(self): + """Test parsing of ACTIVATED entries with complex power format.""" + log_entry = "[ FCR-D ACTIVATED ] test@example.com --12345-- 96,5/4,0/106,3 % (10,0/10,0 kW) 2025-08-07 00:04:45 API-BACKEND" + + self.manager.logbook_entries = [log_entry] + self.manager._extract_fcr_d_state() + + assert self.manager.fcrd_state == "ACTIVATED" + assert self.manager.fcrd_percentage_up == "96,5" + assert self.manager.fcrd_percentage_response == "4,0" + assert self.manager.fcrd_percentage_down == "106,3" + assert self.manager.fcrd_power == "10,0/10,0" + assert self.manager.fcrd_timestamp == "2025-08-07 00:04:45" + + def test_deactivate_with_frequency_up_hz(self): + """Test parsing of DEACTIVATE entries with UP frequency.""" + log_entry = "[ FCR-D DEACTIVATE ] UP 49,83 Hz 0,0 % (10 kW) - 2025-08-06 17:58:07 API-BACKEND" + + self.manager.logbook_entries = [log_entry] + self.manager._extract_fcr_d_state() + + assert self.manager.fcrd_state == "DEACTIVATE" + # For DEACTIVATE, the percentage info goes to fcrd_info + assert self.manager.fcrd_power == "10" + assert self.manager.fcrd_timestamp == "2025-08-06 17:58:07" + + def test_multiple_entries_first_match_used(self): + """Test that only the first matching entry is processed.""" + log_entries = [ + "[ FCR-D ACTIVATED ] test@example.com --12345-- 97,7/0,5/99,3 % (7 kW) 2024-07-07 00:08:19 API-BACKEND", + "[ FCR-D FAIL ACTIVATION ] 54x test@example.com --12345-- 85,9/0,6/97,0 % (10,0/10,0 kW) 2025-04-24 00:02:57 API-BACKEND", + ] + + self.manager.logbook_entries = log_entries + self.manager._extract_fcr_d_state() + + # Should use the first entry (ACTIVATED) + assert self.manager.fcrd_state == "ACTIVATED" + assert self.manager.fcrd_power == "7" + assert self.manager.fcrd_timestamp == "2024-07-07 00:08:19"