dxdc / homebridge-blinds

:sunrise: Homebridge Plugin to control my blinds over HTTP
https://www.npmjs.com/package/homebridge-blinds
ISC License
54 stars 25 forks source link

Integrate native Tasmota support #29

Closed Zer0x00 closed 4 years ago

Zer0x00 commented 4 years ago

Hey, first of all: thank you for your very nice plugin!

Would it be possible for you to implement this plugin "the tasmota way"? Could support you if it is necessary with all the details.

Main differences between it and your plugin:

Thank you.

Kind Regards

dxdc commented 4 years ago

@buenyamin-olgun Please provide details of web URL's and responses, and will evaluate.

Wondering if this would be a better fit for you? https://github.com/Nicnl/homebridge-minimal-http-blinds#readme

Zer0x00 commented 4 years ago

I can't use this because I don't know how to get the current_state out of the firmware.

I saw that you use a cache in your project, thought you could make use of that.

Here the details:

Always GET requests.

Get current position (where current position 79): http://<ip>/cm?cmnd=ShutterPosition

Response: {"ShutterPosition1":79} Status Code: 200 OK

Set target position to 75%: http://<ip>/cm?cmnd=ShutterPosition 75

Response: {"POWER2":"ON","ShutterPosition1":75} Status Code: 200 OK

dxdc commented 4 years ago

I can't use this because I don't know how to get the current_state out of the firmware.

I would just have it set to 2. From my understanding of blinds, in fact, this is not a requirement at all. Just setting TargetPosition will define the "state". If Target > Current, or Target < Current, it will define opening/closing etc.

Always GET requests.

Have you tried the following?

This should get you close. If that part is working, let me know I'd be willing to look into it, but it involves some more processing. We also need to consider whether the homekit values of 0-100 mirror the tasmota values of 0-100 for blind position, and if not, how to translate them in a simple and configurable way.

Feel free to submit a PR as well :)

Zer0x00 commented 4 years ago

I would just have it set to 2. From my understanding of blinds, in fact, this is not a requirement at all. Just setting TargetPosition will define the "state". If Target > Current, or Target < Current, it will define opening/closing etc.

2 would mean STOPPED, right? I'm trying to implement it as accurate as possible, so if I set it to 2 there's no way to determine if it is currently opening/closing.

Have you tried the following?

  • Set up_url to http://<ip>/cm?cmnd=ShutterPosition 0
  • Set down_url to http://<ip>/cm?cmnd=ShutterPosition 100 (maybe 0/100 are different in your case)

This works so far.

  • You can also use position_url, but it would have to be run through a secondary address to return the exact value, not a JSON variant.

I've tried before to replace lines 113-114 with

var value = null;
value = Object.values(JSON.parse(body));

const pos = value;

... but that didn't work out.

This should get you close. If that part is working, let me know I'd be willing to look into it, but it involves some more processing. We also need to consider whether the homekit values of 0-100 mirror the tasmota values of 0-100 for blind position, and if not, how to translate them in a simple and configurable way.

Yes, that part works. Also the mapping from 0-100 to homekit values seems to work fine.

Here's my used config:

        {
            "accessory": "BlindsHTTP",
            "name": "Window",
            "up_url": "http://192.168.0.94/cm?cmnd=ShutterPosition%20100",
            "down_url": "http://192.168.0.94/cm?cmnd=ShutterPosition%200",
            "stop_url": "http://192.168.0.94/cm?cmnd=Power3%20ON",
            "http_method": {
                "method": "GET"
            },
            "success_codes": [
                200
            ],
            "max_http_attempts": 5,
            "retry_delay": 2000,
            "use_same_url_for_stop": false,
            "show_stop_button": true,
            "show_toggle_button": false,
            "motion_time": 20000,
            "response_lag": 0,
            "trigger_stop_at_boundaries": false,
            "verbose": false
        }

Maybe a bit off-topic but I've seen that it spams the hardware with http requests & the console log with:

[...]
[10.2.2020, 23:57:46] [Window] End Move up (to 73%)
[10.2.2020, 23:57:46] [Window] End Move down (to 73%)
[10.2.2020, 23:57:46] [Window] End Move up (to 73%)
[10.2.2020, 23:57:47] [Window] End Move down (to 73%)
[10.2.2020, 23:57:47] [Window] End Move up (to 73%)
[10.2.2020, 23:57:47] [Window] End Move down (to 73%)
[10.2.2020, 23:57:47] [Window] End Move up (to 73%)
[10.2.2020, 23:57:47] [Window] End Move down (to 73%)
[10.2.2020, 23:57:47] [Window] End Move up (to 73%)
[10.2.2020, 23:57:47] [Window] End Move down (to 73%)
[10.2.2020, 23:57:47] [Window] End Move up (to 73%)
[10.2.2020, 23:57:47] [Window] End Move down (to 73%)
[10.2.2020, 23:57:47] [Window] End Move up (to 73%)
[10.2.2020, 23:57:48] [Window] End Move down (to 73%)
[...]

Feel free to submit a PR as well :)

Like you see above I have a basic knowledge of coding but I'm too unexperienced with HomeKit, homebridge and Node.js in general to realize such a thing on my own :/

dxdc commented 4 years ago

2 would mean STOPPED, right?

Yes, but the code for this plugin also just indicates that it is stopped at certain points. There is no need for this really - HomeKit handles opening/closing states based on target/current position.

I've tried before to replace lines 113-114 with

Try this version.

       // add these lines
        try {
            const json = JSON.parse(body);
            body = Object.values(json)[0];
        } catch (err) {
        }

        // unchanged part below
        const pos = parseInt(body, 10);
        if (pos < 0 || pos > 100) { // invalid
            return callback(pos);
        }

Maybe a bit off-topic but I've seen that it spams the hardware with http requests & the console log with:

That is weird. Are you running the latest version (1.3.13)? Also, maybe something with the position_url before? It seems like it's triggering an endless loop. I recall something about that in an earlier release but I thought it should be fixed now. If it's still happening, please enable verbose would like to see how this loop happens.

dxdc commented 4 years ago

@buenyamin-olgun see this commit:

https://github.com/zwerch/homebridge-blinds/commit/59142c3d4a590e54d97a3dc48fbe2aaf0b13fbf3

Now, I added a way for you to have the position specified in the URL. Instead of 100 or 0, simply use the keyword %%POS%%. Let me know how this testing goes. Actually, we may be most of the way there after these changes.

        {
            "accessory": "BlindsHTTP",
            "name": "Window",
            "up_url": "http://192.168.0.94/cm?cmnd=ShutterPosition%20%%POS%%",
            "down_url": "http://192.168.0.94/cm?cmnd=ShutterPosition%20%%POS%%",
            "stop_url": "http://192.168.0.94/cm?cmnd=Power3%20ON",
            "http_method": {
                "method": "GET"
            },
            "success_codes": [
                200
            ],
            "max_http_attempts": 5,
            "retry_delay": 2000,
            "use_same_url_for_stop": false,
            "show_stop_button": true,
            "show_toggle_button": false,
            "motion_time": 20000,
            "response_lag": 0,
            "trigger_stop_at_boundaries": false,
            "verbose": false
        }
Zer0x00 commented 4 years ago

Yes, the loop seems to be in dependency with the position_url set before.

I've tried your code from the first post, it triggers also the loop.

image

...and tried it a second time: image

Should I check out your commited change still?

dxdc commented 4 years ago

I've just committed a fix for that issue, I think. I didn't have a way of testing it before, so I appreciate the fact that you have a way to test it.

Please replace your index.js file with this one, and let me know the result:

https://raw.githubusercontent.com/zwerch/homebridge-blinds/master/index.js

Also, make the changes as I mentioned to add %%POS%% into config.json.

Zer0x00 commented 4 years ago

After downloading the new version & changing the config.json there's this error (& it's again looping):

(node:26328) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'lastPosition' of undefined
    at C:\Users\olgunb\AppData\Roaming\npm\node_modules\homebridge-blinds\index.js:63:47
    at BlindsHTTPAccessory.<anonymous> (C:\Users\olgunb\AppData\Roaming\npm\node_modules\homebridge-blinds\index.js:101:20)
    at BlindsHTTPAccessory.<anonymous> (C:\Users\olgunb\AppData\Roaming\npm\node_modules\homebridge-blinds\index.js:127:16)
    at BlindsHTTPAccessory.<anonymous> (C:\Users\olgunb\AppData\Roaming\npm\node_modules\homebridge-blinds\index.js:325:20)
    at Request._callback (C:\Users\olgunb\AppData\Roaming\npm\node_modules\homebridge-blinds\node_modules\lodash\lodash.js:10050:25)
    at Request.requestRetryReply [as reply] (C:\Users\olgunb\AppData\Roaming\npm\node_modules\homebridge-blinds\node_modules\requestretry\index.js:105:19)
    at Request.<anonymous> (C:\Users\olgunb\AppData\Roaming\npm\node_modules\homebridge-blinds\node_modules\requestretry\index.js:146:10)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:26328) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:26328) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
dxdc commented 4 years ago

Missed that one. Try again:

https://raw.githubusercontent.com/zwerch/homebridge-blinds/master/index.js

Zer0x00 commented 4 years ago

No errors this time but again a loop when I trigger a move up while it is moving down: image

dxdc commented 4 years ago

OK, I think I know the cause. Try again:

https://raw.githubusercontent.com/zwerch/homebridge-blinds/master/index.js

Zer0x00 commented 4 years ago

I'm sorry but that also doesn't seem to fix the problem: image

dxdc commented 4 years ago
  1. Do the messages go on forever or does it eventually stop?

  2. What commands are you pressing to reproduce this? Does it happen only when you choose values very close to one another?

  3. Please provide your entire config.json. I'm particularly interested in the motionTime values.

  4. Also, I'm wondering if you should have stopURL blank. Seems rather pointless, doesn't it? It's also sending an additional "STOP" command which probably isn't ideal, given that

dxdc commented 4 years ago

Btw, have made one other batch of changes I'm hoping will fix it.

https://raw.githubusercontent.com/zwerch/homebridge-blinds/master/index.js

Zer0x00 commented 4 years ago

Your last change seems to fix the loop issue, thank you!

To point 4: im using it to stop the blinds accuractely when I want instead of using a percentage value because percentage values are kinda hard to guess. This is also a reason why I like your plugin so much.

Hopefully the last couple of problems:

Case Stop Button used via Home App: Here the value must be 75, which the endpoint is also responding but the Home app does show 78:

[11.2.2020, 12:46:04] [Window] Requesting manual stop
[11.2.2020, 12:46:05] [Window] Request succeeded after 1 / 5 attempts
[11.2.2020, 12:46:05] [Window] Stop request sent
[11.2.2020, 12:46:05] [Window] End Move down (to 78%)
[11.2.2020, 12:46:52] [Window] Requested CurrentPosition: 78%
[11.2.2020, 12:46:52] [Window] Requested TargetPosition: 78%
[11.2.2020, 12:46:53] [Window] Request succeeded after 1 / 5 attempts
[11.2.2020, 12:47:56] [Window] Requested TargetPosition: 78%
[11.2.2020, 12:47:56] [Window] Requested CurrentPosition: 75%
[11.2.2020, 12:47:57] [Window] Request succeeded after 1 / 5 attempts

Blind position changed via physical buttons (blinds are at position 63%, Home app shows 75%):

