ikalchev / HAP-python

A python implementation of the HomeKit Accessory Protocol (HAP)
Other
619 stars 119 forks source link

Fake WindowCovering accessory / get the 'PositionState' value #164

Open lboue opened 6 years ago

lboue commented 6 years ago

Hello,

I am trying to implement a fake WindowCovering accessory (shutter) with HAP-python. I already have tested this with a copy of the busy_home.py file. You can check my shutter.py testing file.

I am getting "TargetPosition" value on the debug log. But on the iOS HomeKit app, when I change the target value.

Could you tell me how to get the 'PositionState' value on the HAP-python console?

$ python3 shutter.py 
[accessory_driver] Loading Accessory state from `shutter.state`
[accessory_driver] Starting the event loop
[accessory_driver] Starting accessory Bridge on address 192.168.1.91, port 51800.
[hap_server] Got connection with ('192.168.1.5', 50943).
[hap_server] 192.168.1.5 - "POST /pair-verify HTTP/1.1" 200 -
[hap_server] 192.168.1.5 - "POST /pair-verify HTTP/1.1" 200 -
[hap_server] 192.168.1.5 - "GET /accessories HTTP/1.1" 200 -
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[hap_server] 192.168.1.5 - "GET /characteristics?id=4.9,4.10,3.9,3.10,3.11,2.10,2.9,2.11 HTTP/1.1" 207 -
[shutter] WindowCovering TargetPosition value: 100
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[shutter] WindowCovering TargetPosition value: 0
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[shutter] WindowCovering TargetPosition value: 100
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[shutter] WindowCovering TargetPosition value: 0
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[shutter] WindowCovering TargetPosition value: 100
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[shutter] WindowCovering TargetPosition value: 0
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -

Here is my code from the file:

        # Add the fan service. Also add optional characteristics to it.
        serv_cover = self.add_preload_service(
            'WindowCovering', chars=['CurrentPosition', 'TargetPosition', 'PositionState'])

        self.char_rotation_speed = serv_cover.configure_char(
            'TargetPosition', setter_callback=self.set_target_position)

        self.char_state = serv_cover.configure_char(
            'PositionState', setter_callback=self.set_position_state)

        self.char_rotation_direction = serv_cover.configure_char(
            'CurrentPosition', setter_callback=self.set_current_position)

    '''
    def change_state(self, value):
        logging.info("WindowCovering CurrentPosition value: %s", value)
        self.get_service('WindowCovering')\
            .get_characteristic('CurrentPosition')\
            .set_value(value)
    '''
    def set_target_position(self, value):
        logging.info("WindowCovering TargetPosition value: %s", value)
        self.get_service('WindowCovering')\
            .get_characteristic('TargetPosition')\
            .set_value(value)

    # The value property of PositionState must be one of the following:
    # Characteristic.PositionState.DECREASING = 0;
    # Characteristic.PositionState.INCREASING = 1;
    # Characteristic.PositionState.STOPPED = 2; 
    def set_position_state(self, value):
        logging.info("WindowCovering PositionState value: %s", value)
        self.get_service('PositionState')\
            .get_characteristic('PositionState')\
            .set_value(value)

I would appreciate some help. When it works I will make a PR to merge this in the main repo.

Regards, Ludovic

cdce8p commented 6 years ago

The way HomeKit handles this is a bit tricky. Maybe two examples help:

Case 1, Cover closed, want to open

  1. HomeKit will update TargetPosition to 100 (start was 0)
  2. The accessory needs to set CurrentPosition to 100 (start was 0)
  3. And PositionState to 2 (for stopped)

Case 2, Cover open, want to close

  1. HomeKit will update TargetPosition to 0
  2. The accessory needs to set CurrentPosition to 0
  3. And PositionState to 2 (for stopped)

To summarize, HomeKit will only update the TargetPosition char, so that's the only one you need a setter for. Setting the CurrentPostion attribute is required for the accessory, since HomeKit uses the difference to calculate if the cover is opening, closing or stopped. I mentioned PositionState as well, but as far as I've noticed, it doesn't have any influence what so ever. Best to set it to stopped during init and leave it there:

serv_cover.configure_char('PositionState', value=2)
lboue commented 6 years ago

Thanks, It seems to work with that code:

    def set_target_position(self, value):
        logging.info("WindowCovering TargetPosition value: %s", value)
        self.get_service('WindowCovering')\
            .get_characteristic('TargetPosition')\
            .set_value(value)

        time.sleep(2)   # Delays for 2 seconds. You can also use a float value.

        logging.info("WindowCovering CurrentPosition value: %s", value)
        self.get_service('WindowCovering')\
            .get_characteristic('CurrentPosition')\
            .set_value(value)

When I set open at 0% (closed):

shutter] WindowCovering TargetPosition value: 0
[shutter] WindowCovering CurrentPosition value: 0
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -

When I set open at 20%:

[shutter] WindowCovering CurrentPosition value: 26
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[shutter] WindowCovering TargetPosition value: 24
[shutter] WindowCovering CurrentPosition value: 24
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[shutter] WindowCovering TargetPosition value: 22
[shutter] WindowCovering CurrentPosition value: 22
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[shutter] WindowCovering TargetPosition value: 21
[shutter] WindowCovering CurrentPosition value: 21
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -
[shutter] WindowCovering TargetPosition value: 20
[shutter] WindowCovering CurrentPosition value: 20
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -

When I set open at 100% (full open):

[shutter] WindowCovering TargetPosition value: 100
[shutter] WindowCovering CurrentPosition value: 100
[hap_server] 192.168.1.5 - "PUT /characteristics HTTP/1.1" 204 -

You can check the file new shutter.py file version. Can I make a PR to merge this in the main repo?

Regards, Ludovic