Feature Request - Make it easier to create button to send HTTP requests

I have managed to create two buttons that when pressed they send out a HTTP request. One button was an ON command and the other button was an OFF command.

I followed the example here

However for creating lots of buttons with this functionality I can see it being very difficult and a lot of hassle.

You have to have a script file that contains the two http requests for ON / OFF amongst other things in there. So would I need a different script file for each pair of buttons I want to create?

You then need to add a Plugin entity that points to that script file and a device underneath that.

Then on your page you create a button and on its EventTrigger action, your binding points to that device and the value is On or Off

It just seems daunting and a lot of work for me to add any more buttons, which I need to do but have been putting it off.

Ideally I like to just be able to add a button and in its own properties be able to add the http commands for ON / OFF or IsPressed etc.

There must be an easier way to do this ?

Thanks

You can already achieve exactly what you are asking for already by making a minor change to the plugin code. Add a custom attribute to the device object called HttpCommand. Copy that into the Attributes property for the object then update your script to look like the script below. Now, whenever you want to send a command, you will use the entire URL in your EventTrigger.

function onChangeRequest(device, attribute, value) {
    switch (attribute) {
        case "HttpCommand":
            http.get(value);
            break;
        default:
            break;
    }
}

I personally probably wouldn’t choose that route but that’s just me. I would probably make some adjustments so my Trigger Actions do not need to use the entire URL. I would probably add a Plugin Setting called BaseURL or something like that. That way if my IP address changes I don’t need to find & update all of these Triggers. And depending on the service, I may split up that single device object into multiple ones & include part of the URL in the Device.Id property. The Id part would really depend on what it is I am doing. At the very least, I’d recommend a BaseURL.

function onChangeRequest(device, attribute, value) {
    switch (attribute) {
        case "HttpCommand":
            http.get(plugin.Settings["BaseURL"] + "/" + device.Id + "/" + value);
            break;
        default:
            break;
    }
}

With both of these examples you only need 1 script file.

Hi Bill

Thanks for the reply, I will try to digest what you’ve said and give it a go.

A base URL sounds like a good idea, if I could then just add a value to append to that URL ?

Reason I am asking is because of Multi System Reactor (MSR) which is the new logic engine for Vera and other systems like Hubitat and Home Assistant.

Patrick is building a HTTP API so we can trigger or run MSR actions by sending in a HTTP request to it.

My plan is to replace all my Vera scenes with either MSR “Global Reactions” or “Rule Sets” and then initiate them from my Home Remote dashboard when I press a button.

These would be manual scenes with no trigger other than me manually initiating them by pressing a button etc.

In MSR a “Global Reaction” is a basic “scene” that carries out a set of actions, these can be initiated with HTTP requests like this:

http://msr-ip:8111/api/v1/reaction/re-klkn8rxw/run

Where “re-klkn8rxw” is the internal ID of the Global Reaction I want to initiate.

Rule Sets in MSR on the other hand are the actual logic rules proper and these are generally triggered by things automatically happening, like a sensor tripping or what ever.

However as Rule Sets can also carry out complex conditional checks also, I have some “scenes” where I would use a Rule Set instead of a Global Reaction.

A Rule Set can have its own trigger monitor a Global Expression and for a particular value in that expression to be present.
For example say I have a Global Expression called “scene” I could send in a HTTP Request like this, to trigger that Rule Set and therefore have my desired actions and logic carried out.

http://msr-ip:8111/api/v1/variable/scene/set?value=1

Where 1 is the value and this would be the only Rule Set that monitored for the “scene” expression being 1.

I could have a second different Rule Set that is triggered by a value of 2.

http://msr-ip:8111/api/v1/variable/scene/set?value=2

So I need an easier way in Home Remote to add Scene buttons to my Group pages, that would send these HTTP requests out etc.

When Patrick has finished building Multi System Reactor and has proper documentation for the HTTP API, I was going to ask you, if you might of been able to add support for MSR in to Home Remote, so it could be added as a Device Type and the desired “Global Reactions” aka Scenes are imported in to the Home Remote designer. Maybe down the road.

Out of Interest which Home Automation controller are you using Bill ?

Correct. Write what you want to append to the HttpCommand attribute. Once you study that code I just shared it should begin to click.

I’m using a mix of everything. I’ve got products attached to just about every different controller.

I highly recommend you take a look at Multi System Reactor logic engine if you haven’t already. I have it running on a Raspberry Pi.

I was using the old PLEG logic engine for Vera but have recently moved nearly 100 rules over to MSR and no longer use PLEG.

MSR once I found my feet with it, was very easy to create simple or complex logic rules.

Sure thing. Will do.

This is the forum for it:

And this is the current documentation for it:

https://reactor.toggledbits.com/docs/

@Bill

As I am unsure really what I am doing, I am trying with the first option first as that seemed easier.

I have created a new Plugin called “HTTP” and this is the code in the script:

image

plugin.Name = "HTTPExample";
plugin.OnChangeRequest = onChangeRequest;
plugin.OnConnect = onConnect;
plugin.OnDisconnect = onDisconnect;
plugin.OnPoll = onPoll;
plugin.OnSynchronizeDevices = onSynchronizeDevices;
plugin.PollingInterval = 1000;

var http = new HTTPClient();

function onChangeRequest(device, attribute, value) {
    console.log("Sending " + value + " for " + device.Name);
    if (device.Id == "1") {
        switch (attribute) {
        case "HttpCommand":
            http.get(value);
            break;
        default:
            break;
    }
}
    else {
        throw "Commands for this device Id have not been implemented";
    }
}

function onConnect() {
}

function onDisconnect() {
}

function onPoll() {
}

function onSynchronizeDevices() {
    var switch1 = new Device();
    switch1.Id = "1";
    switch1.DisplayName = "Switch 1";
    switch1.Capabilities = ["Switch"];
    switch1.Attributes = [];
    plugin.Devices[switch1.Id] = switch1;
}

In the designer I can see this:

image

And this, where I added the attribute:

image

Then on my button on my page I have this for the action:

image

When I click the button in the designers emulator, I don’t appear to get an error popup, but the http command isn’t being run, as it should bring up a camera image on my Android tablet which isn’t happening.

Your Binding is wrong. You need to bind to this new “HttpCommand” attribute we added. Not “Switch”.

Also your onChangeRequest doesn’t look like mine I shared earlier. I simplified it a little bit & removed that if-else.

function onChangeRequest(device, attribute, value) {
    switch (attribute) {
        case "HttpCommand":
            http.get(value);
            break;
        default:
            break;
    }
}

OK this is the script code now:

plugin.Name = "HTTPExample";
plugin.OnChangeRequest = onChangeRequest;
plugin.OnConnect = onConnect;
plugin.OnDisconnect = onDisconnect;
plugin.OnPoll = onPoll;
plugin.OnSynchronizeDevices = onSynchronizeDevices;
plugin.PollingInterval = 1000;

var http = new HTTPClient();

function onChangeRequest(device, attribute, value) {
    console.log("Sending " + value + " for " + device.Name);
        switch (attribute) {
        case "HttpCommand":
            http.get(value);
            break;
        default:
            break;
    
}
    
}

function onConnect() {
}

function onDisconnect() {
}

function onPoll() {
}

function onSynchronizeDevices() {
    var switch1 = new Device();
    switch1.Id = "1";
    switch1.DisplayName = "Switch 1";
    switch1.Capabilities = ["Switch"];
    switch1.Attributes = [];
    plugin.Devices[switch1.Id] = switch1;
}

And the binding I changed to be:

VirtualSwitch.HttpCommand

Its working now the HTTP request is being sent to MSR.

However how do I now create a second button to send a different HTTP command ?

Presumably I just create a second button and use the same binding, but put the different HTTP command in its value field.

Yes. Exactly. It is that simple. Use the same binding just update the URL in the Value field.

OK that’s certainly easier than what I had tried to setup previously.

Next question - 99% of my dashboard is GROUP pages not my own pages.

So if I wanted a Scene tile button on a Group page, to send a HTTP request how do I do that ?

For example in this screen shot those tile buttons are Vera scenes:

image

On some Group pages I’d want something that looks similar to this, but each “Scene” tile button sends a different HTTP command to Multi System Reactor.

