Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to add accessory, EVE stuck saying 'Adding Accessory' #21

Closed
Shaun-Sheppard opened this issue Sep 11, 2016 · 14 comments
Closed

Unable to add accessory, EVE stuck saying 'Adding Accessory' #21

Shaun-Sheppard opened this issue Sep 11, 2016 · 14 comments

Comments

@Shaun-Sheppard
Copy link

I'm trying to setup a standalone accessory using the default MockSwitch accessory and the default MockAuthInfo class.

I open EVE on my iPhone, I'm able to see the accessory, select it, enter the access and then EVE gets stuck showing 'Adding Device'. It's as if the HAP server isn't letting EVE know that the process is complete.

Here's the console output from trying to add the accessory;

20:06:47.796 [defaultEventExecutorGroup-4-1] INFO com.beowulfe.hap.impl.http.impl.AccessoryHandler - New homekit connection from /192.168.0.12:49431 20:06:47.799 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacity.default: 262144 20:06:47.813 [defaultEventExecutorGroup-4-1] INFO com.beowulfe.hap.impl.pairing.PairingManager - Starting pair for Test Lightbulb 2 20:06:47.945 [defaultEventExecutorGroup-4-1] INFO com.beowulfe.hap.impl.http.HomekitClientConnection - 200 /pair-setup 20:06:47.949 [defaultEventExecutorGroup-4-1] DEBUG io.netty.util.internal.Cleaner0 - java.nio.ByteBuffer.cleaner(): available 20:06:53.227 [defaultEventExecutorGroup-4-1] DEBUG com.beowulfe.hap.impl.pairing.PairingManager - Entering second stage of pair for Test Lightbulb 2 20:06:53.326 [defaultEventExecutorGroup-4-1] INFO com.beowulfe.hap.impl.http.HomekitClientConnection - 200 /pair-setup 20:06:53.432 [defaultEventExecutorGroup-4-1] DEBUG com.beowulfe.hap.impl.pairing.PairingManager - Entering third stage of pair for Test Lightbulb 2 Added pairing for 6:a8:6c:d7:ca:ca891C4817-03C3-4F7B-9531-417AB50C92D2 20:06:53.552 [defaultEventExecutorGroup-4-1] INFO com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser - Re-creating service due to change in discoverability to false 20:06:55.559 [defaultEventExecutorGroup-4-1] INFO com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser - Registering _hap._tcp.local. on port 9124 20:06:58.151 [defaultEventExecutorGroup-4-1] INFO com.beowulfe.hap.impl.http.HomekitClientConnection - 200 /pair-setup 20:06:58.370 [defaultEventExecutorGroup-4-1] INFO com.beowulfe.hap.impl.http.impl.AccessoryHandler - Terminated homekit connection from /192.168.0.12:49431 20:06:58.380 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x1164b103, /0:0:0:0:0:0:0:0:9124] RECEIVED: [id: 0x4d11f81b, /192.168.0.12:49432 => /192.168.0.14:9124] 20:06:58.381 [defaultEventExecutorGroup-4-2] INFO com.beowulfe.hap.impl.http.impl.AccessoryHandler - New homekit connection from /192.168.0.12:49432 20:06:58.384 [defaultEventExecutorGroup-4-2] DEBUG com.beowulfe.hap.impl.pairing.PairVerificationManager - Starting pair verification for Test Lightbulb 2 20:06:58.391 [defaultEventExecutorGroup-4-2] INFO com.beowulfe.hap.impl.http.HomekitClientConnection - 200 /pair-verify 20:06:58.453 [defaultEventExecutorGroup-4-2] DEBUG com.beowulfe.hap.impl.pairing.PairVerificationManager - Completed pair verification for Test Lightbulb 2 20:06:58.454 [defaultEventExecutorGroup-4-2] INFO com.beowulfe.hap.impl.http.HomekitClientConnection - 200 /pair-verify 20:06:58.458 [defaultEventExecutorGroup-4-2] DEBUG io.netty.util.internal.JavassistTypeParameterMatcherGenerator - Generated: io.netty.util.internal.__matchers__.io.netty.buffer.ByteBufMatcher 20:06:58.492 [defaultEventExecutorGroup-4-2] INFO com.beowulfe.hap.impl.http.HomekitClientConnection - 200 /accessories 20:06:58.632 [defaultEventExecutorGroup-4-2] INFO com.beowulfe.hap.impl.connections.SubscriptionManager - Added subscription to class com.beowulfe.hap.impl.characteristics.common.PowerStateCharacteristic for 1998817436 20:06:58.635 [defaultEventExecutorGroup-4-2] INFO com.beowulfe.hap.impl.http.HomekitClientConnection - 204 /characteristics 20:09:37.209 [defaultEventExecutorGroup-4-2] INFO com.beowulfe.hap.impl.connections.SubscriptionManager - Removed subscription to class com.beowulfe.hap.impl.characteristics.common.PowerStateCharacteristic for 1998817436 20:09:37.209 [defaultEventExecutorGroup-4-2] INFO com.beowulfe.hap.impl.http.HomekitClientConnection - 204 /characteristics

