snowdd1 / homebridge-knx

KNX platform shim for homebridge
https://github.com/nfarina/homebridge
GNU General Public License v2.0
97 stars 56 forks source link

WindowCovering stays in "opening...." status #184

Open Weppel opened 3 years ago

Weppel commented 3 years ago

I'm trying to add a rolling shutter. Control of the shutter (up/down) works as expected but in HomeKit after tapping it it keeps hanging on "opening...." / "closing...." status. I've tried a lot of combinations but can't seem to figure out why this is happening. Any pointers?

My config:

        {
        "ServiceType": "WindowCovering",
                    "ServiceName": "Kantoor screen",
                    "Characteristics": [
                        {
                            "Type": "CurrentPosition",
                            "Listen": [
                                "4/4/1"
                            ],
                            "Reverse": true,
                            "DPT": "DPT5"
                        },
                        {
                            "Type": "TargetPosition",
                            "Set": [
                                "4/1/1"
                            ],
                            "Reverse": true,
                            "DPT": "DPT1"
                        },
                        {
                            "Type": "PositionState"
                        }
                    ],
                    "KNXReadRequests": [
                        "4/1/1"
                    ]
                },

Corresponding GA's: image In this case GA 4/4/1 is configured to be in range 0-100.

marcobastianon commented 3 years ago

i not remember if my case was the same, but i solved using handler..

first i've use the same code @snowdd1 suggest on: https://github.com/snowdd1/homebridge-knx/blob/plugin-2.0/knx_config.json.md using ""Handler": "GiraJalousieActuator","

later i've create a new hendler using "GiraJalousieActuator" fo manage my ABB shutter actuator..

snowdd1 commented 3 years ago

Did you see that your 4/1/1 is a one-bit type? That won't work with the set as expected because that one needs a percentage type (one byte)

Weppel commented 3 years ago

@marcobastianon Thanks for the feedback, I'll look into this!

@snowdd1 Yep, figured that out after fiddling around with it some more.

IckHabDieFaxenDick commented 3 years ago

Had the same problem and was able to figure it out, maybe portions of this can be adopted in the WindowCoveringTilt.js script. Works now like a charm (ABB - JAS 8.230.1M):

For some reason in homekit the status for some windows kept hanging in "opening...." / "closing...." status. After noodling around with all possible commands via app and physical buttons i found the reasons and concluded this modifications:

Modification 1: When sending a single move by pressing a physical button "short" (step-stop), the position state changes, causing "opening...." / "closing...." status, but in this case only a "TargetHorizontalTiltAngle" is triggered with the shutter move (the tilt changes, but not the position). So in "TargetHorizontalTiltAngle" section it is necessary to additionally set TargetPosition to CurrentPosition.

Modification 2: In the "TargetPosition" sections position state was "completed" with value 2 (maybe not both senders (onHKValueChange,onKNXValueChange) necessary, but works).

Full script:

Preliminary note: It's the original WindowCoveringTilt.js without comments and without NinetyDegree option (because i use the NinetyDegree == true branch). Instead I added a local constant "Tilt" to distinguish between shutters (Jalousie) and rolling shutters (Rollladen), set to true for shutters and false for rolling shutters; otherwise homebridge dumps with SIGTERM when the "TargetHorizontalTiltAngle" part is send to perform a full close when shutters are at 100% (rolling shutters don't have tilt).

'use strict';

var HandlerPattern = require('./handlerpattern.js');
var log = require('debug')('WindowCovering');

class WindowCovering extends HandlerPattern {

    onKNXValueChange(field, oldValue, knxValue) {
        var newValue;
        console.log('INFO: onKNXValueChange(' + field + ", "+ oldValue + ", "+ knxValue+ ")");

        if (field === "TargetPosition") {
            newValue = 100 - knxValue*100 / 255;
            if (newValue > this.myAPI.getValue("CurrentPosition")) {
                this.myAPI.setValue("PositionState", 1);
            } else if (newValue < this.myAPI.getValue("CurrentPosition")){
                this.myAPI.setValue("PositionState", 0);
            } else {
                this.myAPI.setValue("PositionState", 2);
            }
            this.myAPI.setValue("TargetPosition", newValue);

        } else if (field === "CurrentPosition") {
            newValue = 100 - knxValue*100 / 255;
            this.myAPI.setValue("CurrentPosition", newValue);
            this.myAPI.setValue("TargetPosition", newValue);
            this.myAPI.setValue("PositionState", 2);

        } else if (field==="ShutterMove") {
            switch (knxValue) {
                case 0:
                    this.myAPI.setValue("TargetPosition", 100);
                    this.myAPI.setValue("PositionState", 0);
                    break;
                case 1:
                    this.myAPI.setValue("TargetPosition", 0);
                    this.myAPI.setValue("PositionState", 1);
                    break;
            }

        } else if (field === "TargetHorizontalTiltAngle") {
            newValue = 0 + knxValue/255 * 90;
            this.myAPI.setValue("TargetHorizontalTiltAngle", newValue);
            this.myAPI.setValue("TargetPosition", this.myAPI.getValue("CurrentPosition"));

        } else if (field==="CurrentHorizontalTiltAngle") {
            newValue = 0 + knxValue/255 * 90;
            this.myAPI.setValue("CurrentHorizontalTiltAngle", newValue);
            this.myAPI.setValue("TargetHorizontalTiltAngle", newValue);
        }
    }

    onHKValueChange(field, oldValue, newValue) {

        if (field === "TargetPosition") {
            console.log('INFO: onHKValueChange(' + field + ", "+ oldValue + ", "+ newValue + ")");

            if (newValue > this.myAPI.getValue("CurrentPosition") {
                this.myAPI.setValue("PositionState", 1);
            } else if (newValue < this.myAPI.getValue("CurrentPosition"){
                this.myAPI.setValue("PositionState", 0);
            } else {
                this.myAPI.setValue("PositionState", 2);
            }
            var knxValue = (255 - newValue*255 / 100);
            console.log('INFO: onHKValueChange after calc ('  + knxValue+ ")");
            this.myAPI.knxWrite("TargetPosition", knxValue, "DPT5");
                    var tilt = this.myAPI.getLocalConstant("Tilt");
            if (newValue === 0 && tilt === true){
                this.myAPI.setValue("TargetHorizontalTiltAngle", 90);
                this.onHKValueChange("TargetHorizontalTiltAngle", 0, 90);
            }

        } else if (field==="TargetHorizontalTiltAngle") {
            console.log('INFO: onHKValueChange(' + field + ", "+ oldValue + ", "+ newValue + ")");
            let knxValue;
            if (newValue > 0){
                knxValue = newValue/90 * 255;
            } else {
                knxValue = 0;
            }
            console.log('INFO: onHKValueChange after calc ('  + knxValue+ ")");
            this.myAPI.knxWrite("TargetHorizontalTiltAngle", knxValue, "DPT5");
        }
    }
}
module.exports= WindowCovering;