diff --git a/homeassistant/components/growatt_server/services.py b/homeassistant/components/growatt_server/services.py index bebab342a04..49728598179 100644 --- a/homeassistant/components/growatt_server/services.py +++ b/homeassistant/components/growatt_server/services.py @@ -87,22 +87,26 @@ def _get_coordinator( return coordinators[serial_number] -def _parse_time_str(time_str: str, field_name: str) -> time: +def _parse_time_str( + time_str: str, + translation_key: str, + translation_placeholders: dict[str, str] | None = None, +) -> time: """Parse a time string (HH:MM or HH:MM:SS) to a datetime.time object.""" parts = time_str.split(":") if len(parts) not in (2, 3): raise ServiceValidationError( translation_domain=DOMAIN, - translation_key="invalid_time_format", - translation_placeholders={"field_name": field_name}, + translation_key=translation_key, + translation_placeholders=translation_placeholders or {}, ) try: return datetime.strptime(f"{parts[0]}:{parts[1]}", "%H:%M").time() except (ValueError, IndexError) as err: raise ServiceValidationError( translation_domain=DOMAIN, - translation_key="invalid_time_format", - translation_placeholders={"field_name": field_name}, + translation_key=translation_key, + translation_placeholders=translation_placeholders or {}, ) from err @@ -142,8 +146,8 @@ def async_setup_services(hass: HomeAssistant) -> None: ) batt_mode: int = valid_modes[batt_mode_str] - start_time = _parse_time_str(start_time_str, "start_time") - end_time = _parse_time_str(end_time_str, "end_time") + start_time = _parse_time_str(start_time_str, "invalid_time_format_start_time") + end_time = _parse_time_str(end_time_str, "invalid_time_format_end_time") coordinator: GrowattCoordinator = _get_coordinator(hass, device_id, "min") await coordinator.update_time_segment( @@ -192,11 +196,13 @@ def async_setup_services(hass: HomeAssistant) -> None: cached = current["periods"][i - 1] start = _parse_time_str( call.data.get(f"period_{i}_start", cached["start_time"]), - f"period_{i}_start", + "invalid_time_format_period_start", + {"period": str(i)}, ) end = _parse_time_str( call.data.get(f"period_{i}_end", cached["end_time"]), - f"period_{i}_end", + "invalid_time_format_period_end", + {"period": str(i)}, ) enabled: bool = call.data.get(f"period_{i}_enabled", cached["enabled"]) periods.append({"start_time": start, "end_time": end, "enabled": enabled}) @@ -238,11 +244,13 @@ def async_setup_services(hass: HomeAssistant) -> None: cached = current["periods"][i - 1] start = _parse_time_str( call.data.get(f"period_{i}_start", cached["start_time"]), - f"period_{i}_start", + "invalid_time_format_period_start", + {"period": str(i)}, ) end = _parse_time_str( call.data.get(f"period_{i}_end", cached["end_time"]), - f"period_{i}_end", + "invalid_time_format_period_end", + {"period": str(i)}, ) enabled: bool = call.data.get(f"period_{i}_enabled", cached["enabled"]) periods.append({"start_time": start, "end_time": end, "enabled": enabled}) diff --git a/homeassistant/components/growatt_server/strings.json b/homeassistant/components/growatt_server/strings.json index 12322055da4..ee65115f493 100644 --- a/homeassistant/components/growatt_server/strings.json +++ b/homeassistant/components/growatt_server/strings.json @@ -579,7 +579,7 @@ "message": "Growatt API error: {error}" }, "device_not_configured": { - "message": "{device_type} device {serial_number} is not configured for services." + "message": "{device_type} device {serial_number} is not configured for actions." }, "device_not_found": { "message": "Device {device_id} not found in the device registry." @@ -591,22 +591,31 @@ "message": "{batt_mode} is not a valid battery mode. Allowed values: {allowed_modes}." }, "invalid_charge_power": { - "message": "charge_power must be between 0 and 100, got {value}." + "message": "'Charge power' must be between 0 and 100, got {value}." }, "invalid_charge_stop_soc": { - "message": "charge_stop_soc must be between 0 and 100, got {value}." + "message": "'Charge stop SOC' must be between 0 and 100, got {value}." }, "invalid_discharge_power": { - "message": "discharge_power must be between 0 and 100, got {value}." + "message": "'Discharge power' must be between 0 and 100, got {value}." }, "invalid_discharge_stop_soc": { - "message": "discharge_stop_soc must be between 0 and 100, got {value}." + "message": "'Discharge stop SOC' must be between 0 and 100, got {value}." }, "invalid_segment_id": { - "message": "segment_id must be between 1 and 9, got {segment_id}." + "message": "'Segment ID' must be between 1 and 9, got {segment_id}." }, - "invalid_time_format": { - "message": "{field_name} must be in HH:MM or HH:MM:SS format." + "invalid_time_format_end_time": { + "message": "'End time' must be in HH:MM or HH:MM:SS format." + }, + "invalid_time_format_period_end": { + "message": "'Period {period} end' must be in HH:MM or HH:MM:SS format." + }, + "invalid_time_format_period_start": { + "message": "'Period {period} start' must be in HH:MM or HH:MM:SS format." + }, + "invalid_time_format_start_time": { + "message": "'Start time' must be in HH:MM or HH:MM:SS format." }, "no_devices_configured": { "message": "No {device_type} devices with token authentication are configured. Actions require {device_type} devices with V1 API access." @@ -636,27 +645,27 @@ }, "services": { "read_ac_charge_times": { - "description": "Read AC charge time periods from an SPH device.", + "description": "Reads AC charge time periods from an SPH device.", "fields": { "device_id": { - "description": "The Growatt SPH device to read from.", - "name": "Device" + "description": "[%key:component::growatt_server::services::read_time_segments::fields::device_id::description%]", + "name": "[%key:component::growatt_server::services::read_time_segments::fields::device_id::name%]" } }, "name": "Read AC charge times" }, "read_ac_discharge_times": { - "description": "Read AC discharge time periods from an SPH device.", + "description": "Reads AC discharge time periods from an SPH device.", "fields": { "device_id": { - "description": "[%key:component::growatt_server::services::read_ac_charge_times::fields::device_id::description%]", - "name": "[%key:component::growatt_server::services::read_ac_charge_times::fields::device_id::name%]" + "description": "[%key:component::growatt_server::services::read_time_segments::fields::device_id::description%]", + "name": "[%key:component::growatt_server::services::read_time_segments::fields::device_id::name%]" } }, "name": "Read AC discharge times" }, "read_time_segments": { - "description": "Read all time segments from a supported inverter.", + "description": "Reads all time segments from a supported inverter.", "fields": { "device_id": { "description": "The Growatt device to perform the action on.", @@ -666,7 +675,7 @@ "name": "Read time segments" }, "update_time_segment": { - "description": "Update a time segment for supported inverters.", + "description": "Updates a time segment for supported inverters.", "fields": { "batt_mode": { "description": "Battery operation mode for this time segment.", @@ -696,7 +705,7 @@ "name": "Update time segment" }, "write_ac_charge_times": { - "description": "Write AC charge time periods to an SPH device.", + "description": "Writes AC charge time periods to an SPH device.", "fields": { "charge_power": { "description": "Charge power limit (%).", @@ -707,8 +716,8 @@ "name": "Charge stop SOC" }, "device_id": { - "description": "[%key:component::growatt_server::services::read_ac_charge_times::fields::device_id::description%]", - "name": "[%key:component::growatt_server::services::read_ac_charge_times::fields::device_id::name%]" + "description": "[%key:component::growatt_server::services::read_time_segments::fields::device_id::description%]", + "name": "[%key:component::growatt_server::services::read_time_segments::fields::device_id::name%]" }, "mains_enabled": { "description": "Enable AC (mains) charging.", @@ -754,11 +763,11 @@ "name": "Write AC charge times" }, "write_ac_discharge_times": { - "description": "Write AC discharge time periods to an SPH device.", + "description": "Writes AC discharge time periods to an SPH device.", "fields": { "device_id": { - "description": "[%key:component::growatt_server::services::read_ac_charge_times::fields::device_id::description%]", - "name": "[%key:component::growatt_server::services::read_ac_charge_times::fields::device_id::name%]" + "description": "[%key:component::growatt_server::services::read_time_segments::fields::device_id::description%]", + "name": "[%key:component::growatt_server::services::read_time_segments::fields::device_id::name%]" }, "discharge_power": { "description": "Discharge power limit (%).", diff --git a/tests/components/growatt_server/test_services.py b/tests/components/growatt_server/test_services.py index b844eaa9651..d2dd4aa68ec 100644 --- a/tests/components/growatt_server/test_services.py +++ b/tests/components/growatt_server/test_services.py @@ -376,8 +376,7 @@ async def test_update_time_segment_invalid_time_format( blocking=True, ) assert excinfo.value.translation_domain == DOMAIN - assert excinfo.value.translation_key == "invalid_time_format" - assert excinfo.value.translation_placeholders == {"field_name": "start_time"} + assert excinfo.value.translation_key == "invalid_time_format_start_time" @pytest.mark.usefixtures("mock_growatt_v1_api") @@ -653,8 +652,7 @@ async def test_update_time_segment_invalid_end_time_format( blocking=True, ) assert excinfo.value.translation_domain == DOMAIN - assert excinfo.value.translation_key == "invalid_time_format" - assert excinfo.value.translation_placeholders == {"field_name": "end_time"} + assert excinfo.value.translation_key == "invalid_time_format_end_time" async def test_service_with_unloaded_config_entry( @@ -1056,8 +1054,8 @@ async def test_write_ac_charge_times_invalid_period_time( blocking=True, ) assert excinfo.value.translation_domain == DOMAIN - assert excinfo.value.translation_key == "invalid_time_format" - assert excinfo.value.translation_placeholders == {"field_name": "period_1_start"} + assert excinfo.value.translation_key == "invalid_time_format_period_start" + assert excinfo.value.translation_placeholders == {"period": "1"} async def test_no_sph_devices_fails_gracefully(