Building a binding with gradle

I’m currently trying to build a little binding controlling a custom backend (as a standalone plugin, not to be integrated in the main addon repo). Because I’m not at all familiar with maven (and all it’s black magic) and I’m making use of some custom build logic, I’m using gradle for the build.
It’s also kinda working so far, I can build it, install it (via bundle:install) and start it, but I can’t see the custom binding, even after restart. Also no logs mentioning anything seemingly.

The bundle.xml is present in the final jar and so is the MANIFEST.MF and the HandlerFactory XML file in the OSGI-INF Folder.

MANIFEST.MF

Manifest-Version: 1.0
Bnd-LastModified: 1622580155443
Bundle-ManifestVersion: 2
Bundle-Name: Secure GPIO
Bundle-SymbolicName: secure-gpio
Bundle-Version: 1.0.0.SNAPSHOT
Created-By: 16.0.1 (AdoptOpenJDK)
Export-Package: com.gitlab.cromefire.openhabsecuregpio;uses:="org.open
 hab.core.thing,org.openhab.core.thing.binding,org.openhab.core.thing.
 type,org.openhab.core.types";version="1.0.0"
Import-Package: java.io,java.math,java.net,java.nio,java.nio.channels,
 java.nio.charset,java.security,java.text,java.time,java.util,java.uti
 l.concurrent,java.util.concurrent.atomic,java.util.concurrent.locks,j
 ava.util.function,java.util.jar,java.util.logging,java.util.regex,jav
 a.util.stream,java.util.zip,javax.lang.model.element,org.openhab.core
 .thing;version="[3.0,4)",org.openhab.core.thing.binding;version="[3.0
 ,4)",org.openhab.core.thing.type;version="[3.0,4)",org.openhab.core.t
 ypes;version="[3.0,4)",sun.misc
Private-Package: OH-INF.binding,com.gitlab.cromefire.openhabsecuregpio
 .protocol,com.google.common.annotations,com.google.common.base,com.go
 ogle.common.cache,com.google.common.collect,com.google.common.escape,
 com.google.common.eventbus,com.google.common.graph,com.google.common.
 hash,com.google.common.html,com.google.common.io,com.google.common.ma
 th,com.google.common.net,com.google.common.primitives,com.google.comm
 on.reflect,com.google.common.util.concurrent,com.google.common.util.c
 oncurrent.internal,com.google.common.xml,com.google.errorprone.annota
 tions,com.google.errorprone.annotations.concurrent,com.google.j2objc.
 annotations,com.google.protobuf,google.api,google.cloud.audit,google.
 geo.type,google.logging.type,google.longrunning,google.protobuf,googl
 e.protobuf.compiler,google.rpc,google.rpc.context,google.type,io.grpc
 ,io.grpc.internal,io.grpc.kotlin,io.grpc.netty,io.grpc.protobuf,io.gr
 pc.protobuf.lite,io.grpc.stub,io.grpc.stub.annotations,io.perfmark,ja
 vax.annotation,javax.annotation.concurrent,javax.annotation.meta,java
 x.annotation.security,kotlin,kotlin.annotation,kotlin.collections,kot
 lin.collections.builders,kotlin.collections.jdk8,kotlin.collections.u
 nsigned,kotlin.comparisons,kotlin.coroutines,kotlin.coroutines.cancel
 lation,kotlin.coroutines.intrinsics,kotlin.coroutines.jvm.internal,ko
 tlin.experimental,kotlin.internal,kotlin.internal.jdk7,kotlin.interna
 l.jdk8,kotlin.io,kotlin.js,kotlin.jvm,kotlin.jvm.functions,kotlin.jvm
 .internal,kotlin.jvm.internal.markers,kotlin.math,kotlin.native.concu
 rrent,kotlin.random,kotlin.random.jdk8,kotlin.ranges,kotlin.reflect,k
 otlin.sequences,kotlin.streams.jdk8,kotlin.text,kotlin.text.jdk8,kotl
 in.time,kotlin.time.jdk8,kotlinx.coroutines,kotlinx.coroutines.channe
 ls,kotlinx.coroutines.flow,kotlinx.coroutines.flow.internal,kotlinx.c
 oroutines.internal,kotlinx.coroutines.intrinsics,kotlinx.coroutines.s
 cheduling,kotlinx.coroutines.selects,kotlinx.coroutines.sync,org.chec
 kerframework.checker.nullness.compatqual,org.jetbrains.annotations
