Trouble with the Gain-Offset Correction profile

Hi all, I’m having trouble getting the Gain-Offset Correction profile working (at least, how I think it should work.)

I’m running openHAB 3.3.0.M6 in a docker container on Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-120-generic x86_64.) I have Clipsal PIR occupancy sensors that broadcast luminance measurements to the CBus network as a percentage of their 2550 lux range. These propagate into OH just fine, and the associated item updates.

I would like to apply a multiplier to these values to convert them from a percentage to an absolute lux value, by multiplying the value received from the channel by 25.5.

In the UI, I go to the Item screen (via Things → Channels → Linked Items.) I change the profile from Default to Gain-Offset Correction, I put 25.5 in the gain box, and click Save.

After this, it seems that no values propagate through to the item - it’s value doesn’t change. I’m not seeing any errors in the logs.

Have I got this wrong? Is there something different I need to do?

Thanks in advance, Jon.

I’ve made no progress on this. I guess the solution is just to use a proxy item instead.

The gain offset profile is provided by the modbus binding Modbus - Bindings | openHAB

It is designed to work with raw Numbers (not having associated UoM) from the binding, and scaling/offsetting values towards the item, potentially attaching an unit to otherwise dimensionless Number. The other way works as well.

While the profile is offered by modbus binding, it is usable with other bindings as long the use case is same as above.

  1. What is the input you use with the profile? Are they plain numbers or do they have UoM?
  2. Is there any errors or warnings in the logs? For additional troubleshooting you can set “TRACE” logging for org.openhab.binding.modbus.internal.profiles. Share a snippet of logs when new value is parsed

EDIT: quickly checked what cbus is about. The light level seems to be of type Dimmer, updating its state as PercentType which is subclass of DecimalType (I.e . plain number). I would expect this to work with the profile.

Ah, OK, I didn’t realise that this profile is provided by the Modbus binding. That explains why it’s not covered in the profiles documentation.

I think the number coming from the channel is a raw number. In realty it’s a percentage, but I don’t think units are passed from CBus to OH.

I tries wetting the log level to TRACE as you’ve describes, and here are the results:

