From abfaccf251b8830ff004c5b51e55970a3a83f7f0 Mon Sep 17 00:00:00 2001 From: Markus Michels Date: Tue, 15 Sep 2020 21:27:25 +0200 Subject: [PATCH] [gree] Minor improvements (#8472) * Adding retries for status pool and api request * README updated * Implements #8330: Swing Up/Down values 0-11 * Missing text resources added for V-SwingUpDown 7-11 Signed-off-by: Markus Michels --- bundles/org.openhab.binding.gree/README.md | 4 +- .../gree/internal/GreeBindingConstants.java | 1 + .../gree/internal/handler/GreeAirDevice.java | 40 ++++- .../gree/internal/handler/GreeHandler.java | 143 +++++++++++------- .../resources/ESH-INF/i18n/gree.properties | 5 + .../resources/ESH-INF/i18n/gree_DE.properties | 13 +- 6 files changed, 140 insertions(+), 66 deletions(-) diff --git a/bundles/org.openhab.binding.gree/README.md b/bundles/org.openhab.binding.gree/README.md index 23c27a1b02e06..22dcbb84b8366 100644 --- a/bundles/org.openhab.binding.gree/README.md +++ b/bundles/org.openhab.binding.gree/README.md @@ -24,7 +24,7 @@ No binding configuration is required. | ipAddress | IP Address | IP address of the unit. | | 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. | -| currentTemperatureOffset | Decimal | The 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. | 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 (PaperUI:Configuration:System:Network Settings). @@ -41,7 +41,7 @@ The following channels are supported for fans: | | | Mode can be one of auto/cool/eco/dry/fan/heat or on/off | | | | Check the Air Conditioner's operating manual for supported modes. | | temperature | Number:Temperature | Sets the desired room temperature. | -| currentTemperature | Number:Temperature | Displays the current room temperature. | +| currentTemperature | Number:Temperature | Displays the current room temperature (if supported by the unit, otherwise NaN). | | air | Switch | Set on/off the Air Conditioner's Air function if applicable to the Air Conditioner model | | dry | Switch | Set on/off the Air Conditioner's Dry function if applicable to the Air Conditioner model | | health | Switch | Set on/off the Air Conditioner's Health function if applicable to the Air Conditioner model | diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/GreeBindingConstants.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/GreeBindingConstants.java index b2887f99f35ac..5b7a68062f548 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/GreeBindingConstants.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/GreeBindingConstants.java @@ -159,6 +159,7 @@ public class GreeBindingConstants { public static final int DISCOVERY_TIMEOUT_MS = 7000; // do not change!! public static final int MAX_SCAN_CYCLES = 3; public static final int REFRESH_INTERVAL_SEC = 5; + public static final int MAX_API_RETRIES = 3; public static final int DIGITS_TEMP = 1; diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeAirDevice.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeAirDevice.java index 92b9eaaa3286a..7bc610f6e85d4 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeAirDevice.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeAirDevice.java @@ -189,15 +189,42 @@ public void setDeviceMode(DatagramSocket clientSocket, int value) throws GreeExc setCommandValue(clientSocket, GREE_PROP_MODE, value); } + /** + * SwUpDn: controls the swing mode of the vertical air blades + * + * 0: default + * 1: swing in full range + * 2: fixed in the upmost position (1/5) + * 3: fixed in the middle-up position (2/5) + * 4: fixed in the middle position (3/5) + * 5: fixed in the middle-low position (4/5) + * 6: fixed in the lowest position (5/5) + * 7: swing in the downmost region (5/5) + * 8: swing in the middle-low region (4/5) + * 9: swing in the middle region (3/5) + * 10: swing in the middle-up region (2/5) + * 11: swing in the upmost region (1/5) + */ public void setDeviceSwingUpDown(DatagramSocket clientSocket, int value) throws GreeException { - // Only values 0,1,2,3,4,5,6,10,11 allowed - if ((value < 0 || value > 11) || (value > 6 && value < 10)) { - throw new GreeException("SwingUpDown value out of range!"); + if (value < 0 || value > 11) { + throw new GreeException("SwingUpDown value is out of range!"); } setCommandValue(clientSocket, GREE_PROP_SWINGUPDOWN, value); } + /** + * SwingLfRig: controls the swing mode of the horizontal air blades (available on limited number of devices, e.g. + * some Cooper & Hunter units - thanks to mvmn) + * + * 0: default + * 1: full swing + * 2-6: fixed position from leftmost to rightmost + * Full swing, like for SwUpDn is not supported + */ public void setDeviceSwingLeftRight(DatagramSocket clientSocket, int value) throws GreeException { + if (value < 0 || value > 6) { + throw new GreeException("SwingLeftRight value is out of range!"); + } setCommandValue(clientSocket, GREE_PROP_SWINGLEFTRIGHT, value, 0, 6); } @@ -224,6 +251,13 @@ public void setDeviceWindspeed(DatagramSocket clientSocket, int value) throws Gr executeCommand(clientSocket, parameters); } + /** + * Tur: sets fan speed to the maximum. Fan speed cannot be changed while active and only available in Dry and Cool + * mode. + * + * 0: off + * 1: on + */ public void setDeviceTurbo(DatagramSocket clientSocket, int value) throws GreeException { setCommandValue(clientSocket, GREE_PROP_TURBO, value, 0, 1); } diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeHandler.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeHandler.java index 5c1f1d0d6782a..994992c7514c8 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeHandler.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeHandler.java @@ -43,6 +43,7 @@ import org.eclipse.smarthome.core.types.Command; import org.eclipse.smarthome.core.types.RefreshType; import org.eclipse.smarthome.core.types.State; +import org.eclipse.smarthome.core.types.UnDefType; import org.openhab.binding.gree.internal.GreeConfiguration; import org.openhab.binding.gree.internal.GreeException; import org.openhab.binding.gree.internal.GreeTranslationProvider; @@ -70,6 +71,7 @@ public class GreeHandler extends BaseThingHandler { private @Nullable ScheduledFuture refreshTask; private @Nullable Future initializeFuture; private long lastRefreshTime = 0; + private long apiRetries = 0; public GreeHandler(Thing thing, GreeTranslationProvider messages, GreeDeviceFinder deviceFinder) { super(thing); @@ -138,62 +140,78 @@ public void handleCommand(ChannelUID channelUID, Command command) { String channelId = channelUID.getIdWithoutGroup(); logger.debug("{}: Handle command {} for channel {}, command class {}", thingId, command, channelId, command.getClass()); - try { - DatagramSocket socket = clientSocket.get(); - switch (channelId) { - case MODE_CHANNEL: - handleModeCommand(socket, command); - break; - case POWER_CHANNEL: - device.setDevicePower(socket, getOnOff(command)); - break; - case TURBO_CHANNEL: - device.setDeviceTurbo(socket, getOnOff(command)); - break; - case LIGHT_CHANNEL: - device.setDeviceLight(socket, getOnOff(command)); - break; - case TARGET_TEMP_CHANNEL: - // Set value, read back effective one and update channel - // e.g. 22.5C will result in 22.0, because the AC doesn't support half-steps for C - device.setDeviceTempSet(socket, convertTemp(command)); - break; - case SWINGUD_CHANNEL: - device.setDeviceSwingUpDown(socket, getNumber(command)); - break; - case SWINGLR_CHANNEL: - device.setDeviceSwingLeftRight(socket, getNumber(command)); - break; - case WINDSPEED_CHANNEL: - device.setDeviceWindspeed(socket, getNumber(command)); - break; - case QUIET_CHANNEL: - handleQuietCommand(socket, command); - break; - case AIR_CHANNEL: - device.setDeviceAir(socket, getOnOff(command)); - break; - case DRY_CHANNEL: - device.setDeviceDry(socket, getOnOff(command)); - break; - case HEALTH_CHANNEL: - device.setDeviceHealth(socket, getOnOff(command)); - break; - case PWRSAV_CHANNEL: - device.setDevicePwrSaving(socket, getOnOff(command)); - break; + + int retries = MAX_API_RETRIES; + do { + try { + sendRequest(channelId, command); + // force refresh on next status refresh cycle + forceRefresh = true; + apiRetries = 0; + } catch (GreeException e) { + retries--; + if (retries > 0) { + logger.debug("{}: Command {} failed for channel {}, retry", thingId, command, channelId); + } else { + String message = logInfo( + messages.get("command.exception", command, channelId) + ": " + e.getMessage()); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message); + } + } catch (IllegalArgumentException e) { + logInfo("command.invarg", command, channelId); + retries = 0; + } catch (RuntimeException e) { + logger.warn("{}: {}", thingId, messages.get("command.exception", command, channelId), e); + retries = 0; } + } while (retries > 0); + } + } - // force refresh on next status refresh cycle - forceRefresh = true; - } catch (GreeException e) { - String message = logInfo("command.exception", command, channelId) + ": " + e.getMessage(); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message); - } catch (IllegalArgumentException e) { - logInfo("command.invarg", command, channelId); - } catch (RuntimeException e) { - logger.warn("{}: {}", thingId, messages.get("command.exception", command, channelId), e); - } + private void sendRequest(String channelId, Command command) throws GreeException { + DatagramSocket socket = clientSocket.get(); + switch (channelId) { + case MODE_CHANNEL: + handleModeCommand(socket, command); + break; + case POWER_CHANNEL: + device.setDevicePower(socket, getOnOff(command)); + break; + case TURBO_CHANNEL: + device.setDeviceTurbo(socket, getOnOff(command)); + break; + case LIGHT_CHANNEL: + device.setDeviceLight(socket, getOnOff(command)); + break; + case TARGET_TEMP_CHANNEL: + // Set value, read back effective one and update channel + // e.g. 22.5C will result in 22.0, because the AC doesn't support half-steps for C + device.setDeviceTempSet(socket, convertTemp(command)); + break; + case SWINGUD_CHANNEL: + device.setDeviceSwingUpDown(socket, getNumber(command)); + break; + case SWINGLR_CHANNEL: + device.setDeviceSwingLeftRight(socket, getNumber(command)); + break; + case WINDSPEED_CHANNEL: + device.setDeviceWindspeed(socket, getNumber(command)); + break; + case QUIET_CHANNEL: + handleQuietCommand(socket, command); + break; + case AIR_CHANNEL: + device.setDeviceAir(socket, getOnOff(command)); + break; + case DRY_CHANNEL: + device.setDeviceDry(socket, getOnOff(command)); + break; + case HEALTH_CHANNEL: + device.setDeviceHealth(socket, getOnOff(command)); + break; + case PWRSAV_CHANNEL: + device.setDevicePwrSaving(socket, getOnOff(command)); + break; } } @@ -336,12 +354,15 @@ private void startAutomaticRefresh() { // Get the current status from the Airconditioner if (getThing().getStatus() == ThingStatus.OFFLINE) { + // try to re-initialize thing access + logger.debug("{}: Re-initialize device", thingId); initializeThing(); return; } if (clientSocket.isPresent()) { device.getDeviceStatus(clientSocket.get()); + apiRetries = 0; // the call was successful without an exception logger.debug("{}: Executing automatic update of values", thingId); List channels = getThing().getChannels(); for (Channel channel : channels) { @@ -363,11 +384,16 @@ private void startAutomaticRefresh() { } else { logger.debug("{}: {}", thingId, message); } - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message); + + apiRetries++; + if (apiRetries > MAX_API_RETRIES) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message); + } } } catch (RuntimeException e) { String message = messages.get("update.exception", "RuntimeException"); logger.warn("{}: {}", thingId, message, e); + apiRetries++; } }; @@ -519,8 +545,11 @@ private void publishChannel(ChannelUID channelUID) { private @Nullable State updateCurrentTemp() throws GreeException { if (device.hasStatusValChanged(GREE_PROP_CURRENT_TEMP_SENSOR)) { - return new DecimalType(device.getIntStatusVal(GREE_PROP_CURRENT_TEMP_SENSOR) + INTERNAL_TEMP_SENSOR_OFFSET - + config.currentTemperatureOffset.doubleValue()); + double temp = device.getIntStatusVal(GREE_PROP_CURRENT_TEMP_SENSOR); + return temp != 0 + ? new DecimalType( + temp + INTERNAL_TEMP_SENSOR_OFFSET + config.currentTemperatureOffset.doubleValue()) + : UnDefType.UNDEF; } return null; } diff --git a/bundles/org.openhab.binding.gree/src/main/resources/ESH-INF/i18n/gree.properties b/bundles/org.openhab.binding.gree/src/main/resources/ESH-INF/i18n/gree.properties index b6260678a059a..613f86a7f0443 100644 --- a/bundles/org.openhab.binding.gree/src/main/resources/ESH-INF/i18n/gree.properties +++ b/bundles/org.openhab.binding.gree/src/main/resources/ESH-INF/i18n/gree.properties @@ -63,6 +63,11 @@ channel-type.gree.swingupdown.option.3 = Mid-Up channel-type.gree.swingupdown.option.4 = Mid channel-type.gree.swingupdown.option.5 = Mid-Down channel-type.gree.swingupdown.option.6 = Down +channel-type.gree.swingupdown.option.7 = Swing Downmost +channel-type.gree.swingupdown.option.8 = Swing Middle-Low +channel-type.gree.swingupdown.option.9 = Swing Middle +channel-type.gree.swingupdown.option.10 = Swing Middle-Up +channel-type.gree.swingupdown.option.11 = Swing Upmost 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.option.0 = OFF diff --git a/bundles/org.openhab.binding.gree/src/main/resources/ESH-INF/i18n/gree_DE.properties b/bundles/org.openhab.binding.gree/src/main/resources/ESH-INF/i18n/gree_DE.properties index 0cac488fa37c3..80108e0dbdfb6 100644 --- a/bundles/org.openhab.binding.gree/src/main/resources/ESH-INF/i18n/gree_DE.properties +++ b/bundles/org.openhab.binding.gree/src/main/resources/ESH-INF/i18n/gree_DE.properties @@ -54,8 +54,8 @@ channel-type.gree.quiet.description = Leisemodus w channel-type.gree.quiet.state.option.off = Aus channel-type.gree.quiet.state.option.auto = Auto channel-type.gree.quiet.state.option.quiet = Leise -channel-type.gree.swingupdown.label = Lamellenmodus -channel-type.gree.swingupdown.description = Auswahl des Lamellenmodus: 0=Aus, 1=Voller Flügel, 2=Hoch, 3=Mittelhoch, 3=Mitte, 5=Mitteltief, 6=Tief. Verfügbarkeit ist abhängig vom Gerätemodell. +channel-type.gree.swingupdown.label = V-Lamellenmodus +channel-type.gree.swingupdown.description = Auswahl des vertikalen Lamellenmodus: 0=Aus, 1=Voller Flügel, 2=Hoch, 3=Mittelhoch, 3=Mitte, 5=Mitteltief, 6=Tief. Verfügbarkeit ist abhängig vom Gerätemodell. channel-type.gree.swingupdown.option.0 = Aus channel-type.gree.swingupdown.option.1 = Voller Flügel channel-type.gree.swingupdown.option.2 = Hoch @@ -63,8 +63,13 @@ channel-type.gree.swingupdown.option.3 = Mittelhoch channel-type.gree.swingupdown.option.4 = Mitte channel-type.gree.swingupdown.option.5 = Mitteltief channel-type.gree.swingupdown.option.6 = Tief -channel-type.gree.swingleftright.label = Lamellenmodus -channel-type.gree.swingleftright.description = Auswahl des Lamellenmodus: 0=Aus, 1=Voller Flügel, 2=Links, 3=Mitte-Links, 4=Mitte, 5=Mitte-Rechts, 6=Rechts. Verfügbarkeit ist abhängig vom Gerätemodell. +channel-type.gree.swingupdown.option.7 = Unterre Region +channel-type.gree.swingupdown.option.8 = Mittlere Region +channel-type.gree.swingupdown.option.9 = Region Mitte-unten +channel-type.gree.swingupdown.option.10 = Region Mitte-oben +channel-type.gree.swingupdown.option.11 = Obere Region +channel-type.gree.swingleftright.label = H-Lamellenmodus +channel-type.gree.swingleftright.description = Auswahl des horizontalen Lamellenmodus: 0=Aus, 1=Voller Flügel, 2=Links, 3=Mitte-Links, 4=Mitte, 5=Mitte-Rechts, 6=Rechts. Verfügbarkeit ist abhängig vom Gerätemodell. channel-type.gree.swingleftright.option.0 = AUS channel-type.gree.swingleftright.option.1 = Voller Flügel channel-type.gree.swingleftright.option.2 = Links