mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[amazonechocontrol] Add channels to thermostatController (#13067)
* enhance: add thermostat channels to amazonechocontrol Signed-off-by: Daniel Campbell <djcampbell79@gmail.com>
This commit is contained in:
parent
b9782484c6
commit
8d3828a9a4
@ -27,6 +27,7 @@ It provides features to control and view the current state of echo devices:
|
||||
- change the equalizer settings
|
||||
- get information about the next alarm, reminder and timer
|
||||
- send a message to the echo devices
|
||||
- control alexa smart thermostat
|
||||
|
||||
It also provides features to control devices connected to your echo:
|
||||
|
||||
@ -58,6 +59,7 @@ Some ideas what you can do in your home by using rules and other openHAB control
|
||||
- Change the equalizer settings depending on the bluetooth connection
|
||||
- Turn on a light on your alexa alarm time
|
||||
- Activate or deactivate the Alexa Guard with presence detection
|
||||
- Adjust thermostat setpoint and mode
|
||||
|
||||
With the possibility to control your lights you could do:
|
||||
|
||||
@ -438,20 +440,25 @@ The only possibility to find out the id is by using the discover function in the
|
||||
The channels of the smarthome devices will be generated at runtime. Check in the UI thing configurations, which channels are created.
|
||||
|
||||
| Channel Type ID | Item Type | Access Mode | Thing Type | Description
|
||||
|--------------------------|-----------|-------------|-------------------------------|------------------------------------------------------------------------------------------
|
||||
| powerState | Switch | R/W | smartHomeDevice, smartHomeDeviceGroup | Shows and changes the state (ON/OFF) of your device
|
||||
| brightness | Dimmer | R/W | smartHomeDevice, smartHomeDeviceGroup | Shows and changes the brightness of your lamp
|
||||
| color | Color | R | smartHomeDevice, smartHomeDeviceGroup | Shows the color of your light
|
||||
| colorName | String | R/W | smartHomeDevice, smartHomeDeviceGroup | Shows and changes the color name of your light (groups are not able to show their color)
|
||||
| colorTemperatureName | String | R/W | smartHomeDevice, smartHomeDeviceGroup | White temperatures name of your lights (groups are not able to show their color)
|
||||
| armState | String | R/W | smartHomeDevice, smartHomeDeviceGroup | State of your alarm guard. Options: ARMED_AWAY, ARMED_STAY, ARMED_NIGHT, DISARMED (groups are not able to show their state)
|
||||
| burglaryAlarm | Contact | R | smartHomeDevice | Burglary alarm
|
||||
| carbonMonoxideAlarm | Contact | R | smartHomeDevice | Carbon monoxide detection alarm
|
||||
| fireAlarm | Contact | R | smartHomeDevice | Fire alarm
|
||||
| waterAlarm | Contact | R | smartHomeDevice | Water alarm
|
||||
| glassBreakDetectionState | Contact | R | smartHomeDevice | Glass break detection alarm
|
||||
| smokeAlarmDetectionState | Contact | R | smartHomeDevice | Smoke detection alarm
|
||||
| temperature | Number | R | smartHomeDevice | Temperature
|
||||
|--------------------------|----------------------|-------------|-------------------------------|------------------------------------------------------------------------------------------
|
||||
| powerState | Switch | R/W | smartHomeDevice, smartHomeDeviceGroup | Shows and changes the state (ON/OFF) of your device
|
||||
| brightness | Dimmer | R/W | smartHomeDevice, smartHomeDeviceGroup | Shows and changes the brightness of your lamp
|
||||
| color | Color | R | smartHomeDevice, smartHomeDeviceGroup | Shows the color of your light
|
||||
| colorName | String | R/W | smartHomeDevice, smartHomeDeviceGroup | Shows and changes the color name of your light (groups are not able to show their color)
|
||||
| colorTemperatureName | String | R/W | smartHomeDevice, smartHomeDeviceGroup | White temperatures name of your lights (groups are not able to show their color)
|
||||
| armState | String | R/W | smartHomeDevice, smartHomeDeviceGroup | State of your alarm guard. Options: ARMED_AWAY, ARMED_STAY, ARMED_NIGHT, DISARMED (groups are not able to show their state)
|
||||
| burglaryAlarm | Contact | R | smartHomeDevice | Burglary alarm
|
||||
| carbonMonoxideAlarm | Contact | R | smartHomeDevice | Carbon monoxide detection alarm
|
||||
| fireAlarm | Contact | R | smartHomeDevice | Fire alarm
|
||||
| waterAlarm | Contact | R | smartHomeDevice | Water alarm
|
||||
| glassBreakDetectionState | Contact | R | smartHomeDevice | Glass break detection alarm
|
||||
| smokeAlarmDetectionState | Contact | R | smartHomeDevice | Smoke detection alarm
|
||||
| temperature | Number:Temperature | R | smartHomeDevice | Temperature
|
||||
| targetSetpoint | Number:Temperature | R/W | smartHomeDevice | Thermostat target setpoint
|
||||
| upperSetpoint | Number:Temperature | R/W | smartHomeDevice | Thermostat upper setpoint (AUTO)
|
||||
| lowerSetpoint | Number:Temperature | R/W | smartHomeDevice | Thermostat lower setpoint (AUTO)
|
||||
| relativeHumidity | Number:Dimensionless | R | smartHomeDevice | Thermostat humidity
|
||||
| thermostatMode | String | R/W | smartHomeDevice | Thermostat operation mode
|
||||
|
||||
### Example
|
||||
|
||||
|
@ -145,7 +145,7 @@ public class AccountServlet extends HttpServlet {
|
||||
}
|
||||
|
||||
Connection connection = this.account.findConnection();
|
||||
if (connection != null && uri.equals("/changedomain")) {
|
||||
if (connection != null && "/changedomain".equals(uri)) {
|
||||
Map<String, String[]> map = req.getParameterMap();
|
||||
String[] domainArray = map.get("domain");
|
||||
if (domainArray == null) {
|
||||
@ -199,7 +199,7 @@ public class AccountServlet extends HttpServlet {
|
||||
postDataBuilder.append(name);
|
||||
postDataBuilder.append('=');
|
||||
String value = "";
|
||||
if (name.equals("failedSignInCount")) {
|
||||
if ("failedSignInCount".equals(name)) {
|
||||
value = "ape:AA==";
|
||||
} else {
|
||||
String[] strings = map.get(name);
|
||||
@ -277,29 +277,29 @@ public class AccountServlet extends HttpServlet {
|
||||
|
||||
if (connection != null && connection.verifyLogin()) {
|
||||
// handle commands
|
||||
if (baseUrl.equals("/logout") || baseUrl.equals("/logout/")) {
|
||||
if ("/logout".equals(baseUrl) || "/logout/".equals(baseUrl)) {
|
||||
this.connectionToInitialize = reCreateConnection();
|
||||
this.account.setConnection(null);
|
||||
resp.sendRedirect(this.servletUrl);
|
||||
return;
|
||||
}
|
||||
// handle commands
|
||||
if (baseUrl.equals("/newdevice") || baseUrl.equals("/newdevice/")) {
|
||||
if ("/newdevice".equals(baseUrl) || "/newdevice/".equals(baseUrl)) {
|
||||
this.connectionToInitialize = new Connection(null, this.gson);
|
||||
this.account.setConnection(null);
|
||||
resp.sendRedirect(this.servletUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
if (baseUrl.equals("/devices") || baseUrl.equals("/devices/")) {
|
||||
if ("/devices".equals(baseUrl) || "/devices/".equals(baseUrl)) {
|
||||
handleDevices(resp, connection);
|
||||
return;
|
||||
}
|
||||
if (baseUrl.equals("/changeDomain") || baseUrl.equals("/changeDomain/")) {
|
||||
if ("/changeDomain".equals(baseUrl) || "/changeDomain/".equals(baseUrl)) {
|
||||
handleChangeDomain(resp, connection);
|
||||
return;
|
||||
}
|
||||
if (baseUrl.equals("/ids") || baseUrl.equals("/ids/")) {
|
||||
if ("/ids".equals(baseUrl) || "/ids/".equals(baseUrl)) {
|
||||
String serialNumber = getQueryMap(queryString).get("serialNumber");
|
||||
Device device = account.findDeviceJson(serialNumber);
|
||||
if (device != null) {
|
||||
@ -318,7 +318,7 @@ public class AccountServlet extends HttpServlet {
|
||||
this.connectionToInitialize = connection;
|
||||
}
|
||||
|
||||
if (!uri.equals("/")) {
|
||||
if (!"/".equals(uri)) {
|
||||
String newUri = req.getServletPath() + "/";
|
||||
resp.sendRedirect(newUri);
|
||||
return;
|
||||
|
@ -97,7 +97,7 @@ public class BindingServlet extends HttpServlet {
|
||||
}
|
||||
logger.debug("doGet {}", uri);
|
||||
|
||||
if (!uri.equals("/")) {
|
||||
if (!"/".equals(uri)) {
|
||||
String newUri = req.getServletPath() + "/";
|
||||
resp.sendRedirect(newUri);
|
||||
return;
|
||||
|
@ -12,6 +12,8 @@
|
||||
*/
|
||||
package org.openhab.binding.amazonechocontrol.internal;
|
||||
|
||||
import static org.openhab.binding.amazonechocontrol.internal.smarthome.Constants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
@ -32,10 +34,12 @@ import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.Scanner;
|
||||
@ -109,6 +113,7 @@ import org.openhab.binding.amazonechocontrol.internal.jsons.JsonWebSiteCookie;
|
||||
import org.openhab.binding.amazonechocontrol.internal.jsons.SmartHomeBaseDevice;
|
||||
import org.openhab.core.common.ThreadPoolManager;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.util.HexUtils;
|
||||
import org.slf4j.Logger;
|
||||
@ -118,6 +123,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
@ -644,7 +650,7 @@ public class Connection {
|
||||
for (Map.Entry<@Nullable String, List<String>> header : headerFields.entrySet()) {
|
||||
String key = header.getKey();
|
||||
if (key != null && !key.isEmpty()) {
|
||||
if (key.equalsIgnoreCase("Set-Cookie")) {
|
||||
if ("Set-Cookie".equalsIgnoreCase(key)) {
|
||||
// store cookie
|
||||
for (String cookieHeader : header.getValue()) {
|
||||
if (!cookieHeader.isEmpty()) {
|
||||
@ -655,7 +661,7 @@ public class Connection {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key.equalsIgnoreCase("Location")) {
|
||||
if ("Location".equalsIgnoreCase(key)) {
|
||||
// get redirect location
|
||||
location = header.getValue().get(0);
|
||||
if (!location.isEmpty()) {
|
||||
@ -1074,7 +1080,7 @@ public class Connection {
|
||||
requestObject.add("stateRequests", stateRequests);
|
||||
String requestBody = requestObject.toString();
|
||||
String json = makeRequestAndReturnString("POST", alexaServer + "/api/phoenix/state", requestBody, true, null);
|
||||
logger.trace("Requested {} and received {}", requestBody, json);
|
||||
logger.debug("Requested {} and received {}", requestBody, json);
|
||||
|
||||
JsonObject responseObject = Objects.requireNonNull(gson.fromJson(json, JsonObject.class));
|
||||
JsonArray deviceStates = (JsonArray) responseObject.get("deviceStates");
|
||||
@ -1164,6 +1170,8 @@ public class Connection {
|
||||
public void smartHomeCommand(String entityId, String action, @Nullable String property, @Nullable Object value)
|
||||
throws IOException, InterruptedException {
|
||||
String url = alexaServer + "/api/phoenix/state";
|
||||
Float lowerSetpoint = null;
|
||||
Float upperSetpoint = null;
|
||||
|
||||
JsonObject json = new JsonObject();
|
||||
JsonArray controlRequests = new JsonArray();
|
||||
@ -1173,20 +1181,95 @@ public class Connection {
|
||||
JsonObject parameters = new JsonObject();
|
||||
parameters.addProperty("action", action);
|
||||
if (property != null) {
|
||||
if (value instanceof QuantityType<?>) {
|
||||
parameters.addProperty(property + ".value", ((QuantityType<?>) value).floatValue());
|
||||
parameters.addProperty(property + ".scale",
|
||||
((QuantityType<?>) value).getUnit().equals(SIUnits.CELSIUS) ? "celsius" : "fahrenheit");
|
||||
} else if (value instanceof Boolean) {
|
||||
parameters.addProperty(property, (boolean) value);
|
||||
} else if (value instanceof String) {
|
||||
parameters.addProperty(property, (String) value);
|
||||
} else if (value instanceof Number) {
|
||||
parameters.addProperty(property, (Number) value);
|
||||
} else if (value instanceof Character) {
|
||||
parameters.addProperty(property, (Character) value);
|
||||
} else if (value instanceof JsonElement) {
|
||||
parameters.add(property, (JsonElement) value);
|
||||
if ("setThermostatMode".equals(action)) {
|
||||
if (value instanceof StringType) {
|
||||
parameters.addProperty(property + ".value", value.toString());
|
||||
}
|
||||
} else if ("setTargetTemperature".equals(action)) {
|
||||
if ("targetTemperature".equals(property)) {
|
||||
if (value instanceof QuantityType<?>) {
|
||||
parameters.addProperty(property + ".value", ((QuantityType<?>) value).floatValue());
|
||||
parameters.addProperty(property + ".scale",
|
||||
((QuantityType<?>) value).getUnit().equals(SIUnits.CELSIUS) ? "celsius" : "fahrenheit");
|
||||
}
|
||||
} else {
|
||||
// Get current upper and lower setpoints to build command syntax
|
||||
Map<String, JsonArray> devices = null;
|
||||
try {
|
||||
List<SmartHomeBaseDevice> deviceList = getSmarthomeDeviceList().stream()
|
||||
.filter(device -> entityId.equals(device.findEntityId())).collect(Collectors.toList());
|
||||
devices = getSmartHomeDeviceStatesJson(new HashSet<>(deviceList));
|
||||
} catch (URISyntaxException e) {
|
||||
logger.debug("{}", e.toString());
|
||||
}
|
||||
Entry<String, JsonArray> entry = devices.entrySet().iterator().next();
|
||||
JsonArray states = entry.getValue();
|
||||
for (JsonElement stateElement : states) {
|
||||
JsonObject stateValue = new JsonObject();
|
||||
String stateJson = stateElement.getAsString();
|
||||
if (stateJson.startsWith("{") && stateJson.endsWith("}")) {
|
||||
JsonObject state = Objects.requireNonNull(gson.fromJson(stateJson, JsonObject.class));
|
||||
String interfaceName = Objects.requireNonNullElse(state.get("namespace"), JsonNull.INSTANCE)
|
||||
.getAsString();
|
||||
String name = Objects.requireNonNullElse(state.get("name"), JsonNull.INSTANCE)
|
||||
.getAsString();
|
||||
if ("Alexa.ThermostatController".equals(interfaceName)) {
|
||||
if ("upperSetpoint".equals(name)) {
|
||||
stateValue = Objects.requireNonNullElse(state.get("value"), JsonNull.INSTANCE)
|
||||
.getAsJsonObject();
|
||||
upperSetpoint = Objects
|
||||
.requireNonNullElse(stateValue.get("value"), JsonNull.INSTANCE)
|
||||
.getAsFloat();
|
||||
} else if ("lowerSetpoint".equals(name)) {
|
||||
stateValue = Objects.requireNonNullElse(state.get("value"), JsonNull.INSTANCE)
|
||||
.getAsJsonObject();
|
||||
lowerSetpoint = Objects
|
||||
.requireNonNullElse(stateValue.get("value"), JsonNull.INSTANCE)
|
||||
.getAsFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ("lowerSetTemperature".equals(property)) {
|
||||
if (value instanceof QuantityType<?>) {
|
||||
parameters.addProperty("upperSetTemperature.value", upperSetpoint);
|
||||
parameters.addProperty("upperSetTemperature.scale",
|
||||
((QuantityType<?>) value).getUnit().equals(SIUnits.CELSIUS) ? "celsius"
|
||||
: "fahrenheit");
|
||||
parameters.addProperty(property + ".value", ((QuantityType<?>) value).floatValue());
|
||||
parameters.addProperty(property + ".scale",
|
||||
((QuantityType<?>) value).getUnit().equals(SIUnits.CELSIUS) ? "celsius"
|
||||
: "fahrenheit");
|
||||
}
|
||||
} else if ("upperSetTemperature".equals(property)) {
|
||||
if (value instanceof QuantityType<?>) {
|
||||
parameters.addProperty(property + ".value", ((QuantityType<?>) value).floatValue());
|
||||
parameters.addProperty(property + ".scale",
|
||||
((QuantityType<?>) value).getUnit().equals(SIUnits.CELSIUS) ? "celsius"
|
||||
: "fahrenheit");
|
||||
parameters.addProperty("lowerSetTemperature.value", lowerSetpoint);
|
||||
parameters.addProperty("lowerSetTemperature.scale",
|
||||
((QuantityType<?>) value).getUnit().equals(SIUnits.CELSIUS) ? "celsius"
|
||||
: "fahrenheit");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value instanceof QuantityType<?>) {
|
||||
parameters.addProperty(property + ".value", ((QuantityType<?>) value).floatValue());
|
||||
parameters.addProperty(property + ".scale",
|
||||
((QuantityType<?>) value).getUnit().equals(SIUnits.CELSIUS) ? "celsius" : "fahrenheit");
|
||||
} else if (value instanceof Boolean) {
|
||||
parameters.addProperty(property, (boolean) value);
|
||||
} else if (value instanceof String) {
|
||||
parameters.addProperty(property, (String) value);
|
||||
} else if (value instanceof Number) {
|
||||
parameters.addProperty(property, (Number) value);
|
||||
} else if (value instanceof Character) {
|
||||
parameters.addProperty(property, (Character) value);
|
||||
} else if (value instanceof JsonElement) {
|
||||
parameters.add(property, (JsonElement) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
controlRequest.add("parameters", parameters);
|
||||
|
@ -30,6 +30,7 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
@ -73,10 +74,11 @@ public class WebSocketConnection {
|
||||
IWebSocketCommandHandler webSocketCommandHandler) throws IOException {
|
||||
this.webSocketCommandHandler = webSocketCommandHandler;
|
||||
amazonEchoControlWebSocket = new AmazonEchoControlWebSocket();
|
||||
webSocketClient = new WebSocketClient(new SslContextFactory.Client());
|
||||
HttpClient httpClient = new HttpClient(new SslContextFactory.Client());
|
||||
webSocketClient = new WebSocketClient(httpClient);
|
||||
try {
|
||||
String host;
|
||||
if (amazonSite.equalsIgnoreCase("amazon.com")) {
|
||||
if ("amazon.com".equalsIgnoreCase(amazonSite)) {
|
||||
host = "dp-gw-na-js." + amazonSite;
|
||||
} else {
|
||||
host = "dp-gw-na." + amazonSite;
|
||||
|
@ -139,13 +139,13 @@ public class AmazonEchoDiscovery extends AbstractDiscoveryService {
|
||||
String deviceFamily = device.deviceFamily;
|
||||
if (deviceFamily != null) {
|
||||
ThingTypeUID thingTypeId;
|
||||
if (deviceFamily.equals("ECHO")) {
|
||||
if ("ECHO".equals(deviceFamily)) {
|
||||
thingTypeId = THING_TYPE_ECHO;
|
||||
} else if (deviceFamily.equals("ROOK")) {
|
||||
} else if ("ROOK".equals(deviceFamily)) {
|
||||
thingTypeId = THING_TYPE_ECHO_SPOT;
|
||||
} else if (deviceFamily.equals("KNIGHT")) {
|
||||
} else if ("KNIGHT".equals(deviceFamily)) {
|
||||
thingTypeId = THING_TYPE_ECHO_SHOW;
|
||||
} else if (deviceFamily.equals("WHA")) {
|
||||
} else if ("WHA".equals(deviceFamily)) {
|
||||
thingTypeId = THING_TYPE_ECHO_WHA;
|
||||
} else {
|
||||
logger.debug("Unknown thing type '{}'", deviceFamily);
|
||||
|
@ -49,7 +49,7 @@ import org.slf4j.LoggerFactory;
|
||||
@NonNullByDefault
|
||||
public class SmartHomeDevicesDiscovery extends AbstractDiscoveryService {
|
||||
private AccountHandler accountHandler;
|
||||
private final Logger logger = LoggerFactory.getLogger(SmartHomeDevicesDiscovery.class);
|
||||
private Logger logger = LoggerFactory.getLogger(SmartHomeDevicesDiscovery.class);
|
||||
|
||||
private @Nullable ScheduledFuture<?> startScanStateJob;
|
||||
private @Nullable Long activateTimeStamp;
|
||||
@ -189,6 +189,8 @@ public class SmartHomeDevicesDiscovery extends AbstractDiscoveryService {
|
||||
deviceName = "Alexa Color Controller on " + shd.friendlyName;
|
||||
} else if (interfaces.contains("Alexa.PowerController")) {
|
||||
deviceName = "Alexa Plug on " + shd.friendlyName;
|
||||
} else if (interfaces.contains("Alexa.ThermostatController")) {
|
||||
deviceName = "Alexa Smart " + shd.friendlyName;
|
||||
} else {
|
||||
deviceName = "Unknown Device on " + shd.friendlyName;
|
||||
}
|
||||
|
@ -783,11 +783,11 @@ public class EchoHandler extends BaseThingHandler implements IEchoThingHandler {
|
||||
if (currentNotification != null) {
|
||||
String type = currentNotification.type;
|
||||
if (type != null) {
|
||||
if (type.equals("Reminder")) {
|
||||
if ("Reminder".equals(type)) {
|
||||
updateState(CHANNEL_REMIND, StringType.EMPTY);
|
||||
updateRemind = false;
|
||||
}
|
||||
if (type.equals("Alarm")) {
|
||||
if ("Alarm".equals(type)) {
|
||||
updateState(CHANNEL_PLAY_ALARM_SOUND, StringType.EMPTY);
|
||||
updateAlarm = false;
|
||||
}
|
||||
@ -864,10 +864,10 @@ public class EchoHandler extends BaseThingHandler implements IEchoThingHandler {
|
||||
if (musicProviderId != null) {
|
||||
musicProviderId = musicProviderId.toUpperCase();
|
||||
|
||||
if (musicProviderId.equals("AMAZON MUSIC")) {
|
||||
if ("AMAZON MUSIC".equals(musicProviderId)) {
|
||||
musicProviderId = "AMAZON_MUSIC";
|
||||
}
|
||||
if (musicProviderId.equals("CLOUD_PLAYER")) {
|
||||
if ("CLOUD_PLAYER".equals(musicProviderId)) {
|
||||
musicProviderId = "AMAZON_MUSIC";
|
||||
}
|
||||
if (musicProviderId.startsWith("TUNEIN")) {
|
||||
@ -876,7 +876,7 @@ public class EchoHandler extends BaseThingHandler implements IEchoThingHandler {
|
||||
if (musicProviderId.startsWith("IHEARTRADIO")) {
|
||||
musicProviderId = "I_HEART_RADIO";
|
||||
}
|
||||
if (musicProviderId.equals("APPLE") && musicProviderId.contains("MUSIC")) {
|
||||
if ("APPLE".equals(musicProviderId) && musicProviderId.contains("MUSIC")) {
|
||||
musicProviderId = "APPLE_MUSIC";
|
||||
}
|
||||
}
|
||||
|
@ -347,7 +347,6 @@ public class SmartHomeDeviceHandler extends BaseThingHandler {
|
||||
if (shd.getCapabilities().stream().map(capability -> capability.interfaceName)
|
||||
.anyMatch(SUPPORTED_INTERFACES::contains)) {
|
||||
result.add(shd);
|
||||
|
||||
}
|
||||
} else {
|
||||
SmartHomeGroup shg = (SmartHomeGroup) baseDevice;
|
||||
|
@ -55,6 +55,11 @@ public class JsonSmartHomeDevices {
|
||||
return applianceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String findEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGroup() {
|
||||
return false;
|
||||
|
@ -39,6 +39,19 @@ public class JsonSmartHomeGroups {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String findEntityId() {
|
||||
SmartHomeGroupIdentifier applianceGroupIdentifier = this.applianceGroupIdentifier;
|
||||
if (applianceGroupIdentifier == null) {
|
||||
return null;
|
||||
}
|
||||
String value = applianceGroupIdentifier.value;
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGroup() {
|
||||
return true;
|
||||
|
@ -25,5 +25,8 @@ public interface SmartHomeBaseDevice {
|
||||
@Nullable
|
||||
String findId();
|
||||
|
||||
@Nullable
|
||||
String findEntityId();
|
||||
|
||||
boolean isGroup();
|
||||
}
|
||||
|
@ -26,23 +26,38 @@ import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Constants {
|
||||
public static final Map<String, Function<SmartHomeDeviceHandler, HandlerBase>> HANDLER_FACTORY = Map.of(
|
||||
HandlerPowerController.INTERFACE, HandlerPowerController::new, HandlerBrightnessController.INTERFACE,
|
||||
HandlerBrightnessController::new, HandlerColorController.INTERFACE, HandlerColorController::new,
|
||||
HandlerColorTemperatureController.INTERFACE, HandlerColorTemperatureController::new,
|
||||
HandlerSecurityPanelController.INTERFACE, HandlerSecurityPanelController::new,
|
||||
HandlerAcousticEventSensor.INTERFACE, HandlerAcousticEventSensor::new, HandlerTemperatureSensor.INTERFACE,
|
||||
HandlerTemperatureSensor::new, HandlerThermostatController.INTERFACE, HandlerThermostatController::new,
|
||||
HandlerPercentageController.INTERFACE, HandlerPercentageController::new,
|
||||
HandlerPowerLevelController.INTERFACE, HandlerPowerLevelController::new);
|
||||
public static final Map<String, Function<SmartHomeDeviceHandler, HandlerBase>> HANDLER_FACTORY = Map.ofEntries(
|
||||
Map.entry(HandlerPowerController.INTERFACE, HandlerPowerController::new),
|
||||
Map.entry(HandlerBrightnessController.INTERFACE, HandlerBrightnessController::new),
|
||||
Map.entry(HandlerColorController.INTERFACE, HandlerColorController::new),
|
||||
Map.entry(HandlerColorTemperatureController.INTERFACE, HandlerColorTemperatureController::new),
|
||||
Map.entry(HandlerSecurityPanelController.INTERFACE, HandlerSecurityPanelController::new),
|
||||
Map.entry(HandlerAcousticEventSensor.INTERFACE, HandlerAcousticEventSensor::new),
|
||||
Map.entry(HandlerTemperatureSensor.INTERFACE, HandlerTemperatureSensor::new),
|
||||
Map.entry(HandlerThermostatController.INTERFACE, HandlerThermostatController::new),
|
||||
Map.entry(HandlerPercentageController.INTERFACE, HandlerPercentageController::new),
|
||||
Map.entry(HandlerPowerLevelController.INTERFACE, HandlerPowerLevelController::new),
|
||||
Map.entry(HandlerHumiditySensor.INTERFACE, HandlerHumiditySensor::new));
|
||||
|
||||
public static final Set<String> SUPPORTED_INTERFACES = HANDLER_FACTORY.keySet();
|
||||
|
||||
// channel types
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_TEMPERATURE = new ChannelTypeUID(
|
||||
AmazonEchoControlBindingConstants.BINDING_ID, "temperature");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_HUMIDITY = new ChannelTypeUID(
|
||||
AmazonEchoControlBindingConstants.BINDING_ID, "relativeHumidity");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_TARGETSETPOINT = new ChannelTypeUID(
|
||||
AmazonEchoControlBindingConstants.BINDING_ID, "targetSetpoint");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_LOWERSETPOINT = new ChannelTypeUID(
|
||||
AmazonEchoControlBindingConstants.BINDING_ID, "lowerSetpoint");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UPPERSETPOINT = new ChannelTypeUID(
|
||||
AmazonEchoControlBindingConstants.BINDING_ID, "upperSetpoint");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_THERMOSTATMODE = new ChannelTypeUID(
|
||||
AmazonEchoControlBindingConstants.BINDING_ID, "thermostatMode");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_FAN_OPERATION = new ChannelTypeUID(
|
||||
AmazonEchoControlBindingConstants.BINDING_ID, "fanOperation");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_COOLER_OPERATION = new ChannelTypeUID(
|
||||
AmazonEchoControlBindingConstants.BINDING_ID, "coolerOperation");
|
||||
|
||||
// List of Item types
|
||||
public static final String ITEM_TYPE_SWITCH = "Switch";
|
||||
@ -50,6 +65,7 @@ public class Constants {
|
||||
public static final String ITEM_TYPE_STRING = "String";
|
||||
public static final String ITEM_TYPE_NUMBER = "Number";
|
||||
public static final String ITEM_TYPE_NUMBER_TEMPERATURE = "Number:Temperature";
|
||||
public static final String ITEM_TYPE_HUMIDITY = "Number:Dimensionless";
|
||||
public static final String ITEM_TYPE_CONTACT = "Contact";
|
||||
public static final String ITEM_TYPE_COLOR = "Color";
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
@ -41,6 +43,9 @@ import com.google.gson.JsonObject;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class HandlerBase {
|
||||
// Logger
|
||||
private final Logger logger = LoggerFactory.getLogger(HandlerBase.class);
|
||||
|
||||
protected SmartHomeDeviceHandler smartHomeDeviceHandler;
|
||||
protected Map<String, ChannelInfo> channels = new HashMap<>();
|
||||
|
||||
@ -76,6 +81,7 @@ public abstract class HandlerBase {
|
||||
if (properties != null) {
|
||||
List<JsonSmartHomeCapabilities.Property> supported = Objects.requireNonNullElse(properties.supported,
|
||||
List.of());
|
||||
logger.trace("{} | {}", capability.toString(), supported.toString());
|
||||
for (Property property : supported) {
|
||||
String name = property.name;
|
||||
if (name != null) {
|
||||
|
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.amazonechocontrol.internal.smarthome;
|
||||
|
||||
import static org.openhab.binding.amazonechocontrol.internal.smarthome.Constants.*;
|
||||
import static org.openhab.core.library.unit.Units.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.amazonechocontrol.internal.Connection;
|
||||
import org.openhab.binding.amazonechocontrol.internal.handler.SmartHomeDeviceHandler;
|
||||
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonSmartHomeCapabilities.SmartHomeCapability;
|
||||
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonSmartHomeDevices.SmartHomeDevice;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* The {@link HandlerHumiditySensor} is responsible for the Alexa.HumiditySensorInterface
|
||||
*
|
||||
* @author Daniel Campbell - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HandlerHumiditySensor extends HandlerBase {
|
||||
// Logger
|
||||
private final Logger logger = LoggerFactory.getLogger(HandlerHumiditySensor.class);
|
||||
// Interface
|
||||
public static final String INTERFACE = "Alexa.HumiditySensor";
|
||||
// Channel definitions
|
||||
private static final ChannelInfo HUMIDITY = new ChannelInfo("relativeHumidity" /* propertyName */ ,
|
||||
"relativeHumidity" /* ChannelId */, CHANNEL_TYPE_HUMIDITY /* Channel Type */ ,
|
||||
ITEM_TYPE_HUMIDITY /* Item Type */);
|
||||
|
||||
public HandlerHumiditySensor(SmartHomeDeviceHandler smartHomeDeviceHandler) {
|
||||
super(smartHomeDeviceHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedInterface() {
|
||||
return new String[] { INTERFACE };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelInfo @Nullable [] findChannelInfos(SmartHomeCapability capability, String property) {
|
||||
if (HUMIDITY.propertyName.equals(property)) {
|
||||
return new ChannelInfo[] { HUMIDITY };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(String interfaceName, List<JsonObject> stateList, UpdateChannelResult result) {
|
||||
for (JsonObject state : stateList) {
|
||||
State humidityValue = null;
|
||||
logger.debug("Updating {} with state: {}", interfaceName, state.toString());
|
||||
if (HUMIDITY.propertyName.equals(state.get("name").getAsString())) {
|
||||
// For groups take the first
|
||||
humidityValue = getQuantityTypeState(state.get("value").getAsInt(), PERCENT);
|
||||
updateState(HUMIDITY.channelId, humidityValue == null ? UnDefType.UNDEF : humidityValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected State getQuantityTypeState(@Nullable Number value, Unit<?> unit) {
|
||||
return (value == null) ? UnDefType.UNDEF : new QuantityType<>(value, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleCommand(Connection connection, SmartHomeDevice shd, String entityId,
|
||||
List<SmartHomeCapability> capabilities, String channelId, Command command) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable StateDescription findStateDescription(String channelId, StateDescription originalStateDescription,
|
||||
@Nullable Locale locale) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -32,17 +32,21 @@ import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* The {@link HandlerTemperatureSensor} is responsible for the Alexa.PowerControllerInterface
|
||||
* The {@link HandlerTemperatureSensor} is responsible for the Alexa.TemperatureSensorInterface
|
||||
*
|
||||
* @author Lukas Knoeller - Initial contribution
|
||||
* @author Michael Geramb - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HandlerTemperatureSensor extends HandlerBase {
|
||||
// Logger
|
||||
private final Logger logger = LoggerFactory.getLogger(HandlerTemperatureSensor.class);
|
||||
// Interface
|
||||
public static final String INTERFACE = "Alexa.TemperatureSensor";
|
||||
// Channel definitions
|
||||
@ -71,6 +75,7 @@ public class HandlerTemperatureSensor extends HandlerBase {
|
||||
public void updateChannels(String interfaceName, List<JsonObject> stateList, UpdateChannelResult result) {
|
||||
QuantityType<Temperature> temperatureValue = null;
|
||||
for (JsonObject state : stateList) {
|
||||
logger.debug("Updating {} with state: {}", interfaceName, state.toString());
|
||||
if (TEMPERATURE.propertyName.equals(state.get("name").getAsString())) {
|
||||
JsonObject value = state.get("value").getAsJsonObject();
|
||||
// For groups take the first
|
||||
|
@ -27,11 +27,14 @@ import org.openhab.binding.amazonechocontrol.internal.handler.SmartHomeDeviceHan
|
||||
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonSmartHomeCapabilities.SmartHomeCapability;
|
||||
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonSmartHomeDevices.SmartHomeDevice;
|
||||
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.library.unit.SIUnits;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
@ -42,12 +45,23 @@ import com.google.gson.JsonObject;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HandlerThermostatController extends HandlerBase {
|
||||
// Logger
|
||||
private final Logger logger = LoggerFactory.getLogger(HandlerThermostatController.class);
|
||||
// Interface
|
||||
public static final String INTERFACE = "Alexa.ThermostatController";
|
||||
// Channel definitions
|
||||
private static final ChannelInfo TARGET_SETPOINT = new ChannelInfo("targetSetpoint" /* propertyName */ ,
|
||||
"targetSetpoint" /* ChannelId */, CHANNEL_TYPE_TARGETSETPOINT /* Channel Type */ ,
|
||||
ITEM_TYPE_NUMBER_TEMPERATURE /* Item Type */);
|
||||
private static final ChannelInfo LOWER_SETPOINT = new ChannelInfo("lowerSetpoint" /* propertyName */ ,
|
||||
"lowerSetpoint" /* ChannelId */, CHANNEL_TYPE_LOWERSETPOINT /* Channel Type */ ,
|
||||
ITEM_TYPE_NUMBER_TEMPERATURE /* Item Type */);
|
||||
private static final ChannelInfo UPPER_SETPOINT = new ChannelInfo("upperSetpoint" /* propertyName */ ,
|
||||
"upperSetpoint" /* ChannelId */, CHANNEL_TYPE_UPPERSETPOINT /* Channel Type */ ,
|
||||
ITEM_TYPE_NUMBER_TEMPERATURE /* Item Type */);
|
||||
private static final ChannelInfo THERMOSTAT_MODE = new ChannelInfo("thermostatMode" /* propertyName */ ,
|
||||
"thermostatMode" /* ChannelId */, CHANNEL_TYPE_THERMOSTATMODE /* Channel Type */ ,
|
||||
ITEM_TYPE_STRING /* Item Type */);
|
||||
|
||||
public HandlerThermostatController(SmartHomeDeviceHandler smartHomeDeviceHandler) {
|
||||
super(smartHomeDeviceHandler);
|
||||
@ -63,17 +77,27 @@ public class HandlerThermostatController extends HandlerBase {
|
||||
if (TARGET_SETPOINT.propertyName.equals(property)) {
|
||||
return new ChannelInfo[] { TARGET_SETPOINT };
|
||||
}
|
||||
if (LOWER_SETPOINT.propertyName.equals(property)) {
|
||||
return new ChannelInfo[] { LOWER_SETPOINT };
|
||||
}
|
||||
if (UPPER_SETPOINT.propertyName.equals(property)) {
|
||||
return new ChannelInfo[] { UPPER_SETPOINT };
|
||||
}
|
||||
if (THERMOSTAT_MODE.propertyName.equals(property)) {
|
||||
return new ChannelInfo[] { THERMOSTAT_MODE };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(String interfaceName, List<JsonObject> stateList, UpdateChannelResult result) {
|
||||
QuantityType<Temperature> temperatureValue = null;
|
||||
for (JsonObject state : stateList) {
|
||||
QuantityType<Temperature> temperatureValue = null;
|
||||
logger.debug("Updating {} with state: {}", interfaceName, state.toString());
|
||||
if (TARGET_SETPOINT.propertyName.equals(state.get("name").getAsString())) {
|
||||
JsonObject value = state.get("value").getAsJsonObject();
|
||||
// For groups take the first
|
||||
if (temperatureValue == null) {
|
||||
JsonObject value = state.get("value").getAsJsonObject();
|
||||
float temperature = value.get("value").getAsFloat();
|
||||
String scale = value.get("scale").getAsString().toUpperCase();
|
||||
if ("CELSIUS".equals(scale)) {
|
||||
@ -82,9 +106,43 @@ public class HandlerThermostatController extends HandlerBase {
|
||||
temperatureValue = new QuantityType<Temperature>(temperature, ImperialUnits.FAHRENHEIT);
|
||||
}
|
||||
}
|
||||
updateState(TARGET_SETPOINT.channelId, temperatureValue == null ? UnDefType.UNDEF : temperatureValue);
|
||||
}
|
||||
if (THERMOSTAT_MODE.propertyName.equals(state.get("name").getAsString())) {
|
||||
// For groups take the first
|
||||
String operation = state.get("value").getAsString().toUpperCase();
|
||||
StringType operationValue = new StringType(operation);
|
||||
updateState(THERMOSTAT_MODE.channelId, operationValue);
|
||||
}
|
||||
if (UPPER_SETPOINT.propertyName.equals(state.get("name").getAsString())) {
|
||||
// For groups take the first
|
||||
if (temperatureValue == null) {
|
||||
JsonObject value = state.get("value").getAsJsonObject();
|
||||
float temperature = value.get("value").getAsFloat();
|
||||
String scale = value.get("scale").getAsString().toUpperCase();
|
||||
if ("CELSIUS".equals(scale)) {
|
||||
temperatureValue = new QuantityType<Temperature>(temperature, SIUnits.CELSIUS);
|
||||
} else {
|
||||
temperatureValue = new QuantityType<Temperature>(temperature, ImperialUnits.FAHRENHEIT);
|
||||
}
|
||||
}
|
||||
updateState(UPPER_SETPOINT.channelId, temperatureValue == null ? UnDefType.UNDEF : temperatureValue);
|
||||
}
|
||||
if (LOWER_SETPOINT.propertyName.equals(state.get("name").getAsString())) {
|
||||
// For groups take the first
|
||||
if (temperatureValue == null) {
|
||||
JsonObject value = state.get("value").getAsJsonObject();
|
||||
float temperature = value.get("value").getAsFloat();
|
||||
String scale = value.get("scale").getAsString().toUpperCase();
|
||||
if ("CELSIUS".equals(scale)) {
|
||||
temperatureValue = new QuantityType<Temperature>(temperature, SIUnits.CELSIUS);
|
||||
} else {
|
||||
temperatureValue = new QuantityType<Temperature>(temperature, ImperialUnits.FAHRENHEIT);
|
||||
}
|
||||
}
|
||||
updateState(LOWER_SETPOINT.channelId, temperatureValue == null ? UnDefType.UNDEF : temperatureValue);
|
||||
}
|
||||
}
|
||||
updateState(TARGET_SETPOINT.channelId, temperatureValue == null ? UnDefType.UNDEF : temperatureValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -99,6 +157,30 @@ public class HandlerThermostatController extends HandlerBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (channelId.equals(LOWER_SETPOINT.channelId)) {
|
||||
if (containsCapabilityProperty(capabilities, LOWER_SETPOINT.propertyName)) {
|
||||
if (command instanceof QuantityType) {
|
||||
connection.smartHomeCommand(entityId, "setTargetTemperature", "lowerSetTemperature", command);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (channelId.equals(UPPER_SETPOINT.channelId)) {
|
||||
if (containsCapabilityProperty(capabilities, UPPER_SETPOINT.propertyName)) {
|
||||
if (command instanceof QuantityType) {
|
||||
connection.smartHomeCommand(entityId, "setTargetTemperature", "upperSetTemperature", command);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (channelId.equals(THERMOSTAT_MODE.channelId)) {
|
||||
if (containsCapabilityProperty(capabilities, THERMOSTAT_MODE.propertyName)) {
|
||||
if (command instanceof StringType) {
|
||||
connection.smartHomeCommand(entityId, "setThermostatMode", "thermostatMode", command);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,8 @@ channel-type.amazonechocontrol.lastVoiceCommand.label = Last Voice Command
|
||||
channel-type.amazonechocontrol.lastVoiceCommand.description = Last voice command spoken to the device. Writing to the channel starts voice output.
|
||||
channel-type.amazonechocontrol.loop.label = Loop
|
||||
channel-type.amazonechocontrol.loop.description = Loop
|
||||
channel-type.amazonechocontrol.lowerSetpoint.label = Lower Setpoint
|
||||
channel-type.amazonechocontrol.lowerSetpoint.description = Lower Setpoint
|
||||
channel-type.amazonechocontrol.mediaLength.label = Media Length
|
||||
channel-type.amazonechocontrol.mediaLength.description = Media length
|
||||
channel-type.amazonechocontrol.mediaProgress.label = Media Progress
|
||||
@ -139,6 +141,8 @@ channel-type.amazonechocontrol.radio.label = TuneIn Radio
|
||||
channel-type.amazonechocontrol.radio.description = Radio turned on
|
||||
channel-type.amazonechocontrol.radioStationId.label = TuneIn Radio Station Id
|
||||
channel-type.amazonechocontrol.radioStationId.description = Id of the radio station
|
||||
channel-type.amazonechocontrol.relativeHumidity.label = Humidity
|
||||
channel-type.amazonechocontrol.relativeHumidity.description = Relative humidity measured by the thermostat.
|
||||
channel-type.amazonechocontrol.remind.label = Remind
|
||||
channel-type.amazonechocontrol.remind.description = Speak the reminder and send a notification to the Alexa app
|
||||
channel-type.amazonechocontrol.save.label = Save
|
||||
@ -173,8 +177,12 @@ channel-type.amazonechocontrol.textToSpeech.label = Speak
|
||||
channel-type.amazonechocontrol.textToSpeech.description = Speak the text (Write only). It is possible to use plain text or SSML: <speak>I want to tell you a secret.<amazon:effect name="whispered">I am not a real human.</amazon:effect>.Can you believe it?</speak>
|
||||
channel-type.amazonechocontrol.textToSpeechVolume.label = Speak Volume
|
||||
channel-type.amazonechocontrol.textToSpeechVolume.description = Volume of the Speak channel. If 0, the current volume will be used.
|
||||
channel-type.amazonechocontrol.thermostatMode.label = Thermostat Mode
|
||||
channel-type.amazonechocontrol.thermostatMode.description = Thermostat Mode
|
||||
channel-type.amazonechocontrol.title.label = Title
|
||||
channel-type.amazonechocontrol.title.description = Title
|
||||
channel-type.amazonechocontrol.upperSetpoint.label = Upper Setpoint
|
||||
channel-type.amazonechocontrol.upperSetpoint.description = Upper Setpoint
|
||||
channel-type.amazonechocontrol.volume.label = Volume
|
||||
channel-type.amazonechocontrol.volume.description = Volume of the sound
|
||||
channel-type.amazonechocontrol.waterAlarm.label = Water Alarm
|
||||
|
@ -634,6 +634,18 @@
|
||||
<description>Temperature</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<!-- Alexa.HumiditySensor -->
|
||||
<channel-type id="relativeHumidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>Relative humidity measured by the thermostat.</description>
|
||||
<category>Humidity</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern=":.1%"/>
|
||||
</channel-type>
|
||||
<!-- Alexa.ThermostatController -->
|
||||
<channel-type id="targetSetpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
@ -641,4 +653,32 @@
|
||||
<description>Target Setpoint</description>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<channel-type id="upperSetpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Upper Setpoint</label>
|
||||
<description>Upper Setpoint</description>
|
||||
<category>Temperature</category>
|
||||
<tags>
|
||||
<tag>Setpoint</tag>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<channel-type id="lowerSetpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Lower Setpoint</label>
|
||||
<description>Lower Setpoint</description>
|
||||
<category>Temperature</category>
|
||||
<tags>
|
||||
<tag>Setpoint</tag>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<channel-type id="thermostatMode">
|
||||
<item-type>String</item-type>
|
||||
<label>Thermostat Mode</label>
|
||||
<description>Thermostat Mode</description>
|
||||
<state pattern="%s"/>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
|
Loading…
Reference in New Issue
Block a user