This commit is contained in:
Alex Janka 2024-02-23 15:06:10 +11:00
parent 8982b11073
commit c3cd4e7bdb
5 changed files with 1048 additions and 61 deletions

947
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@ use x25519_dalek::{EphemeralSecret, PublicKey};
use pairing_data::{Accessory, DevicePairingData}; use pairing_data::{Accessory, DevicePairingData};
pub use crate::pairing_data::{CharacteristicType, Data}; pub use crate::pairing_data::{CharacteristicType, Data, ServiceType};
use crate::{ use crate::{
homekit_http::AccessorySocket, homekit_http::AccessorySocket,
tlv8::{decode, TlvEncodableData}, tlv8::{decode, TlvEncodableData},

View file

@ -9,3 +9,4 @@ env_logger = "0.11"
log = "0.4" log = "0.4"
clap = { version = "4.0", features = ["derive"] } clap = { version = "4.0", features = ["derive"] }
homekit-controller = { path = "../homekit-controller" } homekit-controller = { path = "../homekit-controller" }
rocket = { version = "0.5", features = ["json"] }

View file

@ -1,70 +1,55 @@
use std::path::PathBuf; #[macro_use]
extern crate rocket;
use clap::{Parser, Subcommand}; use std::{collections::HashMap, path::PathBuf};
use homekit_controller::{Data, HomekitError};
use clap::Parser;
use homekit_controller::{ConnectedDevice, HomekitError, ServiceType};
use server::launch;
mod server;
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
#[clap(author, version, about, long_about = None)] #[clap(author, version, about, long_about = None)]
struct Args { struct Args {
#[command(subcommand)]
command: Commands,
#[clap(long)] #[clap(long)]
pairing_data: PathBuf, pairing_data: PathBuf,
#[clap(long)]
device_name: String,
} }
#[derive(Subcommand, Debug, Clone)] const SENSORS: [ServiceType; 11] = [
enum Commands { ServiceType::AirQualitySensor,
/// Run logging server ServiceType::CarbonDioxideSensor,
Watch, ServiceType::CarbonMonoxideSensor,
/// List endpoints ServiceType::ContactSensor,
ListEndpoints, ServiceType::HumiditySensor,
} ServiceType::LeakSensor,
ServiceType::LightSensor,
ServiceType::MotionSensor,
ServiceType::OccupancySensor,
ServiceType::SmokeSensor,
ServiceType::TemperatureSensor,
];
#[tokio::main] #[launch]
async fn main() -> Result<(), HomekitError> { async fn rocket() -> rocket::Rocket<rocket::Build> {
env_logger::init(); env_logger::init();
let args = Args::parse(); let args = Args::parse();
match init(args.pairing_data).await {
Ok(paired) => launch(paired),
Err(e) => panic!("Error {e:#?}"),
}
}
if args.pairing_data.is_file() { async fn init(pairing_data: PathBuf) -> Result<HashMap<String, ConnectedDevice>, HomekitError> {
let devices = homekit_controller::load(args.pairing_data)?; if pairing_data.is_file() {
let devices = homekit_controller::load(pairing_data)?;
if let Some(device) = devices.get(&args.device_name) { let mut connected_devices = HashMap::new();
let mut connected = device.connect().await?; for (k, v) in devices {
connected.update_characteristics().await?; connected_devices.insert(k, v.connect().await?);
for (aid, accessory) in connected.accessories {
println!("{} ({}): [", accessory.name, aid);
for (sid, service) in accessory.services {
println!(
"\t{} ({}): [",
service.name.as_ref().unwrap_or(&String::from("Unknown")),
sid
);
for (cid, characteristic) in &service.characteristics {
println!(
"\t\t{:?} ({}): {}{}",
characteristic.characteristic_type,
cid,
match &characteristic.value {
Some(Data::String(s)) => s.clone(),
Some(other) => format!("{other:?}"),
None => String::from("no data"),
},
characteristic
.unit
.map(|v| format!(" ({v:?})"))
.unwrap_or_default()
);
}
println!("\t]");
}
println!("]");
}
} }
Ok(connected_devices)
} else { } else {
log::error!("{:?} is not a file!", args.pairing_data) log::error!("{:?} is not a file!", pairing_data);
Err(HomekitError::NoPairingData)
} }
Ok(())
} }

View file

@ -0,0 +1,62 @@
use homekit_controller::{ConnectedDevice, Data};
use rocket::State;
use std::collections::HashMap;
use tokio::sync::Mutex;
use crate::SENSORS;
pub fn launch(paired: HashMap<String, ConnectedDevice>) -> rocket::Rocket<rocket::Build> {
rocket::build()
.manage(Mutex::new(paired))
.mount("/", routes![index])
}
#[get("/")]
pub async fn index(state: &State<Mutex<HashMap<String, ConnectedDevice>>>) -> Option<String> {
let mut s = String::new();
let mut state = state.lock().await;
for connected in state.values_mut() {
connected.update_characteristics().await.ok()?;
for (aid, accessory) in &connected.accessories {
s.push_str(format!("{} ({}): [\n", accessory.name, aid).as_str());
for (sid, service) in &accessory.services {
if !SENSORS.contains(&service.service_type) {
continue;
}
s.push_str(
format!(
"\t{} ({:?}) ({}): [\n",
service.name.as_ref().unwrap_or(&String::from("Unknown")),
service.service_type,
sid,
)
.as_str(),
);
for (cid, characteristic) in &service.characteristics {
s.push_str(
format!(
"\t\t{:?} ({}): {}{}\n",
characteristic.characteristic_type,
cid,
match &characteristic.value {
Some(Data::String(s)) => s.clone(),
Some(other) => format!("{other:?}"),
None => String::from("no data"),
},
characteristic
.unit
.map(|v| format!(" ({v:?})"))
.unwrap_or_default()
)
.as_str(),
);
}
s.push_str("\t]\n");
}
s.push_str("]\n");
}
}
Some(s)
}