Declarative Thing configuration

I’m trying to define a thing declaratively in the Thing file, but cannot figure out how the properties should be defined. I can define the Bridge just fine, but problem is with the individual Things.

A working bridge is:

Bridge lgthinq:bridge:df7c4e9d43 "LG ThinQ Bridge" [ country="--", manualCountry="FI", language="--", manualLanguage="fi-FI", username="my@email.com", password="mypwd" ] 
{ // thing comes here, see below
}

If I add a thing via UI, it will result with this in the org.openhab.core.thing.Thing.json:

  "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc": {
    "class": "org.openhab.core.thing.internal.ThingStorageEntity",
    "value": {
      "isBridge": false,
      "channels": ["OMITTED"],
      "label": "Washing Machine",
      "bridgeUID": "lgthinq:bridge:df7c4e9d43",
      "configuration": {},
      "properties": {
        "device_alias": "Washing Machine",
        "device_id": "459f59e5-d80e-1871-9e0a-4cbad7f8eddc",
        "modelId": "F_VB_Y___W.B_2QEUK",
        "model_url_info": "https://objectcontent.lgthinq.com/39dd1e90-5aea-4ace-8bd1-e10bed926779?hdnts\u003dexp\u003d1680656673~hmac\u003d2a73517c5d9a3aa0c27eb45320d54b28e71a56490e59b05eefe742a43e4a4d63",
        "platform_type": "thinq2"
      },
      "UID": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc",
      "thingTypeUID": "lgthinq:201"
    }

Now, turning that into Thing definition (and placed inside the Bridge definition) should be something like this:

{
    Thing 201 WashingMachine "Washing machine" [device_alias="Washing Machine", device_id="459f59e5-d80e-1871-9e0a-4cbad7f8eddc", modelId="F_VB_Y___W.B_2QEUK", model_url_info="https://objectcontent.lgthinq.com/39dd1e90-5aea-4ace-8bd1-e10bed926779?hdnts\u003dexp\u003d1680656673~hmac\u003d2a73517c5d9a3aa0c27eb45320d54b28e71a56490e59b05eefe742a43e4a4d63", platform_type="thinq2"]  

    // also decoding the unicode = chars in URL gives same result
    // Thing 201 WashingMachine "Washing machine" [device_alias="Washing Machine", device_id="459f59e5-d80e-1871-9e0a-4cbad7f8eddc", modelId="F_VB_Y___W.B_2QEUK", model_url_info="https://objectcontent.lgthinq.com/39dd1e90-5aea-4ace-8bd1-e10bed926779?hdnts=exp=1680656673~hmac=2a73517c5d9a3aa0c27eb45320d54b28e71a56490e59b05eefe742a43e4a4d63", platform_type="thinq2"]
}

However, it doesn’t work:

2022-11-28 17:40:57.680 [INFO ] [ab.event.ThingStatusInfoChangedEvent] - Thing 'lgthinq:201:df7c4e9d43:WashingMachine' changed from UNINITIALIZED to INITIALIZING

==> /var/log/openhab/openhab.log <==

2022-11-28 17:40:57.689 [DEBUG] [nternal.handler.LGThinQWasherHandler] - Initializing Thinq thing. Washer Thing v0.1

2022-11-28 17:40:57.691 [DEBUG] [nternal.handler.LGThinQWasherHandler] - initializeThing LQ Thinq lgthinq:201:df7c4e9d43:WashingMachine. Bridge status ONLINE

2022-11-28 17:40:57.693 [ERROR] [ices.LGThinQAbstractApiClientService] - Error reading resource from URI: 

java.net.MalformedURLException: no protocol: 

	at java.net.URL.<init>(URL.java:645) ~[?:?]

	at java.net.URL.<init>(URL.java:541) ~[?:?]

	at java.net.URL.<init>(URL.java:488) ~[?:?]

	at org.openhab.binding.lgthinq.lgservices.LGThinQAbstractApiClientService.loadDeviceCapability(LGThinQAbstractApiClientService.java:114) [bundleFile:?]

	at org.openhab.binding.lgthinq.lgservices.LGThinQAbstractApiClientService.getCapability(LGThinQAbstractApiClientService.java:248) [bundleFile:?]

	at org.openhab.binding.lgthinq.internal.handler.LGThinQAbstractDeviceHandler.getCapabilities(LGThinQAbstractDeviceHandler.java:192) [bundleFile:?]

	at org.openhab.binding.lgthinq.internal.handler.LGThinQWasherHandler.updateChannelDynStateDescription(LGThinQWasherHandler.java:110) [bundleFile:?]

	at org.openhab.binding.lgthinq.internal.handler.LGThinQAbstractDeviceHandler.initializeThing(LGThinQAbstractDeviceHandler.java:207) [bundleFile:?]

	at org.openhab.binding.lgthinq.internal.handler.LGThinQWasherHandler.initialize(LGThinQWasherHandler.java:105) [bundleFile:?]

	at jdk.internal.reflect.GeneratedMethodAccessor94.invoke(Unknown Source) ~[?:?]

	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]

	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]

	at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:154) [bundleFile:?]

	at org.openhab.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]

	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]

	at java.lang.Thread.run(Thread.java:829) [?:?]

2022-11-28 17:40:57.698 [ERROR] [nternal.handler.LGThinQWasherHandler] - Error updating channels dynamic options descriptions based on capabilities of the device. Fallback to default values.

org.openhab.binding.lgthinq.internal.errors.LGThinqApiException: Error reading IO interface

	at org.openhab.binding.lgthinq.lgservices.LGThinQAbstractApiClientService.loadDeviceCapability(LGThinQAbstractApiClientService.java:120) ~[bundleFile:?]

	at org.openhab.binding.lgthinq.lgservices.LGThinQAbstractApiClientService.getCapability(LGThinQAbstractApiClientService.java:248) ~[bundleFile:?]

	at org.openhab.binding.lgthinq.internal.handler.LGThinQAbstractDeviceHandler.getCapabilities(LGThinQAbstractDeviceHandler.java:192) ~[bundleFile:?]

	at org.openhab.binding.lgthinq.internal.handler.LGThinQWasherHandler.updateChannelDynStateDescription(LGThinQWasherHandler.java:110) ~[bundleFile:?]

	at org.openhab.binding.lgthinq.internal.handler.LGThinQAbstractDeviceHandler.initializeThing(LGThinQAbstractDeviceHandler.java:207) [bundleFile:?]

	at org.openhab.binding.lgthinq.internal.handler.LGThinQWasherHandler.initialize(LGThinQWasherHandler.java:105) [bundleFile:?]

	at jdk.internal.reflect.GeneratedMethodAccessor94.invoke(Unknown Source) ~[?:?]

	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]

	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]

	at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:154) [bundleFile:?]

	at org.openhab.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]

	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]

	at java.lang.Thread.run(Thread.java:829) [?:?]

Caused by: java.net.MalformedURLException: no protocol: 

	at java.net.URL.<init>(URL.java:645) ~[?:?]

	at java.net.URL.<init>(URL.java:541) ~[?:?]

	at java.net.URL.<init>(URL.java:488) ~[?:?]

	at org.openhab.binding.lgthinq.lgservices.LGThinQAbstractApiClientService.loadDeviceCapability(LGThinQAbstractApiClientService.java:114) ~[bundleFile:?]

	... 14 more

Any pointers what could be causing this and what am I configuring incorrectly in the Thing definition?

What does the JSON it produces look like? (API Explorer)

I have a worry that xxx.things input ends up in configuration{} JSON, nor properties{}

(For other readers, this story begins here

1 Like

If created via the Thing file (and NOT working), it is:

{
  "channels": [
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:WashingMachine:power",
      "id": "power",
      "channelTypeUID": "system:power",
      "itemType": "Switch",
      "kind": "STATE",
      "label": "Power",
      "description": "Device is operable when channel has state ON",
      "defaultTags": [
        "Switch",
        "Power"
      ],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:WashingMachine:state",
      "id": "state",
      "channelTypeUID": "lgthinq:washer-state",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer State",
      "description": "Washer State Operation",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:WashingMachine:course",
      "id": "course",
      "channelTypeUID": "lgthinq:washer-course",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer Course",
      "description": "Washer Course",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:WashingMachine:smart-course",
      "id": "smart-course",
      "channelTypeUID": "lgthinq:washer-smart-course",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer Smart Course",
      "description": "Washer Smart Course",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:WashingMachine:downloaded-course",
      "id": "downloaded-course",
      "channelTypeUID": "lgthinq:washer-downloaded-course",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer Downloaded Course",
      "description": "Washer Downloaded Course",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:WashingMachine:temperature-level",
      "id": "temperature-level",
      "channelTypeUID": "lgthinq:washer-temp-level",
      "itemType": "String",
      "kind": "STATE",
      "label": "Temperature Level",
      "description": "Target Temperature Level",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:WashingMachine:door-lock",
      "id": "door-lock",
      "channelTypeUID": "lgthinq:washer-door-lock",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer Door Lock",
      "description": "Washer Door Lock",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:WashingMachine:remain-time",
      "id": "remain-time",
      "channelTypeUID": "lgthinq:washerdryer-remain-time",
      "itemType": "DateTime",
      "kind": "STATE",
      "label": "Remaining Time",
      "description": "Remaining Time",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:WashingMachine:delay-time",
      "id": "delay-time",
      "channelTypeUID": "lgthinq:washerdryer-delay-time",
      "itemType": "DateTime",
      "kind": "STATE",
      "label": "Delay Time",
      "description": "Delay Time",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    }
  ],
  "statusInfo": {
    "status": "OFFLINE",
    "statusDetail": "COMMUNICATION_ERROR",
    "description": "Error starting device monitor in LG API for the device:undef"
  },
  "editable": false,
  "label": "Washing machine",
  "bridgeUID": "lgthinq:bridge:df7c4e9d43",
  "configuration": {
    "model_url_info": "https://objectcontent.lgthinq.com/39dd1e90-5aea-4ace-8bd1-e10bed926779?hdnts=exp=1680656673~hmac=2a73517c5d9a3aa0c27eb45320d54b28e71a56490e59b05eefe742a43e4a4d63",
    "device_id": "459f59e5-d80e-1871-9e0a-4cbad7f8eddc",
    "platform_type": "thinq2",
    "modelId": "F_VB_Y___W.B_2QEUK",
    "device_alias": "Washing Machine"
  },
  "properties": {},
  "UID": "lgthinq:201:df7c4e9d43:WashingMachine",
  "thingTypeUID": "lgthinq:201"
}

If created via UI (and working OK), it is:

{
  "channels": [
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc:power",
      "id": "power",
      "channelTypeUID": "system:power",
      "itemType": "Switch",
      "kind": "STATE",
      "label": "Power",
      "description": "Device is operable when channel has state ON",
      "defaultTags": [
        "Switch",
        "Power"
      ],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc:state",
      "id": "state",
      "channelTypeUID": "lgthinq:washer-state",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer State",
      "description": "Washer State Operation",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc:course",
      "id": "course",
      "channelTypeUID": "lgthinq:washer-course",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer Course",
      "description": "Washer Course",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc:smart-course",
      "id": "smart-course",
      "channelTypeUID": "lgthinq:washer-smart-course",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer Smart Course",
      "description": "Washer Smart Course",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc:downloaded-course",
      "id": "downloaded-course",
      "channelTypeUID": "lgthinq:washer-downloaded-course",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer Downloaded Course",
      "description": "Washer Downloaded Course",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc:temperature-level",
      "id": "temperature-level",
      "channelTypeUID": "lgthinq:washer-temp-level",
      "itemType": "String",
      "kind": "STATE",
      "label": "Temperature Level",
      "description": "Target Temperature Level",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc:door-lock",
      "id": "door-lock",
      "channelTypeUID": "lgthinq:washer-door-lock",
      "itemType": "String",
      "kind": "STATE",
      "label": "Washer Door Lock",
      "description": "Washer Door Lock",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc:remain-time",
      "id": "remain-time",
      "channelTypeUID": "lgthinq:washerdryer-remain-time",
      "itemType": "DateTime",
      "kind": "STATE",
      "label": "Remaining Time",
      "description": "Remaining Time",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    },
    {
      "linkedItems": [],
      "uid": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc:delay-time",
      "id": "delay-time",
      "channelTypeUID": "lgthinq:washerdryer-delay-time",
      "itemType": "DateTime",
      "kind": "STATE",
      "label": "Delay Time",
      "description": "Delay Time",
      "defaultTags": [],
      "properties": {},
      "configuration": {}
    }
  ],
  "statusInfo": {
    "status": "ONLINE",
    "statusDetail": "NONE"
  },
  "editable": true,
  "label": "Washing Machine",
  "bridgeUID": "lgthinq:bridge:df7c4e9d43",
  "configuration": {},
  "properties": {
    "model_url_info": "https://objectcontent.lgthinq.com/39dd1e90-5aea-4ace-8bd1-e10bed926779?hdnts=exp=1680656673~hmac=2a73517c5d9a3aa0c27eb45320d54b28e71a56490e59b05eefe742a43e4a4d63",
    "device_id": "459f59e5-d80e-1871-9e0a-4cbad7f8eddc",
    "platform_type": "thinq2",
    "modelId": "F_VB_Y___W.B_2QEUK",
    "device_alias": "Washing Machine"
  },
  "UID": "lgthinq:201:df7c4e9d43:459f59e5-d80e-1871-9e0a-4cbad7f8eddc",
  "thingTypeUID": "lgthinq:201"
}

And it indeed shows configuration vs. properties issue. :exploding_head:

I can’t/won’t spend too much time helping with things file syntax problems. But I can say that the names of the properties you see in the YAML in the code tab for the Thing in the UI, the JSON in the JSONDB and from the REST API, and the properties you use in the .things file will all be the same.

You won’t have a case where it’s device_id in one place and ID in another. It will be device_id everywhere.

Beyond that, the .things file syntax is documented at Things | openHAB. Comparing what you are trying with what’s documented there shows lots of differences. The generic structure documented there:

Thing <binding_id>:<type_id>:<thing_id> "Label" @ "Location" [ <parameters> ]

201 is definitely not a binding ID nor is “WashingMachine”, for example.

Syntax is valid as Thing is under a Bridge. I have lots if Bridges and Things configured in a similar manner. See here Things | openHAB

I’d draw conclusion at this point that the Binding in question works differently from other Bindings and expects for the configuration values to be in the properties object while correct place is in the configuration properties.

As e.g., with Hue binding, this Bridge+Thing definition

Bridge hue:bridge:g "MyHue" [ ipAddress="192.168.1.31", userName="xyz" ] {
    Thing 0107 65 "StaircaseMotion" [sensorId="65"]
}

gives Thing such as this:

{
  "...snip...": [],
  "statusInfo": {
    "status": "ONLINE",
    "statusDetail": "NONE"
  },
  "editable": false,
  "label": "StaircaseMotion",
  "bridgeUID": "hue:bridge:g",
  "configuration": {
    "sensorId": "65"
  },
  "properties": {},
  "UID": "hue:0107:g:65",
  "thingTypeUID": "hue:0107"
}

I think you’ve run into a fundamental problem; the discovery stuff I speculate goes in properties{}, while manually configured stuff goes in configuration{}.
In other bindings, “newly discovered” stuff can then be compared to existing Things for matches and ignored.

I do not know if a succesfully genuine newly discovered and accepted device would then normally have its setup transferred to configuration{} - seems reasonable, the info might need massaging in some way. A look at a zwave device (which binding is also heavily “discovery” led) might be informative.

But I further suspect this binding is simply not written to even look at configuration{}.

Appreaciate it @rossko57, we’ve reached the same conclusion. :+1: Will ask the binding developer about this as it doesn’t seem like a big update to perhaps take into account both, considering other Bindings do that too.

@jpalo Please keep in mind that the lgthinq binding is work in progress, so don‘t expect everything, especially textual config, is already working.
There might be a lot of changes during review process, which had not started yet.

1 Like