Yale/August smart locks with WiFi support

This binding integrates some Yale/August locks that are linked to a Yale/August Connect WiFi Bridge.

Support for reading/writing lock bolt state and reading door ajar state as well as battery.

Resources

Jar file (OH4)

Jar file (OH3)

Source code and documentation

beer_me

Changelog

Version 0.11 + 0.12 + 0.13

  • Updated API key for Yale API backend. Thanks @jpalo !
  • Add support for accounts migrated to Yale Home App

I need your help!

The API is undocumented and development is based on analysing 3rd party SDKs and trial/error.

I’m trying to decode the lockType parameter - if it cannot decode please post to the forum which lock you have. You find this information in the thing properties.

2 Likes

Thanks - this is really cool!

Installed under openhab 3, managed to get the bridge installed and discovered a lock. Everything fine for about 15 minutes, after which the bridge went offline with the following message:

Status:

OFFLINE

COMMUNICATION_ERROR

Error fetching data: Error sending request to server: org.eclipse.jetty.client.HttpResponseException: HTTP protocol violation: Authentication challenge without WWW-Authenticate header

Tried to restart openhab, but did not help. Any ideas?

Appears that the session expired very quickly.

Could you enable logs, remove any sensitive data and send them to me via PM?

Regards
Arne

Hi @Casper_Lassenius, the same thing happened to me as well. Found a snag in the code, I updated the linked jar (see top) file with a fix.

Thanks for testing!

Thanks for both the great work and the swift response!

Casper

BTW did you test with some other lock than the Yale Doorman L3? I believe more locks should work, but I have none to test with.

Arne

Yes, the Doorman V2N with the Access module and Wi-Fi bridge. Works like a charm.

Casper

Added a new version that supports push messages from server. This gives more instant response when the lock or door status is changed.

I’d appreciate if you could give it a spin @Casper_Lassenius.

If anyone else is using this binding, feel free to respond to this post so I know if it is working for other locks or users as well - if anyone else is using the binding at all? openHAB system provides close to 0 feedback (by design), but it also leaves developers in the dark regarding usage.

I am giving this a try this evening and I’m having trouble figuring out how to get the lockid. I’ve added the bridge and updated with the validation code from email. I can see from the openhab.log that it has logged in to the August account and has found the correct number of locks, but what do I do from there to find the lockid for each lock (i.e, how do I find the bridge to see the locks it has discovered)?

Thanks,
Jeff

I ended up using the Rest API to trigger a discovery for the binding, then my locks showed up in my Inbox and I was able to add things for them. Getting it all setup with items now, so I’ll report back if I encounter any other issues. Thanks!

Thought I’d take a look about setting this up with my old August Pro (3rd Gen). When I try to save the validation code, I get this error every time:

2023-02-05 21:10:40.640 [ERROR] [st.core.internal.thing.ThingResource] - Exception during HTTP PUT request for update config at 'things/august:account:ed82c29c49/config'
Full Error
java.lang.NullPointerException: null
	at org.openhab.binding.august.internal.comm.PubNubMessageSubscriber.dispose(PubNubMessageSubscriber.java:238) ~[?:?]
	at org.openhab.binding.august.internal.handler.AugustAccountHandler.dispose(AugustAccountHandler.java:234) ~[?:?]
	at org.openhab.core.thing.binding.BaseThingHandler.handleConfigurationUpdate(BaseThingHandler.java:108) ~[?:?]
	at org.openhab.core.thing.internal.ThingRegistryImpl.updateConfiguration(ThingRegistryImpl.java:94) ~[?:?]
	at org.openhab.core.io.rest.core.internal.thing.ThingResource.updateConfiguration(ThingResource.java:505) ~[?:?]
	at jdk.internal.reflect.GeneratedMethodAccessor683.invoke(Unknown Source) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:179) ~[bundleFile:3.4.5]
	at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) ~[bundleFile:3.4.5]
	at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:201) ~[bundleFile:3.4.5]
	at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:104) ~[bundleFile:3.4.5]
	at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59) ~[bundleFile:3.4.5]
	at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96) ~[bundleFile:3.4.5]
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) ~[bundleFile:3.4.5]
	at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) ~[bundleFile:3.4.5]
	at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:265) ~[bundleFile:3.4.5]
	at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) ~[bundleFile:3.4.5]
	at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) ~[bundleFile:3.4.5]
	at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) ~[bundleFile:3.4.5]
	at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:225) ~[bundleFile:3.4.5]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:298) ~[bundleFile:3.4.5]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPut(AbstractHTTPServlet.java:234) ~[bundleFile:3.4.5]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:710) ~[bundleFile:3.1.0]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:273) ~[bundleFile:3.4.5]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:550) ~[bundleFile:9.4.46.v20220331]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:74) ~[bundleFile:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440) ~[bundleFile:9.4.46.v20220331]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:294) ~[bundleFile:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) ~[bundleFile:9.4.46.v20220331]
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:90) ~[bundleFile:?]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.Server.handle(Server.java:516) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487) ~[bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) [bundleFile:9.4.46.v20220331]
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) [bundleFile:9.4.46.v20220331]
	at java.lang.Thread.run(Thread.java:829) [?:?]

