Homekit shutter/shade integration glitch

Hi all,

anybody else experiencing a glitch when controlling shutters/shades through HomeKit?

The angle of the slats is persisting while opening/closing, making the shutters to lower themselves for a little (to achieve the angle) after they are completely opened.

Searched everywhere: HomeKit, KNX (as this is my HW shutter controller), HA topics, …
Shutter control works fine through HA, so it must be the HomeKit communication/interpretation.

Thanks!

I have since learned this is a feature, not a bug of the HomeKit integration: it has a persisting tilt angle built in.

I have been trying to work around this with cover template and scripts. This is how I planned it so far:

  1. I built a cover template with custom open_cover and close_cover actions. All others can remain the same.
cover:
  - platform: template
    covers:
      dnevna_template:
        device_class: blind
        friendly_name: "Dnevna template"
        position_template: "{{ states('sensor.dnevna_pozicija') }}"
        open_cover:
          service: script.tilt_after_opening_dnevna
        close_cover:
          service: script.tilt_after_closing_dnevna
        stop_cover:
          service: cover.stop_cover
          target:
            entity_id: cover.zaluzije_dnevna
        set_cover_position:
          service: cover.set_cover_position
          target:
            entity_id: cover.zaluzije_dnevna
        set_cover_tilt_position:
          service: cover.set_cover_tilt_position
          target:
            entity_id: cover.zaluzije_dnevna
  1. I also have a binary sensor for the cover, to figure out the current position of the blinds
    - name: "Dnevna pozicija"
      state_address: "3/0/206"

this refers to the KNX group address of that same cover

      position_state_address: "3/0/206"
  1. both custom actions are essentially a sequence of:
    3.1 first opening/closing the cover
    3.2 then tilting to open/closed tilt angle
tilt_after_opening_dnevna:
  sequence:
    - alias: "First OPEN the cover"
      service: cover.open_cover
      target:
        entity_id: cover.zaluzije_dnevna
    - alias: "Then change tilt angle acoringly for the cover to stay opened"
      service: cover.set_cover_tilt_position
      target:
        entity_id: cover.zaluzije_dnevna
      data:
        tilt: 0

tilt_after_closing_dnevna:
  sequence:
    - alias: "First CLOSE the cover"
      service: cover.close_cover
      target:
        entity_id: cover.zaluzije_dnevna
    - alias: "Then change tilt angle acoringly for the cover to stay closed"
      service: cover.set_cover_tilt_position
      target:
        entity_id: cover.zaluzije_dnevna
      data:
        tilt: 100

What am I missing/doing wrong? Any help would be greatly appreciated, as I’m pretty new to the more advance sides of HA.

Thanks!

Hi all! I just can’t make this work - any input would be greatly appreciated. Anyone?

I have now two scripts to override the persisting slat tilting (keeping the same angle from before changing the cover position.). This persistence is only counterproductive in the two extreme positions.

After thoroughly searching the forums and documentation, I have ended up with two scripts that get activated by a template cover: Essentially opening/closing the cover and then tilting the slats to completely open or closed.

But even the two scripts malfunction (before even integrating them in a template cover as a complete functionality).

These are the two scripts:

tilt_after_opening_dnevna:
  sequence:
    - alias: "First OPEN the cover"
      service: cover.open_cover
      target:
        entity_id: cover.zaluzije_dnevna
    - alias: "Wait until cover is opened"
      wait_template: "{{ is_state('cover.zaluzije_dnevna', 0) }}"
    - alias: "Then change tilt angle acoringly for the cover to stay opened"
      service: cover.set_cover_tilt_position
      target:
        entity_id: cover.zaluzije_dnevna
      data:
        tilt_position: 0

tilt_after_closing_dnevna:
  sequence:
    - alias: "First CLOSE the cover"
      service: cover.close_cover
      target:
        entity_id: cover.zaluzije_dnevna
    - alias: "Wait until cover is closed"
       wait_template: "{{ is_state('cover.zaluzije_dnevna', 100) }}"
    - alias: "Then change tilt angle acoringly for the cover to stay closed"
      service: cover.set_cover_tilt_position
      target:
        entity_id: cover.zaluzije_dnevna
      data:
        tilt_position: 100

Any help would be greatly appreciated. Cheers

Hi @lsid,

I am observing a similar behavior and wonder whether You were able to make it work?

I would of course prefer HA to have an option / setting for covers like „Disable restore tilt“.

Best regards

Do you have any source for that?

Afaik HK always only sends a new absolute position in %. So whenever you eg. say “close cover” HK will internally convert this to a cover.set_cover_position: 0 service call (not a cover.close_cover call). It does not care what the receiving integration does with that information.
So if the receiving thing restores its tilt, that’s not HK’s concern anymore.

