How To Set Ecobee "Away and Hold"

How do I create an action in a rule to set the thermostat to “Away and Hold” or “Home and Hold”. I tried sending the command “away” (without the quotes) through the Ecobee Hold Action channel but the logfile shows:

2023-02-27 14:58:58.710 [INFO ] [openhab.event.ItemCommandEvent ] - Item ‘Ecobee_Thermostat_Hold_Action’ received command away
2023-02-27 14:58:58.712 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item ‘Ecobee_Thermostat_Hold_Action’ predicted to become away
2023-02-27 14:58:58.717 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item ‘Ecobee_Thermostat_Hold_Action’ changed from askMe to away
2023-02-27 14:59:05.407 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item ‘Ecobee_Thermostat_Hold_Action’ changed from away to askMe

Do I need to use a different channel or a different command to make this work?

You need to call one of the setHold actions from within a rule.

There also are some example rules further down in the documentation.

Here’s a rule I worked out in ECMAScript to set multiple thermostats. Substitute “Away” for “Arriving”

ecobeeActions = actions.thingActions("ecobee", "ecobee:thermostat:7...8");
setClimateHold("Main Floor", ecobeeActions, "Arriving"); 

ecobeeActions = actions.thingActions("ecobee", "ecobee:thermostat:7...7");
setClimateHold("Office", ecobeeActions, "Arriving"); 

ecobeeActions = actions.thingActions("ecobee", "ecobee:thermostat:7...6");
setClimateHold("Bedroom", ecobeeActions, "Arriving"); 

ecobeeActions = actions.thingActions("ecobee", "ecobee:thermostat:7...0");
setClimateHold("Hall", ecobeeActions, "Arriving"); 

function setClimateHold(statName, statActions, desiredClimate) {
  var climates = statActions.getClimates()
  // console.log("climate = " + climates);
  if (climates !== null) {
    climates = JSON.parse(climates);
    var numElements = climates.length;
    console.log("Climates: There are ", numElements, " climates in array");
    console.log(JSON.stringify(climates[numElements-1]));

    var nameMap = {};
    for (var i=0; i < numElements; i++) {
        climateSettings = climates[i];
        nameMap[climateSettings.name] = climateSettings.climateRef;
        // console.log("Climate ", i, " Name: " + climateSettings.name, " Ref: ", climateSettings.climateRef, " Heat: ",  (climateSettings.heatTemp/10.0));
    }
    if (desiredClimate in nameMap ) {
      console.log("Setting ", nameMap[desiredClimate], " for ", statName);
      ecobeeActions.setHold(nameMap[desiredClimate]);
    } else {
      console.log("Did not find ", desiredClimate, " for ", statName);
      console.log(JSON.stringify(nameMap));
    }
  } else {
      console.log("No climates found for " + statName)
  }
}
1 Like

@tcgerhard Nice use of getClimates action!

Reviving this thread. Is there a way to do this by sending a command to an item in a rule? Or with Blockly?

Still looking for an answer here. Is there no channel to use for this? I can see the state in Current_Climate_Ref but I can’t find a channel to take the command to change it.

No, there currently is not a channel to change the climate ref.

The Ecobee API defines currentClimateRef as read-only, so sending a climate ref to that channel will have no effect.

I suppose internally the binding could accept a command on the currentClimateRef channel and convert it to the Ecobee API function call to set the climate ref. But the binding doesn’t work that way today.

mhilbush thanks for clarifying that. I have a script similar to teh one above which I thought used to work at my wifes airbnb, but it gives me an error now. Script:

ecobeeActions = actions.thingActions("ecobee", "ecobee:thermostat:Ecobee_Account:...");
setClimateHold("Ecobee Thermostat", ecobeeActions, "Away"); 

function setClimateHold(statName, statActions, desiredClimate) {
  var climates = statActions.getClimates()
  // console.log("climate = " + climates);
  if (climates !== null) {
    climates = JSON.parse(climates);
    var numElements = climates.length;
    console.log("Climates: There are ", numElements, " climates in array");
    console.log(JSON.stringify(climates[numElements-1]));

    var nameMap = {};
    for (var i=0; i < numElements; i++) {
        climateSettings = climates[i];
        nameMap[climateSettings.name] = climateSettings.climateRef;
        // console.log("Climate ", i, " Name: " + climateSettings.name, " Ref: ", climateSettings.climateRef, " Heat: ",  (climateSettings.heatTemp/10.0));
    }
    if (desiredClimate in nameMap ) {
      console.log("Setting ", nameMap[desiredClimate], " for ", statName);
      ecobeeActions.setHold(nameMap[desiredClimate]);
    } else {
      console.log("Did not find ", desiredClimate, " for ", statName);
      console.log(JSON.stringify(nameMap));
    }
  } else {
      console.log("No climates found for " + statName)
  }
}

Error:
TypeError: actions.thingActions is not a function in <eval> at line number 1