After adding a bridge, the regular discovery should find them if you push the “Scan” button?

Thanks for testing @JustinG.

I seem to have introduced a regression in the 2 factor login when adding async messages.

I posted a new version at the top, let me know if this fixes login.

Regards
Arne

Yep. that was it. Thanks for the quick fix.

Initial testing indicates that it works very well with the August Pro Gen3. I’m delighted by this because the z-wave connection on this lock was starting to get on my nerves (always asleep unless the lock had just been manually used, but what’s the point of a remote connect that requires you to use the lock first?).

I’ll report back after some longer term usage.

Great!

I keep a list of tested devices on the README page, could you confim this is your config?

Cheers

After getting this set up about 12 hours ago things appear to be working correctly for me today and my 3 locks:

  • Yale YR C/D 226/246/256
  • ASL-03 3rd Gen Pro (2 of these)

Thanks!

1 Like

That’s correct.

Just in case anybody else has problems with “Could not resolve module: org.openhab.binding.august” and “Unresolved requirement: Import-Package: org.json” after downloading this module: I downloaded json-20220924.jar and placed in the /usr/share/openhab/addons directory. and now it loads.

I posted a new version that might fix this, do you mind testing @austvik ?

Cheers

Tested, but I still get the same exception with alpha 5.

2023-02-13 08:27:29.937 [WARN ] [org.apache.felix.fileinstall        ] - Error while starting bundle: file:/usr/share/openhab/addons/org.openhab.binding.august-3.4.0-SNAPSHOT.jar
org.osgi.framework.BundleException: Could not resolve module: org.openhab.binding.august [336]
  Unresolved requirement: Import-Package: kotlin.internal.jdk7; resolution:="optional"
  Unresolved requirement: Import-Package: kotlin.internal.jdk8; resolution:="optional"
  Unresolved requirement: Import-Package: android.net.http; resolution:="optional"
  Unresolved requirement: Import-Package: android.net.ssl; resolution:="optional"
  Unresolved requirement: Import-Package: android.os; resolution:="optional"
  Unresolved requirement: Import-Package: android.security; resolution:="optional"
  Unresolved requirement: Import-Package: android.util; resolution:="optional"
  Unresolved requirement: Import-Package: org.bouncycastle.jsse; resolution:="optional"
  Unresolved requirement: Import-Package: org.bouncycastle.jsse.provider; resolution:="optional"
  Unresolved requirement: Import-Package: org.openjsse.javax.net.ssl; resolution:="optional"
  Unresolved requirement: Import-Package: org.openjsse.net.ssl; resolution:="optional"
  Unresolved requirement: Import-Package: dalvik.system; resolution:="optional"
  Unresolved requirement: Import-Package: javax.annotation.meta; resolution:="optional"
  Unresolved requirement: Import-Package: org.conscrypt; resolution:="optional"
  Unresolved requirement: Import-Package: sun.security.ssl; resolution:="optional"
  Unresolved requirement: Import-Package: org.json; version="[20180813.0.0,20180814.0.0)"
	at org.eclipse.osgi.container.Module.start(Module.java:463) ~[org.eclipse.osgi-3.17.200.jar:?]
	at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:445) ~[org.eclipse.osgi-3.17.200.jar:?]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1260) [bundleFile:3.7.4]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1233) [bundleFile:3.7.4]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.doProcess(DirectoryWatcher.java:520) [bundleFile:3.7.4]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:365) [bundleFile:3.7.4]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:316) [bundleFile:3.7.4]