dkerr64 / homebridge-yolink

Apache License 2.0
12 stars 2 forks source link

YoLInk Smart Lock M1 (new device) #35

Closed hdinwiddie closed 2 years ago

hdinwiddie commented 2 years ago

Please add Homebridge support for the new YoLink Smart Lock M1 as shown: https://shop.yosmart.com/collections/all-products/products/yolink-smart-lock-m1-yolink-hub-required I hope YoLink will provide you one for this purpose. I don't have one and don't really need another one, but I have friends who might.

dkerr64 commented 2 years ago

@hdinwiddie thank you for opening this requirement. Once other work-in-progress completes and stabilizes I will look at this.

dkerr64 commented 2 years ago

This will take a while for me to work on as I have upcoming travel. But I'll get to it.

ShamelessWizard commented 2 years ago

I have one arriving around september 2nd'ish. If you don't have any logs before I install mine I'll dump them here.

dkerr64 commented 2 years ago

@ShamelessWizard thank you for the offer. If an unknown device is added to YoLink then this plugin should notice and place warnings into the log (will appear in orange/yellow text). Those are what I will need to get started. As noted above though, I have several weeks of travel coming up so it could take time to get to this.

hdinwiddie commented 2 years ago

@dkerr64 Thanks for the schedule info. We'll pick it up whenever you're ready.

dkerr64 commented 2 years ago

For anyone that has a lock... can you tell me if the YoLink app allows you to lock/unlock from the app, or if it just reports status and allows you to check/update settings.

The YoLink documentation here and here is not clear (looks like two different devices that can be identifies as Lock. And there is something called an AppartmentLock that has different controls. But it doesn't look like the basic lock device can be locked or unlocked from the API?

It would be helpful to actually see what messages are/can be sent to/from each type.

hdinwiddie commented 2 years ago

@dkerr64 Mine has been shipped and is supposed to be here Tuesday.

dkerr64 commented 2 years ago

@hdinwiddie when your lock arrives, please test with version 1.2.2 that I just published. It has the framework around which lock support will be built. It might work to the extent of reporting status (locked / unlocked) but it will not remotely lock/unlock the device because I don't know how to do that. Please capture whatever logs you can. Thanks.

hdinwiddie commented 2 years ago

@dkerr64 I got the lock in and set up on a table and it's working fine in the YoLink app and with Alexa. It looks like a very well-made lock. You can unlock/lock it in the app. You can also do it with Alexa except you're prompted to give the passcode before it will unlock. It locks without a code. I'm seeing it in Homebridge and in Homekit fine, but it isn't reflecting the status and won't respond to a lock/unlock event. I'm attaching a couple of logs. BTW, I sent you an email (I think) with a question if you haven't already seen it. homebridge.log (2).txt

dkerr64 commented 2 years ago

@hdinwiddie Thanks for the log. I can see that it took the plugin several attempts to connect to the lock, over a minute, but was successful in the end...

{
    "code": "000000",
    "time": 1661884194053,
    "msgid": 1661884194053,
    "method": "Lock.getState",
    "desc": "Success",
    "data": {
        "state": "locked",
        "battery": 4,
        "rlSet": "left",
        "loraInfo": {
            "signal": -26,
            "gatewayId": "abcdef1234567890",
            "gateways": 2
        }
    }
}

Which of course does not match the documentation here, that I was working from... that explains why Homebridge/HomeKit is not showing status. I should be able to fix that quickly enough.

I was hoping that some MQTT messages would show up in your log each time you did a lock/unlock from the YoLink app, but I don't see any.

Is good to know that you can lock/unlock from the app... that suggests I will be able to do the same from the plugin, but there is no documentation for that, and I doubt that any MQTT message will tell me how it is done... so I will need to wait until I obtain one myself to figure it out.

dkerr64 commented 2 years ago

I just pushed 1.2.4 which should now get the right lock status. However I don't know if it will update automatically on lock/unlock as I don't know what the MQTT messages look like.

hdinwiddie commented 2 years ago

@dkerr64 I did the update and at first I thought it wasn't updating in Homekit because I didn't see it updating in Homebridge/Accessories even after a couple of minutes. Then I looked on my iPhone and sure enough it is updating there in Home. It's a long log with several cycles from the YoLink app. It appears that when I change the state in Homekit it doesn't change the state of the lock itself. When I change the state in the app, Homekit does reflect the change. I hope this makes sense to you. It appeared from the log that MQTT was using port 8003 so just to be sure, I opened that port in my router (Eero) settling, but it didn't appear to make any difference. I'll try again tomorrow and see if I can see something different. I meant to say that when doing a state change in Homekit, it appeared to work as the tile changed after a bit, but the lock didn't actually follow.

homebridge.log (3).txt

dkerr64 commented 2 years ago

Thanks for the log. I see that it is now getting the correct lock state and battery level. I'm definitely going to need to get one for myself though in order to do anything more than this.

ShamelessWizard commented 2 years ago

Nope, excuse the spam, lock.setState does something, but it isn't doing more then causing the lock to beep. Weird. I've emailed one person regarding their docs. No idea if I will get a response.

ShamelessWizard commented 2 years ago

I am able to lock with lock.setState, but I must have the parameters wrong. I can't unlock remotely.

ShamelessWizard commented 2 years ago

Seems they cloned the Siren setState api. http://doc.yosmart.com/docs/yolinkapi/Siren

Using the keyword lock and unlock does the trick. Really, any keyword other then unlock seems to lock it... so I'm taking a guess on lock being the verb, but it sounds right. I have the lock next to me and not only does it sound the engagement beep, but the lock mechanism engages correctly.

Unlock!

curl --location --request POST 'https://api.yosmart.com/open/yolink/v2/api' --header 'Content-Type: application/json' --header "Authorization: Bearer ${access_token}" --data-raw '{ "method":"Lock.setState", "targetDevice": "xxxxxxxxxxxxxxxxxx", "token": "xxxxxxxxxxxxxxxxxx", "params":{"state": "unlock"} }' {"code":"000000","time":1662008191988,"msgid":1662008191988,"method":"Lock.setState","desc":"Success","data":{"state":"unlocked","loraInfo":{"signal":-44,"gatewayId":"d88b4c1603011301","gateways":1},"source":"app"}}(

Lock!

curl --location --request POST 'https://api.yosmart.com/open/yolink/v2/api' --header 'Content-Type: application/json' --header "Authorization: Bearer ${access_token}" --data-raw '{ "method":"Lock.setState", "targetDevice": "d88b4c0100036572", "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "params":{"state": "lock"} }' {"code":"000000","time":1662008265011,"msgid":1662008265011,"method":"Lock.setState","desc":"Success","data":{"state":"locked","loraInfo":{"signal":-45,"gatewayId":"d88b4c1603011301","gateways":1},"source":"app"}}((yolink-api) ) [

dkerr64 commented 2 years ago

@ShamelessWizard Thank you for doing the detective work. This is huge help. I'll try implementing lock/unlock this evening.

dkerr64 commented 2 years ago

@ShamelessWizard The other data we need is MQTT messages that are sent if someone manually locks/unlocks a door. If your lock is registered with this plugin, then you should see messages in the Homebridge log each time you manually lock/unlock (assuming that YoLink reports this... which I expect they would as they do for all other devices that are manually controlled). Thanks.

ShamelessWizard commented 2 years ago

Will get the logs after coffee. Yaochi confirmed the setState Api this morning. I don’t know if he intentionally signed up for support, but he put his email address in a malformed api request response ;)

Eric

On Sep 1, 2022, at 7:01 AM, David Kerr @.***> wrote:

 @ShamelessWizard The other data we need is MQTT messages that are sent if someone manually locks/unlocks a door. If your lock is registered with this plugin, then you should see messages in the Homebridge log each time you manually lock/unlock (assuming that YoLink reports this... which I expect they would as they do for all other devices that are manually controlled). Thanks.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.

dkerr64 commented 2 years ago

One more thing... when registered to the plugin can you click on the lock accessory in Homebridge and/or in Apple Home app and look at the log. There should be a warning message that that says unsupported request to lock or unlock followed by the device name and ID and then the "value" being passed into the set handler. I need to know if that value is 0/1 or a string "lock" / "unlock" or a boolean true/false. If not a string then I need to know what represents a request to lock and what represents a request to unlock. Thanks.

ShamelessWizard commented 2 years ago

Right now I see this in the homebridge when manipulating from homekit: Unsupported request to lock or unlock Front Door (d88b4c0100036572) to '1' Unsupported request to lock or unlock Front Door (d88b4c0100036572) to '0

Based on UAC it should be a string of 'lock' or 'unlock'. I'm playing around with the code a bit.

When I manually set the lock state I don't see any change in homebridge. Eventually it will refresh the device and I see a log like: [YoLink] At 9/1/2022, 10:56:12 AM: Device state for Front Door (d88b4c0100036572) is: Lock: locked, Battery: 4 [lite]

dkerr64 commented 2 years ago

The 1/0 is consistent with how a switch/siren works... in those cases the value is a boolean true/false which I then convert to a string that is sent up to YoLink.... true being 'open' and false being 'close' (for siren it is a longer object). I expect that for the lock device I translate 0 into 'unlock' and 1 into 'lock' which would be consistent with how Homebridge/HomeKit expects status to be reported by the get handler.

dkerr64 commented 2 years ago

When I manually set the lock state I don't see any change in homebridge. Eventually it will refresh the device and I see a log like: [YoLink] At 9/1/2022, 10:56:12 AM: Device state for Front Door (d88b4c0100036572) is: Lock: locked, Battery: 4 [lite]

If you manually lock/unlock does the YoLink app reflect the status in real time? That will tell us if there is something we're missing. Maybe my code is wrong, but I thought I was logging any unrecognized MQTT messages and its odd that none are sent.

hdinwiddie commented 2 years ago

@dkerr64 and @ShamelessWizard I'm glad the pros are working on this one. When you need a user to check/verify, let me know. Thanks, guys.

dkerr64 commented 2 years ago

Please try version 1.2.5 and see whether lock/unlock works from Homebridge/HomeKit. Thanks.

ShamelessWizard commented 2 years ago

If I enter the combination on the lock the YoLink app does see the state change. Physically setting the lock state does not update the app status. Interesting to know the key doesn't seem to trigger a response.

I don't know if I'm getting all of the debug data I want. I have debug and recently added verbose plugin settings. Do you know if there is a further debug level I can get? I'm attempting tcpdump to see if mqtt subscribe is working for the lock.

dkerr64 commented 2 years ago

If you enable verboseLog in the plugin config then that gives you the most logging that I wrote into the code. Any more than that is tcpdump or Wireshark.

ShamelessWizard commented 2 years ago

That seems to work with the new update.

I can set lock/unlock via homekit now.

[9/1/2022, 12:31:22 PM] [YoLink] YoLinkAPI.setDeviceState for Front Door (d88b4c0100036572): {"state":"lock"} [9/1/2022, 12:31:22 PM] [YoLink] [verbose] YoLinkAPI.getAccessToken [9/1/2022, 12:31:22 PM] [YoLink] [verbose] SENDING: {"time":1662049882664,"method":"Lock.setState","targetDevice":"d88b4c0100036572","token":"AED45A2EA16E377E99C38D8B2C9AB0DE","params":{"state":"lock"}} [9/1/2022, 12:31:25 PM] [YoLink] [verbose] RECEIVED: {"code":"000000","time":1662049885274,"msgid":1662049885274,"method":"Lock.setState","desc":"Success","data":{"state":"locked","loraInfo":{"signal":-61,"gatewayId":"d88b4c1603011301","gateways":1},"source":"app"}} [9/1/2022, 12:31:30 PM] [YoLink] YoLinkAPI.setDeviceState for Front Door (d88b4c0100036572): {"state":"unlock"} [9/1/2022, 12:31:30 PM] [YoLink] [verbose] YoLinkAPI.getAccessToken [9/1/2022, 12:31:30 PM] [YoLink] [verbose] SENDING: {"time":1662049890480,"method":"Lock.setState","targetDevice":"d88b4c0100036572","token":"AED45A2EA16E377E99C38D8B2C9AB0DE","params":{"state":"unlock"}} [9/1/2022, 12:31:32 PM] [YoLink] [verbose] RECEIVED: {"code":"000000","time":1662049892796,"msgid":1662049892796,"method":"Lock.setState","desc":"Success","data":{"state":"unlocked","loraInfo":{"signal":-51,"gatewayId":"d88b4c1603011301","gateways":1},"source":"app"}}

ShamelessWizard commented 2 years ago

The only issue without the status updates is homekit can be out of sync. When that occurs, homekit/homebridge simply sends a state request for the current lock state. This results in the lock simply beeping and then homekit gets the current state properly reflected.

I'll have to tcpdump my way through and see if I see a subscription message.

ShamelessWizard commented 2 years ago

No mqtt messages. I confirmed with the Siren that I could see them via tcpdump.

hdinwiddie commented 2 years ago

When I open/close the lock from Home or from Accessories it works fine and reports the status reasonably fast. When I use the keypad or the manual lock the status isn't picked up. When I then click on a tile, the lock beeps and doesn't move and the status updates and everything is back in sync.

dkerr64 commented 2 years ago

Its unfortunate that YoLink is not sending MQTT messages on lock status changes, we should probably ask them about that. In the meantime...

My plugin was designed on the assumption that it would receive status updates by MQTT... and I go to some lengths to maintain that connection. This assumption allows me to optimize responding to "get status" requests from HomeKit... which are very frequent. Slow response to such get status requests can make the Apple Home user interface feel slow. So the plugin responds to status requests very quickly with the last known state -- which is usually updated in real time by the device (think temperature changes coming in every few minutes) through MQTT messages. From time-to-time the plugin will refresh the state either on a timer or when a "get status" is requested after the refreshAfter time has expired... that requires going back to the YoLink servers and asking.

We can tell the plugin to always go back and ask YoLink servers for the lock status. To do that set a specific entry for the lock in the config devices array, and set refreshAfter to 0. It will look something like this...

"devices": [
              {
                    "deviceId": "abcdef1234567890",
                    "config": {
                        "name": "Front Door Lock",
                        "refreshAfter": 0
                    }
                }
]

refreshAfter is the maximum number of seconds the plugin should allow its "cached" value for status to age. Zero means always ask YoLink (over the internet) for the status. This also strongly suggests that you should run the plugin within a Homebridge child bridge as that will minimize any knock-on effects of waiting for a response from YoLink's servers (which in turn may push a request to the actual lock).

refreshAfter can be set globally (apply to all YoLink devices) but that feels like bad idea to me!.

dkerr64 commented 2 years ago

Further thoughts on refreshAfter... zero may be too extreme. 5 or 10 seconds might be better. Anything less than 60 seconds and the automatic refresh timer is not run, but setting to 5 or 10 seconds means that any rapid series of requests for status are responded to quickly, while still checking with the server is a few seconds have elapsed since last request.

ShamelessWizard commented 2 years ago

I'm not in a hurry myself because I can always revert back to the yolink app. Homekit is far more reliable about sending a notice that something has changed.

While the lock is performing a state update from the keypad it temporarily doesn't respond to state requests. Looks like this lasts for roughly five seconds after a successful pad entry has completed. It will throw some noise into the logs if the lock state is being aggressively evaluated.

I sent an email out asking for someone to bother. Maybe we should get discord access at some point.

ShamelessWizard commented 2 years ago

I'm fairly well convinced at this point that yolink is simply not pushing device events to the report channel for the lock. I dug in and learned a bit about yolink, plus dumps and looked at this code more. Their mqtt api is about three lines... so yeah.

dkerr64 commented 2 years ago

I am thinking I should default the refreshAfter to 10 seconds for the lock.... so rapid series of get requests are handled very quickly, but if 10 seconds had elapsed then it will get it again from YoLink. My hesitation is whether to set a timer to automatically update it whether requested by HomeKit or not. Currently if <60 seconds is requested then I don't bother with a timer... just letting it get the data "on demand". If I do let the timer run say every 60 seconds there will be a log entry, which is unnecessary -- I had designed this with the assumption that the timer would trigger much less frequently (it defaults to every 4 hours, because YoLink sensors (motion, leak, etc.) report back no more frequently than that. Temperature sensors report at least once an hour. So, you see, that this lock is not reporting status changes is very unusual.

ShamelessWizard commented 2 years ago

Even the YoLink app has some weird behaviors with the locking behavior of the Smart Lock. Especially if I double send a request. refreshAfter 10 is probably a good idea for on demand.. I've got one email out asking where I should direct my request regarding the mqtt behavior. I think it is a bit early to start remodeling behavior. It's just not in the report channel. I confirmed this with tcpdump on the mqtt port. I could monitor updates for things that are working, but nothing for the smartlock. I'm fairly safe to install it in the door now as I believe we just need backend changes.

dkerr64 commented 2 years ago

Lets see what YoLink has to say. In the meantime I pushed an update that sets refreshAfter to 10 seconds if a specific value is not set in the config file... and updated the readme to document where we are at.

ShamelessWizard commented 2 years ago

Just tested the update. It's very snappy on lock and unlock now.

hdinwiddie commented 2 years ago

@dkerr64 @ShamelessWizard After updating to 1.2.7 I noticed something I haven't noticed before. When I have the Home app open and am looking at it while manually changing the lock to locked or unlocked it doesn't update. If, however, I have the app opened and am doing something else (Home app now in the background" like email, and go back to the Home app, after the earlie manual change the Lock tile shows "updating" and after a few seconds will come back to the correct status... YoLink isn't the only Plugin that shows "updating" after bringing the Home app to the foreground as the Switchbot Plugin's devices do the same thing. I decided to try manually turning on/off a Switchbot plug/outlet and it acted just like the YoLink Lock does. This might be an issue that will be tough to solve, I'd think?
I then tried the same thing with a YoLink plug/outlet by turning it off/on from the plug while looking at it in the Home app and it updated to the correct status quickly.

dkerr64 commented 2 years ago

This is expected behavior. The outlet is sending status updates when you control it manually, but the lock does not. To work around that I changed how frequently to check the lock status… that takes time waiting for the reply over the internet during which Apple Home shows updating.

ShamelessWizard commented 2 years ago

Looks like it is showing up in the MQTT report channel now! I guess they did listen to my messages.

These messages appear as I manipulate it with the YoLink App.

[9/11/2022, 3:26:12 PM] [YoLink] [verbose] MQTT message: yl-home/c460b484e49b4c08b33647d9815c9741/d88b4c0100036572/report {"event":"Lock.setState","time":1662924372432,"msgid":"1662924372432","data":{"state":"locked","loraInfo":{"signal":-58,"gatewayId":"d88b4c1603011301","gateways":1},"source":"app"},"deviceId":"d88b4c0100036572"} [9/11/2022, 3:26:12 PM] [YoLink] [verbose] Battery level for Smart Lock M1 (d88b4c0100036572) is: 100% [9/11/2022, 3:26:12 PM] [YoLink] At 9/11/2022, 3:26:12 PM: Device state for Smart Lock M1 (d88b4c0100036572) is: Lock: locked, Battery: undefined (MQTT: Lock.setState)

[9/11/2022, 3:26:17 PM] [YoLink] [verbose] MQTT message: yl-home/c460b484e49b4c08b33647d9815c9741/d88b4c0100036572/report {"event":"Lock.setState","time":1662924377373,"msgid":"1662924377372","data":{"state":"unlocked","loraInfo":{"signal":-61,"gatewayId":"d88b4c1603011301","gateways":1},"source":"app"},"deviceId":"d88b4c0100036572"} [9/11/2022, 3:26:17 PM] [YoLink] [verbose] Battery level for Smart Lock M1 (d88b4c0100036572) is: 100% [9/11/2022, 3:26:17 PM] [YoLink] At 9/11/2022, 3:26:17 PM: Device state for Smart Lock M1 (d88b4c0100036572) is: Lock: unlocked, Battery: undefined (MQTT: Lock.setState)

dkerr64 commented 2 years ago

Excellent, thank you @ShamelessWizard. I ordered a lock and it just arrived so I will be able to start testing it myself soon.

ShamelessWizard commented 2 years ago

It will be a sad and joyless experience now. I've taken that from you. I might end up doing shelly switches for the light switches. I'll look at what YoLink has. We may have another adventure in store! Until next time!

dkerr64 commented 2 years ago

YoLink have a firmware update for the lock. Looks like that makes the difference. I just powered up the lock this morning and after initial playing went into YoLink app settings and found there was new firmware. As soon as that was complete the lock sent the following MQTT message...

{
    "event": "Lock.Report",
    "time": 1662985513116,
    "msgid": "1662985513115",
    "data": {
        "state": "unlocked",
        "battery": 4,
        "rlSet": "left",
        "tz": -4,
        "version": "060d",
        "loraInfo": {
            "signal": -69,
            "gatewayId": "xxx",
            "gateways": 1
        }
    },
    "deviceId": "xxx"
}

And then manually locking by turning the knob...

{
    "event": "Lock.StatusChange",
    "time": 1662985760935,
    "msgid": "1662985760934",
    "data": {
        "state": "locked",
        "battery": 4,
        "rlSet": "left",
        "loraInfo": {
            "signal": -61,
            "gatewayId": "xxx",
            "gateways": 1
        }
    },
    "deviceId": "xxx"
}

This is VERY good sign... and already supported by my plugin (I think, need to test to confirm).

dkerr64 commented 2 years ago

@ShamelessWizard, @hdinwiddie. The firmware update for the lock seems to have solved the no-MQTT problem. The plugin now receives timely MQTT reports whether the lock is controlled manually, with a PIN code or from the YoLink app. It is interesting that unlock events are reported as an "Alert" while lock events are a "StatusChange". I was not handling Alerts so had to add that.

Because MQTT appears to be working well, I have removed the 10 second refresh timer... locks are now handled like any other device.

I'm going to declare the lock supported now and no longer experimental.

Download 1.2.8 for the updated code. I am closing this issue. If new problems found please open a new bug report.

Thanks for all your help.

ShamelessWizard commented 2 years ago

I was up to date on the firmware. It was simply not in the report channel. I did nothing and mqtt started working.

On Sep 12, 2022, at 3:11 PM, David Kerr @.***> wrote:

 @ShamelessWizard, @hdinwiddie. The firmware update for the lock seems to have solved the no-MQTT problem. The plugin now receives timely MQTT reports whether the lock is controlled manually, with a PIN code or from the YoLink app. It is interesting that unlock events are reported as an "Alert" while lock events are a "StatusChange". I was not handling Alerts so had to add that.

Because MQTT appears to be working well, I have removed the 10 second refresh timer... locks are now handled like any other device.

I'm going to declare the lock supported now and no longer experimental.

Download 1.2.8 for the updated code. I am closing this issue. If new problems found please open a new bug report.

Thanks for all your help.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.