LATEST UPDATE:
Thanks so much to @RedOranges, here is a version that fixes the problems when using Celsius. This version works for Fahrenheit as well, so I would suggest everyone use this version:
Ecobee.widget.json (15.7 KB)
Original post:
This is an implementation of a widget that can (mostly) control an ecobee thermostat.
First, a few screenshots. If the thermostat is running its normal program, the widget looks like:
You can see the current temperature, humidity, and the temp of the remote sensor. The slider on the right shows what the current temp limit is set to. If you move that slider, it will change from programming mode to the hold mode. The widget will update to show that:
You can click the X button to remove the hold temperature, and return to normal programming mode. You can also click the mode icon to switch between heat, cool, auto and off modes. Here are a couple of final screen shots, showing menu to switch modes, and 1 showing how it looks in cooling mode:
The widget now uses settings for all the various items. (There are quite a few that are needed)
Installation instructions:
First, you will need v. 1.9 of the Ecobee binding and Ecobee action installed.
There are quite a few items that are needed, as well as a few rules For reference, here is a copy of my items file; It has a 1-to-1 mapping with the items needed by the widget. Note that you donāt have to use these item names, but you do need items defined for each item in this list.
/* Ecobee binding items (replace 123456789012 with your thermostat ID) */
String ecobee_name "Ecobee Name [%s]" { ecobee="=[123456789012#name]" }
Group All
Group gSettings (All)
String ecobee_hvacMode "Ecobee hvacMode [%s]" (gSettings) { ecobee="=[123456789012#settings.hvacMode]" }
Switch ecobee_useCelsius "Ecobee useCelsius [%s]" (gSettings) { ecobee="=[123456789012#settings.useCelsius]" }
Group gRuntime (All)
Number ecobee_temperature "Ecobee Temperature [%.1f °F]" (gRuntime) { ecobee="<[123456789012#runtime.actualTemperature]" }
Number ecobee_humidity "Ecobee Humidity [%d %%]" (gRuntime) { ecobee="<[123456789012#runtime.actualHumidity]" }
Number ecobee_desiredCool "Ecobee Desired Cool [%.1f °F]" (gRuntime) { ecobee="<[123456789012#runtime.desiredCool]" }
Number ecobee_desiredHeat "Ecobee Desired Heat [%.1f °F]" (gRuntime) { ecobee="<[123456789012#runtime.desiredHeat]" }
String ecobee_schedule "Ecobee Scheduler" { ecobee="<[123456789012#runningEvent.holdClimateRef]", autoupdate="false" }
Number ecobee_userCool "User Selected Heat [%.1f °F]"
Number ecobee_userHeat "User Selected Cool [%.1f °F]"
/* runningEvent.* is first event marked running, available as of openHAB 1.8 */
String ecobee_eventType "Running event type [%s]" (gEvents) { ecobee="<[123456789012#runningEvent.type]" }
Group gRemoteSensors (All)
/* remote sensor named Office connected to an ecobee3 with ID 123456789012 */
Number ecobee_office_temperature "Ecobee Office Temperature [%.1f °F]" (gRemoteSensors) { ecobee="<[123456789012#remoteSensors(Office).capability(temperature).value]" }
Switch ecobee_office_occupancy "Ecobee Office Occupied [%s]" (gRemoteSensors) { ecobee="<[123456789012#remoteSensors(Office).capability(occupancy).value]" }
You also need the following rules:
import org.openhab.core.library.types.*
rule "Populate userHeat from desiredHeat"
when
Item ecobee_desiredHeat received update
then
if ( ((ecobee_hvacMode.state.toString == "heat") ||
(ecobee_hvacMode.state.toString == "auto")) &&
ecobee_desiredHeat.state instanceof DecimalType) {
ecobee_userHeat.postUpdate(ecobee_desiredHeat.state)
}
end
rule "Populate userCool from desiredCool"
when
Item ecobee_desiredCool received update
then
if ( ((ecobee_hvacMode.state.toString == "cool") ||
(ecobee_hvacMode.state.toString == "auto")) &&
ecobee_desiredCool.state instanceof DecimalType) {
ecobee_userCool.postUpdate(ecobee_desiredCool.state)
}
end
rule UserHeatHold
when
Item ecobee_userHeat received command
then
switch ecobee_hvacMode.state.toString {
case "heat" : ecobee_desiredHeat.sendCommand(receivedCommand)
case "auto" : ecobee_desiredHeat.sendCommand(receivedCommand)
case "cool" : logWarn("UserHeatHold", "in cool mode, heat setpoint ignored")
case "off" : logWarn("UserHeatHold", "in off mode, heat setpoint ignored")
}
end
rule UserCoolHold
when
Item ecobee_userCool received command
then
switch ecobee_hvacMode.state.toString {
case "cool" : ecobee_desiredCool.sendCommand(receivedCommand)
case "auto" : ecobee_desiredCool.sendCommand(receivedCommand)
case "heat" : logWarn("UserCoolHold", "in heat mode, cool setpoint ignored")
case "off" : logWarn("UserCoolHold", "in off mode, heat setpoint ignored")
}
end
rule HeatHold
when
Item ecobee_desiredHeat received command
then
logInfo("HeatHold", "Setting heat setpoint to " + receivedCommand.toString)
val DecimalType desiredHeatTemp = receivedCommand as DecimalType
var DecimalType desiredCoolTemp
if (ecobee_desiredCool.state instanceof DecimalType) {
desiredCoolTemp = ecobee_desiredCool.state as DecimalType
} else {
desiredCoolTemp = new DecimalType(90)
}
// the 1.9 onwards action bundle uses a selection string instead of an item as the first parameter
ecobeeSetHold("319281956903", desiredCoolTemp, desiredHeatTemp, null, null, null, null, null)
end
rule CoolHold
when
Item ecobee_desiredCool received command
then
logInfo("CoolHold", "Setting cool setpoint to " + receivedCommand.toString)
val DecimalType desiredCoolTemp = receivedCommand as DecimalType
var DecimalType desiredHeatTemp
if (ecobee_desiredHeat.state instanceof DecimalType) {
desiredHeatTemp = ecobee_desiredHeat.state as DecimalType
} else {
desiredHeatTemp = new DecimalType(50)
}
// the 1.9 onwards action bundle uses a selection string instead of an item as the first parameter
ecobeeSetHold("319281956903", desiredCoolTemp, desiredHeatTemp, null, null, null, null, null)
end
// rule supported in 1.9 onwards using the new ecobeeSetHold method signature:
rule FanHold
when
Item ecobee_desiredFan received command
then
logInfo("FanHold", "Setting fan hold to " + receivedCommand.toString)
val params = newLinkedHashMap(
'isTemperatureAbsolute'-> false,
'isTemperatureRelative' -> false,
'isCoolOff' -> true,
'isHeatOff' -> true,
'coolHoldTemp' -> 90,
'heatHoldTemp' -> 50,
'fan' -> receivedCommand.toString)
ecobeeSetHold("319281956903", params, null, null, null, null)
end
rule ComfortHold
when
Item ecobee_schedule received command
then
if (receivedCommand.toString.equals("resume")) {
// the 1.9 onwards action bundle uses a selection string instead of an item as the first parameter
ecobeeResumeProgram("319281956903", true)
} else {
// the 1.9 onwards action bundle uses a selection string instead of an item as the first parameter
ecobeeSetHold("319281956903", null, null, receivedCommand.toString, null, null, null, null)
}
end
If you used different item names that are in my file, you will need to edit that file to match.
Once that is done, you can install the widget itself. The icons are available here
Once downloaded, extract the files to your conf/html directory. You should end up with a sub directory named images containing the extracted files.
Finally, import the following custom widget:
Ecobee.widget.json (10.5 KB)
There are still a few bugs to work out. The slider values donāt update correctly every time. It can always be fixed by reloading the widget (either by reloading the page, or going to a different page and going back) but I am still working through how to force updates. There are also a couple of spacing/formatting issues to work out. More updates after I learn more and fix some bugs.