[rotel] Extension of amplifier A14's channel list (#12447)

* A14: new channels: tcbypass, balance, speakera and speakerb
* Specific balance set command for models A1x
* Channels added on other models
* In state TCBYPASS ON: 1) Ignore user adjustments on BASS/TREBLE. 2) Reset BASS/TREBLE to 0.

Signed-off-by: Wilhelm Tonsern <wto.wit01@gmx.net>
Also-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
tonwi 2022-03-22 20:48:18 +01:00 committed by GitHub
parent 109ba0ec06
commit b347491d60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 558 additions and 83 deletions

View File

@ -162,25 +162,29 @@ The following channels are available:
| mainZone#line2 | Front Panel Line 2 | String | The second line displayed on the device front panel | |
| frequency | Current Frequency | Number | The current frequency (in kHz) for digital source input | |
| brightness | Front Panel Display Brightness | Dimmer | The backlight brightness level (in %) of the device front panel | |
| tcbypass | Tone Control Bypass | Switch | The user's bass-/treble-settings are bypassed | ON, OFF |
| balance | Stereo Balance Adjustment | Number | Adjust the balance | INCREASE, DECREASE, value |
| speakera | Speaker-A Adjustment | Switch | Turn on/off the speaker group A | ON, OFF |
| speakerb | Speaker-B Adjustment | Switch | Turn on/off the speaker group B | ON, OFF |
Here are the list of channels available for each thing type:
| Thing Type | Available channels |
|------------|---------------------------------------------------------------------------------------|
| a11 | power, source, volume, mute, bass, treble, brightness |
| a12 | power, source, volume, mute, bass, treble, frequency, brightness |
| a14 | power, source, volume, mute, bass, treble, frequency, brightness |
|------------|---------------------------------------------------------------------------------------------------------|
| a11 | power, source, volume, mute, bass, treble, brightness, tcbypass, balance, speakera, speakerb |
| a12 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb |
| a14 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb |
| cd11 | power, playControl, track, brightness |
| cd14 | power, playControl, track, brightness |
| ra11 | power, source, volume, mute, bass, treble, playControl, frequency, brightness |
| ra12 | power, source, volume, mute, bass, treble, playControl, frequency, brightness |
| ra1570 | power, source, volume, mute, bass, treble, playControl, frequency, brightness |
| ra1572 | power, source, volume, mute, bass, treble, frequency, brightness |
| ra1592 | power, source, volume, mute, bass, treble, frequency, brightness |
| ra11 | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance |
| ra12 | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance |
| ra1570 | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance, speakera, speakerb |
| ra1572 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb |
| ra1592 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb |
| rap1580 | power, source, dsp, volume, mute, brightness |
| rc1570 | power, source, volume, mute, bass, treble, playControl, frequency, brightness |
| rc1572 | power, source, volume, mute, bass, treble, frequency, brightness |
| rc1590 | power, source, volume, mute, bass, treble, frequency, brightness |
| rc1570 | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance |
| rc1572 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance |
| rc1590 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance |
| rcd1570 | power, playControl, brightness |
| rcd1572 | power, playControl, track, brightness |
| rcx1500 | power, source, volume, mute, playControl |
@ -221,6 +225,8 @@ Thing rotel:rsp1570:preamp "RSP-1570" [ serialPort="COM2" ]
Thing rotel:ra1592:preamp "RA-1592" [ serialPort="COM3" ]
Thing rotel:cd14:cd "CD14" [ serialPort="COM4" ]
Thing rotel:a14:amp "A14" [ serialPort="/dev/ttyUSB0" ]
```
example.things using serial over IP connection:
@ -282,6 +288,11 @@ Number amp_bass "Bass Adjustment [%d]" { channel="rotel:ra1592:preamp:bass" }
Number amp_treble "Treble Adjustment [%d]" { channel="rotel:ra1592:preamp:treble" }
Dimmer amp_brightness "Display brightness" { channel="rotel:ra1592:preamp:brightness" }
Switch amp_bypass "TCBypass" { channel="rotel:a14:amp:tcbypass" }
Number amp_balance "Balance Adjustment [%d]" { channel="rotel:a14:amp:balance" }
Switch amp_speakera "Speaker A" { channel="rotel:a14:amp:speakera" }
Switch amp_speakerb "Speaker B" { channel="rotel:a14:amp:speakerb" }
Switch cd_power "Power" { channel="rotel:cd14:cd:power" }
Player cd_control "Playback" { channel="rotel:cd14:cd:power" }
Number cd_track "Track [%d]" { channel="rotel:cd14:cd:power" }

View File

@ -148,6 +148,10 @@ public class RotelBindingConstants {
public static final String CHANNEL_ZONE4_SOURCE = "zone4#source";
public static final String CHANNEL_ZONE4_VOLUME = "zone4#volume";
public static final String CHANNEL_ZONE4_MUTE = "zone4#mute";
public static final String CHANNEL_TCBYPASS = "tcbypass";
public static final String CHANNEL_BALANCE = "balance";
public static final String CHANNEL_SPEAKER_A = "speakera";
public static final String CHANNEL_SPEAKER_B = "speakerb";
// List of all properties
public static final String PROPERTY_PROTOCOL = "protocol";

View File

@ -62,21 +62,27 @@ public enum RotelModel {
5, true, RotelFlagsMapping.MAPPING5),
RSX1562("RSX-1562", 115200, 2, 3, true, 96, true, null, false, RotelCommand.RECORD_FONCTION_SELECT, 4, (byte) 0xCC,
42, 5, true, RotelFlagsMapping.MAPPING5),
A11("A11", 115200, 4, 96, true, 10, false, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
A12("A12", 115200, 5, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
A14("A14", 115200, 5, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
A11("A11", 115200, 4, 96, true, 10, 15, false, -1, false, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
A12("A12", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
A14("A14", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
CD11("CD11", 57600, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
CD14("CD14", 57600, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
RA11("RA-11", 115200, 6, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RA12("RA-12", 115200, 6, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RA1570("RA-1570", 115200, 7, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RA1572("RA-1572", 115200, 8, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RA1592("RA-1592", 115200, 9, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RA11("RA-11", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RA12("RA-12", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RA1570("RA-1570", 115200, 7, 96, true, 10, 15, true, -1, true, true, false, 6, 0,
RotelConnector.SPECIAL_CHARACTERS),
RA1572("RA-1572", 115200, 8, 96, true, 10, 15, false, -1, true, true, true, 6, 0,
RotelConnector.SPECIAL_CHARACTERS),
RA1592("RA-1592", 115200, 9, 96, true, 10, 15, false, -1, true, true, true, 6, 0,
RotelConnector.SPECIAL_CHARACTERS),
RAP1580("RAP-1580", 115200, 11, 96, true, null, false, 5, false, false, -10, 10,
RotelConnector.NO_SPECIAL_CHARACTERS),
RC1570("RC-1570", 115200, 7, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RC1572("RC-1572", 115200, 8, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RC1590("RC-1590", 115200, 9, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RC1570("RC-1570", 115200, 7, 96, true, 10, 15, true, -1, true, false, false, 6, 0,
RotelConnector.SPECIAL_CHARACTERS),
RC1572("RC-1572", 115200, 8, 96, true, 10, 15, false, -1, true, false, true, 6, 0,
RotelConnector.SPECIAL_CHARACTERS),
RC1590("RC-1590", 115200, 9, 96, true, 10, 15, false, -1, true, false, true, 6, 0,
RotelConnector.SPECIAL_CHARACTERS),
RCD1570("RCD-1570", 115200, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
RCD1572("RCD-1572", 57600, 0, null, false, null, true, -1, false, true, 6, 0,
RotelConnector.SPECIAL_CHARACTERS_RCD1572),
@ -118,6 +124,8 @@ public enum RotelModel {
private boolean charsBeforeFlags;
private RotelFlagsMapping flagsMapping;
private byte[][] specialCharacters;
private @Nullable Integer balanceLevelMax;
private boolean getSpeakerGroupsAvailable;
/**
* Constructor
@ -144,8 +152,8 @@ public enum RotelModel {
@Nullable RotelCommand zoneSelectCmd, int dspCategory, byte deviceId, int respNbChars, int respNbFlags,
boolean charsBeforeFlags, RotelFlagsMapping flagsMapping) {
this(name, baudRate, RotelCommand.DISPLAY_REFRESH, sourceCategory, nbAdditionalZones, additionalCommands,
volumeMax, directVolume, toneLevelMax, playControl, zoneSelectCmd, dspCategory, false, false, null,
null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping,
volumeMax, directVolume, toneLevelMax, null, playControl, zoneSelectCmd, dspCategory, false, false,
false, null, null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping,
RotelConnector.NO_SPECIAL_CHARACTERS);
}
@ -170,11 +178,40 @@ public enum RotelModel {
@Nullable Integer toneLevelMax, boolean playControl, int dspCategory, boolean getFrequencyAvailable,
boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax,
byte[][] specialCharacters) {
this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax,
playControl, null, dspCategory, getFrequencyAvailable, getDimmerLevelAvailable, diummerLevelMin,
this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax, null,
playControl, null, dspCategory, getFrequencyAvailable, false, getDimmerLevelAvailable, diummerLevelMin,
diummerLevelMax, (byte) 0, 0, 0, false, RotelFlagsMapping.NO_MAPPING, specialCharacters);
}
/**
* Constructor
*
* @param name the model name
* @param baudRate the baud rate to be used for the RS232 communication
* @param sourceCategory the category from {@link RotelSource}
* @param volumeMax the maximum volume or null if no volume management is available
* @param directVolume true if a command to set the volume with a value is available
* @param toneLevelMax the maximum tone level or null if no bass/treble management is available
* @param balanceLevelMax the maximum balance level or null if no balance management is available
* @param playControl true if control of source playback is available
* @param dspCategory the category from {@link RotelDsp}
* @param getFrequencyAvailable true if the command to get the frequency for digital source input is available
* @param getSpeakerGroupsAvailable true if the command to switch speaker groups is available
* @param getDimmerLevelAvailable true if the command to get the front display dimmer level is available
* @param diummerLevelMin the minimum front display dimmer level or null if dimmer control is unavailable
* @param diummerLevelMax the maximum front display dimmer level or null if dimmer control is unavailable
* @param specialCharacters the table of special characters that can be found in the standard response message
*/
private RotelModel(String name, int baudRate, int sourceCategory, @Nullable Integer volumeMax, boolean directVolume,
@Nullable Integer toneLevelMax, @Nullable Integer balanceLevelMax, boolean playControl, int dspCategory,
boolean getFrequencyAvailable, boolean getSpeakerGroupsAvailable, boolean getDimmerLevelAvailable,
@Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax, byte[][] specialCharacters) {
this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax,
balanceLevelMax, playControl, null, dspCategory, getFrequencyAvailable, getSpeakerGroupsAvailable,
getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, (byte) 0, 0, 0, false,
RotelFlagsMapping.NO_MAPPING, specialCharacters);
}
/**
* Constructor
*
@ -187,10 +224,12 @@ public enum RotelModel {
* @param volumeMax the maximum volume or null if no volume management is available
* @param directVolume true if a command to set the volume with a value is available
* @param toneLevelMax the maximum tone level or null if no bass/treble management is available
* @param balanceLevelMax the maximum balance level or null if no balance management is available
* @param playControl true if control of source playback is available
* @param zoneSelectCmd the command to be used to select a zone
* @param dspCategory the category from {@link RotelDsp}
* @param getFrequencyAvailable true if the command to get the frequency for digital source input is available
* @param getSpeakerGroupsAvailable true if the command to switch speaker groups is available
* @param getDimmerLevelAvailable true if the command to get the front display dimmer level is available
* @param diummerLevelMin the minimum front display dimmer level or null if dimmer control is unavailable
* @param diummerLevelMax the maximum front display dimmer level or null if dimmer control is unavailable
@ -203,8 +242,9 @@ public enum RotelModel {
*/
private RotelModel(String name, int baudRate, RotelCommand powerStateCmd, int sourceCategory, int nbAdditionalZones,
boolean additionalCommands, @Nullable Integer volumeMax, boolean directVolume,
@Nullable Integer toneLevelMax, boolean playControl, @Nullable RotelCommand zoneSelectCmd, int dspCategory,
boolean getFrequencyAvailable, boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin,
@Nullable Integer toneLevelMax, @Nullable Integer balanceLevelMax, boolean playControl,
@Nullable RotelCommand zoneSelectCmd, int dspCategory, boolean getFrequencyAvailable,
boolean getSpeakerGroupsAvailable, boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin,
@Nullable Integer diummerLevelMax, byte deviceId, int respNbChars, int respNbFlags,
boolean charsBeforeFlags, RotelFlagsMapping flagsMapping, byte[][] specialCharacters) {
this.name = name;
@ -216,10 +256,12 @@ public enum RotelModel {
this.volumeMax = volumeMax;
this.directVolume = directVolume;
this.toneLevelMax = toneLevelMax;
this.balanceLevelMax = balanceLevelMax;
this.playControl = playControl;
this.zoneSelectCmd = zoneSelectCmd;
this.dspCategory = dspCategory;
this.getFrequencyAvailable = getFrequencyAvailable;
this.getSpeakerGroupsAvailable = getSpeakerGroupsAvailable;
this.getDimmerLevelAvailable = getDimmerLevelAvailable;
this.diummerLevelMin = diummerLevelMin;
this.diummerLevelMax = diummerLevelMax;
@ -386,6 +428,34 @@ public enum RotelModel {
return toneLevelMax != null ? toneLevelMax.intValue() : 0;
}
/**
* Inform whether balance control is available
*
* @return true if balance control is available
*/
public boolean hasBalanceControl() {
return balanceLevelMax != null;
}
/**
* Get the maximum balance level
*
* @return the maximum balance level or 0
*/
public int getBalanceLevelMax() {
Integer balanceLevelMax = this.balanceLevelMax;
return balanceLevelMax != null ? balanceLevelMax.intValue() : 0;
}
/**
* Inform whether the command to switch speaker groups is available
*
* @return true if the command is available
*/
public boolean hasSpeakerGroups() {
return getSpeakerGroupsAvailable;
}
/**
* Inform whether the command to get the current frequency for digital source input is available
*

View File

@ -227,12 +227,30 @@ public enum RotelCommand {
TRACK_FORWARD("Track Forward", RotelConnector.PRIMARY_CMD, (byte) 0x09, "track_fwd", "trkf"),
TRACK_BACKWORD("Track Backward", RotelConnector.PRIMARY_CMD, (byte) 0x08, "track_back", "trkb"),
TRACK("Request current CD track number", null, "track"),
FREQUENCY("Request current frequency for digital source input", "get_current_freq", "freq"),
FREQUENCY("Request current frequency for digital source input", "get_current_freq", "freq?"),
DISPLAY_REFRESH("Display Refresh", RotelConnector.PRIMARY_CMD, (byte) 0xFF),
DIMMER_LEVEL_GET("Request current front display dimmer level", "get_current_dimmer", "dimmer"),
DIMMER_LEVEL_GET("Request current front display dimmer level", "get_current_dimmer", "dimmer?"),
DIMMER_LEVEL_SET("Set front display dimmer to level", "dimmer_", "dimmer_"),
UPDATE_AUTO("Set Update to Auto", "display_update_auto", "rs232_update_on"),
UPDATE_MANUAL("Set Update to Manual", "display_update_manual", "rs232_update_off");
UPDATE_MANUAL("Set Update to Manual", "display_update_manual", "rs232_update_off"),
TONE_CONTROLS_ON("Tone Controls On", "tone_on", null),
TONE_CONTROLS_OFF("Tone Controls Off", "tone_off", null),
TONE_CONTROLS("Request current tone control state", "get_tone", null),
TCBYPASS_ON("Bypass On", null, "bypass_on"),
TCBYPASS_OFF("Bypass Off", null, "bypass_off"),
TCBYPASS("Request current tone bypass state", null, "bypass?"),
BALANCE_RIGHT("Balance Right", "balance_right", "balance_r"),
BALANCE_LEFT("Balance Left", "balance_left", "balance_l"),
BALANCE_SET("Set Balance to level", "balance_", "balance_"),
BALANCE_SET_FIX("Set Balance to level", "balance_", "balance_"),
BALANCE("Request current balance setting", "get_balance", "balance?"),
SPEAKER_A_TOGGLE("Toggle Speaker A Output", RotelConnector.PRIMARY_CMD, (byte) 0x50, "speaker_a", "speaker_a"),
SPEAKER_A_ON("Set Speaker A Output", "speaker_a_on", "speaker_a_on"),
SPEAKER_A_OFF("Unset Speaker A Output", "speaker_a_off", "speaker_a_off"),
SPEAKER_B_TOGGLE("Toggle Speaker B Output", RotelConnector.PRIMARY_CMD, (byte) 0x51, "speaker_b", "speaker_b"),
SPEAKER_B_ON("Set Speaker B Output", "speaker_b_on", "speaker_b_on"),
SPEAKER_B_OFF("Unset Speaker B Output", "speaker_b_off", "speaker_b_off"),
SPEAKER("Request current active speaker outputs", "get_current_speaker", "speaker?");
public static final byte PRIMARY_COMMAND = (byte) 0x10;

View File

@ -136,6 +136,10 @@ public abstract class RotelConnector {
public static final String KEY_DSP_MODE = "dsp_mode";
public static final String KEY_DIMMER = "dimmer";
public static final String KEY_FREQ = "freq";
public static final String KEY_TONE = "tone";
public static final String KEY_TCBYPASS = "bypass";
public static final String KEY_BALANCE = "balance";
public static final String KEY_SPEAKER = "speaker";
// Special keys used by the binding
public static final String KEY_LINE1 = "line1";
@ -171,6 +175,9 @@ public abstract class RotelConnector {
public static final String PAUSE = "pause";
public static final String STOP = "stop";
private static final String SOURCE = "source";
public static final String MSG_VALUE_SPEAKER_A = "a";
public static final String MSG_VALUE_SPEAKER_B = "b";
public static final String MSG_VALUE_SPEAKER_AB = "a_b";
private RotelModel model;
private RotelProtocol protocol;
@ -458,6 +465,27 @@ public abstract class RotelConnector {
messageStr += String.format("-%02d", -value);
}
break;
case BALANCE_SET:
if (value == 0) {
messageStr += "000";
} else if (value > 0) {
messageStr += String.format("R%02d", value);
} else {
messageStr += String.format("L%02d", -value);
}
break;
case BALANCE_SET_FIX:
// Firmware for models A1x does not follow strictly the Rotel specification
// The firmware expects values like r05 or l04 while the specification mentions
// R05 and L04
if (value == 0) {
messageStr += "000";
} else if (value > 0) {
messageStr += String.format("r%02d", value);
} else {
messageStr += String.format("l%02d", -value);
}
break;
case DIMMER_LEVEL_SET:
if (value > 0 && model.getDimmerLevelMin() < 0) {
messageStr += String.format("+%d", value);

View File

@ -75,6 +75,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
private static final RotelModel DEFAULT_MODEL = RotelModel.RSP1066;
private static final long POLLING_INTERVAL = TimeUnit.SECONDS.toSeconds(60);
private static final boolean USE_SIMULATED_DEVICE = false;
private static final int SLEEP_INTV = 30;
private @Nullable ScheduledFuture<?> reconnectJob;
private @Nullable ScheduledFuture<?> powerOnJob;
@ -125,6 +126,13 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
private String frontPanelLine1 = "";
private String frontPanelLine2 = "";
private int brightness;
private boolean tcbypass;
private int balance;
private int minBalanceLevel;
private int maxBalanceLevel;
private boolean speakera;
private boolean speakerb;
private boolean useFixedBalanceCmd;
private Object sequenceLock = new Object();
@ -191,12 +199,15 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
break;
case THING_TYPE_ID_A11:
rotelModel = RotelModel.A11;
useFixedBalanceCmd = true;
break;
case THING_TYPE_ID_A12:
rotelModel = RotelModel.A12;
useFixedBalanceCmd = true;
break;
case THING_TYPE_ID_A14:
rotelModel = RotelModel.A14;
useFixedBalanceCmd = true;
break;
case THING_TYPE_ID_CD11:
rotelModel = RotelModel.CD11;
@ -312,6 +323,12 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
"Set minValue to {} and maxValue to {} for your sitemap widget attached to your bass or treble item.",
minToneLevel, maxToneLevel);
}
if (rotelModel.hasBalanceControl()) {
maxBalanceLevel = rotelModel.getBalanceLevelMax();
minBalanceLevel = -maxBalanceLevel;
logger.info("Set minValue to {} and maxValue to {} for your sitemap widget attached to your balance item.",
minBalanceLevel, maxBalanceLevel);
}
// Check configuration settings
String configError = null;
@ -519,6 +536,18 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
: src.getCommand();
if (cmd != null) {
connector.sendCommand(cmd);
if (connector.getModel().canGetFrequency()) {
// send <new-source> returns
// 1.) the selected <new-source>
// 2.) the used frequency
// BUT:
// at response-time the frequency has the value of <old-source>
// so we must wait a short moment to get the frequency of <new-source>
Thread.sleep(1000);
connector.sendCommand(RotelCommand.FREQUENCY);
Thread.sleep(100);
updateChannelState(CHANNEL_FREQUENCY);
}
} else {
success = false;
logger.debug("Command {} from channel {} failed: undefined source command", command,
@ -788,6 +817,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
if (!isPowerOn()) {
success = false;
logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
} else if (tcbypass) {
logger.debug("Command {} from channel {} ignored: tone control bypass is ON", command,
channel);
updateChannelState(CHANNEL_BASS);
} else {
handleToneCmd(bass, channel, command, 2, RotelCommand.BASS_UP, RotelCommand.BASS_DOWN,
RotelCommand.BASS_SET);
@ -798,6 +831,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
if (!isPowerOn()) {
success = false;
logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
} else if (tcbypass) {
logger.debug("Command {} from channel {} ignored: tone control bypass is ON", command,
channel);
updateChannelState(CHANNEL_TREBLE);
} else {
handleToneCmd(treble, channel, command, 1, RotelCommand.TREBLE_UP, RotelCommand.TREBLE_DOWN,
RotelCommand.TREBLE_SET);
@ -815,7 +852,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
&& connector.getModel() != RotelModel.RCD1570
&& connector.getModel() != RotelModel.RCD1572
&& connector.getModel() != RotelModel.RCX1500) {
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
connector.sendCommand(RotelCommand.PLAY_STATUS);
}
} else if (command instanceof NextPreviousType && command == NextPreviousType.NEXT) {
@ -845,6 +882,55 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
logger.debug("Command {} from channel {} failed: invalid command value", command, channel);
}
break;
case CHANNEL_TCBYPASS:
if (!isPowerOn()) {
success = false;
logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
} else if (!connector.getModel().hasToneControl()
|| connector.getProtocol() == RotelProtocol.HEX) {
success = false;
logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
} else {
handleTcbypassCmd(channel, command,
connector.getProtocol() == RotelProtocol.ASCII_V1 ? RotelCommand.TONE_CONTROLS_OFF
: RotelCommand.TCBYPASS_ON,
connector.getProtocol() == RotelProtocol.ASCII_V1 ? RotelCommand.TONE_CONTROLS_ON
: RotelCommand.TCBYPASS_OFF);
}
break;
case CHANNEL_BALANCE:
if (!isPowerOn()) {
success = false;
logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
} else if (!connector.getModel().hasBalanceControl()
|| connector.getProtocol() == RotelProtocol.HEX) {
success = false;
logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
} else {
handleBalanceCmd(channel, command, RotelCommand.BALANCE_LEFT, RotelCommand.BALANCE_RIGHT,
useFixedBalanceCmd ? RotelCommand.BALANCE_SET_FIX : RotelCommand.BALANCE_SET);
}
break;
case CHANNEL_SPEAKER_A:
if (!isPowerOn()) {
success = false;
logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
} else {
handleSpeakerCmd(connector.getProtocol() == RotelProtocol.HEX, channel, command,
RotelCommand.SPEAKER_A_ON, RotelCommand.SPEAKER_A_OFF,
RotelCommand.SPEAKER_A_TOGGLE);
}
break;
case CHANNEL_SPEAKER_B:
if (!isPowerOn()) {
success = false;
logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
} else {
handleSpeakerCmd(connector.getProtocol() == RotelProtocol.HEX, channel, command,
RotelCommand.SPEAKER_B_ON, RotelCommand.SPEAKER_B_OFF,
RotelCommand.SPEAKER_B_TOGGLE);
}
break;
default:
success = false;
logger.debug("Command {} from channel {} failed: nnexpected command", command, channel);
@ -992,6 +1078,92 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
}
}
/**
* Handle a tcbypass command (only for ASCII protocol)
*
* @param channel the channel
* @param command the received channel command (OnOffType)
* @param onCmd the command to be sent to the device to bypass_on
* @param offCmd the command to be sent to the device to bypass_off
*
* @throws RotelException in case of communication error with the device
*/
private void handleTcbypassCmd(String channel, Command command, RotelCommand onCmd, RotelCommand offCmd)
throws RotelException, InterruptedException {
if (command instanceof OnOffType) {
if (command == OnOffType.ON) {
connector.sendCommand(onCmd);
bass = 0;
treble = 0;
updateChannelState(CHANNEL_BASS);
updateChannelState(CHANNEL_TREBLE);
} else if (command == OnOffType.OFF) {
connector.sendCommand(offCmd);
Thread.sleep(200);
connector.sendCommand(RotelCommand.BASS);
Thread.sleep(200);
connector.sendCommand(RotelCommand.TREBLE);
}
} else {
logger.debug("Command {} from channel {} failed: invalid command value", command, channel);
}
}
/**
* Handle a speaker command
*
* @param onlyToggle true if only the toggle command must be used
* @param channel the channel
* @param command the received channel command (OnOffType)
* @param onCmd the command to be sent to the device to speaker_x_on
* @param offCmd the command to be sent to the device to speaker_x_off
* @param toggleCmd the command to be sent to the device to toggle the speaker_x state
*
* @throws RotelException in case of communication error with the device
*/
private void handleSpeakerCmd(boolean onlyToggle, String channel, Command command, RotelCommand onCmd,
RotelCommand offCmd, RotelCommand toggleCmd) throws RotelException {
if (command instanceof OnOffType) {
if (onlyToggle) {
connector.sendCommand(toggleCmd);
} else if (command == OnOffType.ON) {
connector.sendCommand(onCmd);
} else if (command == OnOffType.OFF) {
connector.sendCommand(offCmd);
}
} else {
logger.debug("Command {} from channel {} failed: invalid command value", command, channel);
}
}
/**
* Handle a tone balance adjustment command (left or right) (only for ASCII protocol)
*
* @param channel the channel
* @param command the received channel command (IncreaseDecreaseType or DecimalType)
* @param rightCmd the command to be sent to the device to "increase" balance (shift to the right side)
* @param leftCmd the command to be sent to the device to "decrease" balance (shift to the left side)
* @param setCmd the command to be sent to the device to set the balance at a value
*
* @throws RotelException in case of communication error with the device
* @throws InterruptedException in case of interruption during a thread sleep
*/
private void handleBalanceCmd(String channel, Command command, RotelCommand leftCmd, RotelCommand rightCmd,
RotelCommand setCmd) throws RotelException, InterruptedException {
if (command instanceof IncreaseDecreaseType && command == IncreaseDecreaseType.INCREASE) {
connector.sendCommand(rightCmd);
} else if (command instanceof IncreaseDecreaseType && command == IncreaseDecreaseType.DECREASE) {
connector.sendCommand(leftCmd);
} else if (command instanceof DecimalType) {
int value = ((DecimalType) command).intValue();
if (value >= minBalanceLevel && value <= maxBalanceLevel) {
connector.sendCommand(setCmd, value);
}
} else {
logger.debug("Command {} from channel {} failed: invalid command value", command, channel);
}
}
/**
* Run a sequence of commands to display the current tone level (bass or treble) on the device front panel
*
@ -1377,6 +1549,67 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
case RotelConnector.KEY_UPDATE_MODE:
case RotelConnector.KEY_DISPLAY_UPDATE:
break;
case RotelConnector.KEY_TONE:
if (RotelConnector.MSG_VALUE_ON.equalsIgnoreCase(value)) {
tcbypass = false;
updateChannelState(CHANNEL_TCBYPASS);
} else if (RotelConnector.MSG_VALUE_OFF.equalsIgnoreCase(value)) {
tcbypass = true;
updateChannelState(CHANNEL_TCBYPASS);
} else {
throw new RotelException("Invalid value");
}
break;
case RotelConnector.KEY_TCBYPASS:
if (RotelConnector.MSG_VALUE_ON.equalsIgnoreCase(value)) {
tcbypass = true;
updateChannelState(CHANNEL_TCBYPASS);
} else if (RotelConnector.MSG_VALUE_OFF.equalsIgnoreCase(value)) {
tcbypass = false;
updateChannelState(CHANNEL_TCBYPASS);
} else {
throw new RotelException("Invalid value");
}
break;
case RotelConnector.KEY_BALANCE:
if (RotelConnector.MSG_VALUE_MIN.equalsIgnoreCase(value)) {
balance = minBalanceLevel;
} else if (RotelConnector.MSG_VALUE_MAX.equalsIgnoreCase(value)) {
balance = maxBalanceLevel;
} else if (value.toUpperCase().startsWith("L")) {
balance = -Integer.parseInt(value.substring(1));
} else if (value.toLowerCase().startsWith("R")) {
balance = Integer.parseInt(value.substring(1));
} else {
balance = Integer.parseInt(value);
}
updateChannelState(CHANNEL_BALANCE);
break;
case RotelConnector.KEY_SPEAKER:
if (RotelConnector.MSG_VALUE_SPEAKER_A.equalsIgnoreCase(value)) {
speakera = true;
speakerb = false;
updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B);
} else if (RotelConnector.MSG_VALUE_SPEAKER_B.equalsIgnoreCase(value)) {
speakera = false;
speakerb = true;
updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B);
} else if (RotelConnector.MSG_VALUE_SPEAKER_AB.equalsIgnoreCase(value)) {
speakera = true;
speakerb = true;
updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B);
} else if (RotelConnector.MSG_VALUE_OFF.equalsIgnoreCase(value)) {
speakera = false;
speakerb = false;
updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B);
} else {
throw new RotelException("Invalid value");
}
break;
default:
logger.debug("onNewMessageEvent: unhandled key {}", key);
break;
@ -1425,6 +1658,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
updateChannelState(CHANNEL_TRACK);
updateChannelState(CHANNEL_FREQUENCY);
updateChannelState(CHANNEL_BRIGHTNESS);
updateChannelState(CHANNEL_TCBYPASS);
updateChannelState(CHANNEL_BALANCE);
updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B);
}
/**
@ -1582,11 +1819,11 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
&& connector.getModel() != RotelModel.RSP1576
&& connector.getModel() != RotelModel.RSP1582) {
connector.sendCommand(RotelCommand.UPDATE_AUTO);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasSourceControl()) {
connector.sendCommand(RotelCommand.SOURCE);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasVolumeControl() || connector.getModel().hasToneControl()) {
if (connector.getModel().hasVolumeControl()
@ -1594,96 +1831,116 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
&& connector.getModel() != RotelModel.RSP1576
&& connector.getModel() != RotelModel.RSP1582) {
connector.sendCommand(RotelCommand.VOLUME_GET_MIN);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
connector.sendCommand(RotelCommand.VOLUME_GET_MAX);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasToneControl()) {
connector.sendCommand(RotelCommand.TONE_MAX);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
// Wait enough to be sure to get the min/max values requested just before
Thread.sleep(250);
if (connector.getModel().hasVolumeControl()) {
connector.sendCommand(RotelCommand.VOLUME_GET);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
if (connector.getModel() != RotelModel.RA11
&& connector.getModel() != RotelModel.RA12
&& connector.getModel() != RotelModel.RCX1500) {
connector.sendCommand(RotelCommand.MUTE);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
}
if (connector.getModel().hasToneControl()) {
connector.sendCommand(RotelCommand.BASS);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
connector.sendCommand(RotelCommand.TREBLE);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
connector.sendCommand(RotelCommand.TONE_CONTROLS);
Thread.sleep(SLEEP_INTV);
}
}
if (connector.getModel().hasBalanceControl()) {
connector.sendCommand(RotelCommand.BALANCE);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasPlayControl()) {
if (connector.getModel() != RotelModel.RCD1570
&& connector.getModel() != RotelModel.RCD1572
&& (connector.getModel() != RotelModel.RCX1500
|| !source.getName().equals("CD"))) {
connector.sendCommand(RotelCommand.PLAY_STATUS);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
} else {
connector.sendCommand(RotelCommand.CD_PLAY_STATUS);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
}
if (connector.getModel().hasDspControl()) {
connector.sendCommand(RotelCommand.DSP_MODE);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().canGetFrequency()) {
connector.sendCommand(RotelCommand.FREQUENCY);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasDimmerControl() && connector.getModel().canGetDimmerLevel()) {
connector.sendCommand(RotelCommand.DIMMER_LEVEL_GET);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasSpeakerGroups()) {
connector.sendCommand(RotelCommand.SPEAKER);
Thread.sleep(SLEEP_INTV);
}
break;
case ASCII_V2:
connector.sendCommand(RotelCommand.UPDATE_AUTO);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
if (connector.getModel().hasSourceControl()) {
connector.sendCommand(RotelCommand.SOURCE);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasVolumeControl()) {
connector.sendCommand(RotelCommand.VOLUME_GET);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
connector.sendCommand(RotelCommand.MUTE);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasToneControl()) {
connector.sendCommand(RotelCommand.BASS);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
connector.sendCommand(RotelCommand.TREBLE);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
connector.sendCommand(RotelCommand.TCBYPASS);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasBalanceControl()) {
connector.sendCommand(RotelCommand.BALANCE);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasPlayControl()) {
connector.sendCommand(RotelCommand.PLAY_STATUS);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
if (source.getName().equals("CD") && !connector.getModel().hasSourceControl()) {
connector.sendCommand(RotelCommand.TRACK);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
}
if (connector.getModel().hasDspControl()) {
connector.sendCommand(RotelCommand.DSP_MODE);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().canGetFrequency()) {
connector.sendCommand(RotelCommand.FREQUENCY);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasDimmerControl() && connector.getModel().canGetDimmerLevel()) {
connector.sendCommand(RotelCommand.DIMMER_LEVEL_GET);
Thread.sleep(50);
Thread.sleep(SLEEP_INTV);
}
if (connector.getModel().hasSpeakerGroups()) {
connector.sendCommand(RotelCommand.SPEAKER);
Thread.sleep(SLEEP_INTV);
}
break;
}
@ -1907,18 +2164,19 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
switch (channel) {
case CHANNEL_POWER:
case CHANNEL_MAIN_POWER:
if (power != null) {
state = power ? OnOffType.ON : OnOffType.OFF;
Boolean po = power;
if (po != null) {
state = OnOffType.from(po.booleanValue());
}
break;
case CHANNEL_ZONE2_POWER:
state = powerZone2 ? OnOffType.ON : OnOffType.OFF;
state = OnOffType.from(powerZone2);
break;
case CHANNEL_ZONE3_POWER:
state = powerZone3 ? OnOffType.ON : OnOffType.OFF;
state = OnOffType.from(powerZone3);
break;
case CHANNEL_ZONE4_POWER:
state = powerZone4 ? OnOffType.ON : OnOffType.OFF;
state = OnOffType.from(powerZone4);
break;
case CHANNEL_SOURCE:
case CHANNEL_MAIN_SOURCE:
@ -1998,22 +2256,22 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
case CHANNEL_MUTE:
case CHANNEL_MAIN_MUTE:
if (isPowerOn()) {
state = mute ? OnOffType.ON : OnOffType.OFF;
state = OnOffType.from(mute);
}
break;
case CHANNEL_ZONE2_MUTE:
if (powerZone2) {
state = muteZone2 ? OnOffType.ON : OnOffType.OFF;
state = OnOffType.from(muteZone2);
}
break;
case CHANNEL_ZONE3_MUTE:
if (powerZone3) {
state = muteZone3 ? OnOffType.ON : OnOffType.OFF;
state = OnOffType.from(muteZone3);
}
break;
case CHANNEL_ZONE4_MUTE:
if (powerZone4) {
state = muteZone4 ? OnOffType.ON : OnOffType.OFF;
state = OnOffType.from(muteZone4);
}
break;
case CHANNEL_BASS:
@ -2066,6 +2324,26 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
state = new PercentType(BigDecimal.valueOf(dimmerPct));
}
break;
case CHANNEL_TCBYPASS:
if (isPowerOn()) {
state = OnOffType.from(tcbypass);
}
break;
case CHANNEL_BALANCE:
if (isPowerOn()) {
state = new DecimalType(balance);
}
break;
case CHANNEL_SPEAKER_A:
if (isPowerOn()) {
state = OnOffType.from(speakera);
}
break;
case CHANNEL_SPEAKER_B:
if (isPowerOn()) {
state = OnOffType.from(speakerb);
}
break;
default:
break;
}

View File

@ -319,4 +319,5 @@
<description>@text/config.inputLabelMulti.description</description>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@ -110,6 +110,14 @@ channel-type.rotel.treble.label = Treble Adjustment
channel-type.rotel.treble.description = Adjust the treble
channel-type.rotel.volumeUpDown.label = Volume
channel-type.rotel.volumeUpDown.description = Increase or decrease the volume
channel-type.rotel.tcbypass.label = Tone Control Bypass
channel-type.rotel.tcbypass.description = The user's bass-/treble-settings are bypassed
channel-type.rotel.balance.label = Balance Adjustment
channel-type.rotel.balance.description = Adjust the speakers left-right balance
channel-type.rotel.speakera.label = Speaker-A Adjustment
channel-type.rotel.speakera.description = Turn on/off the speaker group A
channel-type.rotel.speakerb.label = Speaker-B Adjustment
channel-type.rotel.speakerb.description = Turn on/off the speaker group B
# thing type configuration

View File

@ -17,6 +17,10 @@
<channel id="bass" typeId="bass"/>
<channel id="treble" typeId="treble"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
<channel id="speakera" typeId="speakera"/>
<channel id="speakerb" typeId="speakerb"/>
</channels>
<properties>

View File

@ -18,6 +18,10 @@
<channel id="treble" typeId="treble"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
<channel id="speakera" typeId="speakera"/>
<channel id="speakerb" typeId="speakerb"/>
</channels>
<properties>

View File

@ -18,6 +18,10 @@
<channel id="treble" typeId="treble"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
<channel id="speakera" typeId="speakera"/>
<channel id="speakerb" typeId="speakerb"/>
</channels>
<properties>

View File

@ -201,4 +201,27 @@
<description>The backlight brightness level (in %) of the device front panel</description>
</channel-type>
<channel-type id="tcbypass" advanced="true">
<item-type>Switch</item-type>
<label>Tone Control Bypass</label>
<description>The user's bass-/treble-settings are bypassed</description>
</channel-type>
<channel-type id="balance" advanced="true">
<item-type>Number</item-type>
<label>Balance Adjustment</label>
<description>Adjust the speakers left-right balance</description>
</channel-type>
<channel-type id="speakera" advanced="true">
<item-type>Switch</item-type>
<label>Speaker-A Adjustment</label>
<description>Turn on/off the speaker group A</description>
</channel-type>
<channel-type id="speakerb" advanced="true">
<item-type>Switch</item-type>
<label>Speaker-B Adjustment</label>
<description>Turn on/off the speaker group B</description>
</channel-type>
</thing:thing-descriptions>

View File

@ -19,6 +19,8 @@
<channel id="playControl" typeId="system.media-control"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
</channels>
<properties>

View File

@ -19,6 +19,8 @@
<channel id="playControl" typeId="system.media-control"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
</channels>
<properties>

View File

@ -19,6 +19,10 @@
<channel id="playControl" typeId="system.media-control"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
<channel id="speakera" typeId="speakera"/>
<channel id="speakerb" typeId="speakerb"/>
</channels>
<properties>

View File

@ -18,6 +18,10 @@
<channel id="treble" typeId="treble"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
<channel id="speakera" typeId="speakera"/>
<channel id="speakerb" typeId="speakerb"/>
</channels>
<config-description-ref uri="thing-type:rotel:serialandipandprotocol"/>

View File

@ -18,6 +18,10 @@
<channel id="treble" typeId="treble"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
<channel id="speakera" typeId="speakera"/>
<channel id="speakerb" typeId="speakerb"/>
</channels>
<config-description-ref uri="thing-type:rotel:serialandipandprotocol"/>

View File

@ -19,6 +19,8 @@
<channel id="playControl" typeId="system.media-control"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
</channels>
<properties>

View File

@ -18,6 +18,8 @@
<channel id="treble" typeId="treble"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
</channels>
<config-description-ref uri="thing-type:rotel:serialandipandprotocol"/>

View File

@ -18,6 +18,8 @@
<channel id="treble" typeId="treble"/>
<channel id="frequency" typeId="frequency"/>
<channel id="brightness" typeId="brightness"/>
<channel id="tcbypass" typeId="tcbypass"/>
<channel id="balance" typeId="balance"/>
</channels>
<config-description-ref uri="thing-type:rotel:serialandipandprotocol"/>