Skip to content

Commit

Permalink
Merge upstream/4.1.x into lastVoiceCommandFireTvCube
Browse files Browse the repository at this point in the history
  • Loading branch information
Trinitus01 committed Jun 6, 2024
2 parents 6bc35e8 + b79bf4d commit a7883dd
Show file tree
Hide file tree
Showing 14 changed files with 666 additions and 197 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@
import org.openhab.core.library.unit.Units;
import org.openhab.core.types.Command;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smarthomej.binding.amazonechocontrol.internal.connection.Connection;
import org.smarthomej.binding.amazonechocontrol.internal.dto.smarthome.JsonSmartHomeCapability;
import org.smarthomej.binding.amazonechocontrol.internal.dto.smarthome.JsonSmartHomeDevice;
import org.smarthomej.binding.amazonechocontrol.internal.handler.SmartHomeDeviceHandler;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

/**
Expand All @@ -41,6 +44,7 @@
*/
@NonNullByDefault
public class HandlerHumiditySensor extends AbstractInterfaceHandler {
private final Logger logger = LoggerFactory.getLogger(HandlerHumiditySensor.class);
public static final String INTERFACE = "Alexa.HumiditySensor";

private static final ChannelInfo HUMIDITY = new ChannelInfo("relativeHumidity", "humidity",
Expand All @@ -62,13 +66,18 @@ protected Set<ChannelInfo> findChannelInfos(JsonSmartHomeCapability capability,
public void updateChannels(String interfaceName, List<JsonObject> stateList, UpdateChannelResult result) {
QuantityType<Dimensionless> humidityValue = null;
for (JsonObject state : stateList) {
if (HUMIDITY.propertyName.equals(state.get("name").getAsString())) {
JsonObject value = state.get("value").getAsJsonObject();
// For groups take the first
if (humidityValue == null) {
BigDecimal humidity = value.get("value").getAsBigDecimal();
humidityValue = new QuantityType<>(humidity, Units.PERCENT);
if (HUMIDITY.propertyName.equals(state.get("name").getAsString()) && humidityValue == null) {
JsonElement value = state.get("value");
BigDecimal humidity;
if (value.isJsonObject()) {
humidity = value.getAsJsonObject().getAsBigDecimal();
} else if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isNumber()) {
humidity = value.getAsJsonPrimitive().getAsBigDecimal();
} else {
logger.warn("Could not properly convert {}", state);
continue;
}
humidityValue = new QuantityType<>(humidity, Units.PERCENT);
}
}
smartHomeDeviceHandler.updateState(HUMIDITY.channelId, humidityValue == null ? UnDefType.UNDEF : humidityValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,27 @@ public void updateChannels(String interfaceName, List<JsonObject> stateList, Upd
Boolean fireAlarmValue = null;
Boolean waterAlarmValue = null;
for (JsonObject state : stateList) {
if (ARM_STATE.propertyName.equals(state.get("name").getAsString())) {
String propertyValue = state.get("value").getAsJsonObject().get("value").getAsString();
String propertyName = state.get("name").getAsString();
if (ARM_STATE.propertyName.equals(propertyName)) {
if (armStateValue == null) {
armStateValue = state.get("value").getAsString();
}
} else if (BURGLARY_ALARM.propertyName.equals(state.get("name").getAsString())) {
} else if (BURGLARY_ALARM.propertyName.equals(propertyName)) {
if (burglaryAlarmValue == null) {
burglaryAlarmValue = "ALARM".equals(state.get("value").getAsString());
burglaryAlarmValue = "ALARM".equals(propertyValue);
}
} else if (CARBON_MONOXIDE_ALARM.propertyName.equals(state.get("name").getAsString())) {
} else if (CARBON_MONOXIDE_ALARM.propertyName.equals(propertyName)) {
if (carbonMonoxideAlarmValue == null) {
carbonMonoxideAlarmValue = "ALARM".equals(state.get("value").getAsString());
carbonMonoxideAlarmValue = "ALARM".equals(propertyValue);
}
} else if (FIRE_ALARM.propertyName.equals(state.get("name").getAsString())) {
} else if (FIRE_ALARM.propertyName.equals(propertyName)) {
if (fireAlarmValue == null) {
fireAlarmValue = "ALARM".equals(state.get("value").getAsString());
fireAlarmValue = "ALARM".equals(propertyValue);
}
} else if (WATER_ALARM.propertyName.equals(state.get("name").getAsString())) {
} else if (WATER_ALARM.propertyName.equals(propertyName)) {
if (waterAlarmValue == null) {
waterAlarmValue = "ALARM".equals(state.get("value").getAsString());
waterAlarmValue = "ALARM".equals(propertyValue);
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions bundles/org.smarthomej.binding.tuya/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ It contains a comma-separated list of command options for this channel (e.g. `wh
### Type `ir-code`

IR code types:

+ `Tuya DIY-mode` - use study codes from real remotes.

Make a virtual remote control in DIY, learn virtual buttons.
Expand All @@ -139,6 +140,7 @@ IR code types:
+ `Samsung` - IR Code in Samsung format.

**Additional options:**

* `Active Listening` - Device will be always in learning mode.
After send command with key code device stays in the learning mode
* `DP Study Key` - **Advanced**. DP number for study key. Uses for receive key code in learning mode. Change it own your
Expand All @@ -150,11 +152,13 @@ If linked item received a command with `Key Code` (Code Library Parameter) then
#### How to use IR Code in NEC format.

Example, from Tasmota you need to use **_Data_** parameter, it can be with or without **_0x_**

```json
{"Time": "2023-07-05T18:17:42", "IrReceived": {"Protocol": "NEC", "Bits": 32, "Data": "0x10EFD02F"}}
```

Another example, use **_hex_** parameter

```json
{ "type": "nec", "uint32": 284151855, "address": 8, "data": 11, "hex": "10EFD02F" }
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ public class ChannelConfiguration {
public int irSendDelay = 300;
public int irCodeType = 0;
public String irType = "";
public Boolean activeListen = Boolean.FALSE;
public boolean activeListen = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,17 +148,16 @@ public void processDeviceStatus(Map<Integer, Object> deviceStatus) {
private void processChannelStatus(Integer dp, Object value) {
String channelId = dpToChannelId.get(dp);
if (channelId != null) {
ChannelConfiguration configuration = channelIdToConfiguration.get(channelId);
ChannelConfiguration channelConfiguration = channelIdToConfiguration.get(channelId);
ChannelTypeUID channelTypeUID = channelIdToChannelTypeUID.get(channelId);

if (configuration == null || channelTypeUID == null) {
if (channelConfiguration == null || channelTypeUID == null) {
logger.warn("Could not find configuration or type for channel '{}' in thing '{}'", channelId,
thing.getUID());
return;
}

ChannelConfiguration channelConfiguration = channelIdToConfiguration.get(channelId);
if (channelConfiguration != null && Boolean.FALSE.equals(deviceStatusCache.get(channelConfiguration.dp2))) {
if (Boolean.FALSE.equals(deviceStatusCache.get(channelConfiguration.dp2))) {
// skip update if the channel is off!
return;
}
Expand All @@ -173,7 +172,8 @@ private void processChannelStatus(Integer dp, Object value) {
return;
} else if (Double.class.isAssignableFrom(value.getClass())
&& CHANNEL_TYPE_UID_DIMMER.equals(channelTypeUID)) {
updateState(channelId, ConversionUtil.brightnessDecode((double) value, 0, configuration.max));
updateState(channelId,
ConversionUtil.brightnessDecode((double) value, 0, channelConfiguration.max));
return;
} else if (Double.class.isAssignableFrom(value.getClass())
&& CHANNEL_TYPE_UID_NUMBER.equals(channelTypeUID)) {
Expand All @@ -186,11 +186,11 @@ private void processChannelStatus(Integer dp, Object value) {
updateState(channelId, OnOffType.from((boolean) value));
return;
} else if (value instanceof String && CHANNEL_TYPE_UID_IR_CODE.equals(channelTypeUID)) {
if (configuration.dp == 2) {
String decoded = convertBase64Code(configuration, (String) value);
if (channelConfiguration.dp == 2) {
String decoded = convertBase64Code(channelConfiguration, (String) value);
logger.info("thing {} received ir code: {}", thing.getUID(), decoded);
updateState(channelId, new StringType(decoded));
irStartLearning(configuration.activeListen);
irStartLearning(channelConfiguration.activeListen);
}
return;
}
Expand Down Expand Up @@ -228,14 +228,9 @@ public void connectionStatus(boolean status) {
}

// start learning code if thing is online and presents 'ir-code' channel
this.getThing().getChannels().stream()
.filter(channel -> CHANNEL_TYPE_UID_IR_CODE.equals(channel.getChannelTypeUID())).findFirst()
.ifPresent(channel -> {
ChannelConfiguration config = channelIdToConfiguration.get(channel.getChannelTypeUID());
if (config != null) {
irStartLearning(config.activeListen);
}
});
channelIdToChannelTypeUID.entrySet().stream().filter(e -> CHANNEL_TYPE_UID_IR_CODE.equals(e.getValue()))
.map(Map.Entry::getKey).findAny().map(channelIdToConfiguration::get)
.ifPresent(irCodeChannelConfig -> irStartLearning(irCodeChannelConfig.activeListen));
} else {
updateStatus(ThingStatus.OFFLINE);
ScheduledFuture<?> pollingJob = this.pollingJob;
Expand All @@ -250,7 +245,9 @@ public void connectionStatus(boolean status) {
if (tuyaDevice != null && !disposing && (reconnectFuture == null || reconnectFuture.isDone())) {
this.reconnectFuture = scheduler.schedule(this::connectDevice, 5000, TimeUnit.MILLISECONDS);
}
irStopLearning();
if (channelIdToChannelTypeUID.containsValue(CHANNEL_TYPE_UID_IR_CODE)) {
irStopLearning();
}
}
}

Expand Down Expand Up @@ -338,29 +335,34 @@ public void handleCommand(ChannelUID channelUID, Command command) {
}
} else if (CHANNEL_TYPE_UID_IR_CODE.equals(channelTypeUID)) {
if (command instanceof StringType) {
if (configuration.irType.equals("base64")) {
commandRequest.put(1, "study_key");
commandRequest.put(7, command.toString());
} else if (configuration.irType.equals("tuya-head")) {
if (configuration.irCode != null && !configuration.irCode.isEmpty()) {
commandRequest.put(1, "send_ir");
commandRequest.put(3, configuration.irCode);
commandRequest.put(4, command.toString());
commandRequest.put(10, configuration.irSendDelay);
commandRequest.put(13, configuration.irCodeType);
} else {
logger.warn("irCode is not set for channel {}", channelUID);
switch (configuration.irType) {
case "base64" -> {
commandRequest.put(1, "study_key");
commandRequest.put(7, command.toString());
}
case "tuya-head" -> {
if (!configuration.irCode.isBlank()) {
commandRequest.put(1, "send_ir");
commandRequest.put(3, configuration.irCode);
commandRequest.put(4, command.toString());
commandRequest.put(10, configuration.irSendDelay);
commandRequest.put(13, configuration.irCodeType);
} else {
logger.warn("irCode is not set for channel {}", channelUID);
}
}
case "nec" -> {
long code = convertHexCode(command.toString());
String base64Code = IrUtils.necToBase64(code);
commandRequest.put(1, "study_key");
commandRequest.put(7, base64Code);
}
case "samsung" -> {
long code = convertHexCode(command.toString());
String base64Code = IrUtils.samsungToBase64(code);
commandRequest.put(1, "study_key");
commandRequest.put(7, base64Code);
}
} else if (configuration.irType.equals("nec")) {
long code = convertHexCode(command.toString());
String base64Code = IrUtils.necToBase64(code);
commandRequest.put(1, "study_key");
commandRequest.put(7, base64Code);
} else if (configuration.irType.equals("samsung")) {
long code = convertHexCode(command.toString());
String base64Code = IrUtils.samsungToBase64(code);
commandRequest.put(1, "study_key");
commandRequest.put(7, base64Code);
}
irStopLearning();
}
Expand Down Expand Up @@ -610,7 +612,7 @@ private String convertBase64Code(ChannelConfiguration channelConfig, String enco
} else {
if (encoded.length() > 68) {
decoded = IrUtils.base64ToNec(encoded);
if (decoded == null || decoded.isEmpty()) {
if (decoded.isEmpty()) {
decoded = IrUtils.base64ToSamsung(encoded);
}
IrCode code = Objects.requireNonNull(gson.fromJson(decoded, IrCode.class));
Expand All @@ -620,28 +622,19 @@ private String convertBase64Code(ChannelConfiguration channelConfig, String enco
}
}
} catch (JsonSyntaxException e) {
logger.error("Incorrect json response: {}", e.getMessage());
logger.warn("Incorrect json response: {}", e.getMessage());
decoded = encoded;
} catch (NullPointerException e) {
logger.error("unable decode key code'{}', reason: {}", decoded, e.getMessage());
} catch (RuntimeException e) {
logger.warn("Unable decode key code'{}', reason: {}", decoded, e.getMessage());
}
return decoded;
}

private void finishStudyCode() {
Map<Integer, @Nullable Object> commandRequest = new HashMap<>();
commandRequest.put(1, "study_exit");
TuyaDevice tuyaDevice = this.tuyaDevice;
if (!commandRequest.isEmpty() && tuyaDevice != null) {
tuyaDevice.set(commandRequest);
}
}

private void repeatStudyCode() {
Map<Integer, @Nullable Object> commandRequest = new HashMap<>();
commandRequest.put(1, "study");
TuyaDevice tuyaDevice = this.tuyaDevice;
if (!commandRequest.isEmpty() && tuyaDevice != null) {
if (tuyaDevice != null) {
tuyaDevice.set(commandRequest);
}
}
Expand All @@ -655,7 +648,7 @@ private void irStopLearning() {
}
}

private void irStartLearning(Boolean available) {
private void irStartLearning(boolean available) {
irStopLearning();
if (available) {
logger.debug("[tuya:ir-controller] start ir learning");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
package org.smarthomej.binding.tuya.internal.local.dto;

import org.eclipse.jdt.annotation.*;
import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* The {@link IrCode} represents the IR code decoded messages sent by Tuya devices
Expand Down
Loading

0 comments on commit a7883dd

Please sign in to comment.