So just create an automation listening for cover.set_cover_position: 0, extract the triggers entity_id and call an action cover.set_cover_tilt_position: 0 to that entity_id. Same for 100%. Ignore values between, as you probably want to persist tilt then.
Or see if there is any setting in the receiving device to not persist tilt when moving position.

Would this not be easily reproduced by having a KNX sensor (such as a push button) sent the absolut value? I didn’t yet try, but will the week to come hopefully.

Sure, if your receiving entity is Knx you can just try it from “Developer Tools → Services”.

So, did some testing: when using HomeKit as well as when using Home assistant directly the behavior is the exact same, the tilting-capable cover restores the previously set tilting angle.

As mentioned earlier, I’d appreciate a configurable solution in the sense of, when closing the covers (read: the covers cover the window) „disable restore of tilt position“. In all consequence, the window would be covered totally and with no gap.

Since I’m changing from Shelly 2.5 to KNX Blind actuator (MDT Jalousieaktor JAL-B1UP.02), I am still in doubt: Is it the actor, is it Home assistant, is it something in between… For now, I believe the actuator is out of scope. (Shellys don’t support tilting)

Why is there any doubt? Just look at a Group Monitor - HA will send a new position value. End of story.
The rest is the actuator acting according to its application.

It‘s both doubt and hope.

Hope because, I don’t want to ditch the dozen of actuators I‘ve bought as well as the time spent getting KNX cable into the boxes. Which in principle should be superior in a lot of ways to the Shellys I would be replacing.

But, restoring of tilt upon closing of the blinds would be a knock out for usability and therefore for the whole move to KNX blind actuators.

And that‘s for the doubt, I don’t seem to get the value of this restoring as the default (and non-configurable) behavior. This is so counterintuitive. Imagine explaining to the people of Your household that in order to close the blinds not only to You have to set to 0%, but also walk to the push button and adjust the angle to be fully closed.

I’m not playing blame game here, I’m sincerely trying to get an understanding where there’s a disconnect and try to get that sorted out.

So, I have gained some better understanding here after reaching product support of MDT (for the blinds actuators named JAL-B1UP01.02):

  • The actuator can be configured to not restore tilt, when the closed end position is reached
  • The actuator will restore the slat angle / tilt when receiving absolute position commands by default
  • In order to not restore the tilt, the actuator needs to receive the tilt position too
  • The default behavior for restoring tilt cannot be configured
  • HomeKit sends absolute values of 0% or 100% when an user requests to fully open or close the blinds (other Group Addresses seem to be ignored)

Because of other reasons I need and want to stay with this actuator. But am now seeking for a way out of my dilemma. I would want the blinds to not restore the angle after moving - irrespective if an end position is reached or not.

Options:
A) Is it possible to define a (template) cover that upon receiving absolute position information sets the tilt to 0% or 100% depending on the direction the blinds are going?
B) Is it possible to somehow force the use of the move long group addresses, when 0% or 100% calls are being made? (And as a simplification only for those)
C) Other options?

=> Ok, I have re-read this thread and see @farmio‘s suggestion. I will see what I can do. Thanks!

Hi @dubtec,

First of all, I will try the workaround that @farmio is suggesting - thanks for that!

But also to clarify on your previous followups:

  • I also have the MDT actuator
  • If I close the blinds through HA panel directly, this persisting tilt does not happen. According to Group Monitor, I suspect this is because HA is using the move_long_address: to close the blinds, and HK is using the position_address: to move the blinds
  • I still can’t understand why an interaction HK → HA → KNX would add this “tilt” action approximately 8s after the move occurs if only position is sent from HK → HA → KNX? For me, the expected behaviour would be to stay in that position. I understand tilt as a subsequent action AFTER reaching the shade position.

I will keep you updated. Farmio’s suggestion would be acceptable in my scenario.

This is the output when using HK

11:15:58.533 Outgoing 1.1.12 3/0/106 Group ValueWrite Oxff
11:15:58.279 Outgoing 1.1.12 3/0/106 Group ValueWrite Oxff
11:15:58.039 Outgoing 1.1.12 3/0/106 Group ValueWrite Oxff
11:15:57.766 Outgoing 1.1.12 3/0/106 Group ValueWrite Oxbf
11:15:57.532 Outgoing 1.1.12 3/0/106 Group ValueWrite OхO3

And this is the output when using HA

11:24:13.911 Outgoing 1.1.12 3/0/6 GroupValueWrite 1

Hi @lsid,

thank You very much for the update and clarification. I second Your observations.

My understanding of the issue is that the MDT actuators by design restore tilt when receiving only the cover position. Which makes it more of a non-issue or rather a feature than a bug. Admittedly, this feature can come in handy, when You want to have different positions of a cover during the day, but keep the tilt constant at all times. And yes, the behavior can be controlled by using the right group address. Therefore, Your analysis is right on point.

