mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[radiothermostat] Add message display channel and improve ThingActions (#14799)
* Add price message channel Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>
This commit is contained in:
parent
ec30333314
commit
2c006ccd31
@ -88,6 +88,7 @@ The thermostat information that is retrieved is available as these channels:
|
||||
| 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 |
|
||||
| message | String (Write Only) | Used to display a number in the upper left 'price message' area of the thermostat's screen where the time is normally displayed |
|
||||
|
||||
## Full Example
|
||||
|
||||
@ -158,15 +159,16 @@ Number Therm_FanStatus "Fan Status [MAP(radiotherm.map):%s_fstus]"
|
||||
Number Therm_Override "Override [MAP(radiotherm.map):%s_over]" { channel="radiothermostat:rtherm:mytherm1:override" }
|
||||
Switch Therm_Hold "Hold" { channel="radiothermostat:rtherm:mytherm1:hold" }
|
||||
|
||||
Number Therm_Day "Thermostat Day [%s]" { channel="radiothermostat:rtherm:mytherm1:day" }
|
||||
Number Therm_Hour "Thermostat Hour [%s]" { channel="radiothermostat:rtherm:mytherm1:hour" }
|
||||
Number Therm_Minute "Thermostat Minute [%s]" { channel="radiothermostat:rtherm:mytherm1:minute" }
|
||||
Number Therm_Day "Thermostat Day [%d]" { channel="radiothermostat:rtherm:mytherm1:day" }
|
||||
Number Therm_Hour "Thermostat Hour [%d]" { channel="radiothermostat:rtherm:mytherm1:hour" }
|
||||
Number Therm_Minute "Thermostat Minute [%d]" { channel="radiothermostat:rtherm:mytherm1:minute" }
|
||||
String Therm_Dstmp "Thermostat DateStamp [%s]" <time> { channel="radiothermostat:rtherm:mytherm1:dt_stamp" }
|
||||
|
||||
Number:Time Therm_todayheat "Today's Heating Runtime [%d %unit%]" { channel="radiothermostat:rtherm:mytherm1:today_heat_runtime" }
|
||||
Number:Time Therm_todaycool "Today's Cooling Runtime [%d %unit%]" { channel="radiothermostat:rtherm:mytherm1:today_cool_runtime" }
|
||||
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" }
|
||||
String Therm_Message "Message: [%s]" { channel="radiothermostat:rtherm:mytherm1:message" }
|
||||
|
||||
// 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" }
|
||||
@ -228,5 +230,30 @@ 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":' + "68" + ', "tmode":1}')
|
||||
|
||||
// Also a command can be sent to a specific endpoint on the thermostat by
|
||||
// specifying it as the second argument to sendRawCommand():
|
||||
|
||||
// Reboot the thermostat
|
||||
// actions.sendRawCommand('{"command": "reboot"}', 'sys/command')
|
||||
|
||||
// Control the energy LED (CT80 only) [0 = off, 1 = green, 2 = yellow, 4 = red]
|
||||
// actions.sendRawCommand('{"energy_led": 1}', 'tstat/led')
|
||||
|
||||
// Send a message to the User Message Area (CT80 only)
|
||||
// actions.sendRawCommand('{"line": 0, "message": "Hello World!"}', 'tstat/uma')
|
||||
|
||||
end
|
||||
|
||||
rule "Display outside temp in thermostat message area"
|
||||
when
|
||||
// An item containing the current outside temperature
|
||||
Item OutsideTemp changed
|
||||
then
|
||||
// Display up to 5 numbers in the thermostat's Price Message Area (PMA)
|
||||
// A decimal point can be used. CT80 can display a negative '-' number
|
||||
// Send null or empty string to clear the number and restore the time display
|
||||
var Number temp = Math.round((OutsideTemp.state as DecimalType).doubleValue).intValue
|
||||
Therm_Message.sendCommand(temp)
|
||||
end
|
||||
```
|
||||
|
@ -14,8 +14,6 @@ package org.openhab.binding.radiothermostat.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.measure.Unit;
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
@ -41,6 +39,8 @@ public class RadioThermostatBindingConstants {
|
||||
public static final String PROPERTY_IP = "hostName";
|
||||
public static final String PROPERTY_ISCT80 = "isCT80";
|
||||
public static final String JSON_TIME = "{\"day\":%s,\"hour\":%s,\"minute\":%s}";
|
||||
public static final String JSON_PMA = "{\"line\":1,\"message\":\"%s\"}";
|
||||
public static final String BLANK = "";
|
||||
|
||||
public static final String KEY_ERROR = "error";
|
||||
|
||||
@ -52,6 +52,7 @@ public class RadioThermostatBindingConstants {
|
||||
public static final String TIME_RESOURCE = "tstat/time";
|
||||
public static final String HEAT_PROGRAM_RESOURCE = "tstat/program/heat";
|
||||
public static final String COOL_PROGRAM_RESOURCE = "tstat/program/cool";
|
||||
public static final String PMA_RESOURCE = "tstat/pma";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_RTHERM = new ThingTypeUID(BINDING_ID, "rtherm");
|
||||
@ -76,12 +77,15 @@ public class RadioThermostatBindingConstants {
|
||||
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 String MESSAGE = "message";
|
||||
|
||||
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, REMOTE_TEMP)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
public static final Set<String> SUPPORTED_CHANNEL_IDS = Set.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, REMOTE_TEMP, MESSAGE);
|
||||
|
||||
public static final Set<String> NO_UPDATE_CHANNEL_IDS = Set.of(REMOTE_TEMP, MESSAGE);
|
||||
|
||||
// Units of measurement of the data delivered by the API
|
||||
public static final Unit<Temperature> API_TEMPERATURE_UNIT = ImperialUnits.FAHRENHEIT;
|
||||
|
@ -35,7 +35,7 @@ public class RadioThermostatThingActions implements ThingActions {
|
||||
|
||||
private @Nullable RadioThermostatHandler handler;
|
||||
|
||||
@RuleAction(label = "send a raw command", description = "Send a raw command to the thermostat.")
|
||||
@RuleAction(label = "send a raw command", description = "Send a raw command to the thermostat's 'tstat' endpoint.")
|
||||
public void sendRawCommand(@ActionInput(name = "sendRawCommand") @Nullable String rawCommand) {
|
||||
if (rawCommand == null) {
|
||||
logger.warn("sendRawCommand called with null command, ignoring");
|
||||
@ -49,11 +49,30 @@ public class RadioThermostatThingActions implements ThingActions {
|
||||
}
|
||||
}
|
||||
|
||||
/** Static alias to support the old DSL rules engine and make the action available there. */
|
||||
@RuleAction(label = "send a raw command", description = "Send a raw command to a specific endpoint on the thermostat.")
|
||||
public void sendRawCommand(@ActionInput(name = "sendRawCommand") @Nullable String rawCommand,
|
||||
@Nullable String resource) {
|
||||
if (rawCommand == null || resource == null) {
|
||||
logger.warn("sendRawCommand called with null command, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
RadioThermostatHandler localHandler = handler;
|
||||
if (localHandler != null) {
|
||||
localHandler.handleRawCommand(rawCommand, resource);
|
||||
logger.debug("sendRawCommand called with raw command: {}, resource: {}", rawCommand, resource);
|
||||
}
|
||||
}
|
||||
|
||||
/** Static aliases to support the old DSL rules engine and make the action available there. */
|
||||
public static void sendRawCommand(ThingActions actions, @Nullable String rawCommand) {
|
||||
((RadioThermostatThingActions) actions).sendRawCommand(rawCommand);
|
||||
}
|
||||
|
||||
public static void sendRawCommand(ThingActions actions, @Nullable String rawCommand, @Nullable String resource) {
|
||||
((RadioThermostatThingActions) actions).sendRawCommand(rawCommand, resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
this.handler = (RadioThermostatHandler) handler;
|
||||
|
@ -44,18 +44,18 @@ import org.slf4j.LoggerFactory;
|
||||
public class RadioThermostatConnector {
|
||||
private final Logger logger = LoggerFactory.getLogger(RadioThermostatConnector.class);
|
||||
|
||||
private static final String URL = "http://%hostName%/%resource%";
|
||||
private static final String URL = "http://%s/%s";
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final List<RadioThermostatEventListener> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private @Nullable String hostName;
|
||||
private String hostName = BLANK;
|
||||
|
||||
public RadioThermostatConnector(HttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public void setThermostatHostName(@Nullable String hostName) {
|
||||
public void setThermostatHostName(String hostName) {
|
||||
this.hostName = hostName;
|
||||
}
|
||||
|
||||
@ -84,16 +84,14 @@ public class RadioThermostatConnector {
|
||||
* @param resouce the url of the json resource on the thermostat
|
||||
*/
|
||||
public void getAsyncThermostatData(String resource) {
|
||||
String urlStr = buildRequestURL(resource);
|
||||
|
||||
httpClient.newRequest(urlStr).method(GET).timeout(30, TimeUnit.SECONDS).send(new BufferingResponseListener() {
|
||||
httpClient.newRequest(buildRequestURL(resource)).method(GET).timeout(30, TimeUnit.SECONDS)
|
||||
.send(new BufferingResponseListener() {
|
||||
@Override
|
||||
public void onComplete(@Nullable Result result) {
|
||||
if (result != null && !result.isFailed()) {
|
||||
String response = getContentAsString();
|
||||
dispatchKeyValue(resource, response);
|
||||
dispatchKeyValue(resource, getContentAsString());
|
||||
} else {
|
||||
dispatchKeyValue(KEY_ERROR, "");
|
||||
dispatchKeyValue(KEY_ERROR, BLANK);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -124,30 +122,27 @@ public class RadioThermostatConnector {
|
||||
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(resource);
|
||||
|
||||
String output = "";
|
||||
|
||||
try {
|
||||
Request request = httpClient.POST(urlStr);
|
||||
Request request = httpClient.POST(buildRequestURL(resource));
|
||||
request.header(HttpHeader.ACCEPT, "text/plain");
|
||||
request.header(HttpHeader.CONTENT_TYPE, "text/plain");
|
||||
request.content(new StringContentProvider(postJson), "application/json");
|
||||
logger.trace("Sending POST request to '{}', data: {}", resource, postJson);
|
||||
|
||||
ContentResponse contentResponse = request.send();
|
||||
int httpStatus = contentResponse.getStatus();
|
||||
|
||||
if (httpStatus != OK_200) {
|
||||
throw new RadioThermostatHttpException("Thermostat HTTP response code was: " + httpStatus);
|
||||
if (contentResponse.getStatus() != OK_200) {
|
||||
throw new RadioThermostatHttpException(
|
||||
"Thermostat HTTP response code was: " + contentResponse.getStatus());
|
||||
}
|
||||
output = contentResponse.getContentAsString();
|
||||
logger.trace("Response: {}", output);
|
||||
|
||||
logger.trace("Response: {}", contentResponse.getContentAsString());
|
||||
return contentResponse.getContentAsString();
|
||||
} catch (RadioThermostatHttpException | InterruptedException | TimeoutException | ExecutionException e) {
|
||||
logger.debug("Error executing thermostat command: {}, {}", postJson, e.getMessage());
|
||||
return BLANK;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,14 +151,7 @@ public class RadioThermostatConnector {
|
||||
* @return a valid URL for the thermostat's JSON interface
|
||||
*/
|
||||
private String buildRequestURL(String resource) {
|
||||
String hostName = this.hostName;
|
||||
if (hostName == null) {
|
||||
throw new IllegalStateException("hostname must not be null");
|
||||
}
|
||||
String urlStr = URL.replace("%hostName%", hostName);
|
||||
urlStr = urlStr.replace("%resource%", resource);
|
||||
|
||||
return urlStr;
|
||||
return String.format(URL, hostName, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,6 @@ package org.openhab.binding.radiothermostat.internal.handler;
|
||||
|
||||
import static org.openhab.binding.radiothermostat.internal.RadioThermostatBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.time.ZonedDateTime;
|
||||
@ -96,8 +95,8 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
|
||||
private boolean disableLogs = false;
|
||||
private boolean clockSync = false;
|
||||
private String setpointCmdKeyPrefix = "t_";
|
||||
private String heatProgramJson = "";
|
||||
private String coolProgramJson = "";
|
||||
private String heatProgramJson = BLANK;
|
||||
private String coolProgramJson = BLANK;
|
||||
|
||||
public RadioThermostatHandler(Thing thing, RadioThermostatStateDescriptionProvider stateDescriptionProvider,
|
||||
HttpClient httpClient) {
|
||||
@ -119,7 +118,7 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
|
||||
this.disableLogs = config.disableLogs;
|
||||
this.clockSync = config.clockSync;
|
||||
|
||||
if (hostName == null || "".equals(hostName)) {
|
||||
if (hostName == null || hostName.isBlank()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.configuration-error-hostname");
|
||||
return;
|
||||
@ -198,17 +197,17 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
|
||||
Runnable runnable = () -> {
|
||||
// populate the heat and cool programs on the thermostat from the user configuration,
|
||||
// the commands will be sent each time the refresh job runs until a success response is seen
|
||||
if (!"".equals(heatProgramJson)) {
|
||||
if (!heatProgramJson.isEmpty()) {
|
||||
final String response = connector.sendCommand(null, null, heatProgramJson, HEAT_PROGRAM_RESOURCE);
|
||||
if (response.contains("success")) {
|
||||
heatProgramJson = "";
|
||||
heatProgramJson = BLANK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!"".equals(coolProgramJson)) {
|
||||
if (!coolProgramJson.isEmpty()) {
|
||||
final String response = connector.sendCommand(null, null, coolProgramJson, COOL_PROGRAM_RESOURCE);
|
||||
if (response.contains("success")) {
|
||||
coolProgramJson = "";
|
||||
coolProgramJson = BLANK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,6 +306,10 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
|
||||
connector.sendCommand(null, null, rawCommand, DEFAULT_RESOURCE);
|
||||
}
|
||||
|
||||
public void handleRawCommand(@Nullable String rawCommand, String resource) {
|
||||
connector.sendCommand(null, null, rawCommand, resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
@ -384,6 +387,13 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
|
||||
connector.sendCommand("rem_mode", "0", REMOTE_TEMP_RESOURCE);
|
||||
}
|
||||
break;
|
||||
case MESSAGE:
|
||||
if (!cmdStr.isEmpty()) {
|
||||
connector.sendCommand(null, null, String.format(JSON_PMA, cmdStr), PMA_RESOURCE);
|
||||
} else {
|
||||
connector.sendCommand("mode", "0", PMA_RESOURCE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unsupported command: {}", command.toString());
|
||||
}
|
||||
@ -460,10 +470,8 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
|
||||
state = new DateTimeType((ZonedDateTime) value);
|
||||
} else if (value instanceof QuantityType<?>) {
|
||||
state = (QuantityType<?>) value;
|
||||
} else if (value instanceof BigDecimal) {
|
||||
state = new DecimalType((BigDecimal) value);
|
||||
} else if (value instanceof Integer) {
|
||||
state = new DecimalType(BigDecimal.valueOf(((Integer) value).longValue()));
|
||||
} else if (value instanceof Number) {
|
||||
state = new DecimalType((Number) value);
|
||||
} else if (value instanceof String) {
|
||||
state = new StringType(value.toString());
|
||||
} else if (value instanceof OnOffType) {
|
||||
@ -556,9 +564,11 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
|
||||
*/
|
||||
private void updateAllChannels() {
|
||||
// Update all channels from rthermData
|
||||
for (Channel channel : getThing().getChannels()) {
|
||||
getThing().getChannels().forEach(channel -> {
|
||||
if (!NO_UPDATE_CHANNEL_IDS.contains(channel.getUID().getId())) {
|
||||
updateChannel(channel.getUID().getId(), rthermData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -569,11 +579,11 @@ public class RadioThermostatHandler extends BaseThingHandler implements RadioThe
|
||||
private List<StateOption> getFanModeOptions() {
|
||||
List<StateOption> fanModeOptions = new ArrayList<>();
|
||||
|
||||
fanModeOptions.add(new StateOption("0", "Auto"));
|
||||
fanModeOptions.add(new StateOption("0", "@text/options.fan-option-auto"));
|
||||
if (this.isCT80) {
|
||||
fanModeOptions.add(new StateOption("1", "Auto/Circulate"));
|
||||
fanModeOptions.add(new StateOption("1", "@text/options.fan-option-circulate"));
|
||||
}
|
||||
fanModeOptions.add(new StateOption("2", "On"));
|
||||
fanModeOptions.add(new StateOption("2", "@text/options.fan-option-on"));
|
||||
|
||||
return fanModeOptions;
|
||||
}
|
||||
|
@ -267,6 +267,8 @@ channel-type.radiothermostat.hold.label = Hold
|
||||
channel-type.radiothermostat.hold.description = Indicates If the Current Set Point Temperature Is to Be Held Indefinitely
|
||||
channel-type.radiothermostat.humidity.label = Humidity
|
||||
channel-type.radiothermostat.humidity.description = The Current Humidity Reading of the Thermostat
|
||||
channel-type.radiothermostat.message.label = Message
|
||||
channel-type.radiothermostat.message.description = Use this channel to display a number in the price message area
|
||||
channel-type.radiothermostat.mode.label = Mode
|
||||
channel-type.radiothermostat.mode.description = The Current Operating Mode of the HVAC System
|
||||
channel-type.radiothermostat.mode.state.option.0 = Off
|
||||
@ -311,3 +313,6 @@ offline.configuration-error-hostname = Thermostat hostname must be specified
|
||||
offline.configuration-error-heating-program = Thermostat HEATING program schedule is invalid, check configuration!
|
||||
offline.configuration-error-cooling-program = Thermostat COOLING program schedule is invalid, check configuration!
|
||||
offline.communication-error-get-data = Error retrieving data from Thermostat
|
||||
options.fan-option-auto = Auto
|
||||
options.fan-option-circulate = Auto/Circulate
|
||||
options.fan-option-on = On
|
||||
|
@ -31,10 +31,14 @@
|
||||
<channel id="today_cool_runtime" typeId="today_cool_runtime"/>
|
||||
<channel id="yesterday_heat_runtime" typeId="yesterday_heat_runtime"/>
|
||||
<channel id="yesterday_cool_runtime" typeId="yesterday_cool_runtime"/>
|
||||
<channel id="message" typeId="message"/>
|
||||
</channels>
|
||||
|
||||
<config-description-ref uri="thing-type:radiothermostat:thermostatconfig"/>
|
||||
<properties>
|
||||
<property name="thingTypeVersion">1</property>
|
||||
</properties>
|
||||
|
||||
<config-description-ref uri="thing-type:radiothermostat:thermostatconfig"/>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="temp-temperature">
|
||||
@ -187,4 +191,10 @@
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="message" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Message</label>
|
||||
<description>Use this channel to display a number in the price message area</description>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
|
||||
|
||||
<thing-type uid="radiothermostat:rtherm">
|
||||
<instruction-set targetVersion="1">
|
||||
<add-channel id="message">
|
||||
<type>radiothermostat:message</type>
|
||||
</add-channel>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
</update:update-descriptions>
|
Loading…
Reference in New Issue
Block a user