[radiothermostat] Add Remote Temperature channel (#10194)

* Add Remote Temperature channel

Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>

* Fix spelling error

Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>

* Fix spelling error2

Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>

* review changes

Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>

* review changes

Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>

* review changes

Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>

* minor README update

Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>
This commit is contained in:
mlobstein 2021-04-09 16:28:38 -05:00 committed by GitHub
parent 3561388061
commit 035556bc55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 83 additions and 48 deletions

View File

@ -1,5 +1,7 @@
# RadioThermostat Binding
![RadioThermostat logo](doc/index.jpg)
This binding connects RadioThermostat/3M Filtrete models CT30, CT50/3M50, CT80, etc. with built-in Wi-Fi module to openHAB.
The binding retrieves and periodically updates all basic system information from the thermostat.
@ -45,26 +47,27 @@ The thing has a few configuration parameters:
The thermostat information that is retrieved is available as these channels:
| Channel ID | Item Type | Description |
|------------------------|----------------------|---------------------------------------------------------------------------|
| temperature | Number:Temperature | The current temperature reading of the thermostat |
| humidity | Number:Dimensionless | The current humidity reading of the thermostat (CT80 only) |
| mode | Number | The current operating mode of the HVAC system |
| fan_mode | Number | The current operating mode of the fan |
| program_mode | Number | The program schedule that the thermostat is running (CT80 Rev B only) |
| set_point | Number:Temperature | The current temperature set point of the thermostat |
| status | Number | Indicates the current running status of the HVAC system |
| fan_status | Number | Indicates the current fan status of the HVAC system |
| override | Number | Indicates if the normal program set-point has been manually overridden |
| hold | Switch | Indicates if the current set point temperature is to be held indefinitely |
| day | Number | The current day of the week reported by the thermostat (0 = Monday) |
| hour | Number | The current hour of the day reported by the thermostat (24 hr) |
| minute | Number | The current minute past the hour reported by the thermostat |
| dt_stamp | String | The current day of the week and time reported by the thermostat (E HH:mm) |
| today_heat_runtime | Number:Time | The total number of minutes of heating run-time today |
| today_cool_runtime | Number:Time | The total number of minutes of cooling run-time today |
| yesterday_heat_runtime | Number:Time | The total number of minutes of heating run-time yesterday |
| yesterday_cool_runtime | Number:Time | The total number of minutes of cooling run-time yesterday |
| Channel ID | Item Type | Description |
|------------------------|----------------------|------------------------------------------------------------------------------------------------------------------------------------|
| temperature | Number:Temperature | The current temperature reading of the thermostat |
| humidity | Number:Dimensionless | The current humidity reading of the thermostat (CT80 only) |
| mode | Number | The current operating mode of the HVAC system |
| fan_mode | Number | The current operating mode of the fan |
| program_mode | Number | The program schedule that the thermostat is running (CT80 Rev B only) |
| set_point | Number:Temperature | The current temperature set point of the thermostat |
| status | Number | Indicates the current running status of the HVAC system |
| fan_status | Number | Indicates the current fan status of the HVAC system |
| override | Number | Indicates if the normal program set-point has been manually overridden |
| hold | Switch | Indicates if the current set point temperature is to be held indefinitely |
| remote_temp | Number:Temperature | Override the internal temperature as read by the thermostat's temperature sensor; Set to -1 to return to internal temperature mode |
| day | Number | The current day of the week reported by the thermostat (0 = Monday) |
| hour | Number | The current hour of the day reported by the thermostat (24 hr) |
| minute | Number | The current minute past the hour reported by the thermostat |
| dt_stamp | String | The current day of the week and time reported by the thermostat (E HH:mm) |
| today_heat_runtime | Number:Time | The total number of minutes of heating run-time today |
| today_cool_runtime | Number:Time | The total number of minutes of cooling run-time today |
| yesterday_heat_runtime | Number:Time | The total number of minutes of heating run-time yesterday |
| yesterday_cool_runtime | Number:Time | The total number of minutes of cooling run-time yesterday |
## Full Example
@ -145,6 +148,9 @@ Number:Time Therm_todaycool "Today's Cooling Runtime [%d %unit%]" { channe
Number:Time Therm_yesterdayheat "Yesterday's Heating Runtime [%d %unit%]" { channel="radiothermostat:rtherm:mytherm1:yesterday_heat_runtime" }
Number:Time Therm_yesterdaycool "Yesterday's Cooling Runtime [%d %unit%]" { channel="radiothermostat:rtherm:mytherm1:yesterday_cool_runtime" }
// Override the thermostat's temperature reading with a value from an external sensor, set to -1 to revert to internal temperature mode
Number:Temperature Therm_Rtemp "Remote Temperature [%d]" <temperature> { channel="radiothermostat:rtherm:mytherm1:remote_temp" }
// A virtual switch used to trigger a rule to send a json command to the thermostat
Switch Therm_mysetting "Send my preferred setting"
```
@ -167,9 +173,12 @@ sitemap radiotherm label="My Thermostat" {
Text item=Therm_Override icon="smoke"
Switch item=Therm_Hold icon="smoke"
// Example of overriding the thermostat's temperature reading
Switch item=Therm_Rtemp label="Remote Temp" icon="temperature" mappings=[60="60", 75="75", 80="80", -1="Reset"]
// Virtual switch/button to trigger a rule to send a custom command
// The ON value displays in the button
Switch item=Therm_mysetting mappings=[ON="Heat, 58, hold"]
Switch item=Therm_mysetting mappings=[ON="Heat, 68, hold"]
Text item=Therm_Day
Text item=Therm_Hour
@ -198,6 +207,6 @@ then
}
// JSON to send directly to the thermostat's '/tstat' endpoint
// See RadioThermostat_CT50_Honeywell_Wifi_API_V1.3.pdf for more detail
actions.sendRawCommand('{"hold":1, "t_heat":' + "58" + ', "tmode":1}')
actions.sendRawCommand('{"hold":1, "t_heat":' + "68" + ', "tmode":1}')
end
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -47,6 +47,7 @@ public class RadioThermostatBindingConstants {
public static final String DEFAULT_RESOURCE = "tstat";
public static final String RUNTIME_RESOURCE = "tstat/datalog";
public static final String HUMIDITY_RESOURCE = "tstat/humidity";
public static final String REMOTE_TEMP_RESOURCE = "tstat/remote_temp";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_RTHERM = new ThingTypeUID(BINDING_ID, "rtherm");
@ -70,11 +71,12 @@ public class RadioThermostatBindingConstants {
public static final String TODAY_COOL_RUNTIME = "today_cool_runtime";
public static final String YESTERDAY_HEAT_RUNTIME = "yesterday_heat_runtime";
public static final String YESTERDAY_COOL_RUNTIME = "yesterday_cool_runtime";
public static final String REMOTE_TEMP = "remote_temp";
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_RTHERM);
public static final Set<String> SUPPORTED_CHANNEL_IDS = Stream.of(TEMPERATURE, HUMIDITY, MODE, FAN_MODE,
PROGRAM_MODE, SET_POINT, OVERRIDE, HOLD, STATUS, FAN_STATUS, DAY, HOUR, MINUTE, DATE_STAMP,
TODAY_HEAT_RUNTIME, TODAY_COOL_RUNTIME, YESTERDAY_HEAT_RUNTIME, YESTERDAY_COOL_RUNTIME)
TODAY_HEAT_RUNTIME, TODAY_COOL_RUNTIME, YESTERDAY_HEAT_RUNTIME, YESTERDAY_COOL_RUNTIME, REMOTE_TEMP)
.collect(Collectors.toSet());
// Units of measurement of the data delivered by the API

View File

@ -105,10 +105,11 @@ public class RadioThermostatConnector {
*
* @param the JSON attribute key for the value to be updated
* @param the value to be updated in the thermostat
* @param the end point URI to use for the command
* @return the JSON response string from the thermostat
*/
public String sendCommand(String cmdKey, @Nullable String cmdVal) {
return sendCommand(cmdKey, cmdVal, null);
public String sendCommand(String cmdKey, @Nullable String cmdVal, String resource) {
return sendCommand(cmdKey, cmdVal, null, resource);
}
/**
@ -117,12 +118,14 @@ public class RadioThermostatConnector {
* @param the JSON attribute key for the value to be updated
* @param the value to be updated in the thermostat
* @param JSON string to send directly to the thermostat instead of a key/value pair
* @param the end point URI to use for the command
* @return the JSON response string from the thermostat
*/
public String sendCommand(@Nullable String cmdKey, @Nullable String cmdVal, @Nullable String cmdJson) {
public String sendCommand(@Nullable String cmdKey, @Nullable String cmdVal, @Nullable String cmdJson,
String resource) {
// if we got a cmdJson string send that, otherwise build the json from the key and val params
String postJson = cmdJson != null ? cmdJson : "{\"" + cmdKey + "\":" + cmdVal + "}";
String urlStr = buildRequestURL(DEFAULT_RESOURCE);
String urlStr = buildRequestURL(resource);
String output = "";

View File

@ -81,11 +81,12 @@ public class RadioThermostatDiscoveryService extends AbstractDiscoveryService {
TimeUnit.SECONDS);
}
@SuppressWarnings("null")
@Override
protected void stopBackgroundDiscovery() {
if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
ScheduledFuture<?> scheduledFuture = this.scheduledFuture;
if (scheduledFuture != null) {
scheduledFuture.cancel(true);
this.scheduledFuture = null;
}
}

View File

@ -46,6 +46,7 @@ import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PointType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
@ -216,7 +217,7 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
}
public void handleRawCommand(@Nullable String rawCommand) {
connector.sendCommand(null, null, rawCommand);
connector.sendCommand(null, null, rawCommand, DEFAULT_RESOURCE);
}
@Override
@ -226,21 +227,19 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
} else {
Integer cmdInt = -1;
String cmdStr = command.toString();
if (cmdStr != null) {
try {
// parse out an Integer from the string
// ie '70.5 F' becomes 70, also handles negative numbers
cmdInt = NumberFormat.getInstance().parse(cmdStr).intValue();
} catch (ParseException e) {
logger.debug("Command: {} -> Not an integer", cmdStr);
}
try {
// parse out an Integer from the string
// ie '70.5 F' becomes 70, also handles negative numbers
cmdInt = NumberFormat.getInstance().parse(cmdStr).intValue();
} catch (ParseException e) {
logger.debug("Command: {} -> Not an integer", cmdStr);
}
switch (channelUID.getId()) {
case MODE:
// only do if commanded mode is different than current mode
if (!cmdInt.equals(rthermData.getThermostatData().getMode())) {
connector.sendCommand("tmode", cmdStr);
connector.sendCommand("tmode", cmdStr, DEFAULT_RESOURCE);
// set the new operating mode, reset everything else,
// because refreshing the tstat data below is really slow.
@ -253,26 +252,26 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
rthermData.getThermostatData().setProgramMode(-1);
updateChannel(PROGRAM_MODE, rthermData);
// now just trigger a refresh of the thermost to get the new active setpoint
// now just trigger a refresh of the thermostat to get the new active setpoint
// this takes a while for the JSON request to complete (async).
connector.getAsyncThermostatData(DEFAULT_RESOURCE);
}
break;
case FAN_MODE:
rthermData.getThermostatData().setFanMode(cmdInt);
connector.sendCommand("fmode", cmdStr);
connector.sendCommand("fmode", cmdStr, DEFAULT_RESOURCE);
break;
case PROGRAM_MODE:
rthermData.getThermostatData().setProgramMode(cmdInt);
connector.sendCommand("program_mode", cmdStr);
connector.sendCommand("program_mode", cmdStr, DEFAULT_RESOURCE);
break;
case HOLD:
if (command instanceof OnOffType && command == OnOffType.ON) {
rthermData.getThermostatData().setHold(1);
connector.sendCommand("hold", "1");
connector.sendCommand("hold", "1", DEFAULT_RESOURCE);
} else if (command instanceof OnOffType && command == OnOffType.OFF) {
rthermData.getThermostatData().setHold(0);
connector.sendCommand("hold", "0");
connector.sendCommand("hold", "0", DEFAULT_RESOURCE);
}
break;
case SET_POINT:
@ -287,7 +286,16 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
// don't do anything if we are not in heat or cool mode
break;
}
connector.sendCommand(cmdKey, cmdInt.toString());
connector.sendCommand(cmdKey, cmdInt.toString(), DEFAULT_RESOURCE);
break;
case REMOTE_TEMP:
if (cmdInt != -1) {
QuantityType<?> remoteTemp = ((QuantityType<Temperature>) command)
.toUnit(ImperialUnits.FAHRENHEIT);
connector.sendCommand("rem_temp", String.valueOf(remoteTemp.intValue()), REMOTE_TEMP_RESOURCE);
} else {
connector.sendCommand("rem_mode", "0", REMOTE_TEMP_RESOURCE);
}
break;
default:
logger.warn("Unsupported command: {}", command.toString());
@ -320,7 +328,10 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
updateAllChannels();
break;
case HUMIDITY_RESOURCE:
rthermData.setHumidity(gson.fromJson(evtVal, RadioThermostatHumidityDTO.class).getHumidity());
RadioThermostatHumidityDTO dto = gson.fromJson(evtVal, RadioThermostatHumidityDTO.class);
if (dto != null) {
rthermData.setHumidity(dto.getHumidity());
}
updateChannel(HUMIDITY, rthermData);
break;
case RUNTIME_RESOURCE:
@ -382,7 +393,7 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
/**
* Update a given channelId from the thermostat data
*
*
* @param the channel id to be updated
* @param data the RadioThermostat dto
* @return the value to be set in the state
@ -456,7 +467,7 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
/**
* Build a list of fan modes based on what model thermostat is used
*
*
* @return list of state options for thermostat fan modes
*/
private List<StateOption> getFanModeOptions() {

View File

@ -22,6 +22,7 @@
<channel id="hold" typeId="hold"/>
<channel id="status" typeId="status"/>
<channel id="fan_status" typeId="fan_status"/>
<channel id="remote_temp" typeId="remote_temp"/>
<channel id="day" typeId="t_day"/>
<channel id="hour" typeId="t_hour"/>
<channel id="minute" typeId="t_minute"/>
@ -157,6 +158,14 @@
<state min="0" max="2" pattern="%d"/>
</channel-type>
<channel-type id="remote_temp" advanced="true">
<item-type>Number:Temperature</item-type>
<label>Remote Temperature</label>
<description>The remote temperature takes the place of the ambient temperature as read by the local thermostat
temperature sensor</description>
<state pattern="%d %unit%"/>
</channel-type>
<channel-type id="t_day" advanced="true">
<item-type>Number</item-type>
<label>Day</label>