How can I trigger a channel event via REST API to test a rule?”

Hi everyone,
I’m trying to test a rule that is triggered by a channel event.
Is there any way to trigger a channel event via the REST API (similar to an incoming trigger event) ?
The goal is to make rule testing reproducible without relying on real hardware interactions.
I’m aware that item states can be set via the REST API (POST /rest/items/…), but I’m specifically looking for a way to trigger channel events / channel triggers.
If this is not possible directly, what is the recommended approach to test rules that depend on channel triggers?
Thanks in advance!

There is the Magic Binding [4.0.0.0;4.2.0.0) but I don’t think it’s been kept up to work with OH 5 unfortunately. This is a “fake” binding that lets you create Channels that let you do this sort of thing though. Maybe a reply on that thread will prompt the original developer or someone to update it for OH 5.

There is no endpoint in the REST API to generate Channel events. That makes sense because Channel events are supposed to come from a binding, not a UI or external system. So there’s no need for it under normal conditions.

If someone were to look through the interanl OH Java APIs I bet there is a way to publish arbitrary events to the event bus, but that is not something generally exposed in rules so it’s going to be a lot of navigating OSGI and Java API calls.

The approach I use is mostly just test with the physical device. Or map the event Channel to a String Item using the trigger-event-string profile so the rule uses an Item trigger instead.

I find it convenient to do it via mqtt :slight_smile:

  • Just define the channels as needed and
  • use a mqtt sniffer to publish the topics.

How?? Can you explain?

I beleive the approach would be to set up an MQTT Thing with event Channels. Use those event Channels to trigger the rule along side what ever Channel is currently triggering the rule. Then you can publish messages that match the payload of the events you want to test to the MQTT topic to trigger the rule usign MQTT Explorer or from what ever testing tools may be in use.

Original Device -> Original Binding -|
                                     |
                                     |->Rule Trigger
                                     |
MQTT Explorer -> MQTT Binding--------|

The payloads from the two events may be different though. For example, the events from the MQTT binding will be in the form topic#message whereas the events from the original binding will probably be just message. But it’s easy enough to do that at the top of your Scripts.

You can tell which Channel triggered the rule in JS with event.channelUID and pull out what you need accordingly.

const channelEvent = (event.channelUID == "mqtt:some:thing:and:channel:uid") 
                       ? event.receivedEvent.split('#')[1] 
                       : event.receivedEvent;

Then you’d use channelEvent everywhere in the rule where you now use event.receivedEvent.

The same approach should work in any of the rules languages.

Of course, if you don’t care about the event payload from the Channel, you don’t need to do this at all.

You might even be able to be a little clever here and overwrite the event.receivedEvent.

event.receivedEvent = (event.channelUID == "mqtt:some:thing:and:channel:uid") 
                       ? event.receivedEvent.split('#')[1] 
                       : event.receivedEvent;

Then you don’t even need to change the rest of your script. But it does overwrite what you actually received so that could become more of a challenge later for debugging.

This idea also raises another idea. You could use an Item that triggers a rule that calls the rule under test. That could be a good choice if you are not already using MQTT. There’s a similar issue that the event’s payload will be different so you’ll need to do some checking to see how the rule was run and get the value based on how it was run.

Another thing I do in my rule tempaltes is when the rule is manually run it goes through a self test mode.

Didn’t really understand it …

I want to test astro event sunset#rise for example how can I do it

Do you use that sunset#rise in the rule somehow?

What exactly are you trying to test? That the rule trigger is correct? Just what the rule does?

How are you trying to test this? Manually? Via some testing script?

If your answers are: not using sunset#rise in the rule, want to test what the rule does, and manually then just manually run the rule. In MainUI there’s a play button. Clikc that and the rule’s script actions will run and you will see what the rule does.

If your answers do not match those you need to provide a whoile lot more details about what you are really trying to do and why because this whole thread is starting to feel like an XY Problem.