I've tried creating another Accessory on the server and exactly the same issue happens with this too.

I have had the same issue when adding accessories to a bridge. The bridge adds to my iPhone fine, but 9 times out of ten the individual accessories don't show on my phone.

Any help would be appreciated.

@andylintner
Copy link
Collaborator

It looks like you need to implement the HomekitAuthInfo.hasUser method. I need to update the sample - it's required as of iOS9. See http://beowulfe.github.io/HAP-Java/apidocs/com/beowulfe/hap/HomekitAuthInfo.html#hasUser--

@Shaun-Sheppard
Copy link
Author

Thanks for the response. In my own Auth file I do have a getUser method which uses a List of users persisted in a JSON file, and that doesn't seem to work either.

`public class MockAuthInfo implements HomekitAuthInfo {

private static final String PIN = "031-45-154";

private List<HAPUser> users = new ArrayList<>();
private String mac;
private BigInteger salt;
private byte[] privateKey;
private final ConcurrentMap<String, byte[]> userKeyMap = new ConcurrentHashMap<>();

public MockAuthInfo() throws InvalidAlgorithmParameterException {
    mac = HomekitServer.generateMac();
    salt = HomekitServer.generateSalt();
    privateKey = HomekitServer.generateKey();
    System.out.println("The PIN for pairing is "+PIN);

    restorePersistence();

    System.out.println("Private key = " + new String(privateKey));
    System.out.println("Mac = " + mac);
    System.out.println("Salt = " + salt.toString());
}

private void restorePersistence() {
    JSONParser parser = new JSONParser();

    /* Clear out any existing users */
    users.clear();

    try {
        Object obj = parser.parse(new FileReader("/tmp/hap_config"));

        JSONObject jsonObject = (JSONObject) obj;

        this.mac = (String) jsonObject.get("mac");

        String jSalt = (String) jsonObject.get("salt");
        this.salt = new BigInteger((String) jsonObject.get("salt"));

        String jPrivateKey = (String) jsonObject.get("privateKey");
        this.privateKey = Base64.decodeBase64(jPrivateKey);

        JSONArray jsonUsers = (JSONArray) jsonObject.get("users");
        for (Object userObject : jsonUsers) {
            JSONObject jUser = (JSONObject) userObject;

            String uName = (String) jUser.get("username");
            String uPublicKey = (String) jUser.get("publicKey");

            System.out.println("Restored username " + uName + " key " + Base64.decodeBase64(uPublicKey));

            HAPUser user = new HAPUser();
            user.setUsername(uName);
            user.setPublicKey(Base64.decodeBase64(uPublicKey));
            users.add(user);
        }
    } catch (FileNotFoundException e) {
        System.out.println("HAP Users file not found... creating");
        persist();
    } catch (Exception e) {
        System.out.println("HAP Users file not found... creating");
        e.printStackTrace();
    }

    for (HAPUser user : users) {
        System.out.println("Username " + user.getUsername() + " restored.");
    }
}

private void persist() {
    System.out.println("Persisting data...");

    JSONObject obj = new JSONObject();
    JSONArray usrs = new JSONArray();

    for (HAPUser user : users) {
        JSONObject u = new JSONObject();
        u.put("username", user.getUsername());
        u.put("publicKey", Base64.encodeBase64String(user.getPublicKey()));
        usrs.add(u);
    }

    obj.put("mac", mac);
    obj.put("privateKey", Base64.encodeBase64String(privateKey));
    obj.put("salt", salt.toString());

    obj.put("users", usrs);

    try {
        FileWriter file = new FileWriter("/tmp/hap_config");
        file.write(obj.toJSONString());
        file.flush();
        file.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public String getPin() {
    return PIN;
}

@Override
public String getMac() {
    return mac;
}

@Override
public BigInteger getSalt() {
    return salt;
}

@Override
public byte[] getPrivateKey() {
    return privateKey;
}

@Override
public void createUser(String username, byte[] publicKey) {
    /* Remove the user first, just incase it already exists */
    removeUser(username);

    HAPUser user = new HAPUser();
    user.setUsername(username);
    user.setPublicKey(publicKey);
    users.add(user);

    persist();

    System.out.println("Added pairing for "+username+ " key " + Base64.encodeBase64String(publicKey));
}

@Override
public void removeUser(String username) {
    int index = -1;

    for (HAPUser user : users) {
        if (user.getUsername().equals(username)) {
            index = users.indexOf(user);
        }
    }

    if (index > -1) {
        users.remove(index);
    }

    persist();

    System.out.println("Removed pairing for "+username);
}

@Override
public byte[] getUserPublicKey(String username) {
    for (HAPUser user : users) {
        if (user.getUsername().equals(username)) {
            return user.getPublicKey();
        }
    }

    return null;
}

@Override
public boolean hasUser() {
    if (users.size() > 0) {
        System.out.println("Has users? yes.");
        return true;
    } else {
        System.out.println("Has users? no.");
        return false;
    }
};

}`