[11.2.2020, 12:53:01] [Window] Request succeeded after 1 / 5 attempts
[11.2.2020, 12:53:01] [Config] Homebridge Config UI X v4.10.0 is listening on :: port 8581
[11.2.2020, 12:53:05] [Window] Requested TargetPosition: 75%
[11.2.2020, 12:53:05] [Window] Requested CurrentPosition: 75%
[11.2.2020, 12:53:06] [Window] Request succeeded after 1 / 5 attempts
[11.2.2020, 12:53:47] [Window] Requested TargetPosition: 75%
[11.2.2020, 12:53:47] [Window] Requested CurrentPosition: 75%
[11.2.2020, 12:53:47] [Window] Request succeeded after 1 / 5 attempts
[11.2.2020, 12:53:53] [Window] Requested CurrentPosition: 63%
[11.2.2020, 12:53:53] [Window] Requested TargetPosition: 75%
[11.2.2020, 12:53:54] [Window] Request succeeded after 1 / 5 attempts
dxdc commented 4 years ago

@buenyamin-olgun thanks for your testing and reports.

if the action is stopped by the stop button the value doesn't update to the stopped (correct) one. This can be spotted also when the blind position is changed via the pyhsical buttons. Restarting the homebridge service fixes this.

I've pushed a number of changes that I'm hoping will address at least the majority of your issues. Would be grateful for you to test it as I have no practical way to do so since my blinds don't work like this. I've also added a feature to disable sending the stop command when a value is provided. To me, this makes intuitive sense -- if your blinds can receive a value to target, there should be no reason that we need to also send a stop command for intermediate values. (Note: the stop 'button' still works).

https://raw.githubusercontent.com/zwerch/homebridge-blinds/master/index.js

Currently it seems to respect the motion time, could this be disabled?

The problem is: the blinds only have knowledge of the position from the position_url in this case. If we poll this URL multiple times per second it is very inefficient. Also, note that the blinds appropriately use a fraction of the motion time if only a few % is changed.

Therefore, I modified the behavior as follows. The motion time is used as an internal estimate. Once this "estimate" is reached, it will poll the position_url to update the blind's position. If the desired position is reached, it will end the motion. However, if the desired position is not reached it will keep waiting and retrying again using similar estimates.

The goal is that it should not be polling for current position so frequently. The icon may be very slightly out of sync, but I think it should be quite close if you're using the correct motion time for your blinds.

Zer0x00 commented 4 years ago

Sorry for the delay, had working hours of nonstop +1 day.

First everything seemed to be okay, what I did was: Took the blind, set it to a lower position and stopped the blinds with the stop button. After that I tried to move the blinds up, it spammed me and the device again with values. The device crashed and restarted so I'm not sure which commands were spammed. Something noticable: The move to a upper position is registered as a move down.

Here's the full log:

[14.2.2020, 00:11:07] Homebridge is running on port 51946.
[14.2.2020, 00:11:07] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:11:07] [Window] Body (200): {"ShutterPosition1":63}
[14.2.2020, 00:11:07] [Config] Homebridge Config UI X v4.10.0 is listening on :: port 8581
[14.2.2020, 00:11:17] [Window] Requested CurrentPosition: 63%
[14.2.2020, 00:11:17] [Window] Requested TargetPosition: 63%
[14.2.2020, 00:11:17] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:11:17] [Window] Body (200): {"ShutterPosition1":63}
[14.2.2020, 00:11:20] [Window] Requested CurrentPosition: 63%
[14.2.2020, 00:11:20] [Window] Requested TargetPosition: 63%
[14.2.2020, 00:11:20] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:11:20] [Window] Body (200): {"ShutterPosition1":63}
[14.2.2020, 00:11:23] [Window] Requested TargetPosition: 63%
[14.2.2020, 00:11:23] [Window] Requested CurrentPosition: 63%
[14.2.2020, 00:11:23] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:11:23] [Window] Body (200): {"ShutterPosition1":63}
[14.2.2020, 00:11:29] [Window] Requested Move down (to 49%)
[14.2.2020, 00:11:29] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:11:29] [Window] Body (200): {"POWER2":"ON","ShutterPosition1":49}
[14.2.2020, 00:11:29] [Window] Move request sent (211 ms), waiting 2.8s (+ 0s response lag)...
[14.2.2020, 00:11:29] [Window] Stop command will be skipped; exact position specified
[14.2.2020, 00:11:29] [Window] Timeout finished
[14.2.2020, 00:11:31] [Window] Requesting manual stop
[14.2.2020, 00:11:32] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:11:32] [Window] Body (200): {"POWER2":"OFF","POWER3":"ON"}
[14.2.2020, 00:11:32] [Window] Stop request sent
[14.2.2020, 00:11:32] [Window] Requested CurrentPosition: 53%
[14.2.2020, 00:11:32] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:11:32] [Window] Body (200): {"POWER3":"OFF","POWER1":"ON","ShutterPosition1":0}
[14.2.2020, 00:11:32] [Window] End Move down (to 49%)
[14.2.2020, 00:12:11] [Window] Requested Move down (to 59%)
[14.2.2020, 00:12:12] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:12] [Window] Body (200): {"POWER1":"ON","ShutterPosition1":59}
[14.2.2020, 00:12:12] [Window] Move request sent (120 ms), waiting NaNs (+ 0s response lag)...
[14.2.2020, 00:12:12] [Window] Stop command will be skipped; exact position specified
[14.2.2020, 00:12:12] [Window] Timeout finished
[14.2.2020, 00:12:12] [Window] Requested Move down (to 71%)
[14.2.2020, 00:12:12] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:12] [Window] Body (200): {"ShutterPosition1":71}
[14.2.2020, 00:12:12] [Window] Move request sent (195 ms), waiting NaNs (+ 0s response lag)...
[14.2.2020, 00:12:12] [Window] Stop command will be skipped; exact position specified
[14.2.2020, 00:12:12] [Window] Timeout finished
[14.2.2020, 00:12:12] [Window] Requested CurrentPosition: NaN%
[14.2.2020, 00:12:12] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:12] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:12] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:12] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:12] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:13] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:13] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:13] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:13] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:13] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:13] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:13] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:13] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:13] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:13] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:13] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:13] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:14] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:14] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:14] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:14] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:14] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:14] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:14] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:14] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:14] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:14] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:14] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:14] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:12:14] [Window] Requested CurrentPosition: 0%
[14.2.2020, 00:12:15] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:15] [Window] Body (200): {"ShutterPosition1":70}
[14.2.2020, 00:12:15] [Window] Requested CurrentPosition: 70%
[14.2.2020, 00:12:15] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:15] [Window] Body (200): {"ShutterPosition1":71}
[14.2.2020, 00:12:15] [Window] End Move down (to 71%)
[14.2.2020, 00:12:15] [Window] Requesting manual stop
[14.2.2020, 00:12:15] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:12:15] [Window] Body (200): {"POWER3":"ON"}
[14.2.2020, 00:12:15] [Window] Stop request sent
dxdc commented 4 years ago

Thanks @buenyamin-olgun. Pushed a few more commits.

Originally, you wrote:

Get current position (where current position 79): http:///cm?cmnd=ShutterPosition Response: {"ShutterPosition1":79} Status Code: 200 OK

But, in some cases, your blinds are returning multiple values for the getPosition response.

{"POWER3":"OFF","POWER1":"ON","ShutterPosition1":0}

That was causing an issue. For now, I just filter to return only the numeric values. More robust handling probably needs to be added at some point. In your case, there is only one so hopefully it will resolve the issue.

Zer0x00 commented 4 years ago

Thank you for your further fixes.

Forgot to mention that the endpoint is reporting ShutterPosition1 = 0 during movement and also while it is really fully closed. Already opened an issue on tasmota for this.