I’ve presented at least three different ways to do testing above and it could be that none of them are appropriate for what you really want to do. So I’m not going to spend an hour breaking them down step-by-step until I know it’s relevant.

This rule exactly…But it was more a general question…

const { items, log, rules, triggers } = require('openhab');

rules.JSRule({
  name: "Tageszeit Phasen setzen mit Astro-Events",
  description: "Setzt die Tageszeitphase anhand von Astro-Events (9 Phasen)",
  triggers: [
    triggers.ChannelEventTrigger("astro:sun:smarthome:civilDawn#event",  "START"),  // 0 - Morgendämmerung
    triggers.ChannelEventTrigger("astro:sun:smarthome:rise#event",       "START"),  // 1 - Sonnenaufgang
    triggers.ChannelEventTrigger("astro:sun:smarthome:rise#event",       "END"),    // 2 - Morgen
    triggers.ChannelEventTrigger("astro:sun:smarthome:noon#event",       "START"),  // 3 - Tagsüber
    triggers.ChannelEventTrigger("astro:sun:smarthome:set#event",        "START"),  // 4 - Sonnenuntergang
    triggers.ChannelEventTrigger("astro:sun:smarthome:set#event",        "END"),    // 5 - Abend
    triggers.ChannelEventTrigger("astro:sun:smarthome:civilDusk#event",  "START"),  // 6 - Abenddämmerung
    triggers.ChannelEventTrigger("astro:sun:smarthome:nauticDusk#event", "END"),    // 7 - Nacht
    triggers.ChannelEventTrigger("astro:sun:smarthome:midnight#event",   "START"),  // 8 - Mitternacht
  ],
  execute: (event) => {
    const logger = log("Tageszeit-Phase");

    var channel = String(event.channelUID);
    var eventType = String(event.receivedEvent);

    const phaseMap = {
      "astro:sun:smarthome:civilDawn#event|START":  { name: "Morgendämmerung", value: 0 },
      "astro:sun:smarthome:rise#event|START":       { name: "Sonnenaufgang",   value: 1 },
      "astro:sun:smarthome:rise#event|END":         { name: "Morgen",          value: 2 },
      "astro:sun:smarthome:noon#event|START":       { name: "Tagsüber",        value: 3 },
      "astro:sun:smarthome:set#event|START":        { name: "Sonnenuntergang", value: 4 },
      "astro:sun:smarthome:set#event|END":          { name: "Abend",           value: 5 },
      "astro:sun:smarthome:civilDusk#event|START":  { name: "Abenddämmerung",  value: 6 },
      "astro:sun:smarthome:nauticDusk#event|END":   { name: "Nacht",           value: 7 },
      "astro:sun:smarthome:midnight#event|START":   { name: "Mitternacht",     value: 8 },
    };

    var key   = channel + "|" + eventType;
    var phase = phaseMap[key];

    if (phase) {
      logger.info("✓ Neue Tageszeit: " + phase.name + " (" + phase.value + ")");
      items.getItem("Sensor_House_SmartHomeOperatingDayphase").postUpdate(phase.value);
    } else {
      logger.warn("✗ Kein Match für Key: [" + key + "]");
    }
  },
  tags: ["Astro", "Tageszeit", "Automatisierung", "Sonnenstand"],
  id: "tageszeitPhaseSetzenNachAstroEvents"
});

The general question was answered. No, you cannot inject a Channel event through the REST API nor any other easily accessible method.

It’s still not clear what you are trying to test. If you want to test taht the Astro binding is triggering the rule, all you can do is wait for the Astro binding to generate the events.