@andylintner
Copy link
Collaborator

Issues like this are usually attributable to something wrong in the mdns
record HomeKit uses to advertise itself. You might try firing up an mdns
browser and look at the data. You can post it here and I can take a look
too.

On Sunday, September 11, 2016, shepparddigital notifications@github.com
wrote:

Thanks for the response. In my own Auth file I do have a getUser method
which uses a List of users persisted in a JSON file, and that doesn't seem
to work either.

`public class MockAuthInfo implements HomekitAuthInfo {

private static final String PIN = "031-45-154";

private List users = new ArrayList<>();
private String mac;
private BigInteger salt;
private byte[] privateKey;
private final ConcurrentMap<String, byte[]> userKeyMap = new ConcurrentHashMap<>();

public MockAuthInfo() throws InvalidAlgorithmParameterException {
mac = HomekitServer.generateMac();
salt = HomekitServer.generateSalt();
privateKey = HomekitServer.generateKey();
System.out.println("The PIN for pairing is "+PIN);

restorePersistence();

System.out.println("Private key = " + new String(privateKey));
System.out.println("Mac = " + mac);
System.out.println("Salt = " + salt.toString());

}

private void restorePersistence() {
JSONParser parser = new JSONParser();

/* Clear out any existing users */
users.clear();

try {
    Object obj = parser.parse(new FileReader("/tmp/hap_config"));

    JSONObject jsonObject = (JSONObject) obj;

    this.mac = (String) jsonObject.get("mac");

    String jSalt = (String) jsonObject.get("salt");
    this.salt = new BigInteger((String) jsonObject.get("salt"));

    String jPrivateKey = (String) jsonObject.get("privateKey");
    this.privateKey = Base64.decodeBase64(jPrivateKey);

    JSONArray jsonUsers = (JSONArray) jsonObject.get("users");
    for (Object userObject : jsonUsers) {
        JSONObject jUser = (JSONObject) userObject;

        String uName = (String) jUser.get("username");
        String uPublicKey = (String) jUser.get("publicKey");

        System.out.println("Restored username " + uName + " key " + Base64.decodeBase64(uPublicKey));

        HAPUser user = new HAPUser();
        user.setUsername(uName);
        user.setPublicKey(Base64.decodeBase64(uPublicKey));
        users.add(user);
    }
} catch (FileNotFoundException e) {
    System.out.println("HAP Users file not found... creating");
    persist();
} catch (Exception e) {
    System.out.println("HAP Users file not found... creating");
    e.printStackTrace();
}

for (HAPUser user : users) {
    System.out.println("Username " + user.getUsername() + " restored.");
}

}

private void persist() {
System.out.println("Persisting data...");

JSONObject obj = new JSONObject();
JSONArray usrs = new JSONArray();

for (HAPUser user : users) {
    JSONObject u = new JSONObject();
    u.put("username", user.getUsername());
    u.put("publicKey", Base64.encodeBase64String(user.getPublicKey()));
    usrs.add(u);
}

obj.put("mac", mac);
obj.put("privateKey", Base64.encodeBase64String(privateKey));
obj.put("salt", salt.toString());

obj.put("users", usrs);

try {
    FileWriter file = new FileWriter("/tmp/hap_config");
    file.write(obj.toJSONString());
    file.flush();
    file.close();
} catch (IOException e) {
    e.printStackTrace();
}

}

@OverRide
public String getPin() {
return PIN;
}

@OverRide
public String getMac() {
return mac;
}

@OverRide
public BigInteger getSalt() {
return salt;
}

@OverRide
public byte[] getPrivateKey() {
return privateKey;
}

@OverRide
public void createUser(String username, byte[] publicKey) {
/* Remove the user first, just incase it already exists */
removeUser(username);

HAPUser user = new HAPUser();
user.setUsername(username);
user.setPublicKey(publicKey);
users.add(user);

persist();

System.out.println("Added pairing for "+username+ " key " + Base64.encodeBase64String(publicKey));

}

@OverRide
public void removeUser(String username) {
int index = -1;

for (HAPUser user : users) {
    if (user.getUsername().equals(username)) {
        index = users.indexOf(user);
    }
}

if (index > -1) {
    users.remove(index);
}

persist();

System.out.println("Removed pairing for "+username);

}

@OverRide
public byte[] getUserPublicKey(String username) {
for (HAPUser user : users) {
if (user.getUsername().equals(username)) {
return user.getPublicKey();
}
}

return null;

}

@OverRide
public boolean hasUser() {
if (users.size() > 0) {
System.out.println("Has users? yes.");
return true;
} else {
System.out.println("Has users? no.");
return false;
}
};

}`


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#21 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEwwNCwxYdorbdntrSWe2AydPV-a4fSks5qpFh5gaJpZM4J6FDz
.

