55
66import json
77from datetime import datetime , timedelta , timezone
8+ from itertools import chain
89from typing import Any , Literal , cast
910
1011import asyncclick as click
1112import parsedatetime # type: ignore
1213from tzlocal import get_localzone
1314
1415from frequenz .client .common .microgrid .components import ComponentCategory
16+ from frequenz .client .dispatch .types import (
17+ BatteryType ,
18+ EvChargerType ,
19+ InverterType ,
20+ TargetCategories ,
21+ TargetComponents ,
22+ TargetIds ,
23+ )
1524
1625# Disable a false positive from pylint
1726# pylint: disable=inconsistent-return-statements
@@ -140,7 +149,7 @@ class TargetComponentParamType(click.ParamType):
140149
141150 def convert (
142151 self , value : Any , param : click .Parameter | None , ctx : click .Context | None
143- ) -> list [ ComponentCategory ] | list [ int ] :
152+ ) -> TargetIds | TargetCategories :
144153 """Convert the input value into a list of ComponentCategory or IDs.
145154
146155 Args:
@@ -149,9 +158,9 @@ def convert(
149158 ctx: The Click context object.
150159
151160 Returns:
152- A list of component ids or component categories.
161+ A list of targets, either as component IDs or component categories.
153162 """
154- if isinstance (value , list ): # Already a list
163+ if isinstance (value , TargetComponents ):
155164 return value
156165
157166 values = value .split ("," )
@@ -162,20 +171,46 @@ def convert(
162171 error : Exception | None = None
163172 # Attempt to parse component ids
164173 try :
165- return [int (id ) for id in values ]
174+ return TargetIds ( * [int (id ) for id in values ])
166175 except ValueError as e :
167176 error = e
168177
178+ def enum_from_str (
179+ name : str ,
180+ ) -> InverterType | BatteryType | EvChargerType | ComponentCategory :
181+ """Convert a string to an enum member."""
182+ name = name .strip ().upper ()
183+ if name in ComponentCategory .__members__ :
184+ return ComponentCategory [name ]
185+ if name in InverterType .__members__ :
186+ return InverterType [name ]
187+ if name in BatteryType .__members__ :
188+ return BatteryType [name ]
189+ if name in EvChargerType .__members__ :
190+ return EvChargerType [name ]
191+ raise KeyError (f"Invalid target specification: { name } " )
192+
169193 # Attempt to parse as component categories, trim whitespace
170194 try :
171- return [ ComponentCategory [ cat . strip (). upper ()] for cat in values ]
195+ return TargetCategories ( * [ enum_from_str ( cat ) for cat in values ])
172196 except KeyError as e :
173197 error = e
174198
199+ types_str = ", " .join (
200+ [f"{ type .name } " for type in chain (BatteryType , InverterType , EvChargerType )]
201+ )
202+
175203 self .fail (
176204 f'Invalid component category list or ID list: "{ value } ".\n '
177205 f'Error: "{ error } "\n \n '
178- "Possible categories: BATTERY, GRID, METER, INVERTER, EV_CHARGER, CHP " ,
206+ "Valid formats:\n "
207+ "- 1,2,3 # A list of component IDs\n "
208+ "- METER,INVERTER # A list of component categories\n "
209+ "- NA_ION,SOLAR # A list of component category types (category is derived)\n "
210+ "Valid categories:\n "
211+ f"{ ', ' .join ([cat .name for cat in ComponentCategory ])} \n "
212+ "Valid types:\n "
213+ f"{ types_str } \n " ,
179214 param ,
180215 ctx ,
181216 )
0 commit comments