Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 13 additions & 39 deletions pyhap/accessory.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,14 @@
from pyqrcode import QRCode

from pyhap import util
from pyhap.const import (
STANDALONE_AID, HAP_REPR_AID, HAP_REPR_IID, HAP_REPR_SERVICES,
HAP_REPR_VALUE, CATEGORY_OTHER, CATEGORY_BRIDGE)
from pyhap.loader import get_serv_loader

logger = logging.getLogger(__name__)


class Category:
"""Known category values.

Category is a hint to iOS clients about what "type" of Accessory this represents,
for UI only.
"""
OTHER = 1
BRIDGE = 2
FAN = 3
GARAGE_DOOR_OPENER = 4
LIGHTBULB = 5
DOOR_LOCK = 6
OUTLET = 7
SWITCH = 8
THERMOSTAT = 9
SENSOR = 10
ALARM_SYSTEM = 11
DOOR = 12
WINDOW = 13
WINDOW_COVERING = 14
PROGRAMMABLE_SWITCH = 15
RANGE_EXTENDER = 16
CAMERA = 17


# Standalone accessory ID (i.e. not bridged)
STANDALONE_AID = 1


class IIDManager(object):
"""Maintains a mapping between Service/Characteristic objects and IIDs."""

Expand Down Expand Up @@ -110,7 +84,7 @@ class Accessory(object):
Use this to set your HAP services.
"""

category = Category.OTHER
category = CATEGORY_OTHER

@classmethod
def create(cls, display_name, pincode, aid=STANDALONE_AID):
Expand Down Expand Up @@ -319,7 +293,7 @@ def xhm_uri(self):
value_low |= 1 << 28
struct.pack_into('>L', buffer, 4, value_low)

if self.category == Category.OTHER:
if self.category == CATEGORY_OTHER:
buffer[4] = buffer[4] | 1 << 7

value_high = self.category >> 1
Expand Down Expand Up @@ -372,8 +346,8 @@ def to_HAP(self):
:rtype: dict
"""
return {
"aid": self.aid,
"services": [s.to_HAP() for s in self.services],
HAP_REPR_AID: self.aid,
HAP_REPR_SERVICES: [s.to_HAP() for s in self.services],
}

def setup_message(self):
Expand Down Expand Up @@ -435,9 +409,9 @@ def publish(self, value, sender):
return

acc_data = {
"aid": self.aid,
"iid": self.iid_manager.get_iid(sender),
"value": value,
HAP_REPR_AID: self.aid,
HAP_REPR_IID: self.iid_manager.get_iid(sender),
HAP_REPR_VALUE: value,
}
self.broker.publish(acc_data)

Expand Down Expand Up @@ -480,7 +454,7 @@ class Bridge(AsyncAccessory):
A `Bridge` can have multiple `Accessories`.
"""

category = Category.BRIDGE
category = CATEGORY_BRIDGE

def __init__(self, display_name, mac=None, pincode=None,
iid_manager=None, setup_id=None):
Expand Down Expand Up @@ -513,11 +487,11 @@ def add_accessory(self, acc):
:param acc: The ``Accessory`` to be bridged.
:type acc: Accessory

:raise ValueError: When the given ``Accessory`` is of category ``Category.BRIDGE``
:raise ValueError: When the given ``Accessory`` is of category ``CATEGORY_BRIDGE``
or if the AID of the ``Accessory`` clashes with another ``Accessory`` already in this
``Bridge``.
"""
if acc.category == Category.BRIDGE:
if acc.category == CATEGORY_BRIDGE:
raise ValueError("Bridges cannot be bridged")

if acc.aid is None:
Expand Down
50 changes: 26 additions & 24 deletions pyhap/accessory_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,19 @@
from pyhap import util
from pyhap.accessory import AsyncAccessory, get_topic, STANDALONE_AID
from pyhap.characteristic import CharacteristicError
from pyhap.const import (
STANDALONE_AID, HAP_PERMISSION_NOTIFY, HAP_REPR_ACCS, HAP_REPR_AID,
HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_STATUS, HAP_REPR_VALUE)
from pyhap.params import get_srp_context
from pyhap.hsrp import Server as SrpServer
from pyhap.hap_server import HAPServer
from pyhap.encoder import AccessoryEncoder