@Shaun-Sheppard
Copy link
Author

Here's a screenshot of what shows in an mdns browser, I'm not really sure what I'm looking for, but I did notice that before trying to add the accessory the data looked like this...

mdns

After adding and getting stuck saying 'Adding accessory' it changed to this.

mdns2

@andylintner
Copy link
Collaborator

That all looks perfect. Must be something in the http response instead. Try
turning the logging level up to TRACE - it will capture the http requests
and responses.

On Monday, September 12, 2016, shepparddigital notifications@github.com
wrote:

Here's a screenshot of what shows in an mdns browser, I'm not really sure
what I'm looking for, but I did notice that before trying to add the
accessory the data looked like this...

[image: mdns]
https://cloud.githubusercontent.com/assets/5153221/18427852/9ab6815a-78c2-11e6-95b8-4ee25da7552e.jpg

After adding and getting stuck saying 'Adding accessory' it changed to
this.

[image: mdns2]
https://cloud.githubusercontent.com/assets/5153221/18427877/acbbc8f6-78c2-11e6-862f-ee55bc92e8b2.jpg


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#21 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEwwATsOGagDXJfCTd3ROHDcbDqxUITks5qpP7GgaJpZM4J6FDz
.

@Shaun-Sheppard
Copy link
Author

Sorry, I seem to be having issues changing the log level. I've added -Dorg.slf4j.simpleLogger.defaultLogLevel=TRACE to the VM arguments but I don't see any additional information?

@Shaun-Sheppard
Copy link
Author

Shaun-Sheppard commented Sep 12, 2016

I figured out how to change the log level to trace, I'm attaching the trace as a txt file as it's a little too long to paste in here I think.

trace.txt

@Shaun-Sheppard
Copy link
Author

Is there anything else I can provide to help diagnose this issue?

@mariusz2108
Copy link

I had similar issue on my iPhone with iOS 10.
When I deleted cache on iPhone (I used 3rd party app) everything worked fine.

@comdata
Copy link

comdata commented Jan 8, 2017

Is there any new on this issue?

@leonborko
Copy link

Sample project is not working by me. It hangs by pairing. Can you prepare working sample or post link to working sample

@bakkerv
Copy link

bakkerv commented May 20, 2017

I have the exact same issue with the pairing (iOS 10)

@leonborko
Copy link

I have solved problem with sample. My computer has multiple network interfaces and sample app get wrong ip address.
Just change
HomekitServer homekit = new HomekitServer(PORT);
to
HomekitServer homekit = new HomekitServer(NETWORK ADDRESS, PORT);

Network address in ip address of your computer

@yfre
Copy link
Contributor

yfre commented Jan 29, 2022

close as solution found according to the last comment

@yfre yfre closed this as completed Jan 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants