Oh-knob-cell and displayState

I have a widget on a page which is bound to an item that controls my hybrid solar inverter putting it into forced charge/discharge mode. This is done via a modbus binding, which sends a register value of 0 for off, 1 for forced charge and 2 for forced discharge.

The display state of the modbus item maps 0,1,2 to Off, Charge, Discharge

However many times the widgets display is out of synch with the underlying item. E.g it showing charge even though the item value is 0

The YAML for the widget is

component: oh-knob-cell
config:
  item: Battery_Discharge_Mode_Value_as_Number
  subtitle: =items["Battery_Discharge_Mode_Value_as_Number"].displayState
  min: 0
  max: 2
  step: 1
  title: Discharge Mode
  ignoreDisplayState: false
  releaseOnly: true

The code for the item is

version: 1
items:
  Battery_Discharge_Mode_Value_as_Number:
    type: Number
    label: Battery Discharge Mode Value as Number
    tags:
      - Point
    channel: modbus:data:Solis_Discharge:Solis_43135:number
    metadata:
      stateDescription:
        value: ' '
        config:
          min: 0
          max: 2
          step: 1
          options: "0=OFF,1=CHARGE,2=DISCHARGE"
          pattern: '%s'

The Modbus definition is

UID: modbus:data:Solis_Discharge:Solis_43135
label: Battery Discharge Mode
thingTypeUID: modbus:data
configuration:
  readValueType: uint16
  readTransform:
    - default
  writeType: holding
  writeTransform:
    - default
  readStart: "43135"
  updateUnchangedValuesEveryMillis: 1000
  writeValueType: int16
  writeMultipleEvenWithSingleRegisterOrCoil: false
  writeMaxTries: 3
  writeStart: "43135"
bridgeUID: modbus:poller:4dc853c392:Solis_Discharge
channels:
  - id: number
    channelTypeUID: modbus:number-type
    label: Value as Number
    description: Number item channel
    configuration: {}

What configuration change is needed ?

That sounds like a bug. Your widget code looks correct to me.

Do you see this in one particular browser or all devices and browsers?

What version of OH are you using?

There are situations where just calling the .displayState of an item in the widget expression can lead to problems where the displayState is invalid, but this should not be one of those situations.

There are couple of things you can check to see if this is really a bug in the UI or just some strange behavior of your system/browser.

The next time this happens open the Developer Sidebar (alt + shft + d) and go to the Code Tools Widget expression tester and paste in: =items[“Battery_Discharge_Mode_Value_as_Number”] (without the displayState). That should show you the whole items object for that item which might tell us something.

Also check your browser console when you see this happen to see if there are any obvious errors.

Thanks, version info is

openHAB 5.0.1
Release Build

Main UI Commit 540f6daf 

I can reproduce the situation a bit more:

  • click the widget, set the value to Charge (1), wait a few seconds and the widget resets itself to 0.

So visually it is reading “0” in the centre of the widget and the circular indicator has gone back to the left (0) but the text is reading Charge”. Closing the widget the text still reads Charge.

Reopening the widget leads to teh confusing state as the visual feedback from the bar is 0 (as it the value in the centre) but the text still says charge.

Using the debugging tool shows the actual value of the item is 1

{ "state": "1", "displayState": "CHARGE", "numericState": 1, "type": "Decimal" } 

So it appears the widget is not polling the value correctly.

Are you using Firefox when you see this issue? There have been issues in the past related to Firefox’s data caching. Those should be cleared up with the version you are on, but this sounds a little like those older problems.

version 144.02 on Ubuntu. I stick with the latest stable releases.

It seems counter intuitive but, when I click the “Ignore Display State” option then the synchronisation works properly.

The prompt under the options says “Ignore the display state if available and always use the raw state.“

So I’m guessing that the widget then reads the raw state for synchronisation and maps that to the displayState to actually paint the control ?

D’oh, of course, that should have occurred to me, sorry about that. I was too busy trying to understand the partial function you were getting before. To be honest, it’s still bothering me.

Without ignoreDisplayState the knob will always use the displayState as the source of the value and only fall back to the state in those instances where there is no valid displayState. Your item should always have a valid displayState (the displayState will always be different than the value since you are mapping numeric to string), so there should never be a point where the knob reads the state instead. But, the displayState, being a non-numeric value should never have given the knob a valid result. So, why did it even partially work?

With ignoreDisplayState set to true, the widget will use the numeric raw state values and only those. There’s no mapping back to the displayState as far as the knob is concerned (you’ve done that explicitly withsubtitle: =items["Battery_Discharge_Mode_Value_as_Number"].displayState) but the position of knob indicator is based solely on that numeric state.

There’s something else going on here as well, but at least you have a solution to your immediate problem.

1 Like