Search code examples
iosarduinoesp8266homekitmdns

How does HomeKit find nearby devices?


First of all I am sorry if this is not the most appropriate forum to post this question. I looked at AskDifferent which seems not technical enough for this and I looked at Super User which seems too technical for it. Hence why I am asking it here as it is also related to programming.

Description

I am using the Arduino IDE to set up an HAP (HomeKit Accessory Protocol) server on an ESP8266 (-01). I have successfully set up an mDNS server on it for discovery using the ESP8266mDNS library. However, I am facing one slight problem with this:

After the mDNS server has been started and an _hap._tcp service been added, the device initially does not show up in the Home app. It is only after I "probe" the _hap._tcp service using $ dns-sd -B _hap._tcp from a Terminal that the ESP8266 shows up in the Home app.

It seems that this "probing" does something on the network which is not initially done by the mDNS server but is required by HomeKit to be discoverable.

I have tested this with other services such as "_http._tcp" and using an App on my iPhone called Radar to search for Bonjour services. It finds any other service but not hap (until I "probe" it).

Using WireShark shows me that the Home app does not send any mDNS requests until an (already discovered) device is clicked on. This makes me think that the initial discovery (to show devices to click on) is not done by mDNS but by some other method. Perhaps some kind of registry on the network which is then filled in after I probe using dns-sd.

Using the Radar app I can see mDNS packets on the network for any service that I select there except for hap. This is strange as if the iPhone is blocking the mDNS requests for the hap service.

I have spent 3 days now trying to get this to work and I really don't know where to go from here. I would like to know what I am missing to make the ESP8266 instantly discoverable by the Home app without having to use dsn-sd to "activate" this. If you want to reproduce the issue I have put a simplified version of my code which still has the same problem below. You can upload this to an ESP8266 using the Arduino IDE after installing the appropriate boards.

After installation, try to see if the device shows up in HomeKit. If it does not, use a Mac on the same network and enter $ dns-sd -B _hap._tcp into a Terminal. While this is running go back to the Home app and you should be able to see the device there.

Code

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>


const char* ssid = "WiFi"; //Change to your SSID
const char* password = "xxxxx"; //Change to your password

ESP8266WebServer server(80);

void handleNotFound(){
  server.send(404, "text/plain", "Not Found!");
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.hostname("ESP8266");
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  if (MDNS.begin("ESP8266")) {
    Serial.println("MDNS Started.");
  }
  server.onNotFound(handleNotFound);

  server.begin();

  MDNS.addService("hap", "tcp", 80);
  MDNS.addServiceTxt("hap", "tcp", "md", "ESP8266");
  MDNS.addServiceTxt("hap", "tcp", "pv", "1.0");
  MDNS.addServiceTxt("hap", "tcp", "id", "A0:20:A6:15:46:44");
  MDNS.addServiceTxt("hap", "tcp", "c#", "3");
  MDNS.addServiceTxt("hap", "tcp", "s#", "1");
  MDNS.addServiceTxt("hap", "tcp", "ff", "0");
  MDNS.addServiceTxt("hap", "tcp", "ci", "5");
  MDNS.addServiceTxt("hap", "tcp", "sf", "1");
}

void loop() {
  server.handleClient();
}

Solution

  • I have done some more testing and installed Homebridge on a Mac and monitored it's mDNS packets using WireShark. On startup of the server it sends out a couple of "ANY" queries and a couple of responses. What it is doing here is as described in section 8 of RFC 6762 namely, "Probing and Announcing on Startup". It seems that the ESP8266mDNS library is currently not doing this so I have reopened my issue on GitHub to get this implemented. I will be making an attempt myself but I urge anyone with enough knowledge to contribute! The library is currently being rewritten based on the idf implementation which passes Apple's conformance test. This issue should be fixed once that is complete.