ewilken / hap-rs

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

Struggling get demo to work. #14

Closed chrismatheson closed 3 years ago

chrismatheson commented 5 years ago

Hi,

im quite new to rust & homexit so apologies in advance if this is something obvious but id really appreciate any pointers / help.

Im trying to get the demo code working between my map & my phone. However when trying to add the device, after adding the PIN the home iOS app just hangs with a spinner.

ive managed to enable logging and this is what i get

[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::io] read 0 bytes
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::conn] read eof
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::io] read 161 bytes
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::io] parsed 3 headers
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::conn] incoming body is content-length (37 bytes)
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::conn] incoming body completed
[2019-06-26T12:09:27Z DEBUG hap::transport::http::handler::pair_verify] M1: Got Verify Start Request
[2019-06-26T12:09:27Z DEBUG hap::transport::http::handler::pair_verify] M2: Sending Verify Start Response
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::io] flushed 117 bytes
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::io] flushed 140 bytes
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::io] read 250 bytes
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::io] parsed 3 headers
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::conn] incoming body is content-length (125 bytes)
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::conn] incoming body completed
[2019-06-26T12:09:27Z DEBUG hap::transport::http::handler::pair_verify] M3: Got Verify Finish Request
[2019-06-26T12:09:27Z DEBUG hap::transport::http::handler::pair_verify] M4: Sending Verify Finish Response
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::io] flushed 118 bytes

It seems like maybe something in the M4 step isn't working correctly maybe?? Im unsure how to debug from this point onward.

also the program I'm trying to get working

#[macro_use] extern crate log;
extern crate env_logger;
use env_logger::Env;
use hap::{
    transport::{Transport, IpTransport},
    accessory::{Category, Information, outlet},
    characteristic::{Readable, Updatable},
    Config,
    HapType,
};

use log::Level;

#[derive(Clone)]
pub struct VirtualOutlet {
    on: bool,
}

impl Readable<bool> for VirtualOutlet {
    fn on_read(&mut self, _: HapType) -> Option<bool> {
        println!("On read.");
        Some(self.on)
    }
}

impl Updatable<bool> for VirtualOutlet {
    fn on_update(&mut self, old_val: &bool, new_val: &bool, _: HapType) {
        println!("On updated from {} to {}.", old_val, new_val);
        if new_val != old_val { self.on = *new_val; }
    }
}

fn main() {
    env_logger::from_env(Env::default().default_filter_or("hap=debug,tokio=warn")).init();

    debug!("this is a debug {}", "message");

    let info = Information {
        name: "My Plug".into(),
        ..Default::default()
    };

    let mut outlet = outlet::new(info).unwrap();

    let virtual_outlet = VirtualOutlet { on: false };
    outlet.inner.outlet.inner.on.set_readable(virtual_outlet.clone()).unwrap();
    outlet.inner.outlet.inner.on.set_updatable(virtual_outlet).unwrap();

    let config = Config {
        name: "My Plug".into(),
        category: Category::Outlet,
        ..Default::default()
    };

    let mut ip_transport = IpTransport::new(config).unwrap();
    ip_transport.add_accessory(outlet).unwrap();
    ip_transport.start().unwrap();
}
chrismatheson commented 5 years ago

Ive dug into this a little (and with next to no rust knowledge so apologies if this is redundant info or ive missed something....) but it seems as though the response in M4 is missing some info.

the spec says to reply with kTLVType_State & kTLVType_Proof however i can only make out a response that includes the state Ok(vec![Value::State(StepNumber::FinishRes as u8)])

is this maybe a new part of the protocol added since 0.0.5 of hap was released? or has this step never worked maybe ?

ewilken commented 5 years ago

Thanks for the report & sorry for the delayed reply!

Unfortunately, I have very little time for maintaining this project at the moment, but I'm gonna try to reproduce & look into this sometime this week.

Which version of iOS have you tried it on?

chrismatheson commented 5 years ago

Hey no bother! its open source and you don't owe me anything ;)

in fact I've taken a local copy and I'm going to try and get stuck in and help out! :) I've started by trying to implement a MemoryStorage option in the hole of adding some integration tests that would exercise the entire pairing process.

Seemed useful to have those run completely in memory so i started there :)

but to answer your question, my current iOS version is 12.3.1

If you have the time to do a bit of mentoring id love to try and contribute. My approach was going to be adding testing (from the outside and work in) which i figured would give me a good process for learning the functionality / requirements. If you wanted to suggest some Pseudo Code style tests i can try and implement those ?

ewilken commented 5 years ago

I would be absolutely happy about any sort of contribution! :) Adding tests sounds like a great idea (that I managed to procrastinate on so far). Also my implementation is based on the first release of the specification and it looks like a second version of it got released just 3 days ago. Will try to find some time to dig into that in the upcoming weeks, too.

Regarding the tests, I don't have any preferences. Choose whatever style/framework you like! Or do you have any specific questions about testing the whole thing?

