[ntfy] Wrong casting in DSL rules for Ntfy Binding

Hi everyone,

I tried out the new Ntfy binding from OH5.2.0 and I’m a little frustrated. Installing Bridge and Token-Thing via a things file went smoothly, but I can’t seem to generate a notification using a DSL rule as described in documentation.

Environment

  • openHAB version: 5.2.0 (Release Version)
  • Binding: org.openhab.binding.ntfy
  • Rule type: Rules DSL (Xtend), executed via a UI Script Action

Description

The Rule Actions exposed by the ntfy binding (NtfyActions) cannot be used from Rules DSL as documented in the binding’s README. Calling the builder-style methods (withMessage, withPriority, send, etc.) fails with type errors, even when following the exact example shown in the documentation and even after casting explicitly to NtfyActions.

Steps to Reproduce

  1. Configure a ntfy:server bridge and a ntfy:ntfy-topic Thing.
  2. Create a DSL rule with the following script, exactly as shown in the binding’s README:
val bindingActions = getActions("ntfy", "ntfy:ntfy-topic:SMH-Events")
if (bindingActions !== null) {
    val msgId = bindingActions.withMessage("Someone is at the door").withPriority(4).send()
}

Result:
Script execution of rule with UID ‘ntfy-1’ failed: ‘withMessage’ is not a member of ‘org.openhab.core.thing.binding.ThingActions’; line 3, column 17, length 26 in ntfy

  1. Add an explicit cast to NtfyActions (importing org.openhab.binding.ntfy.internal.action.NtfyActions):
import org.openhab.binding.ntfy.internal.action.NtfyActions

val bindingActions = getActions("ntfy", "ntfy:ntfy-topic:SMH-Events")
if (bindingActions !== null) {
    val NtfyActions ntfyActions = bindingActions as NtfyActions
    ntfyActions.withMessage("Someone is at the door").withPriority(4).send()
}

Result:
Script execution of rule with UID ‘ntfy-1’ failed: Could not cast org.openhab.binding.ntfy.internal.action.NtfyActions@6e9512e0 to void; line 5, column 35, length 29 in ntfy

  1. Even breaking the fluent chain into individual, explicitly-cast statements still fails, and the error now occurs on the very first cast expression itself (bindingActions as NtfyActions):
var NtfyActions ntfyActions = bindingActions as NtfyActions
ntfyActions = ntfyActions.withMessage("Someone is at the door") as NtfyActions
ntfyActions = ntfyActions.withPriority(4) as NtfyActions
val String msgId = ntfyActions.send()

Script execution of rule with UID ‘ntfy-1’ failed: Could not cast org.openhab.binding.ntfy.internal.action.NtfyActions@6e9512e0 to void; line 2, column 15, length 64 in ntfy

Expected behavior

The Rules DSL usage documented in the README (calling withMessage(...).withPriority(...).send() directly on the object returned by getActions(), without any cast) should work without errors, as it does for other bindings using fluent Thing Action APIs.

Suspected cause

The NtfyActions builder methods appear to use a generic self-referencing return type pattern (e.g. <T extends X> T withMessage(...)), which the Rules DSL / Xbase interpreter seems unable to resolve correctly at runtime. The interpreter’s type inference for the cast/chain expression appears to incorrectly resolve the expected type to void, causing a ClassCastException-style failure even though the runtime object is a valid NtfyActions instance.

Request

Could the return types of the builder methods in NtfyActions be reviewed to avoid the generic self-type pattern (using a concrete NtfyActions return type instead), or could the README be updated to reflect a working Rules DSL example? Happy to provide further logs/debug output if needed.

I think @Christian_Kittel has to help here :wink:

Greets

You should be explicit about posting AI slop, I can’t find any truth in the claims about the cause for the failure when checking the code. No generics is used that I can see, here is one of the methods:

    public static ThingActions withMessage(ThingActions actions, String message) {
        return ((NtfyActions) actions).withMessage(message);
    }

No human would have look at this and decided “Ah, the problem is caused by wrong use of generics”, which makes me pretty sure it’s AI slop.

What seems to me to be the problem, is that it returns the interface type, not the concrete implementation type. The interface has no methods, so they will be claimed to “not exist”.

I’ve created a PR that I believe solves it:

