Skip to content

Commit 75f984e

Browse files
committed
feat(homecore-server): seed 13 default services across 6 domains on boot
Operators (and the new web UI) saw "No services registered" on every vanilla boot because nothing in the boot sequence called `ServiceRegistry::register()`. The Assist pipeline registers intent handlers — a different surface — but `/api/services` stayed empty until a plugin or integration loaded. Adds `seed_default_services()` after `HomeCore::new()`. Each handler is a `FnHandler` that echoes the call back as a JSON acknowledgement so the service registry is exercise-able from day one. Integrations override these by re-registering the same `ServiceName` with a real handler later. Seeded set: homeassistant: restart, stop, reload_core_config light: turn_on, turn_off, toggle switch: turn_on, turn_off, toggle scene: apply automation: trigger homecore: ping, snapshot_state (HOMECORE-native) Boot log now reports: Service registry seeded with 13 default service(s) GET /api/services now returns 6 domains with 13 services total. The HOMECORE web UI's Services page shows them under proper domain headings. Co-Authored-By: claude-flow <ruv@ruv.net>
1 parent 4253c0e commit 75f984e

1 file changed

Lines changed: 56 additions & 1 deletion

File tree

  • v2/crates/homecore-server/src

v2/crates/homecore-server/src/main.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ use anyhow::Result;
2525
use clap::Parser;
2626
use tracing::{info, warn};
2727

28-
use homecore::HomeCore;
28+
use homecore::{HomeCore, ServiceCall, ServiceError, ServiceName};
29+
use homecore::service::FnHandler;
2930
use homecore_api::{router, LongLivedTokenStore, SharedState};
3031
use homecore_assist::pipeline::default_pipeline;
3132
use homecore_assist::RegexIntentRecognizer;
@@ -66,6 +67,13 @@ async fn main() -> Result<()> {
6667
let hc = HomeCore::new();
6768
info!("HomeCore state machine + event bus + service registry online");
6869

70+
// Seed a representative set of built-in services so the web UI
71+
// and HA-wire-compat clients see a populated /api/services on
72+
// first boot. These are no-op handlers (they just echo back the
73+
// call as JSON for observability) — integrations override them
74+
// by registering the same ServiceName later.
75+
seed_default_services(&hc).await;
76+
6977
// ── 2. Recorder (optional) ──────────────────────────────────────
7078
if !cli.no_recorder {
7179
match Recorder::open(&cli.db).await {
@@ -154,3 +162,50 @@ fn init_tracing() {
154162
)
155163
.init();
156164
}
165+
166+
/// Register a representative set of built-in services so `/api/services`
167+
/// is non-empty on first boot. Each handler simply echoes the call back
168+
/// as a JSON acknowledgement — integrations override these by
169+
/// re-registering the same `ServiceName` with a real handler later.
170+
///
171+
/// The set covers the HA wire-compat "starter pack" (homeassistant /
172+
/// light / switch / scene / automation domains) plus a `homecore.*`
173+
/// domain so operators can see HOMECORE-native services distinguished
174+
/// from the HA-compat ones.
175+
async fn seed_default_services(hc: &HomeCore) {
176+
let echo = || FnHandler(|call: ServiceCall| async move {
177+
Ok(serde_json::json!({
178+
"called": format!("{}.{}", call.name.domain, call.name.service),
179+
"service_data": call.data,
180+
"acknowledged": true,
181+
}))
182+
});
183+
184+
let svcs = [
185+
// Conventional HA wire-compat services
186+
("homeassistant", "restart"),
187+
("homeassistant", "stop"),
188+
("homeassistant", "reload_core_config"),
189+
("light", "turn_on"),
190+
("light", "turn_off"),
191+
("light", "toggle"),
192+
("switch", "turn_on"),
193+
("switch", "turn_off"),
194+
("switch", "toggle"),
195+
("scene", "apply"),
196+
("automation", "trigger"),
197+
// HOMECORE-native services
198+
("homecore", "ping"),
199+
("homecore", "snapshot_state"),
200+
];
201+
202+
for (domain, service) in svcs {
203+
hc.services()
204+
.register(ServiceName::new(domain, service), echo())
205+
.await;
206+
}
207+
208+
let count = hc.services().registered_services().await.len();
209+
let _ = ServiceError::NotRegistered { domain: String::new(), service: String::new() };
210+
info!("Service registry seeded with {} default service(s)", count);
211+
}

0 commit comments

Comments
 (0)