diff --git a/pyhap/accessory_driver.py b/pyhap/accessory_driver.py index 76033d4f..48f4536c 100644 --- a/pyhap/accessory_driver.py +++ b/pyhap/accessory_driver.py @@ -509,8 +509,7 @@ def load(self): def pair(self, client_uuid, client_public): """Called when a client has paired with the accessory. - Updates the accessory with the paired client and updates the mDNS service. Also, - persist the new state. + Persist the new accessory state. :param client_uuid: The client uuid. :type client_uuid: uuid.UUID @@ -527,17 +526,12 @@ def pair(self, client_uuid, client_public): logger.info("Paired with %s.", client_uuid) self.state.add_paired_client(client_uuid, client_public) self.persist() - # Safe mode added to avoid error during pairing, see - # https://github.com/home-assistant/home-assistant/issues/14567 - if not self.safe_mode: - self.update_advertisement() return True def unpair(self, client_uuid): """Removes the paired client from the accessory. - Updates the accessory and updates the mDNS service. Persist the new accessory - state. + Persist the new accessory state. :param client_uuid: The client uuid. :type client_uuid: uuid.UUID @@ -545,6 +539,24 @@ def unpair(self, client_uuid): logger.info("Unpairing client %s.", client_uuid) self.state.remove_paired_client(client_uuid) self.persist() + + def finish_pair(self): + """Finishing pairing or unpairing. + + Updates the accessory and updates the mDNS service. + + The mDNS announcement must not be updated until AFTER + the final pairing response is sent or homekit will + see that the accessory is already paired and assume + it should stop pairing. + """ + # Safe mode added to avoid error during pairing, see + # https://github.com/home-assistant/home-assistant/issues/14567 + # + # This may no longer be needed now that we defer + # updating the advertisement until after the final + # pairing response is sent. + # if not self.safe_mode: self.update_advertisement() diff --git a/pyhap/hap_server.py b/pyhap/hap_server.py index abef1be5..1d3bc128 100644 --- a/pyhap/hap_server.py +++ b/pyhap/hap_server.py @@ -598,6 +598,13 @@ def _handle_add_pairing(self, tlv_objects): self.send_header("Content-Type", self.PAIRING_RESPONSE_TYPE) self.end_response(data) + # Avoid updating the announcement until + # after the response is sent as homekit will + # drop the connection and fail to pair if it + # sees the accessory is now paired as it doesn't + # know that it was the one doing the pairing. + self.accessory_handler.finish_pair() + def _handle_remove_pairing(self, tlv_objects): """Remove pairing with the client.""" logger.debug("Removing client pairing.") @@ -610,6 +617,10 @@ def _handle_remove_pairing(self, tlv_objects): self.send_header("Content-Type", self.PAIRING_RESPONSE_TYPE) self.end_response(data) + # Avoid updating the announcement until + # after the response is sent. + self.accessory_handler.finish_pair() + def handle_resource(self): """Get a snapshot from the camera.""" if not hasattr(self.accessory_handler.accessory, 'get_snapshot'):