The 0 value (completely closed) seems to be problem for your plugin: Return:

{"ShutterPosition1":0}

Homebridge Log:

[14.2.2020, 00:52:00] [Window] Requested CurrentPosition: 38%
[14.2.2020, 00:52:00] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:52:00] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:52:00] [Window] setCurrentPositionByUrl failed; invalid response (should be 0-100): -1
[14.2.2020, 00:52:00] [Window] End Move down to 38% (target 0%)
[14.2.2020, 00:52:08] [Window] Requested TargetPosition: 38%
[14.2.2020, 00:52:08] [Window] Requested CurrentPosition: 38%
[14.2.2020, 00:52:08] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:52:08] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:52:08] [Window] setCurrentPositionByUrl failed; invalid response (should be 0-100): -1

and updating the estimated value by the correct one by closing and reopening the Home App also does not work (real value: 6%; set value via Home App: 7%):

[14.2.2020, 00:56:03] [Window] Requested CurrentPosition: 7%
[14.2.2020, 00:56:03] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:56:03] [Window] Body (200): {"ShutterPosition1":0}
[14.2.2020, 00:56:03] [Window] setCurrentPositionByUrl failed; invalid response (should be 0-100): -1
[14.2.2020, 00:56:03] [Window] End Move up to 7% (target 7%)
[14.2.2020, 00:56:15] [Window] Requested TargetPosition: 7%
[14.2.2020, 00:56:15] [Window] Requested CurrentPosition: 7%
[14.2.2020, 00:56:16] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:56:16] [Window] Body (200): {"ShutterPosition1":6}
[14.2.2020, 00:56:17] [Window] Requested TargetPosition: 7%
[14.2.2020, 00:56:17] [Window] Requested CurrentPosition: 6%
[14.2.2020, 00:56:17] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 00:56:17] [Window] Body (200): {"ShutterPosition1":6}
dxdc commented 4 years ago

Forgot to mention that the endpoint is reporting ShutterPosition1 = 0 during movement and also while it is really fully closed.

This is a problem. The only way to proceed from here (maybe) would be some additional JSON parsing... IF... we can guarantee that the POWER values would also be reported in that timeframe.

The 0 value (completely closed) seems to be problem for your plugin:

Fixed.

and updating the estimated value by the correct one by closing and reopening the Home App also does not work (real value: 6%; set value via Home App: 7%):

I'm not sure what you mean here? Anyway, it is likely related to the 0 issue above since it was unable to retrieve a value so it resorts to an estimated one.

Zer0x00 commented 4 years ago

This is a problem. The only way to proceed from here (maybe) would be some additional JSON parsing... IF... we can guarantee that the POWER values would also be reported in that timeframe. No, unfortunately the POWER values are not everytime reported afaik. This was also an issue as I tried to develop my own plugin.

Hopefully tasmota devs will fix it soon.

Fixed.

Thanks!

I'm not sure what you mean here? Anyway, it is likely related to the 0 issue above since it was unable to retrieve a value so it resorts to an estimated one.

I don't think that it is related to the upper issue since you can see that ShutterPosition1 was reporting 6 at that time but your plugin cached / estimated (?) 7. It does not update itself with the value gathered from the endpoint.

dxdc commented 4 years ago

No, unfortunately the POWER values are not everytime reported afaik.

In anticipation of this, I added some JSONata handling of the result. You will have to run npm install jsonata while in testing mode after replacing the file again.

I don't think that it is related to the upper issue since you can see that ShutterPosition1 was reporting 6 at that time but your plugin cached / estimated (?) 7. It does not update itself with the value gathered from the endpoint.

Can you clearly explain which commands you pressed on your blinds to initiate this? It's not clear to me how it happened. Also, the 0% response from Tasmota is definitely causing a problem. I would suggest increasing motion time / lag time a little bit so that the blinds are never checking while the blinds are in motion.

That being said, this could be a major issue if the position is requested by HomeKit itself while the blinds are moving.