I, unfortunately didn’t yet try the approach @farmio suggested. Even though I do understand it, I struggle with the syntax for the trigger.id within the automation. Once I have something that can be shared, I will do so.

Okay, so I came up with this, but it is still not working as planned. Any thoughts, anyone?

I wanted to define the automation in a way that is not limited to a single entity_id. It should extract the ID from that call and then act on that same ID.

Automation should only influence 0% (tilt 0%) and 100% (tilt 100%) positions. This way, it remains wholly closed (slats down) and completely open (slats up) in extreme positions.

- id: Cover Position Automation
  alias: Cover Position Automation
  trigger:
    - platform: event
      event_type: call_service
      event_data:
        domain: cover
        service: set_cover_position
  condition:
    condition: template
    value_template: "{{ trigger.event.data.position in ['0', '100'] }}"
  action:
    - choose:
        - conditions: "{{ trigger.event.data.position == ''0'' }}"
          sequence:
            - service: cover.set_cover_tilt_position
              data:
                entity_id: "{{ trigger.event.data.entity_id }}"
                tilt_position: 0
        - conditions: "{{ trigger.event.data.position == ''100'' }}"
          sequence:
            - service: cover.set_cover_position
              data:
                entity_id: "{{ trigger.event.data.entity_id }}"
                position: 100

Any help would be greatly appreciated.

@lsid Thanks for sharing. What exactly isn’t working? Are You sure that the event type is call_service? If I remember correctly the event type (and / or contents of the event were related to HomeKit).

I’ve been testing this too. The automation is not getting triggered (at all). So, I believe the criteria isn’t correct.

@lsid Were You able to trigger Your automation?

So, I did a bit of an analysis as to why this isn’t working. Besides some formalities, the reference to the position in the JSON object was not correct. There actually is a service_data that has to be reflected. Without further ado, I paste the corrected code piece, which worked for me at least for when moving covers down.

@lsid Not sure whether that’s still relevant to you, but please feel free to check it out on your end.

alias: Cover Position Automation
trigger:
  - platform: event
    event_type: call_service
    event_data:
      domain: cover
      service: set_cover_position
condition:
  - condition: template
    value_template: "{{ trigger.event.data.service_data.position in [0, 100] }}"
action:
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ trigger.event.data.service_data.position == 0 }}"
        sequence:
          - service: cover.set_cover_tilt_position
            data:
              entity_id: "{{ trigger.event.data.service_data.entity_id }}"
              tilt_position: 0
      - conditions:
          - condition: template
            value_template: "{{ trigger.event.data.service_data.position == 100 }}"
        sequence:
          - service: cover.set_cover_position
            data:
              entity_id: "{{ trigger.event.data.service_data.entity_id }}"
              position: 100
1 Like

I think the called service here should be cover.set_cover_tilt_position like in the first condition sequence.

You could also try something like

- service: cover.set_cover_tilt_position
  data:
    entity_id: "{{ trigger.event.data.service_data.entity_id }}"
    tilt_position: "{{ trigger.event.data.service_data.position }}"

without any choose since position in [0, 100] is already checked in the automation condition.

2 Likes

Guys, that’s why I love HA and this community, thank you so much :blush:
With your help, I’ve got it working, I’ve tested it and this is, what is working for me to avoid this little “endmove” HomeKit is doing at the upper and lower positions.

alias: Cover Position Automation
trigger:
  - platform: event
    event_type: call_service
    event_data:
      domain: cover
      service: set_cover_position
condition:
  - condition: template
    value_template: "{{ trigger.event.data.service_data.position in [0, 100] }}"
action:
  - service: cover.set_cover_tilt_position
    data:
      entity_id: "{{ trigger.event.data.service_data.entity_id }}"
      tilt_position: "{{ trigger.event.data.service_data.position }}"
mode: single
2 Likes

Thank you to you all, works for me too now!

There are some differences using the visual editor, where @dubtec’s solution was closer to mine, but just doing it in yaml as @farmio suggested is just that bit cleaner. @Damageplan’s code didn’t work for me (because of the last line: "mode: single "?)

So, just to make it easier for anyone else, below I pasted code that works with MDT controller (KNX) and HomeKit frontend.

alias: Cover Position Automation
trigger:
  - platform: event
    event_type: call_service
    event_data:
      domain: cover
      service: set_cover_position
condition:
  - condition: template
    value_template: "{{ trigger.event.data.service_data.position in [0, 100] }}"
action:
  - service: cover.set_cover_tilt_position
    data:
      entity_id: "{{ trigger.event.data.service_data.entity_id }}"
      tilt_position: "{{ trigger.event.data.service_data.position }}"