I don’t expect a problem from the PR, but just to be sure the backport is as expected, it would be nice if the jar can be posted so @puschel can confirm it fixes the issue.

Here goes:

org.openhab.binding.ntfy-5.3.0-SNAPSHOT.jar.txt (45.6 KB)

I’ll take a look at the PR. It’s a shame no one checked this during the testing period. I don’t use DSL, and it works without any issues in JavaScript.

Hi,

first of all, sorry for using AI without explicitly checking it. I did all the testing variants by myself and the AI generated cause explanation sounded plausible to me. I won’t do this that way in future, promised.

Thanks for providing the jar:

openhab> bundle:list | grep -i ntfy
345 x Active   x  80 x 5.3.0.202607162108      x openHAB Add-ons :: Bundles :: Ntfy Binding

For testing (without AI), I used the following DSL rules and got the respective log results. I hope, this will help.

import org.openhab.binding.ntfy.internal.action.NtfyActions
rule "ntfy: Send notification to SMH-Events"
then
    val bindingActions = getActions("ntfy", "ntfy:ntfy-topic:SMH-Events")
    if (bindingActions !== null) {
        // simple one-liner: send a message
        val msgId = bindingActions.withMessage("Someone is at the door").withPriority(4).send()
        logInfo("ntfy", "Notification sent")
    } else {
        logWarn("ntfy", "Notification couldn't sent")
    }
end

Execution failed as before (independed whether the import is available or not):
Script execution of rule with UID 'ntfy-1' failed: 'withMessage' is not a member of 'org.openhab.core.thing.binding.ThingActions'; line 7, column 21, length 52 in ntfy

Same result for the unchained version:

import org.openhab.binding.ntfy.internal.action.NtfyActions
rule "ntfy: Send notification to SMH-Events"
then
    var bindingActions = getActions("ntfy", "ntfy:ntfy-topic:SMH-Events")
    if (bindingActions !== null) {
        // simple one-liner: send a message
        bindingActions = bindingActions.withMessage("Someone is at the door")
        bindingActions = bindingActions.withPriority(4)
        val String msgId = bindingActions.send()
        logInfo("ntfy", "Notification sent")
    } else {
        logWarn("ntfy", "Notification couldn't sent")
    }
end

Script execution of rule with UID 'ntfy-1' failed: 'withMessage' is not a member of 'org.openhab.core.thing.binding.ThingActions'; line 7, column 26, length 52 in ntfy

For completeness, I also did a test using casting:

import org.openhab.binding.ntfy.internal.action.NtfyActions
rule "ntfy: Send notification to SMH-Events"
then
    var bindingActions = getActions("ntfy", "ntfy:ntfy-topic:SMH-Events")
    if (bindingActions !== null) {
        var NtfyActions ntfyActions = bindingActions as NtfyActions
        ntfyActions = ntfyActions.withMessage("Someone is at the door") as NtfyActions
        ntfyActions = ntfyActions.withPriority(4) as NtfyActions
        val String msgId = ntfyActions.send()
        logInfo("ntfy", "Notification sent")
    } else {
        logWarn("ntfy", "Notification couldn't sent")
    }
end

Result:
Script execution of rule with UID 'ntfy-1' failed: Could not cast org.openhab.binding.ntfy.internal.action.NtfyActions@6fae30b6 to void; line 6, column 39, length 29 in ntfy

That’s the problem with them IMO. They very often sound plausible, and are delivered with great conviction, which is why we’re so likely to take what they claim as fact. Only that often, it’s not fact at all.

This is disappointing and strange. It’s strange because I had no errors, and the error doesn’t really make sense to me. It’s not actually a failure of the “fluent” call, it rejects the very first call. By this logic, every other Thing action call should fail as well.

This is the strangest of them all. I’ll have to try this rule myself, but why does it claim that you’re trying to cast to void? That’s not how the code reads to me…

I just copied your DSL script into my installation, and only modified the ThingUID to match mine. This is what I see when the script is loaded:

14:02:54.375 [INFO ] (OH-watchservice-3   ) [el.core.internal.ModelRepositoryImpl] - Validation issues found in DSL model 'ntfy-test.rules', using it anyway:
Unnecessary cast from NtfyActions to NtfyActions
Unnecessary cast from NtfyActions to NtfyActions
The value of the local variable msgId is not used

