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};
pub use crate::pairing_data::{CharacteristicType, Data};
pub use crate::pairing_data::{CharacteristicType, Data, ServiceType};
use crate::{
homekit_http::AccessorySocket,
tlv8::{decode, TlvEncodableData},

View file

@ -9,3 +9,4 @@ env_logger = "0.11"
log = "0.4"
clap = { version = "4.0", features = ["derive"] }
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 homekit_controller::{Data, HomekitError};
use std::{collections::HashMap, path::PathBuf};
use clap::Parser;
use homekit_controller::{ConnectedDevice, HomekitError, ServiceType};
use server::launch;
mod server;
#[derive(Parser, Debug, Clone)]
#[clap(author, version, about, long_about = None)]
struct Args {
#[command(subcommand)]
command: Commands,
#[clap(long)]
pairing_data: PathBuf,
#[clap(long)]
device_name: String,
}
#[derive(Subcommand, Debug, Clone)]
enum Commands {
/// Run logging server
Watch,
/// List endpoints
ListEndpoints,
}
const SENSORS: [ServiceType; 11] = [
ServiceType::AirQualitySensor,
ServiceType::CarbonDioxideSensor,
ServiceType::CarbonMonoxideSensor,
ServiceType::ContactSensor,
ServiceType::HumiditySensor,
ServiceType::LeakSensor,
ServiceType::LightSensor,
ServiceType::MotionSensor,
ServiceType::OccupancySensor,
ServiceType::SmokeSensor,
ServiceType::TemperatureSensor,
];
#[tokio::main]
async fn main() -> Result<(), HomekitError> {
#[launch]
async fn rocket() -> rocket::Rocket<rocket::Build> {
env_logger::init();
let args = Args::parse();
if args.pairing_data.is_file() {
let devices = homekit_controller::load(args.pairing_data)?;
if let Some(device) = devices.get(&args.device_name) {
let mut connected = device.connect().await?;
connected.update_characteristics().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()
);
match init(args.pairing_data).await {
Ok(paired) => launch(paired),
Err(e) => panic!("Error {e:#?}"),
}
}
async fn init(pairing_data: PathBuf) -> Result<HashMap<String, ConnectedDevice>, HomekitError> {
if pairing_data.is_file() {
let devices = homekit_controller::load(pairing_data)?;
let mut connected_devices = HashMap::new();
for (k, v) in devices {
connected_devices.insert(k, v.connect().await?);
}
Ok(connected_devices)
} else {
log::error!("{:?} is not a file!", pairing_data);
Err(HomekitError::NoPairingData)
}
println!("\t]");
}
println!("]");
}
}
} else {
log::error!("{:?} is not a file!", args.pairing_data)
}
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)
}