[yamahamusiccast] New channel for volume in decibel (#12519)

* Added volume in decibel channel.
* Fixed default value for syncVolume to match the docs.
* Use QuantityType with unit DECIBEL for volumeDB.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
This commit is contained in:
Florian Hotze 2022-03-28 08:51:33 +02:00 committed by GitHub
parent 2d3f0d68c0
commit bd1f5f8bc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 243 additions and 24 deletions

View File

@ -36,32 +36,36 @@ No auto discovery
| host | String | IP address of the Yamaha model (AVR, ...) | false | true |
| syncVolume | Boolean | Sync volume across linked models (default=false) | false | false |
| defaultAfterMCLink | String | Default Input value for client when MC Link is broken | false | false |
| volumeDbMin | Number | Lowest volume in dB. | true | false |
| volumeDbMax | Number | Highest volume in dB. | true | false |
Default value for *defaultAfterMCLink* is *NET RADIO* as most of the models have this on board.
Default value for *defaultAfterMCLink* is *NET RADIO* (as *net_radio*) as most of the models have this on board.
You can also use *RADIO / TUNER* (as *tuner*).
## Channels
| channel | type | description |
|----------------|--------|---------------------------------------------------------------------|
| power | Switch | Power ON/OFF |
| mute | Switch | Mute ON/OFF |
| volume | Dimmer | Volume as % (recalculated based on Max Volume Model) |
| volumeAbs | Number | Volume as absolute value |
| input | String | See below for list |
| soundProgram | String | See below for list |
| selectPreset | String | Select Netradio/USB preset (fetched from Model) |
| sleep | Number | Fixed values for Sleep : 0/30/60/90/120 in minutes |
| recallScene | Number | Select a scene (8 defaults scenes are foreseen) |
| player | Player | PLAY/PAUSE/NEXT/PREVIOUS/REWIND/FASTFORWARD |
| artist | String | Artist |
| track | String | Track |
| album | String | Album |
| albumArt | Image | Album Art |
| repeat | String | Toggle Repeat. Available values: Off, One, All |
| shuffle | String | Toggle Shuffle. Available values: Off, On, Songs, Album |
| playTime | String | Play time of current selection: radio, song, track, ... |
| totalTime | String | Total time of current selection: radio, song, track, ... |
| mclinkStatus | String | Select your Musiccast Server or set to Standalone, Server or Client |
| channel | type | description |
|----------------|----------------------|---------------------------------------------------------------------|
| power | Switch | Power ON/OFF |
| 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) |
| input | String | See below for list |
| soundProgram | String | See below for list |
| selectPreset | String | Select Netradio/USB preset (fetched from Model) |
| sleep | Number | Fixed values for Sleep : 0/30/60/90/120 in minutes |
| recallScene | Number | Select a scene (8 defaults scenes are foreseen) |
| player | Player | PLAY/PAUSE/NEXT/PREVIOUS/REWIND/FASTFORWARD |
| artist | String | Artist |
| track | String | Track |
| album | String | Album |
| albumArt | Image | Album Art |
| repeat | String | Toggle Repeat. Available values: Off, One, All |
| shuffle | String | Toggle Shuffle. Available values: Off, On, Songs, Album |
| playTime | String | Play time of current selection: radio, song, track, ... |
| totalTime | String | Total time of current selection: radio, song, track, ... |
| mclinkStatus | String | Select your Musiccast Server or set to Standalone, Server or Client |
| Zones | description |
@ -105,7 +109,7 @@ mono_movie / movie / enhanced / 2ch_stereo / 5ch_stereo / 7ch_stereo / 9ch_stere
```
Bridge yamahamusiccast:bridge:virtual "YXC Bridge" {
Thing device Living "YXC Living" [host="1.2.3.4", defaultAfterMCLink="none", syncVolume=false]
Thing device Living "YXC Living" [host="1.2.3.4", defaultAfterMCLink="none", syncVolume=false, volumeDbMin=-80, volumeDbMax=-10]
}
```
@ -116,6 +120,7 @@ Switch YamahaPower "" {channel="yamahamusiccast:device:virtual:Living:main#power
Switch YamahaMute "" {channel="yamahamusiccast:device:virtual:Living:main#mute"}
Dimmer YamahaVolume "" {channel="yamahamusiccast:device:virtual:Living:main#volume"}
Number YamahaVolumeAbs "" {channel="yamahamusiccast:device:virtual:Living:main#volumeAbs"}
Number:Dimensionless YamahaVolumeDb "" {channel="yamahamusiccast:device:virtual:Living:main#volumeDB"}
String YamahaInput "" {channel="yamahamusiccast:device:virtual:Living:main#input"}
String YamahaSelectPreset "" {channel="yamahamusiccast:device:virtual:Living:main#selectPreset"}
String YamahaSoundProgram "" {channel="yamahamusiccast:device:virtual:Living:main#soundProgram"}

View File

@ -21,6 +21,7 @@ import org.openhab.core.thing.type.ChannelTypeUID;
* used across the whole binding.
*
* @author Lennert Coopman - Initial contribution
* @author Florian Hotze - Add volume in decibel
*/
@NonNullByDefault
public class YamahaMusiccastBindingConstants {
@ -36,6 +37,7 @@ public class YamahaMusiccastBindingConstants {
public static final ChannelTypeUID CHANNEL_TYPE_UID_MUTE = new ChannelTypeUID("system:mute");
public static final ChannelTypeUID CHANNEL_TYPE_UID_VOLUME = new ChannelTypeUID("system:volume");
public static final ChannelTypeUID CHANNEL_TYPE_UID_VOLUMEABS = new ChannelTypeUID(BINDING_ID, "volumeAbs");
public static final ChannelTypeUID CHANNEL_TYPE_UID_VOLUMEDB = new ChannelTypeUID(BINDING_ID, "volumeDB");
public static final ChannelTypeUID CHANNEL_TYPE_UID_INPUT = new ChannelTypeUID(BINDING_ID, "input");
public static final ChannelTypeUID CHANNEL_TYPE_UID_SOUNDPROGRAM = new ChannelTypeUID(BINDING_ID, "soundProgram");
public static final ChannelTypeUID CHANNEL_TYPE_UID_SELECTPRESET = new ChannelTypeUID(BINDING_ID, "selectPreset");
@ -48,6 +50,7 @@ public class YamahaMusiccastBindingConstants {
public static final String CHANNEL_MUTE = "mute";
public static final String CHANNEL_VOLUME = "volume";
public static final String CHANNEL_VOLUMEABS = "volumeAbs";
public static final String CHANNEL_VOLUMEDB = "volumeDB";
public static final String CHANNEL_INPUT = "input";
public static final String CHANNEL_SOUNDPROGRAM = "soundProgram";
public static final String CHANNEL_SELECTPRESET = "selectPreset";

View File

@ -19,6 +19,7 @@ import org.eclipse.jdt.annotation.Nullable;
* The {@link YamahaMusiccastConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Lennert Coopman - Initial contribution
* @author Florian Hotze - Add volume in decibel
*/
@NonNullByDefault
public class YamahaMusiccastConfiguration {
@ -26,4 +27,13 @@ public class YamahaMusiccastConfiguration {
public @Nullable String host;
public @Nullable Boolean syncVolume;
public @Nullable String defaultAfterMCLink;
/**
* Minimum allowed volume in dB.
*/
public float volumeDbMin = -80f; // -80.0 dB
/**
* Maximum allowed volume in dB.
*/
public float volumeDbMax = 12f; // 12.0 dB
}

View File

@ -44,8 +44,10 @@ import org.openhab.core.library.types.NextPreviousType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.PlayPauseType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.RewindFastforwardType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
@ -71,6 +73,7 @@ import com.google.gson.JsonObject;
* sent to one of the channels.
*
* @author Lennert Coopman - Initial contribution
* @author Florian Hotze - Add volume in decibel
*/
@NonNullByDefault
public class YamahaMusiccastHandler extends BaseThingHandler {
@ -83,6 +86,7 @@ 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 = "";
@ -222,6 +226,24 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
}
}
break;
case CHANNEL_VOLUMEDB:
setVolumeDb(((QuantityType<?>) command).floatValue(), zone, this.host);
localSyncVolume = Boolean.parseBoolean(getThing().getConfiguration().get("syncVolume").toString());
if (localSyncVolume == Boolean.TRUE) {
tmpString = getDistributionInfo(this.host);
distributioninfo = gson.fromJson(tmpString, DistributionInfo.class);
if (distributioninfo != null) {
localRole = distributioninfo.getRole();
if ("server".equals(localRole)) {
for (JsonElement ip : distributioninfo.getClientList()) {
JsonObject clientObject = ip.getAsJsonObject();
setVolumeDbLinkedDevice(((DecimalType) command).floatValue(), zone,
clientObject.get("ip_address").getAsString());
}
}
}
}
break;
case CHANNEL_INPUT:
// if it is a client, disconnect it first.
tmpString = getDistributionInfo(this.host);
@ -451,6 +473,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
createChannel(zone, CHANNEL_MUTE, CHANNEL_TYPE_UID_MUTE, "Switch");
createChannel(zone, CHANNEL_VOLUME, CHANNEL_TYPE_UID_VOLUME, "Dimmer");
createChannel(zone, CHANNEL_VOLUMEABS, CHANNEL_TYPE_UID_VOLUMEABS, "Number");
createChannel(zone, CHANNEL_VOLUMEDB, CHANNEL_TYPE_UID_VOLUMEDB, "Number:Dimensionless");
createChannel(zone, CHANNEL_INPUT, CHANNEL_TYPE_UID_INPUT, "String");
createChannel(zone, CHANNEL_SOUNDPROGRAM, CHANNEL_TYPE_UID_SOUNDPROGRAM, "String");
createChannel(zone, CHANNEL_SLEEP, CHANNEL_TYPE_UID_SLEEP, "Number");
@ -514,6 +537,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
String muteState = "";
String inputState = "";
int volumeState = 0;
float volumeDbState = -90f; // -90.0 dB
int presetNumber = 0;
int playTime = 0;
String distInfoUpdated = "";
@ -524,6 +548,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
muteState = targetObject.getMain().getMute();
inputState = targetObject.getMain().getInput();
volumeState = targetObject.getMain().getVolume();
volumeDbState = targetObject.getMain().getVolumeDb();
statusUpdated = targetObject.getMain().getstatusUpdated();
break;
case "zone2":
@ -531,6 +556,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
muteState = targetObject.getZone2().getMute();
inputState = targetObject.getZone2().getInput();
volumeState = targetObject.getZone2().getVolume();
volumeDbState = targetObject.getZone2().getVolumeDb();
statusUpdated = targetObject.getZone2().getstatusUpdated();
break;
case "zone3":
@ -538,6 +564,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
muteState = targetObject.getZone3().getMute();
inputState = targetObject.getZone3().getInput();
volumeState = targetObject.getZone3().getVolume();
volumeDbState = targetObject.getZone3().getVolumeDb();
statusUpdated = targetObject.getZone3().getstatusUpdated();
break;
case "zone4":
@ -545,6 +572,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
muteState = targetObject.getZone4().getMute();
inputState = targetObject.getZone4().getInput();
volumeState = targetObject.getZone4().getVolume();
volumeDbState = targetObject.getZone4().getVolumeDb();
statusUpdated = targetObject.getZone4().getstatusUpdated();
break;
case "netusb":
@ -593,6 +621,11 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
updateState(channel, new DecimalType(volumeState));
}
if (volumeDbState != -90f) {
channel = new ChannelUID(getThing().getUID(), zoneToUpdate, CHANNEL_VOLUMEDB);
updateState(channel, new QuantityType<>(volumeDbState, Units.DECIBEL));
}
if (presetNumber != 0) {
logger.trace("Preset detected: {}", presetNumber);
updatePresets(presetNumber);
@ -624,6 +657,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
String powerState = targetObject.getPower();
String muteState = targetObject.getMute();
volumeState = targetObject.getVolume();
volumeDbState = targetObject.getVolumeDb();
maxVolumeState = targetObject.getMaxVolume();
inputState = targetObject.getInput();
soundProgramState = targetObject.getSoundProgram();
@ -633,6 +667,7 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
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);
@ -680,6 +715,11 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
updateState(channelUID, new DecimalType(volumeState));
}
break;
case CHANNEL_VOLUMEDB:
if (localZone.equals(zoneToUpdate)) {
updateState(channelUID, new QuantityType<>(volumeDbState, Units.DECIBEL));
}
break;
case CHANNEL_INPUT:
if (localZone.equals(zoneToUpdate)) {
updateState(channelUID, StringType.valueOf(inputState));
@ -1014,6 +1054,27 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
}
}
private void setVolumeDbLinkedDevice(float value, @Nullable String zone, String host) {
logger.trace("setVolumeDbLinkedDevice: {}", host);
int zoneNumLinkedDevice = getNumberOfZones(host);
for (int i = 1; i <= zoneNumLinkedDevice; i++) {
switch (i) {
case 1:
setVolumeDb(value, "main", host);
break;
case 2:
setVolumeDb(value, "zone2", host);
break;
case 3:
setVolumeDb(value, "zone3", host);
break;
case 4:
setVolumeDb(value, "zone4", host);
break;
}
}
}
public void updateMCLinkStatus() {
tmpString = getDistributionInfo(this.host);
@Nullable
@ -1140,6 +1201,31 @@ public class YamahaMusiccastHandler extends BaseThingHandler {
return makeRequest("Volume", host + YAMAHA_EXTENDED_CONTROL + zone + "/setVolume?volume=" + value);
}
/**
* Sets the volume in decibels (dB).
*
* @param value volume in dB (decibels)
* @param zone name of zone
* @param host hostname or ip address
* @return HTTP request
*/
private @Nullable String setVolumeDb(float value, @Nullable String zone, @Nullable String host) {
float volumeDbMin = Float.parseFloat(getThing().getConfiguration().get("volumeDbMin").toString());
float volumeDbMax = Float.parseFloat(getThing().getConfiguration().get("volumeDbMax").toString());
if (value < volumeDbMin) {
value = volumeDbMin;
}
if (value > volumeDbMax) {
value = volumeDbMax;
}
// Yamaha accepts only integer values with .0 or .5 at the end only (-20.5dB, -20.0dB) - at least on RX-S601D.
// The order matters here. We want to cast to integer first and then scale by 10.
// Effectively we're only allowing dB values with .0 at the end.
logger.trace("setVolumeDb: {} dB", value);
return makeRequest("Volume", host + YAMAHA_EXTENDED_CONTROL + zone + "/setActualVolume?mode=db&value=" + value);
}
private @Nullable String setInput(String value, @Nullable String zone, @Nullable String host) {
return makeRequest("setInput", host + YAMAHA_EXTENDED_CONTROL + zone + "/setInput?input=" + value);
}

View File

@ -0,0 +1,56 @@
/**
* 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.yamahamusiccast.internal.dto;
import com.google.gson.annotations.SerializedName;
/**
* This class represents the actual_volume object of the Status request requested from API or the UDP event from the
* Yamaha model/device.
*
* @author Florian Hotze - Initial contribution
*/
public class ActualVolume {
@SerializedName("mode")
private String mode;
@SerializedName("value")
private float value;
@SerializedName("unit")
private String unit;
public String getMode() {
if (mode == null) {
mode = "";
}
return mode;
}
/**
* Volume in decibels (dB).
*
* @return volume in decibels (dB)
*/
public float getValue() {
return value;
}
public String getUnit() {
if (unit == null) {
unit = "";
}
return unit;
}
}

View File

@ -18,6 +18,7 @@ import com.google.gson.annotations.SerializedName;
* This class represents the Status request requested from the Yamaha model/device via the API.
*
* @author Lennert Coopman - Initial contribution
* @author Florian Hotze - Add volume in decibel
*/
public class Status {
@ -34,6 +35,9 @@ public class Status {
@SerializedName("volume")
private int volume;
@SerializedName("actual_volume")
private ActualVolume actualVolume;
@SerializedName("max_volume")
private int maxVolume = 1;
@ -71,6 +75,17 @@ 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 int getMaxVolume() {
// if no value is returned, set to 1 to avoid division by zero
if (maxVolume == 0) {

View File

@ -18,6 +18,7 @@ import com.google.gson.annotations.SerializedName;
* This class represents the UDP event received from the Yamaha model/device.
*
* @author Lennert Coopman - Initial contribution
* @author Florian Hotze - Add volume in decibel
*/
public class UdpMessage {
@ -74,6 +75,8 @@ public class UdpMessage {
private String power;
@SerializedName("volume")
private int volume = 0;
@SerializedName("actual_volume")
private ActualVolume actualVolume;
@SerializedName("mute")
private String mute;
@SerializedName("input")
@ -106,6 +109,17 @@ 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 String getstatusUpdated() {
if (statusUpdated == null) {
statusUpdated = "";

View File

@ -16,10 +16,15 @@ thing-type.config.yamahamusiccast.device.defaultAfterMCLink.label = MC Link Defa
thing-type.config.yamahamusiccast.device.defaultAfterMCLink.description = Default value for client when MC Link is broken
thing-type.config.yamahamusiccast.device.defaultAfterMCLink.option.none = None
thing-type.config.yamahamusiccast.device.defaultAfterMCLink.option.net_radio = Net Radio
thing-type.config.yamahamusiccast.device.defaultAfterMCLink.option.tuner = Radio
thing-type.config.yamahamusiccast.device.host.label = Address
thing-type.config.yamahamusiccast.device.host.description = The IP address of the AVR to control.
thing-type.config.yamahamusiccast.device.syncVolume.label = Sync Volume
thing-type.config.yamahamusiccast.device.syncVolume.description = Sync Volume across linked Music Cast models
thing-type.config.yamahamusiccast.device.volumeDbMax.label = Maximum Volume
thing-type.config.yamahamusiccast.device.volumeDbMax.description = Highest volume in dB.
thing-type.config.yamahamusiccast.device.volumeDbMin.label = Minimum Volume
thing-type.config.yamahamusiccast.device.volumeDbMin.description = Lowest volume in dB.
# channel group types
@ -83,3 +88,5 @@ 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.volumeDB.label = Volume in dB
channel-type.yamahamusiccast.volumeDB.description = Volume channel - in decibel (dB) (-90 dB if not available)

View File

@ -29,7 +29,7 @@
<parameter name="syncVolume" type="boolean">
<label>Sync Volume</label>
<description>Sync Volume across linked Music Cast models</description>
<default>true</default>
<default>false</default>
</parameter>
<parameter name="defaultAfterMCLink" type="text">
<label>MC Link Default Value</label>
@ -38,8 +38,23 @@
<options>
<option value="none">None</option>
<option value="net_radio">Net Radio</option>
<option value="tuner">Radio</option>
</options>
</parameter>
<parameter name="volumeDbMin" type="decimal" required="false">
<label>Minimum Volume</label>
<description>Lowest volume in dB.</description>
<default>-80</default>
<advanced>true</advanced>
<unitLabel>dB</unitLabel>
</parameter>
<parameter name="volumeDbMax" type="decimal" required="false">
<label>Maximum Volume</label>
<description>Highest volume in dB.</description>
<default>12</default>
<advanced>true</advanced>
<unitLabel>dB</unitLabel>
</parameter>
</config-description>
</thing-type>
@ -78,6 +93,14 @@
<item-type>Number</item-type>
<label>Volume</label>
<description>Volume channel - 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>
<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>