Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial support for ZHADoorLock sensor. #4540

Merged
merged 34 commits into from
Mar 27, 2021

Conversation

Smanar
Copy link
Collaborator

@Smanar Smanar commented Mar 8, 2021

This code create ZHAdoorlock sensor for new doorlock, older one are not impacted and still use "light" type.
The JSON look like this one

{
  "config": {
    "battery": 100,
    "lock": false,
    "on": true,
    "reachable": true
  },
  "ep": 11,
  "etag": "a43862f76b7fa48b0fbb9107df123b0e",
  "lastseen": "2021-03-06T22:25Z",
  "manufacturername": "Onesti Products AS",
  "modelid": "easyCodeTouch_v1",
  "name": "easyCodeTouch_v1",
  "state": {
    "lastupdated": "2021-03-06T21:25:45.624",
    "lockstate": "unlocked"
  },
  "swversion": "20201211",
  "type": "ZHADoorLock",
  "uniqueid": "xx:xx:xx:xx:xx:xx:xx:xx-xx-0101"
}

The code add too some attribute and fonction to the GUI for doorlock cluster 0x0101

It add support for thoses devices.

  • Yale YRD226 TSDB
  • Yale YRD226/246 TSDB
  • Yale YRD256L TSDB SL
  • Yale YRD220/240 TSDB
  • Yale YRD256 TSDB
  • Kwikset 914 ZigBee smart lock
  • Datek ID Lock 150

Not all are tested, have some issue for the EasyAccess EasyCodeTouch #4253

To unlock/lock the device, use config/lock.
State/lockstate give the device state (locked/unlocked/undefined/not fully locked)

Lasted issue used #3750

@Smanar
Copy link
Collaborator Author

Smanar commented Mar 8, 2021

To test the code, you need to use direclty the API, as third app don't use this sensor yet #3750 (comment)

@ebaauw
Copy link
Collaborator

ebaauw commented Mar 8, 2021

Nice, thanks @Smanar !

Some remarks:

  • I think the capitalisation should be ZHADoorLock
  • I would rather see state.locked with values true and false instead of state.lockstate with a string value;
  • Not sure if we need the whitelist in addSensorNode(). I think it's OK to expose the door locks already supported as /lights also as ZHADoorLock /sensors. That would enable a smooth migration of API clients to the /sensors resources. Make sure to blacklist the lumi.vibration.aq1 (and maybe some other) sensor, that (ab)uses a Door Lock cluster;
  • For consistency we would need a CLIPDoorLock as well.

@ebaauw ebaauw requested review from ebaauw and removed request for ebaauw March 8, 2021 17:39
@gabriellanata
Copy link
Contributor

@ebaauw
Copy link
Collaborator

ebaauw commented Mar 8, 2021

Sorry, I though it was requesting me to review, but apparently this was only a suggestion. Not sure how I can mark this as "reviewed".

@Smanar
Copy link
Collaborator Author

Smanar commented Mar 8, 2021

* I think the capitalisation should be `ZHADoorLock`

Yes ( ZHALightLevel)

* I would rather see `state.locked` with values `true` and `false` instead of `state.lockstate` with a string value;

For that it will be config/lock, the state/lockstate can have more values locked/unlocked/undefined/not fully locked

* Not sure if we need the whitelist in `addSensorNode()`.  I think it's OK to expose the door locks already supported as `/lights` also as ZHADoorLock `/sensors`.  That would enable a smooth migration of API clients to the `/sensors` resources. 

Yep, the whitelist is exactly for that

Make sure to blacklist the lumi.vibration.aq1 (and maybe some other) sensor, that (ab)uses a Door Lock cluster;

I m using this kind of check

            // For the moment reserved to doorlock device
            if ((*i == DOOR_LOCK_CLUSTER_ID) && (sensor->type() != QLatin1String("ZHADoorLock")))
            {
                break;
            }

So the code is only used for this kind of sensor, I m making this check at line 3286 binding.cpp and line 9495 in de_web_plugin.cpp, not sure it will be enought ...

* For consistency we would need a `CLIPDoorLock` as well.

Hu ? here I have not understand what i need to do ?

@gabriellanata if you give me the model id visible in deconz, I can add it, all yale are working for the moment, realy standard zigbee use.

@ebaauw
Copy link
Collaborator

ebaauw commented Mar 8, 2021

For that it will be config/lock, the state/lockstate can have more values locked/unlocked/undefined/not fully locked

That's a good reason!

@gabriellanata
Copy link
Contributor

gabriellanata commented Mar 8, 2021

@Smanar Thanks! Unsure which one is the model id though:

image

Ah I think I found where it should be but it's blank, even after asking it to read the configuration :/ I'll try a few things

Got it! Had to completely remove it and readd it:
image

@gabriellanata
Copy link
Contributor

gabriellanata commented Mar 9, 2021

Created a PR to your fork to maybe save you some time. Thanks again! Smanar#22

@Smanar Smanar changed the title Add initial support for ZHADoorlock sensor. Add initial support for ZHADoorLock sensor. Mar 9, 2021
@Smanar
Copy link
Collaborator Author

Smanar commented Mar 9, 2021

Nice perfect ^^, thx.

So the code is working too for this device ?