If you want to test that the rule does what it’s supposed to you can use MQTT.

  1. Create a Generic MQTT Thing
  2. Add an Event Channel that subscribes to some topic, let’s say testing/astro/*
  3. Add this Event Channel as a trigger for this rule.
  4. Modify the rule as follows:
const { items, log, rules, triggers } = require('openhab');

rules.JSRule({
  name: "Tageszeit Phasen setzen mit Astro-Events",
  description: "Setzt die Tageszeitphase anhand von Astro-Events (9 Phasen)",
  triggers: [
    triggers.ChannelEventTrigger("astro:sun:smarthome:civilDawn#event",  "START"),  // 0 - Morgendämmerung
    triggers.ChannelEventTrigger("astro:sun:smarthome:rise#event",       "START"),  // 1 - Sonnenaufgang
    triggers.ChannelEventTrigger("astro:sun:smarthome:rise#event",       "END"),    // 2 - Morgen
    triggers.ChannelEventTrigger("astro:sun:smarthome:noon#event",       "START"),  // 3 - Tagsüber
    triggers.ChannelEventTrigger("astro:sun:smarthome:set#event",        "START"),  // 4 - Sonnenuntergang
    triggers.ChannelEventTrigger("astro:sun:smarthome:set#event",        "END"),    // 5 - Abend
    triggers.ChannelEventTrigger("astro:sun:smarthome:civilDusk#event",  "START"),  // 6 - Abenddämmerung
    triggers.ChannelEventTrigger("astro:sun:smarthome:nauticDusk#event", "END"),    // 7 - Nacht
    triggers.ChannelEventTrigger("astro:sun:smarthome:midnight#event",   "START"),  // 8 - Mitternacht
    triggers.ChannelEventTrigger("mqtt:event:channel:id"), // Testing REPLACE with ID of Channel from step 2
  ],
  execute: (event) => {
    const logger = log("Tageszeit-Phase");

    var channel = String(event.channelUID);
    var eventType = String(event.receivedEvent);

    // !!!!! New Code
    if(channel == "mqtt:event:channel:id") {
        // MQTT receivedEvent will be <topic>#message
        const topic = event.receivedEvent.split('#')[0]; // map topic to Astro Channel
        channel = "astro:sun:smarthome:" + topic.split('/')[2] + '#event');
        eventType = event.receivedEvent.split('#')[1]; // Extract the message
    }
    // !!!!! End New Code


    const phaseMap = {
      "astro:sun:smarthome:civilDawn#event|START":  { name: "Morgendämmerung", value: 0 },
      "astro:sun:smarthome:rise#event|START":       { name: "Sonnenaufgang",   value: 1 },
      "astro:sun:smarthome:rise#event|END":         { name: "Morgen",          value: 2 },
      "astro:sun:smarthome:noon#event|START":       { name: "Tagsüber",        value: 3 },
      "astro:sun:smarthome:set#event|START":        { name: "Sonnenuntergang", value: 4 },
      "astro:sun:smarthome:set#event|END":          { name: "Abend",           value: 5 },
      "astro:sun:smarthome:civilDusk#event|START":  { name: "Abenddämmerung",  value: 6 },
      "astro:sun:smarthome:nauticDusk#event|END":   { name: "Nacht",           value: 7 },
      "astro:sun:smarthome:midnight#event|START":   { name: "Mitternacht",     value: 8 },
    };

    var key   = channel + "|" + eventType;
    var phase = phaseMap[key];

    if (phase) {
      logger.info("✓ Neue Tageszeit: " + phase.name + " (" + phase.value + ")");
      items.getItem("Sensor_House_SmartHomeOperatingDayphase").postUpdate(phase.value);
    } else {
      logger.warn("✗ Kein Match für Key: [" + key + "]");
    }
  },
  tags: ["Astro", "Tageszeit", "Automatisierung", "Sonnenstand"],
  id: "tageszeitPhaseSetzenNachAstroEvents"
});
  1. To test, using MQTTExplorer or your MQTT client of choice publish “START” or “END” to the topic that corresponds to the Astro event you want to simulate. For example, you would publish “START” to testing/astro/noon to simulate the astro:sun:smarthome:noon#event START.

That is clear but I want to test exactly the channel trigger…it would be helpful to test rules during writing…abut anyway I understand it’s not possible

I just read „Tageszeitphasen".

You should try the time based state machine. That’s much easier than setting up everything from scratch