1111
1212from custom_components .pyscript .stubs .pyscript_builtins import StateVal
1313from homeassistant .core import HomeAssistant , split_entity_id
14- from homeassistant .helpers import entity_registry as er
1514from homeassistant .helpers .service import async_get_all_descriptions
1615
1716_LOGGER = logging .getLogger (__name__ )
@@ -70,10 +69,11 @@ async def build(self) -> str:
7069 }
7170
7271 for module , imports in base_imports .items ():
72+ level = 1 if module == "pyscript_builtins" else 0
7373 module_body .append (
7474 ast .ImportFrom (
7575 module = module ,
76- level = 0 ,
76+ level = level ,
7777 names = [ast .alias (name = imp , asname = None ) for imp in imports ],
7878 )
7979 )
@@ -163,13 +163,11 @@ def _get_entity_class_name(self, domain_id: str) -> str:
163163 return f"_{ domain_id } { _STATE_CLASS_SUFFIX } "
164164
165165 async def _build_entity_classes (self ):
166- for entity in er .async_get (self ._hass ).entities .values ():
167- if entity .disabled :
168- continue
169-
170- domain_id , entity_id = split_entity_id (entity .entity_id )
166+ for state_obj in sorted (self ._hass .states .async_all (), key = lambda s : s .entity_id ):
167+ full_entity_id = state_obj .entity_id
168+ domain_id , entity_id = split_entity_id (full_entity_id )
171169
172- if not self ._is_identifier (entity_id , entity . entity_id ):
170+ if not self ._is_identifier (entity_id , full_entity_id ):
173171 continue
174172
175173 self ._collect_entity_atts (domain_id , entity_id )
@@ -235,6 +233,7 @@ async def _create_service_function(
235233 kwonlyargs : list [ast .arg ] = []
236234 kw_defaults : list [ast .expr ] = []
237235 decorator_list : list [ast .expr ] = []
236+ defaults : list [ast .expr ] = []
238237
239238 has_target = "target" in payload
240239
@@ -258,6 +257,9 @@ async def _create_service_function(
258257
259258 if def_type == "entity" and len (field_nodes ) == 1 : # simple calling with 1 arg service
260259 args .append (ast .arg (arg = field_nodes [0 ].name , annotation = field_nodes [0 ].annotation ))
260+ # Preserve the default for the single positional argument.
261+ if field_nodes [0 ].default is not None :
262+ defaults .append (field_nodes [0 ].default )
261263 else :
262264 for field in field_nodes :
263265 kwonlyargs .append (ast .arg (arg = field .name , annotation = field .annotation ))
@@ -287,7 +289,7 @@ async def _create_service_function(
287289 kwonlyargs = kwonlyargs ,
288290 kw_defaults = kw_defaults ,
289291 kwarg = None ,
290- defaults = [] ,
292+ defaults = defaults ,
291293 ),
292294 body = body ,
293295 decorator_list = decorator_list ,
@@ -330,6 +332,13 @@ def _describe_service_field(
330332 if default_value is not None and isinstance (default_value , (int , float , str , bool )):
331333 default_expr = ast .Constant (value = default_value )
332334
335+ # Widen annotation when the default's type conflicts with the selector type.
336+ if default_expr is not None and annotation is not None :
337+ ann_str = ast .unparse (annotation )
338+ default_type = type (default_value ).__name__
339+ if default_type not in ann_str and default_type in ("int" , "float" , "str" , "bool" ):
340+ annotation = ast .BinOp (left = annotation , op = ast .BitOr (), right = self ._name (default_type ))
341+
333342 if not is_required :
334343 if default_expr is None :
335344 if annotation is not None :
@@ -361,8 +370,14 @@ def _selector_annotation(self, selector: dict[str, Any] | None) -> ast.expr | No
361370 if selector_id == "number" :
362371 if selector_value == "any" :
363372 return self ._name ("float" )
364- if isinstance (selector_value , dict ) and selector_value .get ("mode" ) == "box" :
365- return self ._name ("float" )
373+ if isinstance (selector_value , dict ):
374+ if selector_value .get ("mode" ) == "box" :
375+ return self ._name ("float" )
376+ # Use float when step or min/max are fractional.
377+ for key in ("step" , "min" , "max" ):
378+ val = selector_value .get (key )
379+ if isinstance (val , float ) and val != int (val ):
380+ return self ._name ("float" )
366381 return self ._name ("int" )
367382 if selector_id == "select" :
368383 options = []
0 commit comments