Skip to content
Draft
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
85 changes: 72 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ clap = { version = "4.5.29", features = ["std", "color", "derive", "help", "usag
config = { version = "0.15.8", default-features = false, features = ["yaml"] }
futures = "0.3.31"
hyper = "1.6.0"
iana-time-zone = "0.1.61"
log = "0.4.25"
mac_address = { version = "1.1.8", features = ["serde"] }
mdns-sd = "0.13.2"
Expand Down Expand Up @@ -134,9 +133,9 @@ tokio-ssdp = { git = "https://github.com/chrivers/tokio-ssdp.git", rev = "00fc29
udp-stream = { git = "https://github.com/chrivers/udp-stream.git", rev = "da6c76bb" }
native-tls = "0.2.13"
tokio-native-tls = "0.3.1"
tzfile = "0.1.3"
bifrost-api = { version = "0.1.0", path = "crates/bifrost-api", features = ["mac"] }
nix = { version = "0.30.0", default-features = false, features = ["socket"] }
chrono-tz = "0.10.3"

[dev-dependencies]
clap-stdin = "0.6.0"
Expand Down
1 change: 1 addition & 0 deletions crates/bifrost-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ hue = { version = "0.1.0", path = "../hue", default-features = false, features =
svc = { version = "0.1.0", path = "../svc", default-features = false }

mac_address = { version = "1.1.8", optional = true }
chrono-tz = { version = "0.10.3", features = ["serde"] }

[features]
default = []
Expand Down
3 changes: 2 additions & 1 deletion crates/bifrost-api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::net::Ipv4Addr;
use std::{collections::BTreeMap, num::NonZeroU32};

use camino::Utf8PathBuf;
use chrono_tz::Tz;
use hue::api::RoomArchetype;
use serde::{Deserialize, Serialize};
use url::Url;
Expand All @@ -23,7 +24,7 @@ pub struct BridgeConfig {
pub entm_port: u16,
pub netmask: Ipv4Addr,
pub gateway: Ipv4Addr,
pub timezone: String,
pub timezone: Tz,
}

#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
Expand Down
2 changes: 1 addition & 1 deletion crates/hue/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ bitflags = "2.8.0"
byteorder = "1.5.0"
chrono = { version = "0.4.39", default-features = false, features = ["clock", "std"] }
hex = "0.4.3"
iana-time-zone = "0.1.61"
packed_struct = "0.10.1"
serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.140"
Expand All @@ -30,6 +29,7 @@ uuid = { version = "1.13.1", features = ["serde", "v5"] }

mac_address = { version = "1.1.8", features = ["serde"], optional = true }
maplit = "1.0.2"
chrono-tz = { version = "0.10.3", features = ["serde"] }

[features]
default = ["event", "mac", "rng"]
Expand Down
14 changes: 6 additions & 8 deletions crates/hue/src/api/stubs.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::collections::BTreeSet;

use chrono::{DateTime, Utc};
use chrono_tz::Tz;
use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::api::{DeviceArchetype, LightFunction, ResourceLink, SceneMetadata};
use crate::{best_guess_timezone, date_format};
use crate::date_format;

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Bridge {
Expand Down Expand Up @@ -210,15 +211,12 @@ pub struct Temperature {

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TimeZone {
pub time_zone: String,
pub time_zone: Tz,
}

impl TimeZone {
#[must_use]
pub fn best_guess() -> Self {
Self {
time_zone: best_guess_timezone(),
}
impl From<Tz> for TimeZone {
fn from(tz: Tz) -> Self {
Self { time_zone: tz }
}
}

Expand Down
21 changes: 12 additions & 9 deletions crates/hue/src/legacy_api.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use std::{collections::HashMap, net::Ipv4Addr};

use chrono::{DateTime, Local, NaiveDateTime, Utc};
use chrono_tz::Tz;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use uuid::Uuid;

use crate::api;
use crate::api::{ColorGamut, DeviceProductData};
use crate::date_format;
use crate::hs::RawHS;
use crate::{api, best_guess_timezone};

#[cfg(feature = "mac")]
use crate::version::SwVersion;
Expand Down Expand Up @@ -253,14 +254,20 @@ pub struct ApiConfig {
pub ipaddress: Ipv4Addr,
pub netmask: Ipv4Addr,
pub gateway: Ipv4Addr,
pub timezone: String,
pub timezone: Tz,
#[serde(with = "date_format::legacy_utc", rename = "UTC")]
pub utc: DateTime<Utc>,
#[serde(with = "date_format::legacy_naive")]
pub localtime: NaiveDateTime,
pub whitelist: HashMap<String, Whitelist>,
}

#[derive(Debug, Serialize, Deserialize, Default)]
pub struct ApiConfigUpdate {
#[serde(skip_serializing_if = "Option::is_none")]
pub timezone: Option<Tz>,
}

#[derive(Debug, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ApiEffect {
Expand Down Expand Up @@ -796,7 +803,7 @@ impl Default for ApiConfig {
ipaddress: Ipv4Addr::UNSPECIFIED,
netmask: Ipv4Addr::UNSPECIFIED,
gateway: Ipv4Addr::UNSPECIFIED,
timezone: best_guess_timezone(),
timezone: Tz::UTC,
utc: Utc::now(),
localtime: Local::now().naive_local(),
whitelist: HashMap::new(),
Expand Down Expand Up @@ -899,12 +906,8 @@ impl Capabilities {
channels: 20,
},
timezones: json!({
"values": [
"CET",
"UTC",
"GMT",
"Europe/Copenhagen",
],
"values":
chrono_tz::TZ_VARIANTS.iter().collect::<Vec<_>>(),
}),
}
}
Expand Down
12 changes: 0 additions & 12 deletions crates/hue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ pub const HUE_BRIDGE_V2_MODEL_ID: &str = "BSB002";
pub const HUE_BRIDGE_V2_DEFAULT_SWVERSION: u64 = 1_970_084_010;
pub const HUE_BRIDGE_V2_DEFAULT_APIVERSION: &str = "1.70.0";

#[must_use]
pub fn best_guess_timezone() -> String {
iana_time_zone::get_timezone().unwrap_or_else(|_| "none".to_string())
}

#[cfg(feature = "mac")]
#[must_use]
pub fn bridge_id_raw(mac: MacAddress) -> [u8; 8] {
Expand Down Expand Up @@ -144,13 +139,6 @@ mod tests {
);
}

#[test]
fn best_guess_timezone() {
let res = crate::best_guess_timezone();
assert!(!res.is_empty());
assert_ne!(res, "none");
}

#[test]
fn bridge_id() {
let mac = MacAddress::new([0x11, 0x22, 0x33, 0x44, 0x55, 0x66]);
Expand Down
11 changes: 6 additions & 5 deletions src/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::HashSet;
use std::io::{Read, Write};
use std::sync::Arc;

use chrono_tz::Tz;
use itertools::Itertools;
use maplit::btreeset;
use serde::Serialize;
Expand All @@ -14,7 +15,7 @@ use bifrost_api::backend::BackendRequest;
use hue::api::{
Bridge, BridgeHome, Device, DeviceArchetype, DeviceProductData, DimmingUpdate, Entertainment,
EntertainmentConfiguration, GroupedLight, Light, Metadata, On, RType, Resource, ResourceLink,
ResourceRecord, Room, Stub, TimeZone, ZigbeeConnectivity, ZigbeeConnectivityStatus,
ResourceRecord, Room, Stub, ZigbeeConnectivity, ZigbeeConnectivityStatus,
ZigbeeDeviceDiscovery, ZigbeeDeviceDiscoveryAction, ZigbeeDeviceDiscoveryStatus, Zone,
};
use hue::error::{HueError, HueResult};
Expand Down Expand Up @@ -89,8 +90,8 @@ impl Resources {
Ok(serde_yml::to_string(&self.state)?)
}

pub fn init(&mut self, bridge_id: &str) -> ApiResult<()> {
self.add_bridge(bridge_id.to_owned())
pub fn init(&mut self, bridge_id: &str, timezone: Tz) -> ApiResult<()> {
self.add_bridge(bridge_id.to_owned(), timezone)
}

pub fn aux_get(&self, link: &ResourceLink) -> ApiResult<&AuxData> {
Expand Down Expand Up @@ -271,7 +272,7 @@ impl Resources {
Ok(())
}

pub fn add_bridge(&mut self, bridge_id: String) -> ApiResult<()> {
pub fn add_bridge(&mut self, bridge_id: String, timezone: Tz) -> ApiResult<()> {
let link_bridge = RType::Bridge.deterministic(&bridge_id);
let link_bridge_home = RType::BridgeHome.deterministic(format!("{bridge_id}HOME"));
let link_bridge_dev = RType::Device.deterministic(link_bridge.rid);
Expand All @@ -292,7 +293,7 @@ impl Resources {
let bridge = Bridge {
bridge_id,
owner: link_bridge_dev,
time_zone: TimeZone::best_guess(),
time_zone: timezone.into(),
};

let bridge_home_dev = Device {
Expand Down
Loading