Skip to content

Commit

Permalink
Merge pull request #371 from ikalchev/v4.0.0
Browse files Browse the repository at this point in the history
V4.0.0
  • Loading branch information
ikalchev authored Jul 30, 2021
2 parents 25ba016 + 4490a9c commit f1a9784
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 27 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ Sections
### Developers
-->

## [3.6.0] - 2021-7-22
## [4.0.0] - 2021-07-22

- Add support for HAP v 1.1. [#365](https://github.com/ikalchev/HAP-python/pull/365)

## [3.6.0] - 2021-07-22

- Reduce event overhead. [#360](https://github.com/ikalchev/HAP-python/pull/360)
- Ensure floating point values are truncated for int formats. [#361](https://github.com/ikalchev/HAP-python/pull/361)
Expand Down
18 changes: 18 additions & 0 deletions pyhap/accessory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,28 @@
import itertools
import logging

from uuid import UUID
from pyhap import SUPPORT_QR_CODE, util
from pyhap.const import (
CATEGORY_BRIDGE,
CATEGORY_OTHER,
HAP_REPR_AID,
HAP_REPR_IID,
HAP_PROTOCOL_VERSION,
HAP_REPR_SERVICES,
HAP_REPR_VALUE,
STANDALONE_AID,
)
from pyhap.iid_manager import IIDManager
from pyhap.service import Service

if SUPPORT_QR_CODE:
import base36
from pyqrcode import QRCode


HAP_PROTOCOL_INFORMATION_SERVICE_UUID = UUID("000000A2-0000-1000-8000-0026BB765291")

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -48,6 +54,8 @@ def __init__(self, driver, display_name, aid=None):
self.iid_manager = IIDManager()

self.add_info_service()
if aid == STANDALONE_AID:
self.add_protocol_version_service()

def __repr__(self):
"""Return the representation of the accessory."""
Expand Down Expand Up @@ -79,6 +87,16 @@ def add_info_service(self):
serv_info.configure_char("SerialNumber", value="default")
self.add_service(serv_info)

def add_protocol_version_service(self):
"""Helper method to add the required HAP Protocol Information service"""
serv_hap_proto_info = Service(
HAP_PROTOCOL_INFORMATION_SERVICE_UUID,
"HAPProtocolInformation"
)
serv_hap_proto_info.add_characteristic(self.driver.loader.get_char("Version"))
serv_hap_proto_info.configure_char("Version", value=HAP_PROTOCOL_VERSION)
self.add_service(serv_hap_proto_info)

def set_info_service(
self, firmware_revision=None, manufacturer=None, model=None, serial_number=None
):
Expand Down
3 changes: 2 additions & 1 deletion pyhap/accessory_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from pyhap.characteristic import CharacteristicError
from pyhap.const import (
HAP_PERMISSION_NOTIFY,
HAP_PROTOCOL_SHORT_VERSION,
HAP_REPR_ACCS,
HAP_REPR_AID,
HAP_REPR_CHARS,
Expand Down Expand Up @@ -125,7 +126,7 @@ def _get_advert_data(self):
"""Generate advertisement data from the accessory."""
return {
"md": self._valid_name(),
"pv": "1.0",
"pv": HAP_PROTOCOL_SHORT_VERSION,
"id": self.state.mac,
# represents the 'configuration version' of an Accessory.
# Increasing this 'version number' signals iOS devices to
Expand Down
7 changes: 5 additions & 2 deletions pyhap/const.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""This module contains constants used by other modules."""
MAJOR_VERSION = 3
MINOR_VERSION = 6
MAJOR_VERSION = 4
MINOR_VERSION = 0
PATCH_VERSION = 0
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)
Expand Down Expand Up @@ -79,6 +79,9 @@
HAP_REPR_VALUE = "value"
HAP_REPR_VALID_VALUES = "valid-values"

HAP_PROTOCOL_VERSION = "01.01.00"
HAP_PROTOCOL_SHORT_VERSION = "1.1"


# Status codes for underlying HAP calls
class HAP_SERVER_STATUS:
Expand Down
108 changes: 91 additions & 17 deletions tests/test_accessory.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,24 +216,20 @@ def test_cannot_add_bridge_to_bridge(mock_driver):
bridge.add_accessory(bridge2)


def test_to_hap(mock_driver):
def test_to_hap_bridge(mock_driver):
bridge = Bridge(mock_driver, "Test Bridge")
acc = Accessory(mock_driver, "Test Accessory", aid=2)
assert acc.available is True
bridge.add_accessory(acc)

assert bridge.to_HAP() == [
hap = bridge.to_HAP()
assert hap == [
{
"aid": 1,
"services": [
{
"characteristics": [
{
"format": "bool",
"iid": 2,
"perms": ["pw"],
"type": "14",
},
{"format": "bool", "iid": 2, "perms": ["pw"], "type": "14"},
{
"format": "string",
"iid": 3,
Expand Down Expand Up @@ -272,20 +268,28 @@ def test_to_hap(mock_driver):
],
"iid": 1,
"type": "3E",
}
},
{
"characteristics": [
{
"format": "string",
"iid": 9,
"perms": ["pr", "ev"],
"type": "37",
"value": "01.01.00",
}
],
"iid": 8,
"type": "A2",
},
],
},
{
"aid": 2,
"services": [
{
"characteristics": [
{
"format": "bool",
"iid": 2,
"perms": ["pw"],
"type": "14",
},
{"format": "bool", "iid": 2, "perms": ["pw"], "type": "14"},
{
"format": "string",
"iid": 3,
Expand Down Expand Up @@ -328,7 +332,9 @@ def test_to_hap(mock_driver):
],
},
]
assert acc.to_HAP() == {

hap = acc.to_HAP()
assert hap == {
"aid": 2,
"services": [
{
Expand Down Expand Up @@ -381,7 +387,8 @@ def test_to_hap(mock_driver):
],
}
bridge.get_characteristic(2, 2).display_name = "Custom Name Identify"
assert acc.to_HAP() == {
hap = acc.to_HAP()
assert hap == {
"aid": 2,
"services": [
{
Expand Down Expand Up @@ -436,6 +443,73 @@ def test_to_hap(mock_driver):
}


def test_to_hap_standalone(mock_driver):
acc = Accessory(mock_driver, "Test Accessory", aid=1)
assert acc.available is True

hap = acc.to_HAP()
assert hap == {
"aid": 1,
"services": [
{
"characteristics": [
{"format": "bool", "iid": 2, "perms": ["pw"], "type": "14"},
{
"format": "string",
"iid": 3,
"perms": ["pr"],
"type": "20",
"value": "",
},
{
"format": "string",
"iid": 4,
"perms": ["pr"],
"type": "21",
"value": "",
},
{
"format": "string",
"iid": 5,
"perms": ["pr"],
"type": "23",
"value": "Test Accessory",
},
{
"format": "string",
"iid": 6,
"perms": ["pr"],
"type": "30",
"value": "default",
},
{
"format": "string",
"iid": 7,
"perms": ["pr"],
"type": "52",
"value": "",
},
],
"iid": 1,
"type": "3E",
},
{
"characteristics": [
{
"format": "string",
"iid": 9,
"perms": ["pr", "ev"],
"type": "37",
"value": "01.01.00",
}
],
"iid": 8,
"type": "A2",
},
],
}


@pytest.mark.asyncio
async def test_bridge_run_stop():
with patch(
Expand Down
2 changes: 1 addition & 1 deletion tests/test_accessory_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ def test_mdns_service_info(driver):
assert mdns_info.addresses == [b"\xac\x00\x00\x01"]
assert mdns_info.properties == {
"md": "Test Accessory",
"pv": "1.0",
"pv": "1.1",
"id": "00:00:00:00:00:00",
"c#": "2",
"s#": "1",
Expand Down
10 changes: 5 additions & 5 deletions tests/test_hap_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def test_handle_set_handle_set_characteristics_unencrypted(driver):

response = hap_handler.HAPResponse()
handler.response = response
handler.request_body = b'{"characteristics":[{"aid":1,"iid":9,"ev":true}]}'
handler.request_body = b'{"characteristics":[{"aid":1,"iid":10,"ev":true}]}'
handler.handle_set_characteristics()

assert response.status_code == 401
Expand All @@ -319,7 +319,7 @@ def test_handle_set_handle_set_characteristics_encrypted(driver):

response = hap_handler.HAPResponse()
handler.response = response
handler.request_body = b'{"characteristics":[{"aid":1,"iid":9,"ev":true}]}'
handler.request_body = b'{"characteristics":[{"aid":1,"iid":10,"ev":true}]}'
handler.handle_set_characteristics()

assert response.status_code == 204
Expand Down Expand Up @@ -531,7 +531,7 @@ def _mock_failure(*_):

response = hap_handler.HAPResponse()
handler.response = response
handler.request_body = b'{"characteristics":[{"aid":1,"iid":9,"value":1}]}'
handler.request_body = b'{"characteristics":[{"aid":1,"iid":11,"value":1}]}'
handler.handle_set_characteristics()

assert response.status_code == 207
Expand Down Expand Up @@ -593,7 +593,7 @@ def test_handle_get_characteristics_encrypted(driver):

response = hap_handler.HAPResponse()
handler.response = response
handler.path = "/characteristics?id=1.9"
handler.path = "/characteristics?id=1.11"
handler.handle_get_characteristics()

assert response.status_code == 200
Expand All @@ -605,7 +605,7 @@ def test_handle_get_characteristics_encrypted(driver):
with patch.object(acc.iid_manager, "get_obj", side_effect=CharacteristicError):
response = hap_handler.HAPResponse()
handler.response = response
handler.path = "/characteristics?id=1.9"
handler.path = "/characteristics?id=1.10"
handler.handle_get_characteristics()

assert response.status_code == 207
Expand Down

0 comments on commit f1a9784

Please sign in to comment.