Provide-Capability: osgi.service;objectClass:List<String>="com.gitlab.
 cromefire.openhabsecuregpio.SecureGPIOHandlerFactory";uses:="com.gitl
 ab.cromefire.openhabsecuregpio"
Require-Capability: osgi.extender;filter:="(&(osgi.extender=osgi.compo
 nent)(version>=1.4.0)(!(version>=2.0.0)))",osgi.ee;filter:="(&(osgi.e
 e=JavaSE)(version=11))"
Service-Component: OSGI-INF/com.gitlab.cromefire.openhabsecuregpio.Sec
 ureGPIOHandlerFactory.xml
Tool: Bnd-5.3.0.202102221516

Not sure if I’m doing something obviously wrong or if there is some weird OSGI stuff being picky.

Code: Files · b7f0d70bd6b30e2cc609f012f66e9b38496dfeb3 · Cromefire_ / OpenHAB Secure GPIO · GitLab
To build it just run ./gradlew :binding:build, the jar file will be at bridge/build/libs/secure-gpio-[version]-bundle.jar.

I‘m not at all familiar with gradle, but what is wrong with the „usual“ way? If you checkout openhab-addons and use the script for creating a new binding you don‘t need to know anything about maven at all.

Well the build is more complex. In the case of the addon I also work with protobuf & grpc and a rust daemon in the same build and then to add to that the protobuf code is shared almond the rust daemon and the kotlin binding, so it isn’t a good fit for the main addon repo I guess and it’s also a lot more complex in build than just the addon build.

It is very likely to be a cese for you. When you do a list command, can you see your extension set into Active state (second column)? This is ultimate requirement to get services and other XML descriptors be parsed.
You can also do a quick test of what being exported from your bundle via services -a -p <bundle-id> call just to double check that HandlerFactory service is properly declared.
There are some border cases where you might experience troubles, especially when bridging kotlin/java/osgi.
Do you have any errors in log file? Looking at your sources you miss declaration of thing types (in XML) or own implementation of ThingTypeProvider.

1 Like

Yeah, it’s active, I already checked that (I have some limited OSGI experience).

I’ll try that command and have a look at the ThingHandlerProvider (that might be it, I wasn’t aware that that’s a thing).

I couldn’t find anything in the openhab, audit or event log.

Added a ThingTypeProvider, still no result.

I think that works:

Secure GPIO (274) provides:
---------------------------
service.id = 576
service.bundleid = 274
service.scope = bundle
objectClass = [com.gitlab.cromefire.openhabsecuregpio.SecureGPIOHandlerFactory]
component.name = com.gitlab.cromefire.openhabsecuregpio.SecureGPIOHandlerFactory
component.id = 389
----
service.id = 577
service.bundleid = 274
service.scope = bundle
objectClass = [com.gitlab.cromefire.openhabsecuregpio.SecureGPIOThingTypeProvider]
component.name = com.gitlab.cromefire.openhabsecuregpio.SecureGPIOThingTypeProvider
component.id = 390

OSGI seems fine.

Update your @Component annotations to explicitly declare ThingTypeProvider, ThingHandlerFactory and so on. It is set via service attribute on annotation.
If you have above then it should click. You can also try doing very basic test with a small thing type set declared in XML. You should be able to see new thing types in UI regardless of handler factory. This linking is made later, when actual thing is instantiated.

It seems to have worked partially. If I try to create a new thing the binding is now listed, but further down the line after selecting the binding it just shows No thing types can be added with this binding.. It also doesn’t list the binding under the bindings menu in the settings.

Bindings in the addons folder are never listed.

The thing not showing was actually my fault, it didn’t name the UIDs correctly. Thanks for the (good) support y’all.

One last question maybe, is there some better workflow for iterating than to just always execute bundle:uninstall, bundle:install, bundle:start and bundle:status? (Maybe something I can plug into IDEA or Gradle, that can handle it remotely via the API or similar techniques)

If you seek a quick update then do bundle:update. It will re-attempt to fetch JAR from install location (ie. mvn:abc/def/xyz-SNAPSHOT). You can also point update location by calling update <bundle-id> file:/path/to/new.jar. Every next call of update <bundle-id> should try given path.
Last resort is bundle:watch. This one should automatically react on updated JAR in your ~/.m2/repository.

Okay thanks, will give that a try