ewilken / hap-rs

Rust implementation of the Apple HomeKit Accessory Protocol (HAP)
Apache License 2.0
197 stars 35 forks source link

Help with setting values on characteristics #34

Closed ryansouza closed 3 years ago

ryansouza commented 3 years ago

Hello!

I'm having trouble conceptualizing how to code up an accessory like a contact sensor, where I'm tracking a value and pushing updates on its current status "out to homekit". I'm guessing example in the current readme of "Setting a characteristic value directly" is more for pre-setup and not what I should be trying to build around. What I'm seeing is that add_accessory takes ownership and returns a pointer, so I can't store or access the actual service & characteristic directly anymore like the example.

An alternative I see is to handle my own shared state somewhere else and use an on_read callback to update the Homekit state when its actually attempting to be read. Is this how Homekit should be operating? I'm definitely just poking around and not fully sure, but in my tests this only triggers when I'm actively using the Home app and it is reading data.

I was expecting that set_value would be "sending out" status update messages to the system so they could be triggering notifications, automations, etc. The other idea I had but haven't followed through with yet is trying to use the pointer::Acessory returned from add_accessory to try and get to the characteristic to set values on it. Is that what I'm supposed to be doing? If so I can figure that out and propose a readme addition for it, just looking for some guidance.

The example I've been trying to write is a door using a tokio interval to simulate being opened/closed every 10s, just to figure out how push state in to the system and watch those notifications from my phone.

ewilken commented 3 years ago

An alternative I see is to handle my own shared state somewhere else and use an on_read callback to update the Homekit state when its actually attempting to be read.

This is something you can do, but, as you pointed out, not really practical for things like sensors where you want event notifications on value changes.

I was expecting that set_value would be "sending out" status update messages to the system so they could be triggering notifications, automations, etc.

It does! (Or at least should do. I hope I didn't break it since I last tested.)

The other idea I had but haven't followed through with yet is trying to use the pointer::Acessory returned from add_accessory to try and get to the characteristic to set values on it. Is that what I'm supposed to be doing?

Yes. That's what I'd do. You're totally right about the lack of documentation for that. Will try to document it properly.

Just added a (lightly tested) example for a motion sensor that gets triggered every two seconds after one minute after program start. The interesting part is this one:

let sensor_ptr = server.add_accessory(sensor).await.unwrap();

let handle = server.run_handle();

let value_set_interval = async move {
    let mut interval = tokio::time::interval(std::time::Duration::from_secs(2));

    tokio::time::delay_for(std::time::Duration::from_secs(60)).await;

    loop {
        interval.tick().await;

        let mut motion_sensor_accessory = sensor_ptr.lock().await;
        let motion_sensor_service = motion_sensor_accessory.get_mut_service(HapType::MotionSensor).unwrap();
        let motion_detected_characteristic = motion_sensor_service
            .get_mut_characteristic(HapType::MotionDetected)
            .unwrap();

        motion_detected_characteristic
            .set_value(Value::Bool(true))
            .await
            .unwrap();

        tokio::time::delay_for(std::time::Duration::from_secs(1)).await;

        motion_detected_characteristic
            .set_value(Value::Bool(false))
            .await
            .unwrap();
    }
};

std::env::set_var("RUST_LOG", "hap=debug");
env_logger::init();

futures::join!(handle, value_set_interval);
cargo run --example setting_values_after_server_start --release

Apparently the --release build is needed for the pairing process to be fast enough for the iOS controller not to lose patience. Still a lot of stuff left to look into here.

Thanks a lot for caring! Feel free to reach out for further questions anytime. And contributions to help finishing this crate are always welcome, should you find it useful.