:34:31.387 [DEBUG] [rnal.profiles.ModbusGainOffsetProfile] - Configuring profile with pre-gain-offset parameter '0.0'
16:34:31.388 [DEBUG] [rnal.profiles.ModbusGainOffsetProfile] - Configuring profile with gain parameter '25.5'
16:34:31.389 [TRACE] [rnal.profiles.ModbusGainOffsetProfile] - State update '3' from handler, sending converted '76.5' state towards item.
16:34:31.390 [ERROR] [core.common.registry.AbstractRegistry] - Cannot inform the listener "org.openhab.core.thing.internal.ChannelLinkNotifier@c282070" about the "ADDED" event: Value must be between 0 and 100
java.lang.IllegalArgumentException: Value must be between 0 and 100
	at org.openhab.core.library.types.PercentType.validateValue(PercentType.java:93) ~[?:?]
	at org.openhab.core.library.types.PercentType.<init>(PercentType.java:88) ~[?:?]
	at org.openhab.core.library.types.QuantityType.as(QuantityType.java:405) ~[?:?]
	at org.openhab.core.internal.items.ItemStateConverterImpl.convertToAcceptedState(ItemStateConverterImpl.java:64) ~[?:?]
	at org.openhab.core.thing.internal.profiles.ProfileCallbackImpl.sendUpdate(ProfileCallbackImpl.java:121) ~[?:?]
	at org.openhab.binding.modbus.internal.profiles.ModbusGainOffsetProfile.onStateUpdateFromHandler(ModbusGainOffsetProfile.java:126) ~[?:?]
	at org.openhab.core.thing.internal.CommunicationManager.lambda$13(CommunicationManager.java:566) ~[?:?]
	at org.openhab.core.thing.internal.CommunicationManager.lambda$15(CommunicationManager.java:586) ~[?:?]
	at java.lang.Iterable.forEach(Iterable.java:75) ~[?:?]
	at org.openhab.core.thing.internal.CommunicationManager.handleCallFromHandler(CommunicationManager.java:582) ~[?:?]
	at org.openhab.core.thing.internal.CommunicationManager.stateUpdated(CommunicationManager.java:564) ~[?:?]
	at org.openhab.core.thing.internal.ThingManagerImpl$1.stateUpdated(ThingManagerImpl.java:176) ~[?:?]
	at org.openhab.core.thing.binding.BaseThingHandler.updateState(BaseThingHandler.java:268) ~[?:?]
	at org.openhab.binding.cbus.handler.CBusLightHandler.handleCommand(CBusLightHandler.java:61) ~[?:?]
	at org.openhab.core.thing.binding.BaseThingHandler.channelLinked(BaseThingHandler.java:180) ~[?:?]
	at org.openhab.core.thing.internal.ChannelLinkNotifier.lambda$3(ChannelLinkNotifier.java:72) ~[?:?]
	at org.openhab.core.thing.internal.ChannelLinkNotifier.call(ChannelLinkNotifier.java:96) ~[?:?]
	at org.openhab.core.thing.internal.ChannelLinkNotifier.added(ChannelLinkNotifier.java:72) ~[?:?]
	at org.openhab.core.thing.internal.ChannelLinkNotifier.added(ChannelLinkNotifier.java:1) ~[?:?]
	at org.openhab.core.common.registry.AbstractRegistry.notifyListeners(AbstractRegistry.java:367) ~[?:?]
	at org.openhab.core.common.registry.AbstractRegistry.notifyListenersAboutAddedElement(AbstractRegistry.java:400) ~[?:?]
	at org.openhab.core.thing.link.ItemChannelLinkRegistry.notifyListenersAboutAddedElement(ItemChannelLinkRegistry.java:138) ~[?:?]
	at org.openhab.core.thing.link.ItemChannelLinkRegistry.notifyListenersAboutAddedElement(ItemChannelLinkRegistry.java:1) ~[?:?]
	at org.openhab.core.common.registry.AbstractRegistry.added(AbstractRegistry.java:175) ~[?:?]
	at org.openhab.core.common.registry.AbstractRegistry.added(AbstractRegistry.java:1) ~[?:?]
	at org.openhab.core.common.registry.AbstractProvider.notifyListeners(AbstractProvider.java:60) ~[?:?]
	at org.openhab.core.common.registry.AbstractProvider.notifyListeners(AbstractProvider.java:79) ~[?:?]
	at org.openhab.core.common.registry.AbstractProvider.notifyListenersAboutAddedElement(AbstractProvider.java:83) ~[?:?]
	at org.openhab.core.common.registry.AbstractManagedProvider.add(AbstractManagedProvider.java:67) ~[?:?]
	at org.openhab.core.common.registry.AbstractRegistry.add(AbstractRegistry.java:346) ~[?:?]
	at org.openhab.core.io.rest.core.internal.link.ItemChannelLinkResource.link(ItemChannelLinkResource.java:238) ~[?:?]
	at jdk.internal.reflect.GeneratedMethodAccessor2307.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) [?:?]

The light level channel is configured to be a CBUS dimmer, as there aren’t too many CBUS object types. Looking at those logs, it looks like it’s complaining about wanting a percentage value.

This is what the profile is doing, trying to update item with state 76.5 (of type DecimalType)

This how openhab core reacts to the update:

What is the item definition you are using with the profile? It almost looks like it is Dimmer…might be interpreting 76.5 as 7650%. EDIT: yep, value is scaled by 100 by openHAB openhab-core/bundles/org.openhab.core/src/main/java/org/openhab/core/library/types/QuantityType.java at 193da095a8a8d2966b0c456c34c52f1d27e1148d · openhab/openhab-core · GitHub

BTW, you could potentially use gain of 76.5 lx gain with Number:Illuminance (if that is what you are after in the end)

Yes, that worked. Thank you.

My linked item was type “dimmer”. I changed that to Number:LluminousFlux (Number:Illuminance didn’t seem to work) and then set my gain to 25.5 lx.

Thanks again.

1 Like

Curious, what was the error with Illuminance? According to docs, it should have lux as unit. Actually, LluminousFlux should have lumen as unit, not lux.

Actually, it does work using Number:Illuminance. I’ve just tried it again and it works fine. I must have done something wrong when I tried it previously, as the item value became NULL.

Thanks again.

1 Like