Zer0x00 commented 4 years ago

Wow, this time it worked incredibly well until the point where it started looping again :( :

[14.2.2020, 01:59:23] [Window] Body (200): {"POWER2":"ON","ShutterPosition1":12}
[14.2.2020, 01:59:23] [Window] Move request sent (113 ms), waiting 2s (+ 0s response lag)...
[14.2.2020, 01:59:23] [Window] Stop command will be skipped; exact position specified
[14.2.2020, 01:59:23] [Window] Timeout finished
[14.2.2020, 01:59:25] [Window] Requested CurrentPosition: 12%
[14.2.2020, 01:59:25] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:25] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:25] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:25] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:25] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:26] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:26] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:26] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:26] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:26] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:26] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:26] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:26] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:26] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:26] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:26] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:26] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:26] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:26] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:26] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:27] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:27] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:27] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:27] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:27] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:27] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:27] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:27] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:27] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:27] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:27] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:27] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:27] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:27] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:27] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:30] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:30] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:30] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:30] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:30] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:30] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:30] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:30] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:30] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:31] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:31] [Window] Requesting manual stop
[14.2.2020, 01:59:31] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:31] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:31] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:31] [Window] Body (200): {"POWER3":"ON"}
[14.2.2020, 01:59:31] [Window] Stop request sent
[14.2.2020, 01:59:31] [Window] Requested CurrentPosition: 11%
[14.2.2020, 01:59:31] [Window] Request succeeded after 1 / 5 attempts
[14.2.2020, 01:59:31] [Window] Body (200): {"ShutterPosition1":11}
[14.2.2020, 01:59:31] [Window] End Move down to 11% (target 12%)
dxdc commented 4 years ago

There is some issue with the Tasmota or the positions being specified.

When you are requesting 12% from HomeKit, it is sending a request for 12% but stopping at 11%. So, the code is looping waiting for the blinds to hit 12%. I noticed something similar earlier.

Zer0x00 commented 4 years ago

I'll do further tests regarding this problem (but it'll take some time since I will be away from home for a short period).

dxdc commented 4 years ago

@buenyamin-olgun no problem.

