openhab / openhab-webui

Web UIs of openHAB
Eclipse Public License 2.0
212 stars 232 forks source link

Blockly: When loading a list with things, the list keeps changing randomly in the Blockly UI while adding more things #2552

Closed Boldfor closed 1 week ago

Boldfor commented 2 weeks ago

The problem

When creating a list in blockly (in my case: with 30+ items), as I am adding things to the list, preceeding elements keep changing (see video).

This behavior is so prevailing, that it is impossible for me to define a list of all my things, as elements of the list constantly keep changing, and fixing it changes other entries throughout the list.

https://github.com/openhab/openhab-webui/assets/37384006/a56c2223-9e0f-4829-bec9-79a0afac684d

Expected behavior

The list can be defined without items shifting that have been defined before.

Steps to reproduce

Re-build the "create list"-blockly-code as seen in the video, and try adding a large (>10 items) number of things.

Your environment

runtimeInfo:
  version: 4.1.1
  buildString: Release Build
locale: en-DE
systemInfo:
  configFolder: /openhab/conf
  userdataFolder: /openhab/userdata
  logFolder: /openhab/userdata/logs
  javaVersion: 17.0.9
  javaVendor: Debian
  osName: Linux
  osVersion: 6.1.0-rpi8-rpi-2712
  osArchitecture: aarch64
  availableProcessors: 4
  freeMemory: 372064752
  totalMemory: 1065353216
  uptime: 86531
  startLevel: 100
addons:
  - automation-jsscripting
  - binding-amazonechocontrol
  - binding-gardena
  - binding-homematic
  - binding-irobot
  - binding-mqtt
  - binding-systeminfo
  - binding-yamahamusiccast
  - binding-zigbee
  - binding-zwave
  - misc-openhabcloud
  - persistence-influxdb
  - persistence-rrd4j
  - transformation-jinja
  - transformation-jsonpath
  - transformation-regex
  - transformation-xpath
  - ui-basic
  - ui-habpanel
clientInfo:
  device:
    ios: false
    android: false
    androidChrome: false
    desktop: true
    iphone: false
    ipod: false
    ipad: false
    edge: false
    ie: false
    firefox: false
    macos: false
    windows: true
    cordova: false
    phonegap: false
    electron: false
    nwjs: false
    webView: false
    webview: false
    standalone: false
    os: windows
    pixelRatio: 1
    prefersColorScheme: dark
  isSecureContext: false
  locationbarVisible: true
  menubarVisible: true
  navigator:
    cookieEnabled: true
    deviceMemory: N/A
    hardwareConcurrency: 16
    language: de
    languages:
      - de
      - de-DE
      - en
      - en-GB
      - en-US
    onLine: true
    platform: Win32
  screen:
    width: 1920
    height: 1080
    colorDepth: 24
  support:
    touch: false
    pointerEvents: true
    observer: true
    passiveListener: true
    gestures: false
    intersectionObserver: true
  themeOptions:
    dark: dark
    filled: true
    pageTransitionAnimation: default
    bars: light
    homeNavbar: default
    homeBackground: default
    expandableCardAnimation: default
  userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
    like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
timestamp: 2024-04-29T15:01:27.150Z

Browser console

Browser network traffic

Additional information

rkoshak commented 2 weeks ago

This behavior is so prevailing, that it is impossible for me to define a list of all my things, as elements of the list constantly keep changing, and fixing it changes other entries throughout the list.

This is surely a problem that should be looked at but it's also an XY Problem. You shouldn't need to create a list of all your Things in the first place. OH supports getting all your Things as a List out of the box, but it appears that Blockly doesn't have a block for that (yet). But you can access the list of all Things using an inline script block with:

You can then plug "allThings" into the for each loop block.

@stefan-hoehn , would it make sense to add a "get things with tag" type block? Or even just "get all things" block?

Back to the original problem, what does the code look like before and after it jumps like that. That will show if it's just a display problem of if the generate code is wrong too.

stefan-hoehn commented 2 weeks ago

@rkoshak Yes, I lately noticed that we haven't got that. I added it to my todo list.

Boldfor commented 2 weeks ago

Thanks @rkoshak & @stefan-hoehn. A block for that would indeed be marvelous. :)

Quick question on your workaround: I thought I knew what you meant with your hint, but when I try out this... image

... it throws out this error:

2024-05-02 23:04:49.044 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:

org.graalvm.polyglot.PolyglotException: TypeError: instantiate on org.openhab.core.thing.ThingUID failed due to: no applicable overload found (overloads: [Method[public org.openhab.core.thing.ThingUID(java.lang.String,java.lang.String,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String[])], Method[public org.openhab.core.thing.ThingUID(org.openhab.core.thing.ThingTypeUID,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String,org.openhab.core.thing.ThingUID,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(org.openhab.core.thing.ThingTypeUID,java.lang.String,java.lang.String[])], Method[public org.openhab.core.thing.ThingUID(org.openhab.core.thing.ThingTypeUID,org.openhab.core.thing.ThingUID,java.lang.String)]], arguments: [DynamicObject<JSOrdinary>@1bc0d85d (DefaultLayout)]) 

Do you accidentally see what I missed?

rkoshak commented 2 weeks ago

When you dropped the "for each" block it populated with a variable "i". Don't change that. That's the variable that holds the item that the for loop is currently on. Inside the for loop, user "i" to get the status from.

Boldfor commented 2 weeks ago

I feel a bit stupid, because this one... image

... throws an error as well: 2024-05-02 23:16:48.952 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'thing_status_check' failed: java.lang.NullPointerException: Cannot invoke "String.split(String)" because "id" is null

I thought I knew how to work with lists, but I guess I don't know it (yet).

rkoshak commented 2 weeks ago

I don't know what would be trying to use a String split there but you are still not doing it right. i isn't an index, it's the actual item. In this case it's the Thing. For what you are doing, there is no reason to ever reference allThings inside the for loop. Just use i. i is a variable that holds one of the Things in the list of allThings.

image

stefan-hoehn commented 1 week ago

would it make sense to add a "get things with tag" type block? Or even just "get all things" block?

Coming soon ;-)

image
stefan-hoehn commented 1 week ago

Just use i. i is a variable that holds one of the Things in the list of allThings

The reason why this is challenging is because the "get thing status" block requires the name of the thing (aka uid) but there is no easy way until now to access that name of the variable. So stay tuned for the new blocks (see above) which would allow all of that.

Boldfor commented 1 week ago

I don't know what would be trying to use a String split there but you are still not doing it right. i isn't an index, it's the actual item. In this case it's the Thing. For what you are doing, there is no reason to ever reference allThings inside the for loop. Just use i. i is a variable that holds one of the Things in the list of allThings.

image

@rkoshak, thanks for taking the time to reply. In fact, I tried it precisely the way you showed in this screenshot in my first attempt. However, when I do so...

image

I (also back then) keep getting the following error:

2024-05-08 20:46:06.405 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:

org.graalvm.polyglot.PolyglotException: TypeError: instantiate on org.openhab.core.thing.ThingUID failed due to: no applicable overload found (overloads: [Method[public org.openhab.core.thing.ThingUID(java.lang.String,java.lang.String,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String[])], Method[public org.openhab.core.thing.ThingUID(org.openhab.core.thing.ThingTypeUID,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String,org.openhab.core.thing.ThingUID,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(org.openhab.core.thing.ThingTypeUID,java.lang.String,java.lang.String[])], Method[public org.openhab.core.thing.ThingUID(org.openhab.core.thing.ThingTypeUID,org.openhab.core.thing.ThingUID,java.lang.String)]], arguments: [DynamicObject<JSOrdinary>@3fc3d740 (DefaultLayout)])

    at <js>.getThing(@openhab-globals.js:2) ~[?:?]
    at <js>.:program(<eval>:8) ~[?:?]
    at org.graalvm.polyglot.Context.eval(Context.java:399) ~[?:?]
    at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:458) ~[?:?]
    at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:426) ~[?:?]
    at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:262) ~[java.scripting:?]
    at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocableAndAutocloseable.eval(DelegatingScriptEngineWithInvocableAndAutocloseable.java:53) ~[?:?]
    at org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.eval(InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.java:78) ~[?:?]
    at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocableAndAutocloseable.eval(DelegatingScriptEngineWithInvocableAndAutocloseable.java:53) ~[?:?]
    at org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.eval(InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.java:78) ~[?:?]
    at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.lambda$0(ScriptActionHandler.java:71) ~[?:?]
    at java.util.Optional.ifPresent(Optional.java:178) ~[?:?]
    at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.execute(ScriptActionHandler.java:68) ~[?:?]
    at org.openhab.core.automation.internal.RuleEngineImpl.executeActions(RuleEngineImpl.java:1188) ~[?:?]
    at org.openhab.core.automation.internal.RuleEngineImpl.runNow(RuleEngineImpl.java:1039) ~[?:?]
    at org.openhab.core.automation.rest.internal.RuleResource.runNow(RuleResource.java:381) ~[?:?]
    at org.openhab.core.automation.rest.internal.RuleResource.runNow(RuleResource.java:398) ~[?:?]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
    at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:179) ~[bundleFile:3.6.2]
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) ~[bundleFile:3.6.2]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:201) ~[bundleFile:3.6.2]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:104) ~[bundleFile:3.6.2]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59) ~[bundleFile:3.6.2]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96) ~[bundleFile:3.6.2]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307) ~[bundleFile:3.6.2]
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) ~[bundleFile:3.6.2]
    at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:265) ~[bundleFile:3.6.2]
    at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) ~[bundleFile:3.6.2]
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) ~[bundleFile:3.6.2]
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) ~[bundleFile:3.6.2]
    at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:225) ~[bundleFile:3.6.2]
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:304) ~[bundleFile:3.6.2]
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:217) ~[bundleFile:3.6.2]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:517) ~[bundleFile:4.0.4]
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:279) ~[bundleFile:3.6.2]
    at org.ops4j.pax.web.service.spi.servlet.OsgiInitializedServlet.service(OsgiInitializedServlet.java:102) ~[bundleFile:?]
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656) ~[bundleFile:9.4.52.v20230823]
    at org.ops4j.pax.web.service.spi.servlet.OsgiFilterChain.doFilter(OsgiFilterChain.java:100) ~[bundleFile:?]
    at org.ops4j.pax.web.service.jetty.internal.PaxWebServletHandler.doHandle(PaxWebServletHandler.java:320) ~[bundleFile:?]
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:234) ~[bundleFile:9.4.52.v20230823]
    at org.ops4j.pax.web.service.jetty.internal.PrioritizedHandlerCollection.handle(PrioritizedHandlerCollection.java:96) ~[bundleFile:?]
    at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:722) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.Server.handle(Server.java:516) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487) ~[bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) [bundleFile:9.4.52.v20230823]
    at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) [bundleFile:9.4.52.v20230823]
    at java.lang.Thread.run(Thread.java:840) [?:?]
2024-05-08 20:46:06.409 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'thing_status_check' failed: org.graalvm.polyglot.PolyglotException: TypeError: instantiate on org.openhab.core.thing.ThingUID failed due to: no applicable overload found (overloads: [Method[public org.openhab.core.thing.ThingUID(java.lang.String,java.lang.String,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String[])], Method[public org.openhab.core.thing.ThingUID(org.openhab.core.thing.ThingTypeUID,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(java.lang.String,org.openhab.core.thing.ThingUID,java.lang.String)], Method[public org.openhab.core.thing.ThingUID(org.openhab.core.thing.ThingTypeUID,java.lang.String,java.lang.String[])], Method[public org.openhab.core.thing.ThingUID(org.openhab.core.thing.ThingTypeUID,org.openhab.core.thing.ThingUID,java.lang.String)]], arguments: [DynamicObject<JSOrdinary>@3fc3d740 (DefaultLayout)])

Line 8 (the one mentioned in the log entry) is this one (where the status of the thing should be extracted) if (things.getThing(i).status != 'ONLINE' && things.getThing(i).status != 'INITIALIZING') {

Am I missing something completely obvious? I have to admit I feel a bit stupid.

rkoshak commented 1 week ago

There may be a bug or the block doesn't work consistency with how the items blocks work.

The code should be

if(i.status != 'ONLINE' && i.status != 'INITIALIZING')

When you use the Item blocks:

image

becomes

items.getItem('MotionSensor_LastMotion');

And when you link that to the "get [name] of item"

image

it becomes

items.getItem('MotionSensor_LastMotion').name;

That's all good. But the same is not happening for Things. The Thing Object is not being converted to the name of the Thing the same as happens for the Item. Of course, it might not work for Items in a for loop either. @stefan-hoehn, are my expectations on how the block should work unreasonable or is Thing just missing this same trickery that works for Items?

stefan-hoehn commented 5 days ago

With the new thing blocks the topic should be solved, isn't it? see #2562

rkoshak commented 4 days ago

I think so. I think I lost track of how this issue related to that PR.