OpenHAB2 Plugin

I’ve created a plugin which uses the Rest API of OpenHAB2 to read the items and interact with it.

Prequisites:
You have to put all the items you want to see in the plugin in a OpenHAB Group. When you install the plugin you will be asked for the Base URL of OpenHAB (usually something like http://192.168.1.xxx:8080) without trailing slash and the name of the OpenHAB Group containing the items. If you configured your group fine the devices will be read from OpenHAB and you should see them in the plugin. If no devices are found, check the log for errors. Most probably you have some spelling error in the group or URL.

How to use it
Each device you see has 2 attributes: “Command” and “State”. This directly relates to OpenHAB2 commands and states of the items. To execute an action set the “.Command” attribute to the value of an OpenHAB2 command of the device. On the other hand the plugin is polling the “State” of the items from OpenHAB2 and updates the “.State” attribute accordingly. You can also update a “State” field to a new value if this is required by some rules or triggers in OpenHAB2 but this will not trigger any direct action in OpenHAB2. It just updates the Items state value.

Limitations
The plugin does not support any capabilities as there are only few of them in OpenHAB2 anyhow and they do not match the HomeRemote ones and it’s generally not needed, I don’t even know if they are exposed. Also channels of OpenHAB2 items are not directly supported. Of course feel free to improve on this points if you have a need and share it but I think for 99% of the cases the plugin should do fine.

Download plugin here.
openhab.plugin (2.7 KB)

3 Likes

Hi Marc,

thank for your openhab plugin.
I just installed it and prepared my openhab with a dedicated group for home remote including a single item. Settings were accepted by the designer, so it seem the group and URL seem to be correct.
When I add a new variable within the designer, the designer crashes.
What kind of debugging options do I have to identify the root cause?

Thanks in advance,
Sven

Solved: It was related to the “is legacy” issue discussed here:

Now I have a new issue.
My configured openhab item is visible to HomeRemote: “ArbeitszimmerRoom_Helligkeit”.
The dropdown table for value device binding is shown below:
2020-10-05 16_30_52-MqttClient_SE.hrp - Home Remote Designer
I’m trying to assign this openhab item to a slider in home remote.
I need to select either “ArbeitszimmerRoom_Helligkeit.Command” or “ArbeitszimmerRoom_Helligkeit.State” from the dropdown list.
If I select “x.state”, updating the slider works, but I can’t set any value.
The URL includes “/state/” in this case, so the wrong function inside the plugin’s javascript code is called,
when moving the slider button.
If I select xxx.command the value is empty.

Received HTTP POST request at ‘items/ArbeitszimmerRoom_Helligkeit’ with an invalid status value ‘’.

Hi! I’m having the same problem with the dimmer using OpenHAB devices. Has anyone found a solution to this?

Thank you!

You can modify the code so that the change request uses the “command” HTTP post. There is nothing that requires you use the exact code shared at the top of the post. All I ask is that, when you do find & fix issues, please share them.

openhab (1).plugin (2.8 KB)

Bill,

Thank you so much for your time in looking at this, your solution works perfectly!

How can we make the respective change to the plugin so that anyone who downloads it gets the plugin with the HTTP POST change to the State case?

Thanks again!

I’d rather wait to see what @marcelser says about this. I’m worried that maybe the State command he was using is necessary for some devices. I’d hate to break that functionality if many are using it.

I guess we’d have to determine, which is more widely used? The original state request or the new one.

I do agree with you, it definitely will be best to have the most widely used version in the top post. If Marc doesn’t reply in 2 days, I’ll go ahead & use my Admin privileges to update the file myself.

What do you think Marc?

And to clarify, the original PUT command worked fine to retrieve the State of an item. But for using dynamic items, like slider/dimmer actions, PUT didn’t work. The POST edit you made worked.

I haven’t had the chance to fully test other types of items to see if there’s a negative impact to using the POST instead of the PUT.

Hopefully Marc is able to chime in. Thanks to you both!

Changing “State” also to a POST command doesn’t seem to make sense. Why don’t you use “Command” then which executes exactly the same POST command.

Because “Command” executes an action (so it triggers a command in openhab) whereas “State” sets the current state of an item without triggering a command in openhab it just updates the item’s value. This can be useful if you have an openhab item which you just want to update for example to use it in a rule or for displaying it somehwere in openhab.

But there’s really no point having “Command” & “State” doing the same thing unless HomeRemote treats those 2 differently, but that would then rather be somthing to ask @bill about.

So, in my opinion there’s nothing wrong with the code and it does what it is supposed to do and you should use “Command” not “State”.

Best regards,

Marc

Marc, I might agree with @random_dork. I think the more popular use will be dealing with actual devices, like lights & switches. For those you will want to trigger the actual command. Take a Slider for example, based on what you are saying, it would be impossible to get your current code working with a dimmer. The Slider’s Value property needs an attribute that supports both actually changing a device & reading the current state.

Here’s what I propose. Let’s have the State attribute trigger the command. And let’s add a new StateAlt attribute which can be used to update the state without triggering a command. I’m by no means married to those names. You can use whatever naming makes the most sense. I only chose StateAlt because I felt that would be the one that isn’t used as frequently.

I also reordered some of the code in your onChangeRequest method. It should only update the device object after a successful request. If the request fails, you run the risk of displaying a value that isn’t accurate. That’s why I moved those lines of code below the http.post & http.put calls.

Feel free to do whatever you think is best. You know the openHAB platform better than me.

openhab_v2.plugin (2.9 KB)

plugin.OnChangeRequest = onChangeRequest;
plugin.OnConnect = onConnect;
plugin.OnDisconnect = onDisconnect;
plugin.OnPoll = onPoll;
plugin.OnSynchronizeDevices = onSynchronizeDevices;
plugin.PollingInterval = 5000;
plugin.DefaultSettings = { "OpenHABUrl": "http://localhost:8080", "GroupName": "" };
plugin.Name = "OpenHab";

var http = new HTTPClient();
var plainHeaders = { 'Content-Type': 'text/plain' }

// including Protocol & Port
var baseURL;

// an OpenHAB group containing the items you want to control, e.g. MQTT_GROUP
var MqttGroup;

function onChangeRequest(device, attribute, value) {
    switch (attribute) {
        case "State":
            // Trigger a command.
            console.log("State device=" + device.Name + ", value=" + value);
            http.post("items/" + encodeURI(device.Name), value, { baseURL: baseURL, headers: plainHeaders });
            device.State = value;
            device.StateAlt = value;
            break;
        case "StateAlt":
            // Update only the state, do not trigger a command.
            console.log("StateAlt device=" + device.Name + ", value=" + value);
            http.put("items/" + encodeURI(device.DisplayName) + "/state", value, { baseURL: baseURL, headers: plainHeaders });
            device.State = value;
            device.StateAlt = value;
            break;
        default:
            console.log("ERROR: unknown attribute");
            console.log("device: " + device.DisplayName);
            console.log("attribute: " + attribute);
            console.log("value: " + value);
            break;
    }
}

function onConnect() {
    baseURL = plugin.Settings["OpenHABUrl"] + "/rest/";
    console.log("connected to " + baseURL);
}

function onDisconnect() {
    console.log("disconnected");
}

function onPoll() {
    //console.log("polling");

    result = http.get("items/" + encodeURI(plugin.Settings["GroupName"]), { baseURL: baseURL }).data;
    json = result.members;
    for (var i = 0; i < json.length; i++) {
        var obj = json[i];

        var device = plugin.Devices[obj.link];
        if (device != null) {
            device.State = obj.state;
            device.StateAlt = obj.state;
        }
    }
}

function onSynchronizeDevices() {
    result = http.get("items/" + encodeURI(plugin.Settings["GroupName"]), { baseURL: baseURL }).data;
    json = result.members;
    //console.log(JSON.stringify(json));
    //console.log(json.length);
    for (var i = 0; i < json.length; i++) {
        var obj = json[i];

        var device = plugin.Devices[obj.link];
        if (device == null) {
            device = new Device();
            device.Id = obj.link;
            plugin.Devices[device.Id] = device;
        }

        device.DisplayName = obj.label;
        device.Name = obj.name;
        device.Capabilities = [];
        device.Attributes = ["Command", "State"];
        device.State = obj.state;
    }
}

Hey Bill,

The reordering of course makes perfect sense I absolutely agree with that. And I also agree absolutely that the State updating without triggering a command is a rare use case. I think I did not use it anywhere in my project at all and seeing this discussion I even regret having added it.

Cause in the end I don’t get is what’s now the change in logic with your proposal? Just the names? Cause the code you proposal is similar (except of the reordering) to my code except that “Command” is now renamed to “State” and “State” was renamed to “StateAlt”? The only real difference I see is that both OnChangeRequests now update both values (I’m not sure if that makes sense or if the values should stay separate that can be discussed). And the updating of HomeRemote’s attribute (be it now command or state) is anyhow not coming from OpenHAB2 itself. You’re just updating the attribute with the value passed to the OnChangeRequest. Correct my if I’m missing something here.

So I don’t see why we now make a big fuzz about this if the attribute used for the Post command is now named “Command” or “State”. Therefore my statement still stands: use “Command” also for the dimmer it will work cause it does NOTHING different in the new version except it’s now named “State”. “Command” also update it’s internal attribute value to what you pass to onChangeRequest. So you can use it for reading & writing values.

And I actually have to 2 reasons why I would like to keep “Command” as the name of the attribute.

  • from openhab’s view you’re executing a Command (which will update the internal state of openhab2 but that’s a different story as you’re anyhow not using it)
  • it will break any existing projects that already make use of the “Command” and mabe even “State” which will have a new behaviour and all the “Commands” will fail.

I’m a professional programmer 20+ years for backend & frontend systems, microservices and apps. And such an breaking interface change without maintaining backwards comptability you should avoid at all costs

But somehow everybody seems to have a personal problem with the attribute name “Command”.

So, except I’m really completely mislead or overlooking something crucial I would like to keep the current plugin and just update it with the reorderings proposed by bill.

I hope you guys can live with that.

I 100% agree with you in terms of backwards compatibility. Command should still work for existing projects. I shouldn’t have omitted that. I do however feel that it’d make more sense for users to use the State attribute going forward. I propose we support both.

The Command terminology just sounds like a setting that’s going to be write-only. I think it would be a little weird binding a Light.Command attribute to a Label to view the current status. Now State to me, sounds like something that has both read & write support. It also matches the terminology that is in the actual JSON.

My vote would be to keep support for the Command attribute so it is fully compatible with existing projects. But we also revise State support so it sends actual device commands.

openhab_v3.plugin (3.0 KB)

plugin.OnChangeRequest = onChangeRequest;
plugin.OnConnect = onConnect;
plugin.OnDisconnect = onDisconnect;
plugin.OnPoll = onPoll;
plugin.OnSynchronizeDevices = onSynchronizeDevices;
plugin.PollingInterval = 5000;
plugin.DefaultSettings = { "OpenHABUrl": "http://localhost:8080", "GroupName": "" };
plugin.Name = "OpenHab";

var http = new HTTPClient();
var plainHeaders = { 'Content-Type': 'text/plain' }

// including Protocol & Port
var baseURL;

// an OpenHAB group containing the items you want to control, e.g. MQTT_GROUP
var MqttGroup;

function onChangeRequest(device, attribute, value) {
    switch (attribute) {
        case "Command":
        case "State":
            // Trigger a command.
            console.log("State device=" + device.Name + ", value=" + value);
            http.post("items/" + encodeURI(device.Name), value, { baseURL: baseURL, headers: plainHeaders });
            device.Command = value;
            device.State = value;
            device.StateAlt = value;
            break;
        case "StateAlt":
            // Update only the state, do not trigger a command.
            console.log("StateAlt device=" + device.Name + ", value=" + value);
            http.put("items/" + encodeURI(device.DisplayName) + "/state", value, { baseURL: baseURL, headers: plainHeaders });
            device.State = value;
            device.StateAlt = value;
            break;
        default:
            console.log("ERROR: unknown attribute");
            console.log("device: " + device.DisplayName);
            console.log("attribute: " + attribute);
            console.log("value: " + value);
            break;
    }
}

function onConnect() {
    baseURL = plugin.Settings["OpenHABUrl"] + "/rest/";
    console.log("connected to " + baseURL);
}

function onDisconnect() {
    console.log("disconnected");
}

function onPoll() {
    //console.log("polling");

    result = http.get("items/" + encodeURI(plugin.Settings["GroupName"]), { baseURL: baseURL }).data;
    json = result.members;
    for (var i = 0; i < json.length; i++) {
        var obj = json[i];

        var device = plugin.Devices[obj.link];
        if (device != null) {
            device.State = obj.state;
            device.StateAlt = obj.state;
        }
    }
}

function onSynchronizeDevices() {
    result = http.get("items/" + encodeURI(plugin.Settings["GroupName"]), { baseURL: baseURL }).data;
    json = result.members;
    //console.log(JSON.stringify(json));
    //console.log(json.length);
    for (var i = 0; i < json.length; i++) {
        var obj = json[i];

        var device = plugin.Devices[obj.link];
        if (device == null) {
            device = new Device();
            device.Id = obj.link;
            plugin.Devices[device.Id] = device;
        }

        device.DisplayName = obj.label;
        device.Name = obj.name;
        device.Capabilities = [];
        device.Attributes = ["Command", "State"];
        device.State = obj.state;
    }
}

Hey Bill,

Thats a compromise I can live with cause we keep mostly backwards comptability with this (I don’t know if anyone was using the old State (now StateAlt) but these should be rare cases which would need a correction then). Also I do see the need for a better naming as command indeed implies somewhat a one way communication and not necessarily a read-write attribute.

I don’t know if I like the naming of “StateAlt” but as I currently can’t come up with something better I’m fine with that as well.

So, will you update the plugin with the updated version?

Best regards,

Marc

I’ll let you go ahead & make the update.

I’m not sold on “StateAlt” naming either. If someone comes up with something better, by all means, feel free to change that.