I pushed a new commit that sets an upper bound on the number of retries (in case of this type of failure, it won't loop forever).

Also, is it always off by 1 or does it sometimes look equal to the target? If it's always off by 1, this could be resolved by setting position_jsonata to $number(ShutterPosition1 + 1) For example.

You can experiment more with JSONata using their playground.

Zer0x00 commented 4 years ago

It seems to be off by one, couldn't detect any other off-value.

Seems like it is doing this in both ways (up & down).

I've opened a issue on tasmota for this as well.

While moving it reports 0, this causes an issue right now (shows the blinds closed and doesn't revert after it was stopped). Let's wait for the reply on this tasmota issue.

Thank you very much so far!

dxdc commented 4 years ago

It seems to be off by one, couldn't detect any other off-value.

In this case, my suggestion could work fine. You just adjust the value by 1 using the jsonata.

dxdc commented 4 years ago

Btw, have pushed several more commits to account for some other cases. Will be grateful if you're able to test with your setup and just be sure there are no differences.

Zer0x00 commented 4 years ago

Thank you. The problem is that tasmota reports 0 during movement which makes it hard to test things.

Right now your code sets the shutter-value correctly to closed if shutterposition is 0 during a movement but doesn't gets updated afterwards:

[17.2.2020, 19:00:53] [Window] Requesting manual stop
[17.2.2020, 19:00:53] [Window] Request succeeded after 1 / 5 attempts
[17.2.2020, 19:00:53] [Window] Body (200): {"ShutterStop1":9}
[17.2.2020, 19:00:53] [Window] Stop request sent
[17.2.2020, 19:00:53] [Window] Requested CurrentPosition: 11%
[17.2.2020, 19:00:53] [Window] Request succeeded after 1 / 5 attempts
[17.2.2020, 19:00:53] [Window] Body (200): {"ShutterPosition1":0}
[17.2.2020, 19:00:53] [Window] End Move up to 0% (target 28%)
[17.2.2020, 19:00:59] [Window] Requested TargetPosition: 0%
[17.2.2020, 19:00:59] [Window] Requested CurrentPosition: 0%
[17.2.2020, 19:00:59] [Window] Request succeeded after 1 / 5 attempts
[17.2.2020, 19:00:59] [Window] Body (200): {"ShutterPosition1":9}
[17.2.2020, 19:01:01] [Window] Requested TargetPosition: 0%
[17.2.2020, 19:01:01] [Window] Requested CurrentPosition: 9%
[17.2.2020, 19:01:01] [Window] Request succeeded after 1 / 5 attempts
[17.2.2020, 19:01:01] [Window] Body (200): {"ShutterPosition1":9}

I think we'll have to wait for this issue be fixed on tasmota side.

dxdc commented 4 years ago

Sure, np.

dxdc commented 4 years ago

@buenyamin-olgun any progress on this?

I was wondering if (at least part?) of your issue is Tasmota calibration.

  1. Have you followed the instructions here?

  2. Are you running the latest version of Tasmota firmware 8.1?

This all being said, I think perhaps MQTT would be a superior way to interact with Tasmota. You can use apply functions to parse the result.

https://github.com/arachnetech/homebridge-mqttthing#window-covering

  1. It looks like ShutterStop is the correct way to issue a stop command (not the Power command?)

https://github.com/arendst/Tasmota/wiki/commands#blinds-shutters-and-roller-shades

Zer0x00 commented 4 years ago

@dxdc Was away until today, had to do work so didn't had any time yet.

The major issue that it was not reporting its current position should be fixed now, the devs pushed a commit 2 days ago: https://github.com/arendst/Tasmota/pull/7785

I'm waiting that a final version gets released.

1.) Yes, the shutter is calibrated with the provided instructions by tasmota.

2.) Yes, currently it is running the latest version (8.1).

3.) On my device I have a separate stop button (Power 3) which I was using. This was set to the same function as ShutterStop by using the rule:

Rule1 on Power3#State=1 do backlog ShutterStop1; Power3 0 endon

During tests I already silently swapped Power3 by ShutterStop, didn't make any difference.

I agree with you that MQTT would be a superior way to interact with the device but unfortunately I don't have any infrastructure right now and it would be one more item in the chain to the device which I'm trying to avoid.

Your plugin seems to work well so far, when the tasmota devs publishes their changes as a release I think it could work out well how it is right now. Waiting for that.

dxdc commented 4 years ago

Great news @buenyamin-olgun, and thanks for the explanation. Understand about MQTT. Will await the next Tasmota release, please keep me posted.

dxdc commented 4 years ago

Hi @buenyamin-olgun have you had a chance to upgrade to the latest Tasmota release?

dxdc commented 4 years ago

@buenyamin-olgun you may also be interested in the feature I added that lets you update the blinds position manually (on a one-time basis) via webhook. See discussion #30 here

Zer0x00 commented 4 years ago

Hi @buenyamin-olgun have you had a chance to upgrade to the latest Tasmota release?

Just found out through your post that the new version has been released, thanks for that! Will test it in the coming few days.

The position_url parameter would imho be more suitable for my situation if tasmota sends correct values. But will look into it if tasmota starts again to make trouble.

Did I say thank you? Oh, just six times. but one more can't hurt: THANK YOU FOR YOUR GREAT WORK!

dxdc commented 4 years ago

Quite welcome... cheers :) Keep me posted and close the issue (or comment) once you finish testing on your side.

Zer0x00 commented 4 years ago

Tested it now with Tasmota 8.2.0 for about half an hour, seems to work fine so far!

dxdc commented 4 years ago

Great! Thanks for the feedback.