@@ -65,71 +65,163 @@ async def async_unload_entry(
6565
6666def _register_services (hass : Any ) -> None :
6767 """Register Rouvy services (idempotent — safe to call multiple times)."""
68+ from dataclasses import asdict
69+
70+ from homeassistant .core import SupportsResponse
71+
6872 from .const import DOMAIN
6973
74+ def _first_client (hass : Any ) -> Any :
75+ """Return the first available RouvyAsyncApiClient, or raise."""
76+ for entry in hass .config_entries .async_entries (DOMAIN ):
77+ if hasattr (entry , "runtime_data" ) and entry .runtime_data :
78+ return entry .runtime_data
79+ msg = "No Rouvy integration configured"
80+ raise ValueError (msg )
81+
7082 async def _handle_update_weight (call : Any ) -> None :
7183 weight = call .data ["weight" ]
7284 _LOGGER .info ("Service call: update_weight to %s" , weight )
73- for entry in hass .config_entries .async_entries (DOMAIN ):
74- if hasattr (entry , "runtime_data" ) and entry .runtime_data :
75- client = entry .runtime_data .client
76- await client .async_update_user_settings ({"weight" : weight })
77- await entry .runtime_data .coordinator .async_request_refresh ()
85+ rd = _first_client (hass )
86+ await rd .client .async_update_user_settings ({"weight" : weight })
87+ await rd .coordinator .async_request_refresh ()
7888
7989 async def _handle_update_height (call : Any ) -> None :
8090 height = call .data ["height" ]
8191 _LOGGER .info ("Service call: update_height to %s" , height )
82- for entry in hass .config_entries .async_entries (DOMAIN ):
83- if hasattr (entry , "runtime_data" ) and entry .runtime_data :
84- client = entry .runtime_data .client
85- await client .async_update_user_settings ({"height" : height })
86- await entry .runtime_data .coordinator .async_request_refresh ()
92+ rd = _first_client (hass )
93+ await rd .client .async_update_user_settings ({"height" : height })
94+ await rd .coordinator .async_request_refresh ()
8795
8896 async def _handle_update_settings (call : Any ) -> None :
8997 settings = dict (call .data ["settings" ])
9098 _LOGGER .info ("Service call: update_settings %s" , settings )
91- for entry in hass .config_entries .async_entries (DOMAIN ):
92- if hasattr (entry , "runtime_data" ) and entry .runtime_data :
93- client = entry .runtime_data .client
94- await client .async_update_user_settings (settings )
95- await entry .runtime_data .coordinator .async_request_refresh ()
99+ rd = _first_client (hass )
100+ await rd .client .async_update_user_settings (settings )
101+ await rd .coordinator .async_request_refresh ()
102+
103+ async def _handle_update_profile (call : Any ) -> None :
104+ updates : dict [str , Any ] = {}
105+ for key in ("userName" , "firstName" , "team" , "accountPrivacy" ):
106+ if key in call .data :
107+ updates [key ] = call .data [key ]
108+ _LOGGER .info ("Service call: update_profile %s" , updates )
109+ rd = _first_client (hass )
110+ await rd .client .async_update_user_settings (updates )
111+ await rd .coordinator .async_request_refresh ()
112+
113+ async def _handle_update_units (call : Any ) -> None :
114+ units = call .data ["units" ]
115+ _LOGGER .info ("Service call: update_units to %s" , units )
116+ rd = _first_client (hass )
117+ await rd .client .async_update_user_settings ({"units" : units })
118+ await rd .coordinator .async_request_refresh ()
119+
120+ async def _handle_update_timezone (call : Any ) -> None :
121+ timezone = call .data ["timezone" ]
122+ _LOGGER .info ("Service call: update_timezone to %s" , timezone )
123+ rd = _first_client (hass )
124+ await rd .client .async_update_timezone (timezone )
125+ await rd .coordinator .async_request_refresh ()
126+
127+ async def _handle_update_ftp (call : Any ) -> None :
128+ ftp_source = call .data ["ftp_source" ]
129+ value = call .data .get ("value" )
130+ _LOGGER .info ("Service call: update_ftp source=%s value=%s" , ftp_source , value )
131+ rd = _first_client (hass )
132+ await rd .client .async_update_ftp (ftp_source , value )
133+ await rd .coordinator .async_request_refresh ()
134+
135+ async def _handle_update_zones (call : Any ) -> None :
136+ zone_type = call .data ["zone_type" ]
137+ zones = list (call .data ["zones" ])
138+ _LOGGER .info ("Service call: update_zones type=%s zones=%s" , zone_type , zones )
139+ rd = _first_client (hass )
140+ await rd .client .async_update_zones (zone_type , zones )
141+ await rd .coordinator .async_request_refresh ()
96142
97143 async def _handle_register_challenge (call : Any ) -> None :
98144 slug = call .data ["slug" ]
99145 _LOGGER .info ("Service call: register_challenge for %s" , slug )
100- for entry in hass .config_entries .async_entries (DOMAIN ):
101- if hasattr (entry , "runtime_data" ) and entry .runtime_data :
102- client = entry .runtime_data .client
103- await client .async_register_challenge (slug )
104- await entry .runtime_data .coordinator .async_request_refresh ()
146+ rd = _first_client (hass )
147+ await rd .client .async_register_challenge (slug )
148+ await rd .coordinator .async_request_refresh ()
105149
106150 async def _handle_register_event (call : Any ) -> None :
107151 event_id = call .data ["event_id" ]
108152 _LOGGER .info ("Service call: register_event for %s" , event_id )
109- for entry in hass .config_entries .async_entries (DOMAIN ):
110- if hasattr (entry , "runtime_data" ) and entry .runtime_data :
111- client = entry .runtime_data .client
112- await client .async_register_event (event_id )
113- await entry .runtime_data .coordinator .async_request_refresh ()
153+ rd = _first_client (hass )
154+ await rd .client .async_register_event (event_id )
155+ await rd .coordinator .async_request_refresh ()
114156
115157 async def _handle_unregister_event (call : Any ) -> None :
116158 event_id = call .data ["event_id" ]
117159 _LOGGER .info ("Service call: unregister_event for %s" , event_id )
118- for entry in hass .config_entries .async_entries (DOMAIN ):
119- if hasattr (entry , "runtime_data" ) and entry .runtime_data :
120- client = entry .runtime_data .client
121- await client .async_unregister_event (event_id )
122- await entry .runtime_data .coordinator .async_request_refresh ()
123-
124- if not hass .services .has_service (DOMAIN , "update_weight" ):
125- hass .services .async_register (DOMAIN , "update_weight" , _handle_update_weight )
126- if not hass .services .has_service (DOMAIN , "update_height" ):
127- hass .services .async_register (DOMAIN , "update_height" , _handle_update_height )
128- if not hass .services .has_service (DOMAIN , "update_settings" ):
129- hass .services .async_register (DOMAIN , "update_settings" , _handle_update_settings )
130- if not hass .services .has_service (DOMAIN , "register_challenge" ):
131- hass .services .async_register (DOMAIN , "register_challenge" , _handle_register_challenge )
132- if not hass .services .has_service (DOMAIN , "register_event" ):
133- hass .services .async_register (DOMAIN , "register_event" , _handle_register_event )
134- if not hass .services .has_service (DOMAIN , "unregister_event" ):
135- hass .services .async_register (DOMAIN , "unregister_event" , _handle_unregister_event )
160+ rd = _first_client (hass )
161+ await rd .client .async_unregister_event (event_id )
162+ await rd .coordinator .async_request_refresh ()
163+
164+ # Query services return data via SupportsResponse
165+ async def _handle_get_profile (_call : Any ) -> dict [str , Any ]:
166+ _LOGGER .info ("Service call: get_profile" )
167+ rd = _first_client (hass )
168+ profile = await rd .client .async_get_user_profile ()
169+ return {"profile" : asdict (profile )}
170+
171+ async def _handle_get_events (_call : Any ) -> dict [str , Any ]:
172+ _LOGGER .info ("Service call: get_events" )
173+ rd = _first_client (hass )
174+ events = await rd .client .async_get_events ()
175+ return {"events" : [asdict (e ) for e in events ]}
176+
177+ async def _handle_get_challenges (_call : Any ) -> dict [str , Any ]:
178+ _LOGGER .info ("Service call: get_challenges" )
179+ rd = _first_client (hass )
180+ challenges = await rd .client .async_get_challenges ()
181+ return {"challenges" : [asdict (c ) for c in challenges ]}
182+
183+ async def _handle_get_routes (_call : Any ) -> dict [str , Any ]:
184+ _LOGGER .info ("Service call: get_routes" )
185+ rd = _first_client (hass )
186+ routes = await rd .client .async_get_favorite_routes ()
187+ return {"routes" : [asdict (r ) for r in routes ]}
188+
189+ async def _handle_get_activities (_call : Any ) -> dict [str , Any ]:
190+ _LOGGER .info ("Service call: get_activities" )
191+ rd = _first_client (hass )
192+ summary = await rd .client .async_get_activity_summary ()
193+ return {"activities" : [asdict (a ) for a in summary .recent_activities ]}
194+
195+ async def _handle_get_career (_call : Any ) -> dict [str , Any ]:
196+ _LOGGER .info ("Service call: get_career" )
197+ rd = _first_client (hass )
198+ career = await rd .client .async_get_career ()
199+ return {"career" : asdict (career )}
200+
201+ # Register update services
202+ _svc = [
203+ ("update_weight" , _handle_update_weight , None ),
204+ ("update_height" , _handle_update_height , None ),
205+ ("update_settings" , _handle_update_settings , None ),
206+ ("update_profile" , _handle_update_profile , None ),
207+ ("update_units" , _handle_update_units , None ),
208+ ("update_timezone" , _handle_update_timezone , None ),
209+ ("update_ftp" , _handle_update_ftp , None ),
210+ ("update_zones" , _handle_update_zones , None ),
211+ ("register_challenge" , _handle_register_challenge , None ),
212+ ("register_event" , _handle_register_event , None ),
213+ ("unregister_event" , _handle_unregister_event , None ),
214+ ("get_profile" , _handle_get_profile , SupportsResponse .ONLY ),
215+ ("get_events" , _handle_get_events , SupportsResponse .ONLY ),
216+ ("get_challenges" , _handle_get_challenges , SupportsResponse .ONLY ),
217+ ("get_routes" , _handle_get_routes , SupportsResponse .ONLY ),
218+ ("get_activities" , _handle_get_activities , SupportsResponse .ONLY ),
219+ ("get_career" , _handle_get_career , SupportsResponse .ONLY ),
220+ ]
221+
222+ for name , handler , supports_response in _svc :
223+ if not hass .services .has_service (DOMAIN , name ):
224+ kwargs : dict [str , Any ] = {}
225+ if supports_response is not None :
226+ kwargs ["supports_response" ] = supports_response
227+ hass .services .async_register (DOMAIN , name , handler , ** kwargs )
0 commit comments