It’s complaining about actions.thingActions but I don’t see that anywhere in the rule you posted. Did you do a copy/paste and forget to change something elsewhere in the rule?

Thanks yeah the top line was cut off from how I set up the script box. I have corrected it above.

Don’t you need to declare ecobeeActions using var.

var ecobeeActions = actions.thingActions("ecobee", "ecobee:thermostat:Ecobee_Account:...");

Good catch, that seems right to me. Same error though.

OK back on this problem. I really need to get this working and would appreciate any help I can get. @tcgerhard was kind enough to post a script that is working but when I try it I get the error:

TypeError: actions.thingActions is not a function in <eval> at line number 1

I DO have a couple of questions which may or may not be related. In this section:

var ecobeeActions = actions.thingActions("Ecobee Thermostat", "ecobee:thermostat:Ecobee_Account:511...");
setClimateHold("Skyes Ecobee", ecobeeActions, "Away"); 

Is “ecobee:thermostat:Ecobee_Account:511…” (the full name of my thermostat Thing as shown in OH) correct, or should it be missing the “Ecobee_Account:” part?

Next, this name:

actions.thingActions("Ecobee Thermostat"

Is that supposed to be as it is shown, or the name of my Ecobee Account name as shown in OH?

Finally:

setClimateHold("Skyes Ecobee"

That is supposed to be the name of the thermostat as shown in Ecobee right?

Here is my full script:

var ecobeeActions = actions.thingActions("Ecobee Thermostat", "ecobee:thermostat:Ecobee_Account:511...");
setClimateHold("Skyes Ecobee", ecobeeActions, "Away"); 

function setClimateHold(statName, statActions, desiredClimate) {
  var climates = statActions.getClimates()
  // console.log("climate = " + climates);
  if (climates !== null) {
    climates = JSON.parse(climates);
    var numElements = climates.length;
    console.log("Climates: There are ", numElements, " climates in array");
    console.log(JSON.stringify(climates[numElements-1]));

    var nameMap = {};
    for (var i=0; i < numElements; i++) {
        climateSettings = climates[i];
        nameMap[climateSettings.name] = climateSettings.climateRef;
        // console.log("Climate ", i, " Name: " + climateSettings.name, " Ref: ", climateSettings.climateRef, " Heat: ",  (climateSettings.heatTemp/10.0));
    }
    if (desiredClimate in nameMap ) {
      console.log("Setting ", nameMap[desiredClimate], " for ", statName);
      ecobeeActions.setHold(nameMap[desiredClimate]);
    } else {
      console.log("Did not find ", desiredClimate, " for ", statName);
      console.log(JSON.stringify(nameMap));
    }
  } else {
      console.log("No climates found for " + statName)
  }
}

It should be whatever is shown in Main UI as the Identifier for the thermostat thing.

It should be the name of the binding (i.e. “ecobee”).

Thanks mhilbush, the name of my ecobee binding is Ecobee Binding. This didn’t seem right which sent me looking for more examples and I found this one which is supposed to work. The script looks completely different. When I tried it I got the same error. I tried adding var in front of the first line with no change. So why is the error saying that actions.thingactions is not a function? Isn’t that a valid function for a ECMAScript?

New script:

ecobeeActions = actions.thingActions("ecobee", "ecobee:thermostat:account:id");

var climates = ecobeeActions.getClimates()
// console.log("climate = " + climates);
if (climates !== null) {
    climates = JSON.parse(climates);
    var numElements = climates.length;
    console.log("Climates: There are ", numElements, " climates in array");
    console.log(JSON.stringify(climates[numElements-1]));

    for (var i=0; i < numElements; i++) {
        climateSettings = climates[i];
        console.log("Climate ", i, " Name: " + climateSettings.name, " Ref: ", climateSettings.climateRef, " Heat: ",  (climateSettings.heatTemp/10.0));
    }
  ecobeeActions.setHold("smart1");
} else {
    console.log("ecobee", "Climates: No climates!!!")

I just realized that this other script is also from tcgerhard. Interesting that it’s so different. The thread I found is here:
https://community.openhab.org/t/how-to-access-binding-actions-with-js-scripting/142456/2

The thread you linked to was my test script; the one at the top of this thread was the version as of when I posted it in this thread.

Please verify that your script is showing “application/javascript;version=ECMAScript-2021” under the “Edit Script” heading, and not simply “application/javascript” – these are two different engines with different requirements. I pop in and out of working with my rules and often find myself chasing information that applies to the wrong version of JS.

Ah! Mine just says application/javascript. Is there a command I should be using in place of actions.thingactions, or are there more differences than that?

When you add the script to your rule, you select the engine you want to use to process it. The options available will depend on the rules engines you’ve installed; here’s mine:

In this case, the second ECMAScript (Edition 11) was used. If it’s not available for you, you’ll need to go to Settings → Add-ons → Automation and install the JSScripting option.