rest_sensors.cpp Outdated
Comment on lines 814 to 815
//if (item->lastChanged() == item->lastSet())
//{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this expected to be commented out?

Copy link
Collaborator Author

@Smanar Smanar Mar 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IDK ^^.
I have commented it during my test, but I don't see the utility of this code. If the state don't change, you will not have notification, and the state don't change every hour, so not sure it s usefull ....

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to remove commented out/dead code, otherwise it will sit there for ages ;)

@gabriellanata
Copy link
Contributor

Nice perfect ^^, thx.

So the code is working too for this device ?

I haven't tried it honestly. It should be the same as the others though. I verified the state values and commands for lock/unlock match in code.

Copy link
Collaborator

@SwoopX SwoopX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small comments

rest_sensors.cpp Outdated
@@ -789,6 +789,42 @@ int DeRestPluginPrivate::changeSensorConfig(const ApiRequest &req, ApiResponse &
else if (rid.suffix == RConfigTempThreshold || rid.suffix == RConfigHumiThreshold)
{
}
else if (rid.suffix == RConfigLock)
{
bool val = map[pi.key()].toBool();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a type check here, as we have it further down below in that function (e.g. for thermostats)? Please also don't forget about the error message returned in case it's not a bool value ;)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

rest_sensors.cpp Outdated
Comment on lines 812 to 817
rspItemState[QString("/sensors/%1/config/lock").arg(id)] = map["lock"];
rspItem["success"] = rspItemState;
//if (item->lastChanged() == item->lastSet())
//{
updated = true;
//}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we only require the updated part here ;)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question why was for the code I commented ?
I don't see the utility of it ...

Do I need to use it or remove it ?

rest_sensors.cpp Outdated
Comment on lines 822 to 824
rsp.list.append(errorToMap(ERR_INVALID_VALUE, QString("/sensors/%1/config/lock").arg(id), QString("Command error, %1, for parameter, lock").arg(map[pi.key()].toString())));
rsp.httpStatus = HttpStatusBadRequest;
return REQ_READY_SEND;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we should have the error here homogeneously? So just the part which contains ERR_ACTION_ERROR as further down below.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -9432,6 +9492,57 @@ void DeRestPluginPrivate::updateSensorNode(const deCONZ::NodeEvent &event)
}
}
}
else if (i->type() == QLatin1String("ZHADoorLock")) // Door lock
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General question to all: do we want to have/leave it here or have an extra file for it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need one.
Because of notifications, need too much code, it will be in next version, WIP

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 splitting up door lock in separate file sounds clean like it is done for window covering.
But I'm fine when this is done in a extra PR.

else
{
checkSensorNodeReachable(sensor);
checkIasEnrollmentStatus(sensor);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wandering if the IAS check is required here, persumably not?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, at all, removed

Copy link
Member

@manup manup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added my usual code style requests, can you please have a look. :)

In future I hope to automate these checks with clang-tidy to get a more consistent style across the code base.

bindings.cpp Outdated Show resolved Hide resolved
de_web_plugin.cpp Outdated Show resolved Hide resolved
de_web_plugin.cpp Outdated Show resolved Hide resolved
de_web_plugin.cpp Outdated Show resolved Hide resolved
@@ -9432,6 +9492,57 @@ void DeRestPluginPrivate::updateSensorNode(const deCONZ::NodeEvent &event)
}
}
}
else if (i->type() == QLatin1String("ZHADoorLock")) // Door lock
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 splitting up door lock in separate file sounds clean like it is done for window covering.
But I'm fine when this is done in a extra PR.

de_web_plugin.cpp Outdated Show resolved Hide resolved
rest_sensors.cpp Outdated
Comment on lines 814 to 815
//if (item->lastChanged() == item->lastSet())
//{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to remove commented out/dead code, otherwise it will sit there for ages ;)

@Smanar
Copy link
Collaborator Author

Smanar commented Mar 25, 2021

Ok so I m not able to resolve all, but all is resolved.

Just 2 comments.

  • Someone can explain me the utility of this code (visible in the code)
                            if (item->lastChanged() == item->lastSet())
                            {
                                updated = true;
                            }

On my side worked better just with
updated = true;

@manup
Copy link
Member

manup commented Mar 27, 2021

  • Someone can explain me the utility of this code (visible in the code)
                            if (item->lastChanged() == item->lastSet())
                            {
                                updated = true;
                            }

On my side worked better just with
updated = true;

This is used to set updated only if the value was indeed be updated and is different from the previous set value. It depends on use case and code which follows. For example for button events they should trigger an event even if the value hasn't been changed but the timestamp since the same button was pressed multiple times.

In short, we use if (item->lastChanged() == item->lastSet()) only if events should be triggered on actual value change, not only on setting a value.

Copy link
Member

@manup manup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looking better now. I found a missing error handling can you please check.

rest_sensors.cpp Outdated Show resolved Hide resolved
rest_sensors.cpp Outdated Show resolved Hide resolved
@manup manup added this to the v2.11.0-beta milestone Mar 27, 2021
@manup manup merged commit 9cbbae5 into dresden-elektronik:master Mar 27, 2021
@Smanar Smanar deleted the doorlock branch June 19, 2021 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants