Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG-next.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@

- `SessionResetTool` and `SessionDeleteTool` for in-agent session management (#5696).
- `SessionsCurrentTool` exposes the active session identity (#6033).
- `philips_hue` tool — local Hue Bridge v2 CLIP API client, gated by application key and `allowed_resource_types` allowlist; `verify_tls` defaults to `false` for self-signed bridge certs (#6449).

### Plugins

Expand Down
103 changes: 103 additions & 0 deletions crates/zeroclaw-config/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ pub struct Config {
#[nested]
pub jira: JiraConfig,

/// Philips Hue integration configuration (`[philips_hue]`).
#[serde(default)]
#[nested]
pub philips_hue: PhilipsHueConfig,

/// Secure inter-node transport configuration (`[node_transport]`).
#[serde(default)]
#[nested]
Expand Down Expand Up @@ -9316,6 +9321,101 @@ impl Default for JiraConfig {
}
}

/// Philips Hue integration configuration (`[philips_hue]`).
///
/// When `enabled = true`, registers the `philips_hue` tool which can list
/// and control lights, scenes, rooms, and groups on a local Philips Hue
/// Bridge via its v2 CLIP API. Requires `bridge_address` (the bridge's IP
/// or `<id>.local` hostname) and `application_key` (the bridge "username"
/// minted via push-button pairing), or the `PHILIPS_HUE_APPLICATION_KEY`
/// env var.
///
/// ## Defaults
/// - `enabled`: `false`
/// - `allowed_resource_types`: `["light", "grouped_light", "scene", "room"]` —
/// the v2 resource types the agent is permitted to mutate. Read actions
/// (`list_*`, `get_*`) ignore this allowlist.
/// - `verify_tls`: `false` — Hue bridges present a self-signed certificate
/// on the local network, so TLS verification is disabled by default.
/// Set to `true` only if you have installed the bridge's CA in the
/// system trust store.
/// - `request_timeout_secs`: `15`
///
/// ## Auth (push-button pairing)
/// First-time setup, performed once outside ZeroClaw:
///
/// 1. Discover the bridge IP via `https://discovery.meethue.com` or mDNS.
/// 2. Press the round button on top of the bridge.
/// 3. Within 30 seconds:
/// `curl -k -X POST -d '{"devicetype":"zeroclaw#host","generateclientkey":true}' \`
/// ` https://<bridge-ip>/api`
/// 4. Copy the `username` from the response into `application_key`
/// (or export `PHILIPS_HUE_APPLICATION_KEY`).
///
/// The application key is stored encrypted at rest when
/// `[secrets] encrypt = true`.
#[derive(Debug, Clone, Serialize, Deserialize, Configurable)]
#[cfg_attr(feature = "schema-export", derive(schemars::JsonSchema))]
#[prefix = "philips-hue"]
#[integration(
category = "ToolsAutomation",
display_name = "Philips Hue",
description = "Smart lighting via local Hue Bridge",
status_field = "enabled"
)]
pub struct PhilipsHueConfig {
/// Enable the `philips_hue` tool. Default: `false`.
#[serde(default)]
pub enabled: bool,
/// Hue Bridge address — IP (`192.168.1.42`) or mDNS hostname
/// (`<bridge-id>.local`).
#[serde(default)]
pub bridge_address: String,
/// Application key (bridge "username") minted via push-button pairing.
/// Encrypted at rest. Falls back to `PHILIPS_HUE_APPLICATION_KEY` env var.
#[serde(default)]
#[secret]
#[cfg_attr(feature = "schema-export", schemars(extend("x-secret" = true)))]
pub application_key: String,
/// Resource types the agent is permitted to mutate (`set_*`, `recall_*`).
/// Empty means all mutations are blocked.
#[serde(default = "default_philips_hue_allowed_resource_types")]
pub allowed_resource_types: Vec<String>,
/// Verify TLS certificate of the bridge. Default `false` because
/// bridges ship with self-signed certs on the local network.
#[serde(default)]
pub verify_tls: bool,
/// Request timeout in seconds. Default: `15`.
#[serde(default = "default_philips_hue_timeout_secs")]
pub request_timeout_secs: u64,
}

fn default_philips_hue_allowed_resource_types() -> Vec<String> {
vec![
"light".into(),
"grouped_light".into(),
"scene".into(),
"room".into(),
]
}

fn default_philips_hue_timeout_secs() -> u64 {
15
}

impl Default for PhilipsHueConfig {
fn default() -> Self {
Self {
enabled: false,
bridge_address: String::new(),
application_key: String::new(),
allowed_resource_types: default_philips_hue_allowed_resource_types(),
verify_tls: false,
request_timeout_secs: default_philips_hue_timeout_secs(),
}
}
}

///
/// Controls the read-only cloud transformation analysis tools:
/// IaC review, migration assessment, cost analysis, and architecture review.
Expand Down Expand Up @@ -9634,6 +9734,7 @@ impl Default for Config {
onboard_state: OnboardStateConfig::default(),
notion: NotionConfig::default(),
jira: JiraConfig::default(),
philips_hue: PhilipsHueConfig::default(),
node_transport: NodeTransportConfig::default(),
knowledge: KnowledgeConfig::default(),
linkedin: LinkedInConfig::default(),
Expand Down Expand Up @@ -12595,6 +12696,7 @@ auto_save = true
onboard_state: OnboardStateConfig::default(),
notion: NotionConfig::default(),
jira: JiraConfig::default(),
philips_hue: PhilipsHueConfig::default(),
node_transport: NodeTransportConfig::default(),
knowledge: KnowledgeConfig::default(),
linkedin: LinkedInConfig::default(),
Expand Down Expand Up @@ -13166,6 +13268,7 @@ default_temperature = 0.7
onboard_state: OnboardStateConfig::default(),
notion: NotionConfig::default(),
jira: JiraConfig::default(),
philips_hue: PhilipsHueConfig::default(),
node_transport: NodeTransportConfig::default(),
knowledge: KnowledgeConfig::default(),
linkedin: LinkedInConfig::default(),
Expand Down
15 changes: 15 additions & 0 deletions crates/zeroclaw-runtime/src/integrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,21 @@ pub fn show_integration_info(config: &Config, name: &str) -> Result<()> {
println!(" Supports city names, IATA airport codes, GPS coordinates,");
println!(" postal/zip codes, and Unicode location names.");
}
"Philips Hue" => {
println!(" Setup:");
println!(" 1. Discover bridge IP via https://discovery.meethue.com or mDNS.");
println!(" 2. Press the round button on top of the bridge.");
println!(" 3. Within 30 seconds, mint an application key:");
println!(
" curl -k -X POST -d '{{\"devicetype\":\"zeroclaw#host\",\"generateclientkey\":true}}' \\"
);
println!(" https://<bridge-ip>/api");
println!(" 4. Add to config:");
println!(" [philips_hue]");
println!(" enabled = true");
println!(" bridge_address = \"192.168.1.42\"");
println!(" application_key = \"...\" # or set PHILIPS_HUE_APPLICATION_KEY");
}
_ if entry.category == IntegrationCategory::Chat => {
println!(" Setup:");
println!(" Run: zeroclaw onboard --channels-only");
Expand Down
33 changes: 33 additions & 0 deletions crates/zeroclaw-runtime/src/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ pub use zeroclaw_tools::notion_tool::NotionTool;
pub use zeroclaw_tools::opencode_cli::OpenCodeCliTool;
#[cfg(feature = "rag-pdf")]
pub use zeroclaw_tools::pdf_read::PdfReadTool;
pub use zeroclaw_tools::philips_hue::PhilipsHueTool;
pub use zeroclaw_tools::pipeline::PipelineTool;
pub use zeroclaw_tools::poll::PollTool;
pub use zeroclaw_tools::project_intel::ProjectIntelTool;
Expand Down Expand Up @@ -603,6 +604,38 @@ pub fn all_tools_with_runtime(
}
}

// Philips Hue integration (config-gated)
if root_config.philips_hue.enabled {
let application_key = if root_config.philips_hue.application_key.trim().is_empty() {
std::env::var("PHILIPS_HUE_APPLICATION_KEY").unwrap_or_default()
} else {
root_config.philips_hue.application_key.trim().to_string()
};
if application_key.trim().is_empty() {
tracing::warn!(
"philips_hue: enabled but no application key found (set philips_hue.application_key or PHILIPS_HUE_APPLICATION_KEY env var) — skipping registration"
);
} else if root_config.philips_hue.bridge_address.trim().is_empty() {
tracing::warn!(
"philips_hue: enabled but philips_hue.bridge_address is empty — skipping registration"
);
} else {
match PhilipsHueTool::new(
root_config.philips_hue.bridge_address.trim().to_string(),
application_key,
root_config.philips_hue.allowed_resource_types.clone(),
root_config.philips_hue.verify_tls,
root_config.philips_hue.request_timeout_secs,
security.clone(),
) {
Ok(tool) => tool_arcs.push(Arc::new(tool)),
Err(e) => tracing::warn!(
"philips_hue: failed to construct HTTP client: {e} — skipping registration"
),
}
}
}

// Project delivery intelligence
if root_config.project_intel.enabled {
tool_arcs.push(Arc::new(ProjectIntelTool::new(
Expand Down
1 change: 1 addition & 0 deletions crates/zeroclaw-tools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub mod node_capabilities;
pub mod notion_tool;
pub mod opencode_cli;
pub mod pdf_read;
pub mod philips_hue;
pub mod pipeline;
pub mod poll;
pub mod project_intel;
Expand Down
Loading
Loading