mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[gree] Use GCM encryption when bind fails (#17398)
* [gree]: use GCM encryption when binding fails Signed-off-by: Zhivka Dimova <zhivka.dimova@myforest.net>
This commit is contained in:
parent
e6b372c053
commit
90442a3864
@ -19,15 +19,18 @@ No binding configuration is required.
|
|||||||
|
|
||||||
## Thing Configuration
|
## Thing Configuration
|
||||||
|
|
||||||
| Channel Name | Type | Description |
|
| Channel Name | Type | Description |
|
||||||
|--------------------------|------------|-----------------------------------------------------------------------------------------------|
|
|--------------------------|-----------------|-----------------------------------------------------------------------------------------------|
|
||||||
| ipAddress | IP Address | IP address of the unit. |
|
| ipAddress | IP Address | IP address of the unit. |
|
||||||
| broadcastAddress | IP Address | Broadcast address being used for discovery, usually derived from the IP interface address. |
|
| broadcastAddress | IP Address | Broadcast address being used for discovery, usually derived from the IP interface address. |
|
||||||
| refresh | Integer | Refresh interval in seconds for polling the device status. |
|
| refresh | Integer | Refresh interval in seconds for polling the device status. |
|
||||||
| currentTemperatureOffset | Decimal | Offset in Celsius for the current temperature value received from the device. |
|
| currentTemperatureOffset | Decimal | Offset in Celsius for the current temperature value received from the device. |
|
||||||
|
| encryptionType | EncryptionTypes | Encryption type (ECB or GCM) used for communicating with the AC device |
|
||||||
|
|
||||||
The Air Conditioner's IP address is mandatory, all other parameters are optional.
|
The Air Conditioner's IP address is mandatory, all other parameters are optional.
|
||||||
If the broadcast is not set (default) it will be derived from openHAB's network setting (Check Network Settings in the openHAB UI).
|
If the broadcast is not set (default) it will be derived from openHAB's network setting (Check Network Settings in the openHAB UI).
|
||||||
|
The binding tries to automatically detect the encryption type when communicating with the AC.
|
||||||
|
If this fails, you might need need to set the encryption type manually.
|
||||||
Only change this if you have a good reason to.
|
Only change this if you have a good reason to.
|
||||||
|
|
||||||
## Channels
|
## Channels
|
||||||
@ -64,7 +67,7 @@ When changing mode, the air conditioner will be turned on unless "off" is select
|
|||||||
### Things
|
### Things
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Thing gree:airconditioner:a1234561 [ ipAddress="192.168.1.111", refresh=2 ]
|
Thing gree:airconditioner:a1234561 [ ipAddress="192.168.1.111", refresh=2, encryptionType="ECB" ]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Items
|
### Items
|
||||||
|
@ -12,7 +12,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.gree.internal;
|
package org.openhab.binding.gree.internal;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
@ -39,6 +43,8 @@ public class GreeBindingConstants {
|
|||||||
public static final String PROPERTY_IP = "ipAddress";
|
public static final String PROPERTY_IP = "ipAddress";
|
||||||
public static final String PROPERTY_BROADCAST = "broadcastAddress";
|
public static final String PROPERTY_BROADCAST = "broadcastAddress";
|
||||||
|
|
||||||
|
public static final String PROPERTY_ENCRYPTION_TYPE = "encryptionType";
|
||||||
|
|
||||||
// List of all Channel ids
|
// List of all Channel ids
|
||||||
public static final String POWER_CHANNEL = "power";
|
public static final String POWER_CHANNEL = "power";
|
||||||
public static final String MODE_CHANNEL = "mode";
|
public static final String MODE_CHANNEL = "mode";
|
||||||
@ -174,4 +180,17 @@ public class GreeBindingConstants {
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
public static final double INTERNAL_TEMP_SENSOR_OFFSET = -40.0;
|
public static final double INTERNAL_TEMP_SENSOR_OFFSET = -40.0;
|
||||||
|
|
||||||
|
public enum EncryptionTypes {
|
||||||
|
UNKNOWN,
|
||||||
|
ECB,
|
||||||
|
GCM;
|
||||||
|
|
||||||
|
private static final Map<String, EncryptionTypes> MAP = Stream.of(EncryptionTypes.values())
|
||||||
|
.collect(Collectors.toMap(Enum::name, Function.identity()));
|
||||||
|
|
||||||
|
public static EncryptionTypes of(final String name) {
|
||||||
|
return MAP.getOrDefault(name, UNKNOWN);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.gree.internal;
|
package org.openhab.binding.gree.internal;
|
||||||
|
|
||||||
|
import static org.openhab.binding.gree.internal.GreeBindingConstants.*;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
@ -32,10 +34,11 @@ public class GreeConfiguration {
|
|||||||
* of the temperature sensor.
|
* of the temperature sensor.
|
||||||
*/
|
*/
|
||||||
public BigDecimal currentTemperatureOffset = new BigDecimal(0.0);
|
public BigDecimal currentTemperatureOffset = new BigDecimal(0.0);
|
||||||
|
public EncryptionTypes encryptionType = EncryptionTypes.UNKNOWN;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Config: ipAddress=" + ipAddress + ", broadcastAddress=" + broadcastAddress + ", refresh=" + refresh
|
return "Config: ipAddress=" + ipAddress + ", broadcastAddress=" + broadcastAddress + ", refresh=" + refresh
|
||||||
+ ", currentTemperatureOffset=" + currentTemperatureOffset;
|
+ ", currentTemperatureOffset=" + currentTemperatureOffset + ", encryptionType=" + encryptionType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.gree.internal;
|
package org.openhab.binding.gree.internal;
|
||||||
|
|
||||||
|
import static org.openhab.binding.gree.internal.GreeBindingConstants.EncryptionTypes;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
@ -45,11 +47,6 @@ public class GreeCryptoUtil {
|
|||||||
private static final String GCM_ADD = "qualcomm-test";
|
private static final String GCM_ADD = "qualcomm-test";
|
||||||
private static final int TAG_LENGTH = 16;
|
private static final int TAG_LENGTH = 16;
|
||||||
|
|
||||||
public enum EncryptionTypes {
|
|
||||||
ECB,
|
|
||||||
GCM
|
|
||||||
};
|
|
||||||
|
|
||||||
public static byte[] getAESGeneralKeyByteArray() {
|
public static byte[] getAESGeneralKeyByteArray() {
|
||||||
return AES_KEY.getBytes(StandardCharsets.UTF_8);
|
return AES_KEY.getBytes(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
@ -86,6 +83,10 @@ public class GreeCryptoUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends GreeBaseDTO> String decrypt(T response, EncryptionTypes encType) throws GreeException {
|
public static <T extends GreeBaseDTO> String decrypt(T response, EncryptionTypes encType) throws GreeException {
|
||||||
|
if (encType == EncryptionTypes.UNKNOWN) {
|
||||||
|
encType = getEncryptionType(response);
|
||||||
|
}
|
||||||
|
|
||||||
if (encType == EncryptionTypes.GCM) {
|
if (encType == EncryptionTypes.GCM) {
|
||||||
return decrypt(getGCMGeneralKeyByteArray(), response, encType);
|
return decrypt(getGCMGeneralKeyByteArray(), response, encType);
|
||||||
} else {
|
} else {
|
||||||
@ -95,6 +96,10 @@ public class GreeCryptoUtil {
|
|||||||
|
|
||||||
public static <T extends GreeBaseDTO> String decrypt(byte[] keyarray, T response, EncryptionTypes encType)
|
public static <T extends GreeBaseDTO> String decrypt(byte[] keyarray, T response, EncryptionTypes encType)
|
||||||
throws GreeException {
|
throws GreeException {
|
||||||
|
if (encType == EncryptionTypes.UNKNOWN) {
|
||||||
|
encType = getEncryptionType(response);
|
||||||
|
}
|
||||||
|
|
||||||
if (encType == EncryptionTypes.GCM) {
|
if (encType == EncryptionTypes.GCM) {
|
||||||
return decryptGCMPack(keyarray, response.pack, response.tag);
|
return decryptGCMPack(keyarray, response.pack, response.tag);
|
||||||
} else {
|
} else {
|
||||||
|
@ -106,7 +106,7 @@ public class GreeException extends Exception {
|
|||||||
|
|
||||||
private Class<?> getCauseClass() {
|
private Class<?> getCauseClass() {
|
||||||
Throwable cause = getCause();
|
Throwable cause = getCause();
|
||||||
if (getCause() != null) {
|
if (cause != null) {
|
||||||
return cause.getClass();
|
return cause.getClass();
|
||||||
}
|
}
|
||||||
return GreeException.class;
|
return GreeException.class;
|
||||||
|
@ -61,7 +61,8 @@ public class GreeDeviceFinder {
|
|||||||
public GreeDeviceFinder() {
|
public GreeDeviceFinder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scan(DatagramSocket clientSocket, String broadcastAddress, boolean scanNetwork) throws GreeException {
|
public void scan(DatagramSocket clientSocket, String broadcastAddress, boolean scanNetwork,
|
||||||
|
EncryptionTypes encryptionTypeConfig) throws GreeException {
|
||||||
InetAddress ipAddress;
|
InetAddress ipAddress;
|
||||||
try {
|
try {
|
||||||
ipAddress = InetAddress.getByName(broadcastAddress);
|
ipAddress = InetAddress.getByName(broadcastAddress);
|
||||||
@ -103,7 +104,8 @@ public class GreeDeviceFinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt message - a GreeException is thrown when something went wrong
|
// Decrypt message - a GreeException is thrown when something went wrong
|
||||||
String decryptedMsg = scanResponseGson.decryptedPack = GreeCryptoUtil.decrypt(scanResponseGson);
|
String decryptedMsg = scanResponseGson.decryptedPack = GreeCryptoUtil.decrypt(scanResponseGson,
|
||||||
|
encryptionTypeConfig);
|
||||||
|
|
||||||
logger.debug("Response received from address {}: {}", remoteAddress.getHostAddress(), decryptedMsg);
|
logger.debug("Response received from address {}: {}", remoteAddress.getHostAddress(), decryptedMsg);
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ public class GreeDiscoveryService extends AbstractDiscoveryService {
|
|||||||
@Override
|
@Override
|
||||||
protected void startScan() {
|
protected void startScan() {
|
||||||
try (DatagramSocket clientSocket = new DatagramSocket()) {
|
try (DatagramSocket clientSocket = new DatagramSocket()) {
|
||||||
deviceFinder.scan(clientSocket, broadcastAddress, true);
|
deviceFinder.scan(clientSocket, broadcastAddress, true, EncryptionTypes.UNKNOWN);
|
||||||
|
|
||||||
int count = deviceFinder.getScannedDeviceCount();
|
int count = deviceFinder.getScannedDeviceCount();
|
||||||
logger.debug("{}", messages.get("discovery.result", count));
|
logger.debug("{}", messages.get("discovery.result", count));
|
||||||
@ -112,6 +112,7 @@ public class GreeDiscoveryService extends AbstractDiscoveryService {
|
|||||||
properties.put(Thing.PROPERTY_MAC_ADDRESS, device.getId());
|
properties.put(Thing.PROPERTY_MAC_ADDRESS, device.getId());
|
||||||
properties.put(PROPERTY_IP, ipAddress);
|
properties.put(PROPERTY_IP, ipAddress);
|
||||||
properties.put(PROPERTY_BROADCAST, broadcastAddress);
|
properties.put(PROPERTY_BROADCAST, broadcastAddress);
|
||||||
|
properties.put(PROPERTY_ENCRYPTION_TYPE, device.getEncryptionType());
|
||||||
ThingUID thingUID = new ThingUID(THING_TYPE_GREEAIRCON, device.getId());
|
ThingUID thingUID = new ThingUID(THING_TYPE_GREEAIRCON, device.getId());
|
||||||
DiscoveryResult result = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
|
DiscoveryResult result = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
|
||||||
.withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS).withLabel(device.getName()).build();
|
.withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS).withLabel(device.getName()).build();
|
||||||
|
@ -64,7 +64,7 @@ public class GreeAirDevice {
|
|||||||
private final InetAddress ipAddress;
|
private final InetAddress ipAddress;
|
||||||
private int port = 0;
|
private int port = 0;
|
||||||
private String encKey = "";
|
private String encKey = "";
|
||||||
private GreeCryptoUtil.EncryptionTypes encType = GreeCryptoUtil.EncryptionTypes.ECB;
|
private EncryptionTypes encType = EncryptionTypes.UNKNOWN;
|
||||||
private Optional<GreeScanResponseDTO> scanResponseGson = Optional.empty();
|
private Optional<GreeScanResponseDTO> scanResponseGson = Optional.empty();
|
||||||
private Optional<GreeStatusResponseDTO> statusResponseGson = Optional.empty();
|
private Optional<GreeStatusResponseDTO> statusResponseGson = Optional.empty();
|
||||||
private Optional<GreeStatusResponsePackDTO> prevStatusResponsePackGson = Optional.empty();
|
private Optional<GreeStatusResponsePackDTO> prevStatusResponsePackGson = Optional.empty();
|
||||||
@ -148,7 +148,7 @@ public class GreeAirDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindWithDevice(DatagramSocket clientSocket) throws GreeException {
|
public void bindWithDevice(DatagramSocket clientSocket, EncryptionTypes encryptionTypeConfig) throws GreeException {
|
||||||
try {
|
try {
|
||||||
// Prep the Binding Request pack
|
// Prep the Binding Request pack
|
||||||
GreeBindRequestPackDTO bindReqPackGson = new GreeBindRequestPackDTO();
|
GreeBindRequestPackDTO bindReqPackGson = new GreeBindRequestPackDTO();
|
||||||
@ -158,6 +158,7 @@ public class GreeAirDevice {
|
|||||||
String bindReqPackStr = GSON.toJson(bindReqPackGson);
|
String bindReqPackStr = GSON.toJson(bindReqPackGson);
|
||||||
|
|
||||||
// Encrypt and send the Binding Request pack
|
// Encrypt and send the Binding Request pack
|
||||||
|
setEncryptionType(encryptionTypeConfig);
|
||||||
String[] encryptedBindReqData = GreeCryptoUtil.encrypt(GreeCryptoUtil.getGeneralKeyByteArray(encType),
|
String[] encryptedBindReqData = GreeCryptoUtil.encrypt(GreeCryptoUtil.getGeneralKeyByteArray(encType),
|
||||||
bindReqPackStr, encType);
|
bindReqPackStr, encType);
|
||||||
DatagramPacket sendPacket = createPackRequest(1, encryptedBindReqData);
|
DatagramPacket sendPacket = createPackRequest(1, encryptedBindReqData);
|
||||||
@ -174,7 +175,12 @@ public class GreeAirDevice {
|
|||||||
// save the outcome
|
// save the outcome
|
||||||
isBound = true;
|
isBound = true;
|
||||||
} catch (IOException | JsonSyntaxException e) {
|
} catch (IOException | JsonSyntaxException e) {
|
||||||
throw new GreeException("Unable to bind to device", e);
|
if (encType != EncryptionTypes.GCM) {
|
||||||
|
logger.debug("Unable to bind to device - changing the encryption mode to GCM and trying again", e);
|
||||||
|
bindWithDevice(clientSocket, EncryptionTypes.GCM);
|
||||||
|
} else {
|
||||||
|
throw new GreeException("Unable to bind to device", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +466,7 @@ public class GreeAirDevice {
|
|||||||
request.uid = 0;
|
request.uid = 0;
|
||||||
request.tcid = getId();
|
request.tcid = getId();
|
||||||
request.pack = data[0];
|
request.pack = data[0];
|
||||||
if (encType == GreeCryptoUtil.EncryptionTypes.GCM) {
|
if (encType == EncryptionTypes.GCM) {
|
||||||
if (data.length > 1) {
|
if (data.length > 1) {
|
||||||
request.tag = data[1];
|
request.tag = data[1];
|
||||||
} else {
|
} else {
|
||||||
@ -519,6 +525,24 @@ public class GreeAirDevice {
|
|||||||
return isBound;
|
return isBound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setEncryptionType(EncryptionTypes value) {
|
||||||
|
if (value == EncryptionTypes.UNKNOWN) {
|
||||||
|
logger.debug("Trying to set encryption type to 'UNKNOWN' for device: {}, current value: {}", getName(),
|
||||||
|
encType);
|
||||||
|
if (encType == EncryptionTypes.UNKNOWN) {
|
||||||
|
logger.debug("Falling back to 'ECB' for device: {}", getName());
|
||||||
|
encType = EncryptionTypes.ECB;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.debug("Change encryption type for device: {}, from : {}, to: {}", getName(), encType, value);
|
||||||
|
encType = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public EncryptionTypes getEncryptionType() {
|
||||||
|
return encType;
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] getKey() {
|
public byte[] getKey() {
|
||||||
return encKey.getBytes(StandardCharsets.UTF_8);
|
return encKey.getBytes(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
@ -528,7 +552,12 @@ public class GreeAirDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return scanResponseGson.isPresent() ? scanResponseGson.get().packJson.name : "";
|
if (scanResponseGson.isPresent()) {
|
||||||
|
String name = scanResponseGson.get().packJson.name;
|
||||||
|
return name.trim().isEmpty() ? getId() : name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVendor() {
|
public String getVendor() {
|
||||||
|
@ -108,12 +108,12 @@ public class GreeHandler extends BaseThingHandler {
|
|||||||
clientSocket.get().setSoTimeout(DATAGRAM_SOCKET_TIMEOUT);
|
clientSocket.get().setSoTimeout(DATAGRAM_SOCKET_TIMEOUT);
|
||||||
}
|
}
|
||||||
// Find the GREE device
|
// Find the GREE device
|
||||||
deviceFinder.scan(clientSocket.get(), config.ipAddress, false);
|
deviceFinder.scan(clientSocket.get(), config.ipAddress, false, config.encryptionType);
|
||||||
GreeAirDevice newDevice = deviceFinder.getDeviceByIPAddress(config.ipAddress);
|
GreeAirDevice newDevice = deviceFinder.getDeviceByIPAddress(config.ipAddress);
|
||||||
if (newDevice != null) {
|
if (newDevice != null) {
|
||||||
// Ok, our device responded, now let's Bind with it
|
// Ok, our device responded, now let's Bind with it
|
||||||
device = newDevice;
|
device = newDevice;
|
||||||
device.bindWithDevice(clientSocket.get());
|
device.bindWithDevice(clientSocket.get(), config.encryptionType);
|
||||||
if (device.getIsBound()) {
|
if (device.getIsBound()) {
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
return;
|
return;
|
||||||
@ -138,7 +138,7 @@ public class GreeHandler extends BaseThingHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
if (command instanceof RefreshType) {
|
if (command instanceof RefreshType) {
|
||||||
// The thing is updated by the scheduled automatic refresh so do nothing here.
|
initializeThing();
|
||||||
} else {
|
} else {
|
||||||
logger.debug("{}: Issue command {} to channe {}", thingId, command, channelUID.getIdWithoutGroup());
|
logger.debug("{}: Issue command {} to channe {}", thingId, command, channelUID.getIdWithoutGroup());
|
||||||
String channelId = channelUID.getIdWithoutGroup();
|
String channelId = channelUID.getIdWithoutGroup();
|
||||||
@ -377,8 +377,9 @@ public class GreeHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
} catch (GreeException e) {
|
} catch (GreeException e) {
|
||||||
String subcode = "";
|
String subcode = "";
|
||||||
if (e.getCause() != null) {
|
Throwable cause = e.getCause();
|
||||||
subcode = " (" + e.getCause().getMessage() + ")";
|
if (cause != null) {
|
||||||
|
subcode = " (" + cause.getMessage() + ")";
|
||||||
}
|
}
|
||||||
String message = messages.get("update.exception", e.getMessageString() + subcode);
|
String message = messages.get("update.exception", e.getMessageString() + subcode);
|
||||||
if (getThing().getStatus() == ThingStatus.OFFLINE) {
|
if (getThing().getStatus() == ThingStatus.OFFLINE) {
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
# GREE Binding
|
# add-on
|
||||||
|
|
||||||
addon.gree.name = GREE Binding
|
addon.gree.name = GREE Binding
|
||||||
addon.gree.description = This binding integrates the GREE series of air conditioners
|
addon.gree.description = This is the binding for GREE air conditioners.
|
||||||
|
|
||||||
# thing types
|
# thing types
|
||||||
|
|
||||||
thing-type.gree.airconditioner.label = Air Conditioner
|
thing-type.gree.airconditioner.label = Air Conditioner
|
||||||
thing-type.gree.airconditioner.description = A GREE Air Conditioner with WiFi Module
|
thing-type.gree.airconditioner.description = A GREE Air Conditioner with WiFi Module
|
||||||
|
|
||||||
# thing type config description
|
# thing type config description
|
||||||
|
|
||||||
thing-type.config.gree.airconditioner.ipAddress.label = IP Address
|
thing-type.config.gree.airconditioner.ipAddress.label = IP Address
|
||||||
thing-type.config.gree.airconditioner.ipAddress.description = IP Address of the GREE unit.
|
thing-type.config.gree.airconditioner.ipAddress.description = IP Address of the GREE unit.
|
||||||
thing-type.config.gree.airconditioner.broadcastAddress.label = Subnet Broadcast Address
|
thing-type.config.gree.airconditioner.broadcastAddress.label = Subnet Broadcast Address
|
||||||
@ -15,8 +18,13 @@ thing-type.config.gree.airconditioner.refresh.label = Refresh Interval
|
|||||||
thing-type.config.gree.airconditioner.refresh.description = Interval to query an update from the device.
|
thing-type.config.gree.airconditioner.refresh.description = Interval to query an update from the device.
|
||||||
thing-type.config.gree.airconditioner.currentTemperatureOffset.label = Offset for Current Temperature
|
thing-type.config.gree.airconditioner.currentTemperatureOffset.label = Offset for Current Temperature
|
||||||
thing-type.config.gree.airconditioner.currentTemperatureOffset.description = The offset in Celsius for the current temperature value received from the device.
|
thing-type.config.gree.airconditioner.currentTemperatureOffset.description = The offset in Celsius for the current temperature value received from the device.
|
||||||
|
thing-type.config.gree.airconditioner.encryptionType.label = Encryption type
|
||||||
|
thing-type.config.gree.airconditioner.encryptionType.description = The encryption type used for encrypting the data send to the AC device.
|
||||||
|
thing-type.config.gree.airconditioner.encryptionType.state.option.ECB = ECB
|
||||||
|
thing-type.config.gree.airconditioner.encryptionType.state.option.GCM = GCM
|
||||||
|
|
||||||
# channel types
|
# channel types
|
||||||
|
|
||||||
channel-type.gree.power.label = Power
|
channel-type.gree.power.label = Power
|
||||||
channel-type.gree.power.description = Turn power on/off
|
channel-type.gree.power.description = Turn power on/off
|
||||||
channel-type.gree.mode.label = Unit Mode
|
channel-type.gree.mode.label = Unit Mode
|
||||||
@ -70,7 +78,7 @@ channel-type.gree.swingupdown.option.11 = Swing Upmost
|
|||||||
channel-type.gree.swingleftright.label = Horizontal Swing Mode
|
channel-type.gree.swingleftright.label = Horizontal Swing Mode
|
||||||
channel-type.gree.swingleftright.description = Sets the horizontal swing action on the Air Conditioner: 0=OFF, 1=Full Swing, 2=Left, 3=Mid-Left, 4=Mid, 5=Mid-Right, 6=Right
|
channel-type.gree.swingleftright.description = Sets the horizontal swing action on the Air Conditioner: 0=OFF, 1=Full Swing, 2=Left, 3=Mid-Left, 4=Mid, 5=Mid-Right, 6=Right
|
||||||
channel-type.gree.swingleftright.option.0 = OFF
|
channel-type.gree.swingleftright.option.0 = OFF
|
||||||
channel-type.gree.swingleftright.option.1 = Full Swing
|
channel-type.gree.swingleftright.option.1 = Full Swing
|
||||||
channel-type.gree.swingleftright.option.2 = Left
|
channel-type.gree.swingleftright.option.2 = Left
|
||||||
channel-type.gree.swingleftright.option.3 = Mid-Left
|
channel-type.gree.swingleftright.option.3 = Mid-Left
|
||||||
channel-type.gree.swingleftright.option.4 = Mid
|
channel-type.gree.swingleftright.option.4 = Mid
|
||||||
@ -83,7 +91,8 @@ channel-type.gree.light.description = Enable/disable the front display on the Ai
|
|||||||
channel-type.gree.health.label = Health Mode
|
channel-type.gree.health.label = Health Mode
|
||||||
channel-type.gree.health.description = Set on/off the Air Conditioner's Health function if applicable to the Air Conditioner model.
|
channel-type.gree.health.description = Set on/off the Air Conditioner's Health function if applicable to the Air Conditioner model.
|
||||||
|
|
||||||
# User Messages
|
# user messages
|
||||||
|
|
||||||
message.thinginit.failed = Unable to connect to air conditioner
|
message.thinginit.failed = Unable to connect to air conditioner
|
||||||
message.thinginit.invconf = Invalid configuration data
|
message.thinginit.invconf = Invalid configuration data
|
||||||
message.thinginit.exception = Thing initialization failed: {0}
|
message.thinginit.exception = Thing initialization failed: {0}
|
||||||
@ -92,5 +101,5 @@ message.command.exception = Unable to execute command {0} for channel {1}
|
|||||||
message.update.exception = Unable to perform auto-update: {0}
|
message.update.exception = Unable to perform auto-update: {0}
|
||||||
message.channel.exception = Unable to update channel {0} with {1}
|
message.channel.exception = Unable to update channel {0} with {1}
|
||||||
message.discovery.result = {0} units discovered.
|
message.discovery.result = {0} units discovered.
|
||||||
message.discovery.newunit = Device {0} discovered at {1}, MAC={2}
|
message.discovery.newunit = Device {0} discovered at {1}, MAC={2}
|
||||||
message.discovery.exception = Device Discovery failed: {0}
|
message.discovery.exception = Device Discovery failed: {0}
|
||||||
|
@ -41,6 +41,13 @@
|
|||||||
<unitLabel>Degrees Celsius</unitLabel>
|
<unitLabel>Degrees Celsius</unitLabel>
|
||||||
<advanced>true</advanced>
|
<advanced>true</advanced>
|
||||||
</parameter>
|
</parameter>
|
||||||
|
<parameter name="encryptionType" type="text">
|
||||||
|
<options>
|
||||||
|
<option value="ECB">@text/thing-type.config.gree.airconditioner.encryptionType.state.option.ECB</option>
|
||||||
|
<option value="GCM">@text/thing-type.config.gree.airconditioner.encryptionType.state.option.GCM</option>
|
||||||
|
</options>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
</config-description>
|
</config-description>
|
||||||
|
|
||||||
</thing-type>
|
</thing-type>
|
||||||
|
Loading…
Reference in New Issue
Block a user