logger = logging.getLogger(__name__)

CHAR_STAT_OK = 0
SERVICE_COMMUNICATION_FAILURE = -70402


class AccessoryMDNSServiceInfo(ServiceInfo):
"""A mDNS service info representation of an accessory."""
Expand Down Expand Up @@ -91,11 +97,6 @@ def _get_advert_data(self):
return adv_data


class HAP_CONSTANTS:
CHAR_STAT_OK = 0
SERVICE_COMMUNICATION_FAILURE = -70402


class AccessoryDriver(object):
"""
An AccessoryDriver mediates between incoming requests from the HAPServer and
Expand Down Expand Up @@ -208,11 +209,11 @@ def publish(self, data):
"iid".
:type data: dict
"""
topic = get_topic(data["aid"], data["iid"])
topic = get_topic(data[HAP_REPR_AID], data[HAP_REPR_IID])
if topic not in self.topics:
return

data = {"characteristics": [data]}
data = {HAP_REPR_CHARS: [data]}
bytedata = json.dumps(data).encode()
self.event_queue.put((topic, bytedata))

Expand Down Expand Up @@ -356,7 +357,7 @@ def get_accessories(self):
hap_rep = self.accessory.to_HAP()
if not isinstance(hap_rep, list):
hap_rep = [hap_rep, ]
return {"accessories": hap_rep}
return {HAP_REPR_ACCS: hap_rep}

def get_characteristics(self, char_ids):
"""Returns values for the required characteristics.
Expand All @@ -381,17 +382,17 @@ def get_characteristics(self, char_ids):
chars = []
for id in char_ids:
aid, iid = (int(i) for i in id.split("."))
rep = {"aid": aid, "iid": iid}
rep = {HAP_REPR_AID: aid, HAP_REPR_IID: iid}
char = self.accessory.get_characteristic(aid, iid)
try:
rep["value"] = char.value
rep["status"] = HAP_CONSTANTS.CHAR_STAT_OK
rep[HAP_REPR_VALUE] = char.value
rep[HAP_REPR_STATUS] = CHAR_STAT_OK
except CharacteristicError:
logger.error("Error getting value for characteristic %s.", id)
rep["status"] = HAP_CONSTANTS.SERVICE_COMMUNICATION_FAILURE
rep[HAP_REPR_STATUS] = SERVICE_COMMUNICATION_FAILURE

chars.append(rep)
return {"characteristics": chars}
return {HAP_REPR_CHARS: chars}

def set_characteristics(self, chars_query, client_addr):
"""Called from ``HAPServerHandler`` when iOS configures the characteristics.
Expand Down Expand Up @@ -425,29 +426,30 @@ def set_characteristics(self, chars_query, client_addr):

:rtype: dict
"""
chars_query = chars_query["characteristics"]
chars_query = chars_query[HAP_REPR_CHARS]
chars_response = []
for cq in chars_query:
aid, iid = cq["aid"], cq["iid"]
aid, iid = cq[HAP_REPR_AID], cq[HAP_REPR_IID]
char = self.accessory.get_characteristic(aid, iid)

if "ev" in cq:
if HAP_PERMISSION_NOTIFY in cq:
char_topic = get_topic(aid, iid)
self.subscribe_client_topic(client_addr, char_topic, cq["ev"])
self.subscribe_client_topic(
client_addr, char_topic, cq[HAP_PERMISSION_NOTIFY])

response = {
"aid": aid,
"iid": iid,
"status": HAP_CONSTANTS.CHAR_STAT_OK,
HAP_REPR_AID: aid,
HAP_REPR_IID: iid,
HAP_REPR_STATUS: CHAR_STAT_OK,
}
if "value" in cq:
if HAP_REPR_VALUE in cq:
# TODO: status needs to be based on success of set_value
char.client_update_value(cq["value"])
char.client_update_value(cq[HAP_REPR_VALUE])
if "r" in cq:
response["value"] = char.value
response[HAP_REPR_VALUE] = char.value

chars_response.append(response)
return {"characteristics": chars_response}
return {HAP_REPR_CHARS: chars_response}

def start(self):
"""Starts the accessory.
Expand Down
Loading