Running the rule manually results in the following log:

14:05:50.395 [DEBUG] (H-rule-ntfy-test-1-1) [time.internal.engine.DSLScriptEngine] - Script uses context 'ntfy-test-1'.
14:05:50.452 [INFO ] (H-rule-ntfy-test-1-1) [org.openhab.core.model.script.ntfy  ] - Notification sent
14:05:50.452 [DEBUG] (H-rule-ntfy-test-1-1) [e.automation.internal.RuleEngineImpl] - The rule 'ntfy-test-1' was executed.

So, how can our systems behave so differently is the real question I guess…

I spun up a Docker 5.2.0 installation, without my modification PR, and even that runst without problems:

14:31:40.608[DEBUG] [org.openhab.core.automation.module.script.internal.handler.AbstractScriptModuleHandler] - Executing script of rule with UID 'ntfy-test-1'
14:31:40.643[INFO] [org.openhab.core.model.script.ntfy] - Notification sent
14:31:40.645[DEBUG] [org.openhab.core.automation.internal.RuleEngineImpl] - The rule 'ntfy-test-1' was executed.

There must be something with your installation that isn’t quite right. Perhaps you should try clearing the cache, which will force reinstallation of all components..?

That’s strange. I run an OpenHABian system on Raspi 4B with some Bindings, nothing special I think. I started with OH2 some years ago but meanwhile installed OH5.0 completely new. Newer versions are migrated from OH5.0.

As suggested, I tried some resetting: Browser cache clearing (Cntrl-F5), a restart of openhab service (systemctl restart openhab) and finally a reboot of the system.

But running my rule (the unchained version) I get the same result (except the action id):

Script execution of rule with UID 'ntfy-1' failed: Could not cast org.openhab.binding.ntfy.internal.action.NtfyActions@10c37d58 to void; line 6, column 39, length 29 in ntfy

Can I do anything to help?

I was thinking specifically of clearing the Karaf cache, it’s the cache that caches to OH components itself. The reason is that it forces OH to “reinstall” all the components, and if we’re lucky, that will sort out whatever issue there is with your installation.

There are various ways to clean this cache, but I can never remember them all. I think the simplest way might be to run:

sudo openhab-cli clean-cache

I’m not sure if OH must be running or stopped when running that command, but I assume that it will let you know if it must be stopped first. OH must be restarted after the cache is cleared, whether the tool does it for you or not.

On the first start after clearing the cache, all kind of errors will be logged because things are missing, and it’s working on reinstalling them. Give OH some 10 minutes to figure all this out, and then restart again. On the second restart, everything should work properly.

After cleaning the cache using way above, I had to fight with some restarts of OH and the browser to get access to the UI again. But unfortunately, nothing changed. Running the rule, I get the same log messages as before.
Idea: I’m using an unconditional rule newly introduced with OH 5.2.0. Could this leads to problems?

What do you mean “unconditional”? If you mean without a trigger, that should have nothing to do with it. Remember that I have already tested the rule that you posted above on two different installations, and I don’t get those errors.

So, there must be something with your installation, something I don’t quite understand. The errors themselves don’t make sense to me, it feels like there’s something really strange on the Java/JVM level. What JRE/JDK are you using?

Is it possible to see your binding configuration?

I’ve done one further change, can you please see if this version works?

org.openhab.binding.ntfy-5.3.0-SNAPSHOT.jar.txt (45.5 KB)

edit: One important thing with this version: If you do explicit imports of NtfyActions, the coordinates have changes, so it must now be:

import org.openhab.binding.ntfy.action.NtfyActions

Yes, with ‘unconditional’ rule I meant one without a trigger section. The rules above show the complete content of my file ntfy.rules.

My (unchanged) binding configuration within file ntfyBinding.things using one ntfy token for now:

Bridge ntfy:server:myNTFY "NTFY Server" [ hostname="https://ntfy.sh", connectionTimeout=60000, username="", password=""]
Thing ntfy:ntfy-topic:SMH-Events "NTFY SmartHome Notifications" (ntfy:server:myNTFY) [ topicName="SMH-EventsXXXXXXX" ]

I updated with new jar file and did the same cache clearing process as before:

openhab> bundle:list | grep -i ntfy
250 x Active   x  80 x 5.3.0.202607171920      x openHAB Add-ons :: Bundles :: Ntfy Binding

And after updating the import line as well (I almost missed that) , tada, it sends a notification:
Rule 'ntfy-1' has been updated.
Notification sent
And the best part: The message actually went through!

Great, now it seems to work as expected. I’m going to test it next week in some more detail.
What was the cause? Was my installation glitching and just needs a few cleanups?

Thank you very much for your quick and friendly help.

No, it seems to have been a combination of a “wrong” definition in the binding, combined with the fact that you use Rules DSL, and a “random factor” that is determined by the startup order of internal OH components, which is probably affected by which other bindings you have installed.

I’m pretty sure that it won’t stop working again now that the definition has been corrected.

Hi,
sorry for reopening this thread again. Unfortunately, the fix in release OH5.2.1 doesn’t work for me.

As I wrote before, I installed the 2nd jar file Nadahar provided and after some cleanup and restarts my system was able to send messages via ntfy.

openhab> bundle:list | grep -i ntfy
250 x Active   x  80 x 5.3.0.202607171920      x openHAB Add-ons :: Bundles :: Ntfy Binding

When release 5.2.1 became available, I uninstalled the JAR and installed the official Ntfy binding. Now I’m getting the same error messages again as I did at the very beginning, as if the fix weren’t there at all.

For testing, I’m using the following DSL rule:

//=========================================================================
// Sendet eine Push-Nachricht als Testmeldung (manuell ausgelöst)
rule "ntfy: Sende Test-Meldung an SMH-Events"
then
    val String ruleStr    = "Rule 'ntfy: Sende Test-Meldung an SMH-Events' "
    var String messageStr = "Dies ist eine Testmeldung"
    var String tagStr     = "thinking"

    val bindingActions = getActions("ntfy", "ntfy:ntfy-topic:SMH-Events")
    logInfo("ntfy", "bindingActions = " + bindingActions)
    if (bindingActions !== null) {
        logInfo("ntfy", "bA.withTitle = " + bindingActions.withTitle("SMH: Test"))
        val String msgId = bindingActions.withTitle("SMH: Test")
                                          .withMessage(messageStr)
                                          .withTag(tagStr)
                                          .withPriority(3)
                                          .send()
        logInfo("ntfy", ruleStr + messageStr + ", MsgId: " + msgId)
    } else {
        messageStr = "Binding-Fehler, keine Meldung gesendet"
        logWarn("ntfy", ruleStr + messageStr)
    }
end

The log messages are:

13:13:27.274[INFO] [org.openhab.core.model.core.internal.ModelRepositoryImpl] - Loading DSL model 'myntfy.rules'
13:13:27.514[INFO] [openhab.event.RuleUpdatedEvent] - Rule 'myntfy-1' has been updated.
13:13:36.572[INFO] [org.openhab.core.model.script.ntfy] - bindingActions = org.openhab.binding.ntfy.action.NtfyActions@175fe0e6
13:13:36.574[ERROR] [org.openhab.core.automation.module.script.internal.handler.AbstractScriptModuleHandler] - Script execution of rule with UID 'myntfy-1' failed: 'withTitle' is not a member of 'org.openhab.core.thing.binding.ThingActions'; line 12, column 45, length 37 in myntfy

What I did so far:

  • I uninstalled the jar file (v5.3.0.202607171920) completely. There were no remaining parts of any ntfy parts or jar files.
  • I did a complete manual cache and tmp reset, not only with openhab-cli clean-cache)
  • After some restarts I installed the official bundle version 5.2.1
openhab> bundle:list | grep -i ntfy
345 x Active   x  80 x 5.2.1                   x openHAB Add-ons :: Bundles :: Ntfy Binding
  • The Thing status for both bridge and token is Online
  • The Action registration (src:list, service:list) seems to exist.
  • Type casting for bindingActions failed as well, with and without using import org.openhab.binding.ntfy.action.NtfyActions

Additional information that might be helpful:
I’m using current openHAB 5.2.1 distro with openHABian on Raspi.

Nadahar wrote that both his fix and version 5.2.1 of the bundle worked fine for him. Does anyone have any idea what’s different on my system and whether this can be fixed?