Besides the obvious (missing tests), I would like to overhaul the public API of this crate into something looking somewhat nicer for a v0.1 release and beyond. In particular, I don't like that fiddling around with those inner types for interacting with characteristic values and I'm not sure about that IpTransport wrapper around a Tokio runtime, or if we should just emit the HAP server as a Future and let the user choose their own runtime for it. Also I'd like to evaluate what it would take to implement RTP camera streams. If you're interested to help out on any of those topics, let's talk about it, I'd be more than happy! I think I'm gonna have some spare time for this project from mid August.

By the way, your code is working (tested on iOS 12.3.1)! The pairing just takes a very long time and a few retries by the iOS device, which is definitely weird.

[2019-07-29T20:41:24Z DEBUG hap_test] this is a debug message
[2019-07-29T20:42:04Z DEBUG hap::transport::http::handler::pair_setup] M1: Got SRP Start Request
[2019-07-29T20:42:10Z DEBUG hap::transport::http::handler::pair_setup] M2: Sending SRP Start Response
[2019-07-29T20:42:11Z DEBUG hap::transport::http::handler::pair_setup] M3: Got SRP Verify Request
[2019-07-29T20:42:14Z DEBUG hap::transport::http::handler::pair_setup] M4: Sending SRP Verify Response
[2019-07-29T20:42:14Z DEBUG hap::transport::http::handler::pair_setup] M5: Got SRP Exchange Request
[2019-07-29T20:42:14Z DEBUG hap::transport::http::handler::pair_setup] M6: Sending SRP Exchange Response
[2019-07-29T20:42:14Z DEBUG hap::transport::http::handler::pair_verify] M1: Got Verify Start Request
[2019-07-29T20:42:14Z DEBUG hap::transport::http::handler::pair_verify] M2: Sending Verify Start Response
[2019-07-29T20:42:15Z DEBUG hap::transport::http::handler::pair_verify] M3: Got Verify Finish Request
[2019-07-29T20:42:15Z DEBUG hap::transport::http::handler::pair_verify] M4: Sending Verify Finish Response
[2019-07-29T20:43:35Z DEBUG hap::transport::http::handler::pair_verify] M1: Got Verify Start Request
[2019-07-29T20:43:35Z DEBUG hap::transport::http::handler::pair_verify] M2: Sending Verify Start Response
[2019-07-29T20:43:36Z DEBUG hap::transport::http::handler::pair_verify] M3: Got Verify Finish Request
[2019-07-29T20:43:36Z DEBUG hap::transport::http::handler::pair_verify] M4: Sending Verify Finish Response
[2019-07-29T20:43:38Z DEBUG hap::transport::http::handler::pair_verify] M1: Got Verify Start Request
[2019-07-29T20:43:38Z DEBUG hap::transport::http::handler::pair_verify] M2: Sending Verify Start Response
[2019-07-29T20:43:38Z DEBUG hap::transport::http::handler::pair_verify] M3: Got Verify Finish Request
[2019-07-29T20:43:38Z DEBUG hap::transport::http::handler::pair_verify] M4: Sending Verify Finish Response
On read.
On updated from false to false.
[2019-07-29T20:43:38Z DEBUG hap::transport::http::handler::pair_verify] M1: Got Verify Start Request
[2019-07-29T20:43:38Z DEBUG hap::transport::http::handler::pair_verify] M2: Sending Verify Start Response
[2019-07-29T20:43:38Z DEBUG hap::transport::http::handler::pair_verify] M3: Got Verify Finish Request
[2019-07-29T20:43:38Z DEBUG hap::transport::http::handler::pair_verify] M4: Sending Verify Finish Response

Thanks again for your interest in this project!

chrismatheson commented 5 years ago

it takes a while (3/4 secs) to get to

[2019-06-26T12:09:27Z DEBUG hap::transport::http::handler::pair_verify] M4: Sending Verify Finish Response
[2019-06-26T12:09:27Z DEBUG hyper::proto::h1::io] flushed 118 bytes

however i think there might be something not quite right with the M4 response to the phone, at least my one would never actually complete after that? you managed to get that same code to pair fine on your own physical device?

as for future work, i would 100% agree on exposing just the HAP server, thats been my biggest stumbling block when trying to test things so far (not being able to figure out how to run 2 separate tokio runtimes during a test)

another things i would suggest is moving the codeine stuff into a sub package. when trying to test - code - compile - test loop its frustratingly slow to regenerate all those classes etc every time. currently I've actually been writing my tests as a separate project that depends on HAP, but that would be harder if I were chasing the internals of HAP itself during that loop rather than trying to write black box tests around it.

tomorrow is my self allocated open source day ill try and get something useful done and see what you think :)

C

ewilken commented 5 years ago

Yeah, it eventually pairs with my iPhone. Anyway, gonna try and re-check with the updated documentation if we're still doing everything right there.

Also moving the codegen stuff into a separate crate is an excellent idea. Will do that.

ewilken commented 5 years ago

Separating the generated stuff from the rest of the crate turned out to get somewhat messy while not solving the original problem. Instead I implemented another solution that should speed up the build of the crate a lot. Publishing it as v0.0.6 to crates.io now to hopefully ease your development process, too.

As for the API improvements, I'm on it the next days, starting with uncoupling the server from the runtime.

Let me know if I can help you or review something!

Cheers!