Here some new code I want you to use. I’m taking a bit of a different approach. This will allow you to use the same SceneTile.xaml files you are already using. Create a new device object for each scene & set the device Id to the URL you want it to run.

plugin.Name = "HTTPExample";
plugin.OnChangeRequest = onChangeRequest;
plugin.OnConnect = onConnect;
plugin.OnDisconnect = onDisconnect;
plugin.OnPoll = onPoll;
plugin.OnSynchronizeDevices = onSynchronizeDevices;
plugin.PollingInterval = 1000;

var http = new HTTPClient();

function onChangeRequest(device, attribute, value) {
    console.log("Sending " + device.Id + " for " + device.Name);
    switch (attribute) {
        case "Scene":
            http.get(device.Id);
            break;
        default:
            break;
    }
}

function onConnect() {
}

function onDisconnect() {
}

function onPoll() {
}

function onSynchronizeDevices() {
    var switch1 = new Device();
    switch1.Id = "http://msr-ip:8111/api/v1/variable/scene/set?value=1";
    switch1.DisplayName = "Scene 1";
    switch1.Capabilities = ["Scene"];
    switch1.Attributes = [];
    plugin.Devices[switch1.Id] = switch1;
}

WOW that seems to be working !

image

Let me create a second “Scene” device / tile button and try a different HTTP request being sent to Multi System Reactor.

Great thanks Bill !

I have been wanting to be able to do this for a while now, but was putting it off as it seemed too difficult for me.

image

But I can live with this solution. I can now easily create “Scene” devices under the Plugin and just change the URL’s for the various different Multi System Reactor actions I would like to run / initiate.

Many thanks.

1 Like

@Bill

Trying to expand on this and create a button on a custom page not a group page, that is a Toggle button and sends out two HTTP commands one for ON and one for OFF etc.

image

I have created the button and it works and I have a label that changes its text based on the state of the toggle button etc.

Initially the labels text says “Run” as you can see in the above screen shot.

If I press the button it changes the text to “On” and my HTTP command for On is sent.

image

If I press the button again the text on the label changes to “Off” and the HTTP command for Off is sent. So far so good.

image

If I navigate to another area of the HR app and then go back to this custom page again, it still shows the correct state / text of On or Off, which ever state the button was left in etc.

However here is the issue, if I close the HR app and launch it again then the button state is lost and it just says “Run” again. Any way to combat this ?

The way I set the button text up was to use a Property Action on each of the two EventTriggers.

This is the actions for the ON (Checked) EventTigger.

The DataAction is what specifies the HTTP command, the MethodAction is for ShowToast and the PropertyAction is what changes the labels text to “On” in this case.

And these are the Off (Unchecked) EventTrigger actions:

image

Label properties:

image

Thanks

AFAIK this can only be done within a plugin by keeping track of the status in a variable. In the onConnect function you can set an Attribute of the HR device to the value of the status.

There is just one problem. Don’t know if this holds true for non-iOS devices, but on iOS it’s also possible that the HR app is forced stopped first, before it reopens. If it’s forced stopped, then the value of the variable in the plugin is reinitialised (and doesn’t hold the correct value).

Don’t know why this sometimes happens, but only solution for me was to keep track of the status on a MQTT server too. After reopening, I check if the app is forced stopped. In that case, it has to get the values from the MQTT server.

1 Like

I probably should of said, I am using the Android app.

I wonder if an internal variable in HR can be set to 1 or 0 when I click this toggle button and then the label text displays “On” or “Off” based on the state of that variable etc.

I’d need different variables though for each different button / label state.

How many different phones/tablet do you have running home remote or executing these scenes? The problem you are going to have is the hr app on your phone will not know the scene state if changed it on your tablet, and vice versa. That’s why its better to have a server store the states. Then have hr read the states back from the server.

Several phones and tablets.

Sounds like I might be better creating some additional virtual switches in Vera then maybe, for “scenes” with two states.

Or maybe just have two buttons in HR one for On and one for Off and forget the status feedback altogether…

Or just stick with what I have setup today. It works OK if I don’t exit the HR app and if that I know the state won’t be shown on another mobile device as you say.