From 69c3b0f3539fa550a819f099dc92d6221fd8f94c Mon Sep 17 00:00:00 2001
From: Florian Hotze <florianh_dev@icloud.com>
Date: Sun, 1 May 2022 12:50:10 +0200
Subject: [PATCH] [yamahamusiccast] Fix VolumeDB channel resets on UDP event
 (#12671)

* [yamahamusiccast] Fix VolumeDB resets on UDP event
* [yamahamusiccast] Update channel description & docs

Fixes [yamahamusiccast] VolumeDB channel resets to -80 on player channel change #12656.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
---
 .../README.md                                 |  2 +-
 .../internal/YamahaMusiccastHandler.java      | 59 +++++++++++++------
 .../yamahamusiccast/internal/dto/Status.java  | 13 ++--
 .../internal/dto/UdpMessage.java              | 13 ++--
 .../OH-INF/i18n/yamahamusiccast.properties    | 12 ++--
 .../resources/OH-INF/thing/thing-types.xml    | 12 ++--
 6 files changed, 61 insertions(+), 50 deletions(-)

diff --git a/bundles/org.openhab.binding.yamahamusiccast/README.md b/bundles/org.openhab.binding.yamahamusiccast/README.md
index af10c23a61c..71128fbdac2 100644
--- a/bundles/org.openhab.binding.yamahamusiccast/README.md
+++ b/bundles/org.openhab.binding.yamahamusiccast/README.md
@@ -50,7 +50,7 @@ You can also use *RADIO / TUNER* (as *tuner*).
 | mute           | Switch               | Mute ON/OFF                                                         |
 | volume         | Dimmer               | Volume as % (recalculated based on Max Volume Model)                |
 | volumeAbs      | Number               | Volume as absolute value                                            |
-| volumeDB       | Number:Dimensionless | Volume in decibel (dB) (returns -90 dB if not available on device)  |
+| volumeDB       | Number:Dimensionless | Volume in decibel (dB) (availability depends on device)             |
 | input          | String               | See below for list                                                  |
 | soundProgram   | String               | See below for list                                                  |
 | selectPreset   | String               | Select Netradio/USB preset (fetched from Model)                     |
diff --git a/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/YamahaMusiccastHandler.java b/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/YamahaMusiccastHandler.java
index 5a6ceeee876..716980b97f8 100644
--- a/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/YamahaMusiccastHandler.java
+++ b/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/YamahaMusiccastHandler.java
@@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.yamahamusiccast.internal.dto.ActualVolume;
 import org.openhab.binding.yamahamusiccast.internal.dto.DeviceInfo;
 import org.openhab.binding.yamahamusiccast.internal.dto.DistributionInfo;
 import org.openhab.binding.yamahamusiccast.internal.dto.Features;
@@ -61,6 +62,7 @@ import org.openhab.core.thing.type.ChannelTypeUID;
 import org.openhab.core.types.Command;
 import org.openhab.core.types.RefreshType;
 import org.openhab.core.types.StateOption;
+import org.openhab.core.types.UnDefType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -86,7 +88,6 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
     private int volumeAbsValue = 0;
     private @Nullable String responseCode = "";
     private int volumeState = 0;
-    private float volumeDbState = -80f; // -80.0 dB
     private int maxVolumeState = 0;
     private @Nullable String inputState = "";
     private @Nullable String soundProgramState = "";
@@ -537,7 +538,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
         String muteState = "";
         String inputState = "";
         int volumeState = 0;
-        float volumeDbState = -90f; // -90.0 dB
+        ActualVolume actualVolume = null;
         int presetNumber = 0;
         int playTime = 0;
         String distInfoUpdated = "";
@@ -548,7 +549,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
                 muteState = targetObject.getMain().getMute();
                 inputState = targetObject.getMain().getInput();
                 volumeState = targetObject.getMain().getVolume();
-                volumeDbState = targetObject.getMain().getVolumeDb();
+                actualVolume = targetObject.getMain().getActualVolume();
                 statusUpdated = targetObject.getMain().getstatusUpdated();
                 break;
             case "zone2":
@@ -556,7 +557,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
                 muteState = targetObject.getZone2().getMute();
                 inputState = targetObject.getZone2().getInput();
                 volumeState = targetObject.getZone2().getVolume();
-                volumeDbState = targetObject.getZone2().getVolumeDb();
+                actualVolume = targetObject.getZone2().getActualVolume();
                 statusUpdated = targetObject.getZone2().getstatusUpdated();
                 break;
             case "zone3":
@@ -564,7 +565,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
                 muteState = targetObject.getZone3().getMute();
                 inputState = targetObject.getZone3().getInput();
                 volumeState = targetObject.getZone3().getVolume();
-                volumeDbState = targetObject.getZone3().getVolumeDb();
+                actualVolume = targetObject.getZone3().getActualVolume();
                 statusUpdated = targetObject.getZone3().getstatusUpdated();
                 break;
             case "zone4":
@@ -572,7 +573,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
                 muteState = targetObject.getZone4().getMute();
                 inputState = targetObject.getZone4().getInput();
                 volumeState = targetObject.getZone4().getVolume();
-                volumeDbState = targetObject.getZone4().getVolumeDb();
+                actualVolume = targetObject.getZone4().getActualVolume();
                 statusUpdated = targetObject.getZone4().getstatusUpdated();
                 break;
             case "netusb":
@@ -590,6 +591,18 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
                 break;
         }
 
+        if (logger.isTraceEnabled()) {
+            logger.trace("{} - Response: {}", zoneToUpdate, responseCode);
+            logger.trace("{} - Power: {}", zoneToUpdate, powerState);
+            logger.trace("{} - Mute: {}", zoneToUpdate, muteState);
+            logger.trace("{} - Volume: {}", zoneToUpdate, volumeState);
+            logger.trace("{} - Volume in dB: {}", zoneToUpdate, (actualVolume != null) ? actualVolume.getValue() : "");
+            logger.trace("{} - Max Volume: {}", zoneToUpdate, maxVolumeState);
+            logger.trace("{} - Input: {}", zoneToUpdate, inputState);
+            logger.trace("{} - Soundprogram: {}", zoneToUpdate, soundProgramState);
+            logger.trace("{} - Sleep: {}", zoneToUpdate, sleepState);
+        }
+
         if (!powerState.isEmpty()) {
             channel = new ChannelUID(getThing().getUID(), zoneToUpdate, CHANNEL_POWER);
             if ("on".equals(powerState)) {
@@ -621,9 +634,9 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
             updateState(channel, new DecimalType(volumeState));
         }
 
-        if (volumeDbState != -90f) {
+        if (actualVolume != null) {
             channel = new ChannelUID(getThing().getUID(), zoneToUpdate, CHANNEL_VOLUMEDB);
-            updateState(channel, new QuantityType<>(volumeDbState, Units.DECIBEL));
+            updateState(channel, new QuantityType<>(actualVolume.getValue(), Units.DECIBEL));
         }
 
         if (presetNumber != 0) {
@@ -657,21 +670,24 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
             String powerState = targetObject.getPower();
             String muteState = targetObject.getMute();
             volumeState = targetObject.getVolume();
-            volumeDbState = targetObject.getVolumeDb();
+            ActualVolume actualVolume = targetObject.getActualVolume();
             maxVolumeState = targetObject.getMaxVolume();
             inputState = targetObject.getInput();
             soundProgramState = targetObject.getSoundProgram();
             sleepState = targetObject.getSleep();
 
-            logger.trace("{} - Response: {}", zoneToUpdate, responseCode);
-            logger.trace("{} - Power: {}", zoneToUpdate, powerState);
-            logger.trace("{} - Mute: {}", zoneToUpdate, muteState);
-            logger.trace("{} - Volume: {}", zoneToUpdate, volumeState);
-            logger.trace("{} - Volume in dB: {}", zoneToUpdate, volumeDbState);
-            logger.trace("{} - Max Volume: {}", zoneToUpdate, maxVolumeState);
-            logger.trace("{} - Input: {}", zoneToUpdate, inputState);
-            logger.trace("{} - Soundprogram: {}", zoneToUpdate, soundProgramState);
-            logger.trace("{} - Sleep: {}", zoneToUpdate, sleepState);
+            if (logger.isTraceEnabled()) {
+                logger.trace("{} - Response: {}", zoneToUpdate, responseCode);
+                logger.trace("{} - Power: {}", zoneToUpdate, powerState);
+                logger.trace("{} - Mute: {}", zoneToUpdate, muteState);
+                logger.trace("{} - Volume: {}", zoneToUpdate, volumeState);
+                logger.trace("{} - Volume in dB: {}", zoneToUpdate,
+                        (actualVolume != null) ? actualVolume.getValue() : "");
+                logger.trace("{} - Max Volume: {}", zoneToUpdate, maxVolumeState);
+                logger.trace("{} - Input: {}", zoneToUpdate, inputState);
+                logger.trace("{} - Soundprogram: {}", zoneToUpdate, soundProgramState);
+                logger.trace("{} - Sleep: {}", zoneToUpdate, sleepState);
+            }
 
             switch (responseCode) {
                 case "0":
@@ -717,7 +733,12 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
                                         break;
                                     case CHANNEL_VOLUMEDB:
                                         if (localZone.equals(zoneToUpdate)) {
-                                            updateState(channelUID, new QuantityType<>(volumeDbState, Units.DECIBEL));
+                                            if (actualVolume != null) {
+                                                updateState(channelUID,
+                                                        new QuantityType<>(actualVolume.getValue(), Units.DECIBEL));
+                                            } else {
+                                                updateState(channelUID, UnDefType.UNDEF);
+                                            }
                                         }
                                         break;
                                     case CHANNEL_INPUT:
diff --git a/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/dto/Status.java b/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/dto/Status.java
index bd1448841cd..aff3431a987 100644
--- a/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/dto/Status.java
+++ b/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/dto/Status.java
@@ -12,6 +12,8 @@
  */
 package org.openhab.binding.yamahamusiccast.internal.dto;
 
+import org.eclipse.jdt.annotation.Nullable;
+
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -75,15 +77,8 @@ public class Status {
         return volume;
     }
 
-    /**
-     * Get the volume in decibel (dB).
-     * 
-     * @return volume in dB or -90 dB if not available
-     */
-    public float getVolumeDb() {
-        if (actualVolume == null)
-            return -90f;
-        return actualVolume.getValue();
+    public @Nullable ActualVolume getActualVolume() {
+        return actualVolume;
     }
 
     public int getMaxVolume() {
diff --git a/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/dto/UdpMessage.java b/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/dto/UdpMessage.java
index 74f48f360be..393e6f947b6 100644
--- a/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/dto/UdpMessage.java
+++ b/bundles/org.openhab.binding.yamahamusiccast/src/main/java/org/openhab/binding/yamahamusiccast/internal/dto/UdpMessage.java
@@ -12,6 +12,8 @@
  */
 package org.openhab.binding.yamahamusiccast.internal.dto;
 
+import org.eclipse.jdt.annotation.Nullable;
+
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -109,15 +111,8 @@ public class UdpMessage {
             return volume;
         }
 
-        /**
-         * Get the volume in decibel (dB).
-         * 
-         * @return volume in dB or -90 dB if not available
-         */
-        public float getVolumeDb() {
-            if (actualVolume == null)
-                return -80f;
-            return actualVolume.getValue();
+        public @Nullable ActualVolume getActualVolume() {
+            return actualVolume;
         }
 
         public String getstatusUpdated() {
diff --git a/bundles/org.openhab.binding.yamahamusiccast/src/main/resources/OH-INF/i18n/yamahamusiccast.properties b/bundles/org.openhab.binding.yamahamusiccast/src/main/resources/OH-INF/i18n/yamahamusiccast.properties
index 5c596defc32..6772e14e59a 100644
--- a/bundles/org.openhab.binding.yamahamusiccast/src/main/resources/OH-INF/i18n/yamahamusiccast.properties
+++ b/bundles/org.openhab.binding.yamahamusiccast/src/main/resources/OH-INF/i18n/yamahamusiccast.properties
@@ -43,13 +43,13 @@ channel-type.yamahamusiccast.albumArt.description = Album Art
 channel-type.yamahamusiccast.artist.label = Artist
 channel-type.yamahamusiccast.artist.description = Artist
 channel-type.yamahamusiccast.input.label = Input
-channel-type.yamahamusiccast.input.description = Input channel
+channel-type.yamahamusiccast.input.description = Input source
 channel-type.yamahamusiccast.mclinkStatus.label = Status MusicCast
 channel-type.yamahamusiccast.mclinkStatus.description = MusicCast Status
 channel-type.yamahamusiccast.playTime.label = Play Time
 channel-type.yamahamusiccast.playTime.description = Play Time
 channel-type.yamahamusiccast.player.label = NetRadio/USB Player
-channel-type.yamahamusiccast.player.description = Player for Net Radio/USB channel
+channel-type.yamahamusiccast.player.description = Player for Net Radio/USB
 channel-type.yamahamusiccast.recallScene.label = Scene Selection
 channel-type.yamahamusiccast.recallScene.description = Scene selection (if available)
 channel-type.yamahamusiccast.recallScene.state.option.1 = Scene 1
@@ -66,7 +66,7 @@ channel-type.yamahamusiccast.repeat.state.option.off = Off
 channel-type.yamahamusiccast.repeat.state.option.one = One
 channel-type.yamahamusiccast.repeat.state.option.all = All
 channel-type.yamahamusiccast.selectPreset.label = NetRadio/USB Preset
-channel-type.yamahamusiccast.selectPreset.description = Select Net Radio/USB Preset channel
+channel-type.yamahamusiccast.selectPreset.description = Select Net Radio/USB Preset
 channel-type.yamahamusiccast.shuffle.label = Shuffle
 channel-type.yamahamusiccast.shuffle.description = Shuffle mode
 channel-type.yamahamusiccast.shuffle.state.option.off = Off
@@ -81,12 +81,12 @@ channel-type.yamahamusiccast.sleep.state.option.60 = 60 min
 channel-type.yamahamusiccast.sleep.state.option.90 = 90 min
 channel-type.yamahamusiccast.sleep.state.option.120 = 120 min
 channel-type.yamahamusiccast.soundProgram.label = Sound Program
-channel-type.yamahamusiccast.soundProgram.description = SoundProgram channel
+channel-type.yamahamusiccast.soundProgram.description = SoundProgram
 channel-type.yamahamusiccast.totalTime.label = Total Time
 channel-type.yamahamusiccast.totalTime.description = Total Time
 channel-type.yamahamusiccast.track.label = Track
 channel-type.yamahamusiccast.track.description = Track
 channel-type.yamahamusiccast.volumeAbs.label = Volume
-channel-type.yamahamusiccast.volumeAbs.description = Volume channel - Absolute value
+channel-type.yamahamusiccast.volumeAbs.description = Volume level - Absolute value
 channel-type.yamahamusiccast.volumeDB.label = Volume in dB
-channel-type.yamahamusiccast.volumeDB.description = Volume channel - in decibel (dB) (-90 dB if not available)
+channel-type.yamahamusiccast.volumeDB.description = Volume level - decibel (dB)
diff --git a/bundles/org.openhab.binding.yamahamusiccast/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.yamahamusiccast/src/main/resources/OH-INF/thing/thing-types.xml
index 60209b35570..6c19d584631 100644
--- a/bundles/org.openhab.binding.yamahamusiccast/src/main/resources/OH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.yamahamusiccast/src/main/resources/OH-INF/thing/thing-types.xml
@@ -92,35 +92,35 @@
 	<channel-type id="volumeAbs">
 		<item-type>Number</item-type>
 		<label>Volume</label>
-		<description>Volume channel - Absolute value</description>
+		<description>Volume level - Absolute value</description>
 		<category>SoundVolume</category>
 	</channel-type>
 	<channel-type id="volumeDB">
 		<item-type>Number:Dimensionless</item-type>
 		<label>Volume in dB</label>
-		<description>Volume channel - in decibel (dB) (-90 dB if not available)</description>
+		<description>Volume level - decibel (dB)</description>
 		<category>SoundVolume</category>
 		<state min="-80" max="12" step="0.5" pattern="%.1f %unit%"/>
 	</channel-type>
 	<channel-type id="input">
 		<item-type>String</item-type>
 		<label>Input</label>
-		<description>Input channel</description>
+		<description>Input source</description>
 	</channel-type>
 	<channel-type id="soundProgram">
 		<item-type>String</item-type>
 		<label>Sound Program</label>
-		<description>SoundProgram channel</description>
+		<description>SoundProgram</description>
 	</channel-type>
 	<channel-type id="selectPreset">
 		<item-type>String</item-type>
 		<label>NetRadio/USB Preset</label>
-		<description>Select Net Radio/USB Preset channel</description>
+		<description>Select Net Radio/USB Preset</description>
 	</channel-type>
 	<channel-type id="player">
 		<item-type>Player</item-type>
 		<label>NetRadio/USB Player</label>
-		<description>Player for Net Radio/USB channel</description>
+		<description>Player for Net Radio/USB</description>
 	</channel-type>
 	<channel-type id="sleep">
 		<item-type>Number</item-type>