public static final String THING_TYPE_ID_RT1570 = "rt1570";
public static final String THING_TYPE_ID_T11 = "t11";
public static final String THING_TYPE_ID_T14 = "t14";
+ public static final String THING_TYPE_ID_C8 = "c8";
public static final String THING_TYPE_ID_M8 = "m8";
public static final String THING_TYPE_ID_P5 = "p5";
public static final String THING_TYPE_ID_S5 = "s5";
public static final ThingTypeUID THING_TYPE_RT1570 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_RT1570);
public static final ThingTypeUID THING_TYPE_T11 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_T11);
public static final ThingTypeUID THING_TYPE_T14 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_T14);
+ public static final ThingTypeUID THING_TYPE_C8 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_C8);
public static final ThingTypeUID THING_TYPE_M8 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_M8);
public static final ThingTypeUID THING_TYPE_P5 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_P5);
public static final ThingTypeUID THING_TYPE_S5 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_S5);
// List of all Channel ids
public static final String CHANNEL_POWER = "power";
- public static final String CHANNEL_MAIN_POWER = "mainZone#power";
public static final String CHANNEL_SOURCE = "source";
- public static final String CHANNEL_MAIN_SOURCE = "mainZone#source";
- public static final String CHANNEL_MAIN_RECORD_SOURCE = "mainZone#recordSource";
+ public static final String CHANNEL_RECORD_SOURCE = "recordSource";
public static final String CHANNEL_DSP = "dsp";
- public static final String CHANNEL_MAIN_DSP = "mainZone#dsp";
public static final String CHANNEL_VOLUME = "volume";
- public static final String CHANNEL_MAIN_VOLUME = "mainZone#volume";
- public static final String CHANNEL_MAIN_VOLUME_UP_DOWN = "mainZone#volumeUpDown";
+ public static final String CHANNEL_VOLUME_UP_DOWN = "volumeUpDown";
public static final String CHANNEL_MUTE = "mute";
- public static final String CHANNEL_MAIN_MUTE = "mainZone#mute";
public static final String CHANNEL_BASS = "bass";
- public static final String CHANNEL_MAIN_BASS = "mainZone#bass";
public static final String CHANNEL_TREBLE = "treble";
- public static final String CHANNEL_MAIN_TREBLE = "mainZone#treble";
public static final String CHANNEL_PLAY_CONTROL = "playControl";
public static final String CHANNEL_TRACK = "track";
public static final String CHANNEL_FREQUENCY = "frequency";
public static final String CHANNEL_LINE1 = "mainZone#line1";
public static final String CHANNEL_LINE2 = "mainZone#line2";
public static final String CHANNEL_BRIGHTNESS = "brightness";
- public static final String CHANNEL_ZONE2_POWER = "zone2#power";
- public static final String CHANNEL_ZONE2_SOURCE = "zone2#source";
- public static final String CHANNEL_ZONE2_VOLUME = "zone2#volume";
- public static final String CHANNEL_ZONE2_VOLUME_UP_DOWN = "zone2#volumeUpDown";
- public static final String CHANNEL_ZONE2_MUTE = "zone2#mute";
- public static final String CHANNEL_ZONE3_POWER = "zone3#power";
- public static final String CHANNEL_ZONE3_SOURCE = "zone3#source";
- public static final String CHANNEL_ZONE3_VOLUME = "zone3#volume";
- public static final String CHANNEL_ZONE3_MUTE = "zone3#mute";
- public static final String CHANNEL_ZONE4_POWER = "zone4#power";
- 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";
+ public static final String CHANNEL_GROUP_ALL_ZONES = "allZones";
+ public static final String CHANNEL_ALL_POWER = CHANNEL_GROUP_ALL_ZONES + "#" + CHANNEL_POWER;
+ public static final String CHANNEL_ALL_BRIGHTNESS = CHANNEL_GROUP_ALL_ZONES + "#" + CHANNEL_BRIGHTNESS;
+
+ public static final String CHANNEL_GROUP_MAIN_ZONE = "mainZone";
+ public static final String CHANNEL_MAIN_POWER = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_POWER;
+ public static final String CHANNEL_MAIN_SOURCE = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_SOURCE;
+ public static final String CHANNEL_MAIN_RECORD_SOURCE = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_RECORD_SOURCE;
+ public static final String CHANNEL_MAIN_DSP = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_DSP;
+ public static final String CHANNEL_MAIN_VOLUME = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_VOLUME;
+ public static final String CHANNEL_MAIN_VOLUME_UP_DOWN = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_VOLUME_UP_DOWN;
+ public static final String CHANNEL_MAIN_MUTE = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_MUTE;
+ public static final String CHANNEL_MAIN_BASS = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_BASS;
+ public static final String CHANNEL_MAIN_TREBLE = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_TREBLE;
+
+ public static final String CHANNEL_GROUP_ZONE1 = "zone1";
+ public static final String CHANNEL_ZONE1_SOURCE = CHANNEL_GROUP_ZONE1 + "#" + CHANNEL_SOURCE;
+ public static final String CHANNEL_ZONE1_VOLUME = CHANNEL_GROUP_ZONE1 + "#" + CHANNEL_VOLUME;
+ public static final String CHANNEL_ZONE1_MUTE = CHANNEL_GROUP_ZONE1 + "#" + CHANNEL_MUTE;
+ public static final String CHANNEL_ZONE1_BASS = CHANNEL_GROUP_ZONE1 + "#" + CHANNEL_BASS;
+ public static final String CHANNEL_ZONE1_TREBLE = CHANNEL_GROUP_ZONE1 + "#" + CHANNEL_TREBLE;
+ public static final String CHANNEL_ZONE1_BALANCE = CHANNEL_GROUP_ZONE1 + "#" + CHANNEL_BALANCE;
+ public static final String CHANNEL_ZONE1_FREQUENCY = CHANNEL_GROUP_ZONE1 + "#" + CHANNEL_FREQUENCY;
+
+ public static final String CHANNEL_GROUP_ZONE2 = "zone2";
+ public static final String CHANNEL_ZONE2_POWER = CHANNEL_GROUP_ZONE2 + "#" + CHANNEL_POWER;
+ public static final String CHANNEL_ZONE2_SOURCE = CHANNEL_GROUP_ZONE2 + "#" + CHANNEL_SOURCE;
+ public static final String CHANNEL_ZONE2_VOLUME = CHANNEL_GROUP_ZONE2 + "#" + CHANNEL_VOLUME;
+ public static final String CHANNEL_ZONE2_VOLUME_UP_DOWN = CHANNEL_GROUP_ZONE2 + "#" + CHANNEL_VOLUME_UP_DOWN;
+ public static final String CHANNEL_ZONE2_MUTE = CHANNEL_GROUP_ZONE2 + "#" + CHANNEL_MUTE;
+ public static final String CHANNEL_ZONE2_BASS = CHANNEL_GROUP_ZONE2 + "#" + CHANNEL_BASS;
+ public static final String CHANNEL_ZONE2_TREBLE = CHANNEL_GROUP_ZONE2 + "#" + CHANNEL_TREBLE;
+ public static final String CHANNEL_ZONE2_BALANCE = CHANNEL_GROUP_ZONE2 + "#" + CHANNEL_BALANCE;
+ public static final String CHANNEL_ZONE2_FREQUENCY = CHANNEL_GROUP_ZONE2 + "#" + CHANNEL_FREQUENCY;
+
+ public static final String CHANNEL_GROUP_ZONE3 = "zone3";
+ public static final String CHANNEL_ZONE3_POWER = CHANNEL_GROUP_ZONE3 + "#" + CHANNEL_POWER;
+ public static final String CHANNEL_ZONE3_SOURCE = CHANNEL_GROUP_ZONE3 + "#" + CHANNEL_SOURCE;
+ public static final String CHANNEL_ZONE3_VOLUME = CHANNEL_GROUP_ZONE3 + "#" + CHANNEL_VOLUME;
+ public static final String CHANNEL_ZONE3_MUTE = CHANNEL_GROUP_ZONE3 + "#" + CHANNEL_MUTE;
+ public static final String CHANNEL_ZONE3_BASS = CHANNEL_GROUP_ZONE3 + "#" + CHANNEL_BASS;
+ public static final String CHANNEL_ZONE3_TREBLE = CHANNEL_GROUP_ZONE3 + "#" + CHANNEL_TREBLE;
+ public static final String CHANNEL_ZONE3_BALANCE = CHANNEL_GROUP_ZONE3 + "#" + CHANNEL_BALANCE;
+ public static final String CHANNEL_ZONE3_FREQUENCY = CHANNEL_GROUP_ZONE3 + "#" + CHANNEL_FREQUENCY;
+
+ public static final String CHANNEL_GROUP_ZONE4 = "zone4";
+ public static final String CHANNEL_ZONE4_POWER = CHANNEL_GROUP_ZONE4 + "#" + CHANNEL_POWER;
+ public static final String CHANNEL_ZONE4_SOURCE = CHANNEL_GROUP_ZONE4 + "#" + CHANNEL_SOURCE;
+ public static final String CHANNEL_ZONE4_VOLUME = CHANNEL_GROUP_ZONE4 + "#" + CHANNEL_VOLUME;
+ public static final String CHANNEL_ZONE4_MUTE = CHANNEL_GROUP_ZONE4 + "#" + CHANNEL_MUTE;
+ public static final String CHANNEL_ZONE4_BASS = CHANNEL_GROUP_ZONE4 + "#" + CHANNEL_BASS;
+ public static final String CHANNEL_ZONE4_TREBLE = CHANNEL_GROUP_ZONE4 + "#" + CHANNEL_TREBLE;
+ public static final String CHANNEL_ZONE4_BALANCE = CHANNEL_GROUP_ZONE4 + "#" + CHANNEL_BALANCE;
+ public static final String CHANNEL_ZONE4_FREQUENCY = CHANNEL_GROUP_ZONE4 + "#" + CHANNEL_FREQUENCY;
+
// List of all properties
public static final String PROPERTY_PROTOCOL = "protocol";
// Common (output) keys used by the HEX and ASCII protocols
public static final String KEY_POWER = "power";
public static final String KEY_VOLUME = "volume";
+ public static final String KEY_VOLUME_ZONE2 = "volume_zone2";
+ public static final String KEY_VOLUME_ZONE3 = "volume_zone3";
+ public static final String KEY_VOLUME_ZONE4 = "volume_zone4";
public static final String KEY_MUTE = "mute";
+ public static final String KEY_MUTE_ZONE2 = "mute_zone2";
+ public static final String KEY_MUTE_ZONE3 = "mute_zone3";
+ public static final String KEY_MUTE_ZONE4 = "mute_zone4";
public static final String KEY_BASS = "bass";
public static final String KEY_TREBLE = "treble";
public static final String KEY_SOURCE = "source";
public static final String KEY_DSP_MODE = "dsp_mode";
public static final String KEY_ERROR = "error";
// Keys only used by the ASCII protocol
+ public static final String KEY_INPUT = "input";
+ public static final String KEY_INPUT_ZONE1 = "input_zone1";
+ public static final String KEY_INPUT_ZONE2 = "input_zone2";
+ public static final String KEY_INPUT_ZONE3 = "input_zone3";
+ public static final String KEY_INPUT_ZONE4 = "input_zone4";
+ public static final String KEY_VOLUME_ZONE1 = "volume_zone1";
+ public static final String KEY_MUTE_ZONE1 = "mute_zone1";
+ public static final String KEY_BASS_ZONE1 = "bass_zone1";
+ public static final String KEY_BASS_ZONE2 = "bass_zone2";
+ public static final String KEY_BASS_ZONE3 = "bass_zone3";
+ public static final String KEY_BASS_ZONE4 = "bass_zone4";
+ public static final String KEY_TREBLE_ZONE1 = "treble_zone1";
+ public static final String KEY_TREBLE_ZONE2 = "treble_zone2";
+ public static final String KEY_TREBLE_ZONE3 = "treble_zone3";
+ public static final String KEY_TREBLE_ZONE4 = "treble_zone4";
public static final String KEY_UPDATE_MODE = "update_mode";
public static final String KEY_DISPLAY_UPDATE = "display_update";
public static final String KEY_VOLUME_MIN = "volume_min";
public static final String KEY_TRACK = "track";
public static final String KEY_DIMMER = "dimmer";
public static final String KEY_FREQ = "freq";
+ public static final String KEY_FREQ_ZONE1 = "freq_zone1";
+ public static final String KEY_FREQ_ZONE2 = "freq_zone2";
+ public static final String KEY_FREQ_ZONE3 = "freq_zone3";
+ public static final String KEY_FREQ_ZONE4 = "freq_zone4";
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_BALANCE_ZONE1 = "balance_zone1";
+ public static final String KEY_BALANCE_ZONE2 = "balance_zone2";
+ public static final String KEY_BALANCE_ZONE3 = "balance_zone3";
+ public static final String KEY_BALANCE_ZONE4 = "balance_zone4";
public static final String KEY_SPEAKER = "speaker";
+ public static final String KEY_MODEL = "model";
+ public static final String KEY_VERSION = "version";
// Output keys only used by the HEX protocol
public static final String KEY_LINE1 = "line1";
public static final String KEY_LINE2 = "line2";
public static final String KEY_SOURCE_ZONE2 = "source_zone2";
public static final String KEY_SOURCE_ZONE3 = "source_zone3";
public static final String KEY_SOURCE_ZONE4 = "source_zone4";
- public static final String KEY_VOLUME_ZONE2 = "volume_zone2";
- public static final String KEY_VOLUME_ZONE3 = "volume_zone3";
- public static final String KEY_VOLUME_ZONE4 = "volume_zone4";
- public static final String KEY_MUTE_ZONE2 = "mute_zone2";
- public static final String KEY_MUTE_ZONE3 = "mute_zone3";
- public static final String KEY_MUTE_ZONE4 = "mute_zone4";
// Specific values for keys
public static final String MSG_VALUE_OFF = "off";
public static final String MSG_VALUE_ON = "on";
+ public static final String MSG_VALUE_NONE = "none";
public static final String POWER_ON = "on";
public static final String STANDBY = "standby";
public static final String POWER_OFF_DELAYED = "off_delayed";
public static final String PLAY = "play";
public static final String PAUSE = "pause";
public static final String STOP = "stop";
+
+ public static final int MAX_NUMBER_OF_ZONES = 4;
}
THING_TYPE_RA12, THING_TYPE_RA1570, THING_TYPE_RA1572, THING_TYPE_RA1592, THING_TYPE_RAP1580,
THING_TYPE_RC1570, THING_TYPE_RC1572, THING_TYPE_RC1590, THING_TYPE_RCD1570, THING_TYPE_RCD1572,
THING_TYPE_RCX1500, THING_TYPE_RDD1580, THING_TYPE_RDG1520, THING_TYPE_RSP1576, THING_TYPE_RSP1582,
- THING_TYPE_RT09, THING_TYPE_RT11, THING_TYPE_RT1570, THING_TYPE_T11, THING_TYPE_T14, THING_TYPE_M8,
- THING_TYPE_P5, THING_TYPE_S5, THING_TYPE_X3, THING_TYPE_X5)
+ THING_TYPE_RT09, THING_TYPE_RT11, THING_TYPE_RT1570, THING_TYPE_T11, THING_TYPE_T14, THING_TYPE_C8,
+ THING_TYPE_M8, THING_TYPE_P5, THING_TYPE_S5, THING_TYPE_X3, THING_TYPE_X5)
.collect(Collectors.toSet()));
private final SerialPortManager serialPortManager;
*/
package org.openhab.binding.rotel.internal;
+import static org.openhab.binding.rotel.internal.RotelBindingConstants.MAX_NUMBER_OF_ZONES;
import static org.openhab.binding.rotel.internal.communication.RotelCommand.*;
import static org.openhab.binding.rotel.internal.protocol.ascii.RotelAbstractAsciiProtocolHandler.*;
RT1570("RT-1570", 115200, 14, null, false, null, false, -1, false, true, 6, 0, NO_SPECIAL_CHARACTERS),
T11("T11", 115200, 12, null, false, null, false, -1, false, true, 6, 0, NO_SPECIAL_CHARACTERS),
T14("T14", 115200, 13, null, false, null, false, -1, false, true, 6, 0, NO_SPECIAL_CHARACTERS),
+ C8("C8", 115200, POWER, 21, 3, true, false, 96, true, 10, false, 10, false, null, -1, true, false, true, 4, 0,
+ (byte) 0, 0, 0, false, RotelFlagsMapping.NO_MAPPING, NO_SPECIAL_CHARACTERS),
M8("M8", 115200, 0, null, false, null, false, -1, false, true, 4, 0, NO_SPECIAL_CHARACTERS),
P5("P5", 115200, 20, 96, true, 10, 10, false, -1, true, false, true, 4, 0, NO_SPECIAL_CHARACTERS),
S5("S5", 115200, 0, null, false, null, false, -1, false, true, 4, 0, NO_SPECIAL_CHARACTERS),
private int sourceCategory;
private int nbAdditionalZones;
private boolean additionalCommands;
+ private boolean powerControlPerZone;
private @Nullable Integer volumeMax;
private boolean directVolume;
private @Nullable Integer toneLevelMax;
+ private boolean getBypassStatusAvailable;
private boolean playControl;
private @Nullable RotelCommand zoneSelectCmd;
private int dspCategory;
@Nullable Integer volumeMax, boolean directVolume, @Nullable Integer toneLevelMax, boolean playControl,
@Nullable RotelCommand zoneSelectCmd, int dspCategory, byte deviceId, int respNbChars, int respNbFlags,
boolean charsBeforeFlags, RotelFlagsMapping flagsMapping) {
- this(name, baudRate, DISPLAY_REFRESH, sourceCategory, nbAdditionalZones, additionalCommands, volumeMax,
- directVolume, toneLevelMax, null, playControl, zoneSelectCmd, dspCategory, false, false, false, null,
- null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping, NO_SPECIAL_CHARACTERS);
+ this(name, baudRate, DISPLAY_REFRESH, sourceCategory, nbAdditionalZones, additionalCommands, true, volumeMax,
+ directVolume, toneLevelMax, false, null, playControl, zoneSelectCmd, dspCategory, false, false, false,
+ null, null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping, NO_SPECIAL_CHARACTERS);
}
/**
@Nullable Integer toneLevelMax, boolean playControl, int dspCategory, boolean getFrequencyAvailable,
boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax,
byte[][] specialCharacters) {
- this(name, baudRate, 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);
+ this(name, baudRate, POWER, sourceCategory, 0, false, false, volumeMax, directVolume, toneLevelMax,
+ toneLevelMax != null, null, playControl, null, dspCategory, getFrequencyAvailable, false,
+ getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, (byte) 0, 0, 0, false,
+ RotelFlagsMapping.NO_MAPPING, specialCharacters);
}
/**
@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, 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);
+ this(name, baudRate, POWER, sourceCategory, 0, false, false, volumeMax, directVolume, toneLevelMax,
+ toneLevelMax != null, balanceLevelMax, playControl, null, dspCategory, getFrequencyAvailable,
+ getSpeakerGroupsAvailable, getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, (byte) 0, 0, 0,
+ false, RotelFlagsMapping.NO_MAPPING, specialCharacters);
}
/**
* @param sourceCategory the category from {@link RotelSource}
* @param nbAdditionalZones the number of additional zones
* @param additionalCommands true if other than primary commands are available
+ * @param powerControlPerZone true if device supports power control per zone
* @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 getBypassStatusAvailable true if the command to get the bypass status for tone control 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 specialCharacters the table of special characters that can be found in the standard response message
*/
private RotelModel(String name, int baudRate, RotelCommand powerStateCmd, int sourceCategory, int nbAdditionalZones,
- boolean additionalCommands, @Nullable Integer volumeMax, boolean directVolume,
- @Nullable Integer toneLevelMax, @Nullable Integer balanceLevelMax, boolean playControl,
- @Nullable RotelCommand zoneSelectCmd, int dspCategory, boolean getFrequencyAvailable,
+ boolean additionalCommands, boolean powerControlPerZone, @Nullable Integer volumeMax, boolean directVolume,
+ @Nullable Integer toneLevelMax, boolean getBypassStatusAvailable, @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.sourceCategory = sourceCategory;
this.nbAdditionalZones = nbAdditionalZones;
this.additionalCommands = additionalCommands;
+ this.powerControlPerZone = powerControlPerZone;
this.volumeMax = volumeMax;
this.directVolume = directVolume;
this.toneLevelMax = toneLevelMax;
+ this.getBypassStatusAvailable = getBypassStatusAvailable;
this.balanceLevelMax = balanceLevelMax;
this.playControl = playControl;
this.zoneSelectCmd = zoneSelectCmd;
}
/**
- * Get the number of additional zones
+ * Get the number of zones
*
- * @return the number of additional zones
+ * @return the number of zones
*/
- public int getNbAdditionalZones() {
- return nbAdditionalZones;
+ public int getNumberOfZones() {
+ return nbAdditionalZones + 1;
+ }
+
+ private boolean isZoneAvailable(int numZone) {
+ return numZone >= 1 && numZone <= getNumberOfZones();
}
/**
}
/**
- * Inform whether zone 2 commands are available
+ * Inform whether zone N commands are available
*
- * @return true if zone 2 commands are available
- */
- public boolean hasZone2Commands() {
- return nbAdditionalZones >= 1 && additionalCommands;
- }
-
- /**
- * Inform whether zone 3 commands are available
+ * @param numZone the zone number, 1 for for zone 1 until 4 for zone 4
*
- * @return true if zone 3 commands are available
+ * @return true if zone N commands are available
*/
- public boolean hasZone3Commands() {
- return nbAdditionalZones >= 2 && additionalCommands;
+ public boolean hasZoneCommands(int numZone) {
+ if (numZone < 1 || numZone > MAX_NUMBER_OF_ZONES) {
+ throw new IllegalArgumentException("numZone must be in range 1-" + MAX_NUMBER_OF_ZONES);
+ }
+ return additionalCommands && isZoneAvailable(numZone);
}
/**
- * Inform whether zone 4 commands are available
+ * Inform whether source control is available in a zone
*
- * @return true if zone 4 commands are available
- */
- public boolean hasZone4Commands() {
- return nbAdditionalZones >= 3 && additionalCommands;
- }
-
- /**
- * Inform whether source control is available in the zone 2
+ * @param numZone the zone number, 1 for zone 1 until 4 for zone 4
*
* @return true if source control is available
*/
- public boolean hasZone2SourceControl() {
- return sourceCategory >= 1 && nbAdditionalZones >= 1;
- }
-
- /**
- * Inform whether source control is available in the zone 3
- *
- * @return true if source control is available
- */
- public boolean hasZone3SourceControl() {
- return sourceCategory >= 1 && nbAdditionalZones >= 2;
+ public boolean hasZoneSourceControl(int numZone) {
+ if (numZone < 1 || numZone > MAX_NUMBER_OF_ZONES) {
+ throw new IllegalArgumentException("numZone must be in range 1-" + MAX_NUMBER_OF_ZONES);
+ }
+ return hasSourceControl() && isZoneAvailable(numZone);
}
/**
- * Inform whether source control is available in the zone 4
+ * Inform whether device supports power control per zone
*
- * @return true if source control is available
+ * @return true if device supports power control per zone
*/
- public boolean hasZone4SourceControl() {
- return sourceCategory >= 1 && nbAdditionalZones >= 3;
+ public boolean hasPowerControlPerZone() {
+ return powerControlPerZone;
}
/**
return toneLevelMax != null;
}
+ /**
+ * Inform whether the command to get the current bypass status for tone control is available
+ *
+ * @return true if the command is available
+ */
+ public boolean canGetBypassStatus() {
+ return getBypassStatusAvailable;
+ }
+
/**
* Get the maximum tone level
*
}
/**
- * Get the list of available {@link RotelSource} in the main zone
+ * Get the list of available {@link RotelSource} in a zone
*
- * @return the list of available {@link RotelSource} in the main zone
- */
- public List<RotelSource> getMainZoneSources() {
- return (hasSourceControl() && hasOtherThanPrimaryCommands()) ? RotelSource.getSources(sourceCategory, 1)
- : new ArrayList<>();
- }
-
- /**
- * Get the list of available {@link RotelSource} in the zone 2
+ * @param numZone the zone number, 1 for zone 1 until 4 for zone 4
*
* @return the list of available {@link RotelSource} in the zone 2
*/
- public List<RotelSource> getZone2Sources() {
- return hasZone2SourceControl() ? RotelSource.getSources(sourceCategory, 2) : new ArrayList<>();
- }
-
- /**
- * Get the list of available {@link RotelSource} in the zone 3
- *
- * @return the list of available {@link RotelSource} in the zone 3
- */
- public List<RotelSource> getZone3Sources() {
- return hasZone3SourceControl() ? RotelSource.getSources(sourceCategory, 3) : new ArrayList<>();
- }
-
- /**
- * Get the list of available {@link RotelSource} in the zone 4
- *
- * @return the list of available {@link RotelSource} in the zone 4
- */
- public List<RotelSource> getZone4Sources() {
- return hasZone4SourceControl() ? RotelSource.getSources(sourceCategory, 4) : new ArrayList<>();
+ public List<RotelSource> getZoneSources(int numZone) {
+ if (numZone < 1 || numZone > MAX_NUMBER_OF_ZONES) {
+ throw new IllegalArgumentException("numZone must be in range 1-" + MAX_NUMBER_OF_ZONES);
+ }
+ return hasZoneSourceControl(numZone) ? RotelSource.getSources(sourceCategory, numZone) : new ArrayList<>();
}
/**
}
/**
- * Get the main zone source associated to a command
+ * Get the zone N source associated to a command
*
- * @param command the command used to identify the main zone source
+ * @param command the command used to identify the zone N source
+ * @param numZone the zone number, 1 for zone 1 until 4 for zone 4
*
- * @return the main zone source associated to the searched command
+ * @return the zone N source associated to the searched command
*
- * @throws RotelException - If no main zone source is associated to the searched command
+ * @throws RotelException - If no zone N source is associated to the searched command
*/
- public RotelSource getMainZoneSourceFromCommand(RotelCommand command) throws RotelException {
- return RotelSource.getFromCommand(sourceCategory, command, 1);
- }
-
- /**
- * Get the zone 2 source associated to a command
- *
- * @param command the command used to identify the zone 2 source
- *
- * @return the zone 2 source associated to the searched command
- *
- * @throws RotelException - If no zone 2 source is associated to the searched command
- */
- public RotelSource getZone2SourceFromCommand(RotelCommand command) throws RotelException {
- return RotelSource.getFromCommand(sourceCategory, command, 2);
- }
-
- /**
- * Get the zone 3 source associated to a command
- *
- * @param command the command used to identify the zone 3 source
- *
- * @return the zone 3 source associated to the searched command
- *
- * @throws RotelException - If no zone 3 source is associated to the searched command
- */
- public RotelSource getZone3SourceFromCommand(RotelCommand command) throws RotelException {
- return RotelSource.getFromCommand(sourceCategory, command, 3);
- }
-
- /**
- * Get the zone 4 source associated to a command
- *
- * @param command the command used to identify the zone 4 source
- *
- * @return the zone 4 source associated to the searched command
- *
- * @throws RotelException - If no zone 4 source is associated to the searched command
- */
- public RotelSource getZone4SourceFromCommand(RotelCommand command) throws RotelException {
- return RotelSource.getFromCommand(sourceCategory, command, 4);
+ public RotelSource getZoneSourceFromCommand(RotelCommand command, int numZone) throws RotelException {
+ if (numZone < 1 || numZone > MAX_NUMBER_OF_ZONES) {
+ throw new IllegalArgumentException("numZone must be in range 1-" + MAX_NUMBER_OF_ZONES);
+ }
+ return RotelSource.getFromCommand(sourceCategory, command, numZone);
}
/**
MAIN_ZONE_MUTE_TOGGLE("Main Zone Mute Toggle", MAIN_ZONE_CMD, (byte) 0x1E),
MAIN_ZONE_MUTE_ON("Main Zone Mute On", MAIN_ZONE_CMD, (byte) 0x6C),
MAIN_ZONE_MUTE_OFF("Main Zone Mute Off", MAIN_ZONE_CMD, (byte) 0x6D),
- ZONE2_VOLUME_UP("Zone 2 Volume Up", ZONE2_CMD, (byte) 0),
- ZONE2_VOLUME_DOWN("Zone 2 Volume Down", ZONE2_CMD, (byte) 1),
- ZONE2_VOLUME_SET("Set Zone 2 Volume to level", ZONE2_VOLUME_CMD, (byte) 0),
- ZONE2_MUTE_TOGGLE("Zone 2 Mute Toggle", ZONE2_CMD, (byte) 0x1E),
- ZONE2_MUTE_ON("Zone 2 Mute On", ZONE2_CMD, (byte) 0x6C),
- ZONE2_MUTE_OFF("Zone 2 Mute Off", ZONE2_CMD, (byte) 0x6D),
- ZONE3_VOLUME_UP("Zone 3 Volume Up", ZONE3_CMD, (byte) 0),
- ZONE3_VOLUME_DOWN("Zone 3 Volume Down", ZONE3_CMD, (byte) 1),
- ZONE3_VOLUME_SET("Set Zone 3 Volume to level", ZONE3_VOLUME_CMD, (byte) 0),
- ZONE3_MUTE_TOGGLE("Zone 3 Mute Toggle", ZONE3_CMD, (byte) 0x1E),
- ZONE3_MUTE_ON("Zone 3 Mute On", ZONE3_CMD, (byte) 0x6C),
- ZONE3_MUTE_OFF("Zone 3 Mute Off", ZONE3_CMD, (byte) 0x6D),
- ZONE4_VOLUME_UP("Zone 4 Volume Up", ZONE4_CMD, (byte) 0),
- ZONE4_VOLUME_DOWN("Zone 4 Volume Down", ZONE4_CMD, (byte) 1),
- ZONE4_VOLUME_SET("Set Zone 4 Volume to level", ZONE4_VOLUME_CMD, (byte) 0),
- ZONE4_MUTE_TOGGLE("Zone 4 Mute Toggle", ZONE4_CMD, (byte) 0x1E),
- ZONE4_MUTE_ON("Zone 4 Mute On", ZONE4_CMD, (byte) 0x6C),
- ZONE4_MUTE_OFF("Zone 4 Mute Off", ZONE4_CMD, (byte) 0x6D),
+ ZONE1_VOLUME_UP("Zone 1 Volume Up", null, "z1:vol_up"),
+ ZONE1_VOLUME_DOWN("Zone 1 Volume Down", null, "z1:vol_dwn"),
+ ZONE1_VOLUME_SET("Set Zone 1 Volume to level", null, "z1:vol_"),
+ ZONE1_MUTE_TOGGLE("Zone 1 Mute Toggle", null, "z1:mute"),
+ ZONE1_MUTE_ON("Zone 1 Mute On", null, "z1:mute_on"),
+ ZONE1_MUTE_OFF("Zone 1 Mute Off", null, "z1:mute_off"),
+ ZONE2_VOLUME_UP("Zone 2 Volume Up", ZONE2_CMD, (byte) 0, null, "z2:vol_up"),
+ ZONE2_VOLUME_DOWN("Zone 2 Volume Down", ZONE2_CMD, (byte) 1, null, "z2:vol_dwn"),
+ ZONE2_VOLUME_SET("Set Zone 2 Volume to level", ZONE2_VOLUME_CMD, (byte) 0, null, "z2:vol_"),
+ ZONE2_MUTE_TOGGLE("Zone 2 Mute Toggle", ZONE2_CMD, (byte) 0x1E, null, "z2:mute"),
+ ZONE2_MUTE_ON("Zone 2 Mute On", ZONE2_CMD, (byte) 0x6C, null, "z2:mute_on"),
+ ZONE2_MUTE_OFF("Zone 2 Mute Off", ZONE2_CMD, (byte) 0x6D, null, "z2:mute_off"),
+ ZONE3_VOLUME_UP("Zone 3 Volume Up", ZONE3_CMD, (byte) 0, null, "z3:vol_up"),
+ ZONE3_VOLUME_DOWN("Zone 3 Volume Down", ZONE3_CMD, (byte) 1, null, "z3:vol_dwn"),
+ ZONE3_VOLUME_SET("Set Zone 3 Volume to level", ZONE3_VOLUME_CMD, (byte) 0, null, "z3:vol_"),
+ ZONE3_MUTE_TOGGLE("Zone 3 Mute Toggle", ZONE3_CMD, (byte) 0x1E, null, "z3:mute"),
+ ZONE3_MUTE_ON("Zone 3 Mute On", ZONE3_CMD, (byte) 0x6C, null, "z3:mute_on"),
+ ZONE3_MUTE_OFF("Zone 3 Mute Off", ZONE3_CMD, (byte) 0x6D, null, "z3:mute_off"),
+ ZONE4_VOLUME_UP("Zone 4 Volume Up", ZONE4_CMD, (byte) 0, null, "z4:vol_up"),
+ ZONE4_VOLUME_DOWN("Zone 4 Volume Down", ZONE4_CMD, (byte) 1, null, "z4:vol_dwn"),
+ ZONE4_VOLUME_SET("Set Zone 4 Volume to level", ZONE4_VOLUME_CMD, (byte) 0, null, "z4:vol_"),
+ ZONE4_MUTE_TOGGLE("Zone 4 Mute Toggle", ZONE4_CMD, (byte) 0x1E, null, "z4:mute"),
+ ZONE4_MUTE_ON("Zone 4 Mute On", ZONE4_CMD, (byte) 0x6C, null, "z4:mute_on"),
+ ZONE4_MUTE_OFF("Zone 4 Mute Off", ZONE4_CMD, (byte) 0x6D, null, "z4:mute_off"),
SOURCE_CD("Source CD", PRIMARY_CMD, (byte) 0x02, "cd", "cd"),
SOURCE_TUNER("Source Tuner", PRIMARY_CMD, (byte) 0x03, "tuner", "tuner"),
SOURCE_TAPE("Source Tape", PRIMARY_CMD, (byte) 0x04, "tape", "tape"),
SOURCE_PLAYFI("Source PlayFi", "playfi", "playfi"),
SOURCE_IRADIO("Source iRadio", "iradio", "iradio"),
SOURCE_NETWORK("Source Network", "network", "network"),
+ SOURCE_INPUT_A("Source Input A", null, "input_a"),
+ SOURCE_INPUT_B("Source Input B", null, "input_b"),
+ SOURCE_INPUT_C("Source Input C", null, "input_c"),
+ SOURCE_INPUT_D("Source Input D", null, "input_d"),
SOURCE("Request current source", "get_current_source", "source?"),
+ INPUT("Request current source", null, "input?"),
MAIN_ZONE_SOURCE_CD("Main Zone Source CD", MAIN_ZONE_CMD, (byte) 0x02, "main_zone_cd", "main_zone_cd"),
MAIN_ZONE_SOURCE_TUNER("Main Zone Source Tuner", MAIN_ZONE_CMD, (byte) 0x03, "main_zone_tuner", "main_zone_tuner"),
MAIN_ZONE_SOURCE_TAPE("Main Zone Source Tape", MAIN_ZONE_CMD, (byte) 0x04, "main_zone_tape", "main_zone_tape"),
MAIN_ZONE_SOURCE_USB("Main Zone Source Front USB", MAIN_ZONE_CMD, (byte) 0x8E, "main_zone_usb", "main_zone_usb"),
MAIN_ZONE_SOURCE_MULTI_INPUT("Main Zone Source Multi Input", MAIN_ZONE_CMD, (byte) 0x15, "main_zone_multi_input",
"main_zone_multi_input"),
+ ZONE1_SOURCE_INPUT_A("Zone 1 Source Input A", null, "z1:input_a"),
+ ZONE1_SOURCE_INPUT_B("Zone 1 Source Input B", null, "z1:input_b"),
+ ZONE1_SOURCE_INPUT_C("Zone 1 Source Input C", null, "z1:input_c"),
+ ZONE1_SOURCE_INPUT_D("Zone 1 Source Input D", null, "z1:input_d"),
RECORD_SOURCE_CD("Record Source CD", RECORD_SRC_CMD, (byte) 0x02, "record_cd", "record_cd"),
RECORD_SOURCE_TUNER("Record Source Tuner", RECORD_SRC_CMD, (byte) 0x03, "record_tuner", "record_tuner"),
RECORD_SOURCE_TAPE("Record Source Tape", RECORD_SRC_CMD, (byte) 0x04, "record_tape", "record_tape"),
ZONE2_SOURCE_USB("Zone 2 Source Front USB", ZONE2_CMD, (byte) 0x8E, "zone2_usb", "zone2_usb"),
ZONE2_SOURCE_MAIN("Zone 2 Follow Main Zone Source", ZONE2_CMD, (byte) 0x6B, "zone2_follow_main",
"zone2_follow_main"),
+ ZONE2_SOURCE_INPUT_A("Zone 2 Source Input A", null, "z2:input_a"),
+ ZONE2_SOURCE_INPUT_B("Zone 2 Source Input B", null, "z2:input_b"),
+ ZONE2_SOURCE_INPUT_C("Zone 2 Source Input C", null, "z2:input_c"),
+ ZONE2_SOURCE_INPUT_D("Zone 2 Source Input D", null, "z2:input_d"),
ZONE3_SOURCE_CD("Zone 3 Source CD", ZONE3_CMD, (byte) 0x02, "zone3_cd", "zone3_cd"),
ZONE3_SOURCE_TUNER("Zone 3 Source Tuner", ZONE3_CMD, (byte) 0x03, "zone3_tuner", "zone3_tuner"),
ZONE3_SOURCE_TAPE("Zone 3 Source Tape", ZONE3_CMD, (byte) 0x04, "zone3_tape", "zone3_tape"),
ZONE3_SOURCE_USB("Zone 3 Source Front USB", ZONE3_CMD, (byte) 0x8E, "zone3_usb", "zone3_usb"),
ZONE3_SOURCE_MAIN("Zone 3 Follow Main Zone Source", ZONE3_CMD, (byte) 0x6B, "zone3_follow_main",
"zone3_follow_main"),
+ ZONE3_SOURCE_INPUT_A("Zone 3 Source Input A", null, "z3:input_a"),
+ ZONE3_SOURCE_INPUT_B("Zone 3 Source Input B", null, "z3:input_b"),
+ ZONE3_SOURCE_INPUT_C("Zone 3 Source Input C", null, "z3:input_c"),
+ ZONE3_SOURCE_INPUT_D("Zone 3 Source Input D", null, "z3:input_d"),
ZONE4_SOURCE_CD("Zone 4 Source CD", ZONE4_CMD, (byte) 0x02, "zone4_cd", "zone4_cd"),
ZONE4_SOURCE_TUNER("Zone 4 Source Tuner", ZONE4_CMD, (byte) 0x03, "zone4_tuner", "zone4_tuner"),
ZONE4_SOURCE_TAPE("Zone 4 Source Tape", ZONE4_CMD, (byte) 0x04, "zone4_tape", "zone4_tape"),
ZONE4_SOURCE_USB("Zone 4 Source Front USB", ZONE4_CMD, (byte) 0x8E, "zone4_usb", "zone4_usb"),
ZONE4_SOURCE_MAIN("Zone 4 Follow Main Zone Source", ZONE4_CMD, (byte) 0x6B, "zone4_follow_main",
"zone4_follow_main"),
+ ZONE4_SOURCE_INPUT_A("Zone 4 Source Input A", null, "z4:input_a"),
+ ZONE4_SOURCE_INPUT_B("Zone 4 Source Input B", null, "z4:input_b"),
+ ZONE4_SOURCE_INPUT_C("Zone 4 Source Input C", null, "z4:input_c"),
+ ZONE4_SOURCE_INPUT_D("Zone 4 Source Input D", null, "z4:input_d"),
STEREO("Stereo", PRIMARY_CMD, (byte) 0x11, "2channel", "2channel"),
STEREO3("Dolby 3 Stereo ", PRIMARY_CMD, (byte) 0x12, "3channel", "3channel"),
STEREO5("5 Channel Stereo", PRIMARY_CMD, (byte) 0x5B, "5channel", "5channel"),
BASS_DOWN("Bass Down", PRIMARY_CMD, (byte) 0x10, "bass_down", "bass_down"),
BASS_SET("Set Bass to level", "bass_", "bass_"),
BASS("Request current bass level", "get_bass", "bass?"),
+ ZONE1_TREBLE_UP("Zone 1 Treble Up", null, "z1:treble_up"),
+ ZONE1_TREBLE_DOWN("Zone 1 Treble Down", null, "z1:treble_down"),
+ ZONE1_TREBLE_SET("Set Zone 1 Treble to level", null, "z1:treble_"),
+ ZONE1_BASS_UP("Zone 1 Bass Up", null, "z1:bass_up"),
+ ZONE1_BASS_DOWN("Zone 1 Bass Down", null, "z1:bass_down"),
+ ZONE1_BASS_SET("Set Zone 1 Bass to level", null, "z1:bass_"),
+ ZONE2_TREBLE_UP("Zone 2 Treble Up", null, "z2:treble_up"),
+ ZONE2_TREBLE_DOWN("Zone 2 Treble Down", null, "z2:treble_down"),
+ ZONE2_TREBLE_SET("Set Zone 2 Treble to level", null, "z2:treble_"),
+ ZONE2_BASS_UP("Zone 2 Bass Up", null, "z2:bass_up"),
+ ZONE2_BASS_DOWN("Zone 2 Bass Down", null, "z2:bass_down"),
+ ZONE2_BASS_SET("Set Zone 2 Bass to level", null, "z2:bass_"),
+ ZONE3_TREBLE_UP("Zone 3 Treble Up", null, "z3:treble_up"),
+ ZONE3_TREBLE_DOWN("Zone 3 Treble Down", null, "z3:treble_down"),
+ ZONE3_TREBLE_SET("Set Zone 3 Treble to level", null, "z3:treble_"),
+ ZONE3_BASS_UP("Zone 3 Bass Up", null, "z3:bass_up"),
+ ZONE3_BASS_DOWN("Zone 3 Bass Down", null, "z3:bass_down"),
+ ZONE3_BASS_SET("Set Zone 3 Bass to level", null, "z3:bass_"),
+ ZONE4_TREBLE_UP("Zone 4 Treble Up", null, "z4:treble_up"),
+ ZONE4_TREBLE_DOWN("Zone 4 Treble Down", null, "z4:treble_down"),
+ ZONE4_TREBLE_SET("Set Zone 4 Treble to level", null, "z4:treble_"),
+ ZONE4_BASS_UP("Zone 4 Bass Up", null, "z4:bass_up"),
+ ZONE4_BASS_DOWN("Zone 4 Bass Down", null, "z4:bass_down"),
+ ZONE4_BASS_SET("Set Zone 4 Bass to level", null, "z4:bass_"),
RECORD_FONCTION_SELECT("Record Function Select", PRIMARY_CMD, (byte) 0x17),
PLAY("Play Source", PRIMARY_CMD, (byte) 0x04, "play", "play"),
STOP("Stop Source", PRIMARY_CMD, (byte) 0x06, "stop", "stop"),
BALANCE_RIGHT("Balance Right", "balance_right", "balance_r"),
BALANCE_LEFT("Balance Left", "balance_left", "balance_l"),
BALANCE_SET("Set Balance to level", "balance_", "balance_"),
+ ZONE1_BALANCE_RIGHT("Zone 1 Balance Right", null, "z1:balance_r"),
+ ZONE1_BALANCE_LEFT("Zone 1 Balance Left", null, "z1:balance_l"),
+ ZONE1_BALANCE_SET("Set Zone 1 Balance to level", null, "z1:balance_"),
+ ZONE2_BALANCE_RIGHT("Zone 2 Balance Right", null, "z2:balance_r"),
+ ZONE2_BALANCE_LEFT("Zone 2 Balance Left", null, "z2:balance_l"),
+ ZONE2_BALANCE_SET("Set Zone 2 Balance to level", null, "z2:balance_"),
+ ZONE3_BALANCE_RIGHT("Zone 3 Balance Right", null, "z3:balance_r"),
+ ZONE3_BALANCE_LEFT("Zone 3 Balance Left", null, "z3:balance_l"),
+ ZONE3_BALANCE_SET("Set Zone 3 Balance to level", null, "z3:balance_"),
+ ZONE4_BALANCE_RIGHT("Zone 4 Balance Right", null, "z4:balance_r"),
+ ZONE4_BALANCE_LEFT("Zone 4 Balance Left", null, "z4:balance_l"),
+ ZONE4_BALANCE_SET("Set Zone 4 Balance to level", null, "z4:balance_"),
BALANCE("Request current balance setting", "get_balance", "balance?"),
SPEAKER_A_TOGGLE("Toggle Speaker A Output", PRIMARY_CMD, (byte) 0x50, "speaker_a", "speaker_a"),
SPEAKER_A_ON("Set Speaker A Output", "speaker_a_on", "speaker_a_on"),
SPEAKER_B_TOGGLE("Toggle Speaker B Output", 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?");
+ SPEAKER("Request current active speaker outputs", "get_current_speaker", "speaker?"),
+ MODEL("Request the model number", null, "model?"),
+ VERSION("Request the main CPU software version", null, "version?");
public static final byte PRIMARY_COMMAND = (byte) 0x10;
import java.io.InterruptedIOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.StringJoiner;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
private byte[] feedbackMsg = new byte[1];
private int idxInFeedbackMsg = feedbackMsg.length;
- private boolean power;
- private boolean powerZone2;
- private boolean powerZone3;
- private boolean powerZone4;
- private RotelSource source = RotelSource.CAT0_CD;
- private RotelSource recordSource = RotelSource.CAT1_CD;
- private RotelSource sourceZone2 = RotelSource.CAT1_CD;
- private RotelSource sourceZone3 = RotelSource.CAT1_CD;
- private RotelSource sourceZone4 = RotelSource.CAT1_CD;
+ private boolean[] powers = { false, false, false, false, false };
+ private RotelSource[] sources;
+ private RotelSource recordSource;
private boolean multiinput;
private RotelDsp dsp = RotelDsp.CAT4_NONE;
- private int volume = 50;
- private boolean mute;
- private int volumeZone2 = 20;
- private boolean muteZone2;
- private int volumeZone3 = 30;
- private boolean muteZone3;
- private int volumeZone4 = 40;
- private boolean muteZone4;
- private int bass;
- private int treble;
+ private int[] volumes = { 50, 10, 20, 30, 40 };
+ private boolean[] mutes = { false, false, false, false, false };
+ private boolean tcbypass;
+ private int[] basses = { 0, 0, 0, 0, 0 };
+ private int[] trebles = { 0, 0, 0, 0, 0 };
+ private int[] balances = { 0, 0, 0, 0, 0 };
private boolean showTreble;
+ private boolean speakerA = true;
+ private boolean speakerB = false;
private RotelPlayStatus playStatus = RotelPlayStatus.STOPPED;
private int track = 1;
private boolean selectingRecord;
private int maxVolume;
private int minToneLevel;
private int maxToneLevel;
+ private int minBalance;
+ private int maxBalance;
/**
* Constructor
this.maxVolume = model.hasVolumeControl() ? model.getVolumeMax() : 0;
this.maxToneLevel = model.hasToneControl() ? model.getToneLevelMax() : 0;
this.minToneLevel = -this.maxToneLevel;
+ this.maxBalance = model.hasBalanceControl() ? model.getBalanceLevelMax() : 0;
+ this.minBalance = -this.maxBalance;
+ List<RotelSource> modelSources = model.getSources();
+ RotelSource source = modelSources.isEmpty() ? RotelSource.CAT0_CD : modelSources.get(0);
+ sources = new RotelSource[] { source, source, source, source, source };
+ recordSource = source;
}
@Override
String textAscii = "";
boolean accepted = true;
boolean resetZone = true;
+ int numZone = 0;
+ switch (cmd) {
+ case ZONE1_VOLUME_UP:
+ case ZONE1_VOLUME_DOWN:
+ case ZONE1_VOLUME_SET:
+ case ZONE1_MUTE_TOGGLE:
+ case ZONE1_MUTE_ON:
+ case ZONE1_MUTE_OFF:
+ case ZONE1_BASS_UP:
+ case ZONE1_BASS_DOWN:
+ case ZONE1_BASS_SET:
+ case ZONE1_TREBLE_UP:
+ case ZONE1_TREBLE_DOWN:
+ case ZONE1_TREBLE_SET:
+ case ZONE1_BALANCE_LEFT:
+ case ZONE1_BALANCE_RIGHT:
+ case ZONE1_BALANCE_SET:
+ numZone = 1;
+ break;
+ case ZONE2_POWER_OFF:
+ case ZONE2_POWER_ON:
+ case ZONE2_VOLUME_UP:
+ case ZONE2_VOLUME_DOWN:
+ case ZONE2_VOLUME_SET:
+ case ZONE2_MUTE_TOGGLE:
+ case ZONE2_MUTE_ON:
+ case ZONE2_MUTE_OFF:
+ case ZONE2_BASS_UP:
+ case ZONE2_BASS_DOWN:
+ case ZONE2_BASS_SET:
+ case ZONE2_TREBLE_UP:
+ case ZONE2_TREBLE_DOWN:
+ case ZONE2_TREBLE_SET:
+ case ZONE2_BALANCE_LEFT:
+ case ZONE2_BALANCE_RIGHT:
+ case ZONE2_BALANCE_SET:
+ numZone = 2;
+ break;
+ case ZONE3_POWER_OFF:
+ case ZONE3_POWER_ON:
+ case ZONE3_VOLUME_UP:
+ case ZONE3_VOLUME_DOWN:
+ case ZONE3_VOLUME_SET:
+ case ZONE3_MUTE_TOGGLE:
+ case ZONE3_MUTE_ON:
+ case ZONE3_MUTE_OFF:
+ case ZONE3_BASS_UP:
+ case ZONE3_BASS_DOWN:
+ case ZONE3_BASS_SET:
+ case ZONE3_TREBLE_UP:
+ case ZONE3_TREBLE_DOWN:
+ case ZONE3_TREBLE_SET:
+ case ZONE3_BALANCE_LEFT:
+ case ZONE3_BALANCE_RIGHT:
+ case ZONE3_BALANCE_SET:
+ numZone = 3;
+ break;
+ case ZONE4_POWER_OFF:
+ case ZONE4_POWER_ON:
+ case ZONE4_VOLUME_UP:
+ case ZONE4_VOLUME_DOWN:
+ case ZONE4_VOLUME_SET:
+ case ZONE4_MUTE_TOGGLE:
+ case ZONE4_MUTE_ON:
+ case ZONE4_MUTE_OFF:
+ case ZONE4_BASS_UP:
+ case ZONE4_BASS_DOWN:
+ case ZONE4_BASS_SET:
+ case ZONE4_TREBLE_UP:
+ case ZONE4_TREBLE_DOWN:
+ case ZONE4_TREBLE_SET:
+ case ZONE4_BALANCE_LEFT:
+ case ZONE4_BALANCE_RIGHT:
+ case ZONE4_BALANCE_SET:
+ numZone = 4;
+ break;
+ default:
+ break;
+ }
switch (cmd) {
case DISPLAY_REFRESH:
break;
case POWER_OFF:
case MAIN_ZONE_POWER_OFF:
- power = false;
+ powers[0] = false;
+ if (model.getNumberOfZones() > 1 && !model.hasPowerControlPerZone()) {
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ powers[zone] = false;
+ }
+ }
text = buildSourceLine1Response();
textLine1Left = buildSourceLine1LeftResponse();
textLine1Right = buildVolumeLine1RightResponse();
break;
case POWER_ON:
case MAIN_ZONE_POWER_ON:
- power = true;
+ powers[0] = true;
+ if (model.getNumberOfZones() > 1 && !model.hasPowerControlPerZone()) {
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ powers[zone] = true;
+ }
+ }
text = buildSourceLine1Response();
textLine1Left = buildSourceLine1LeftResponse();
textLine1Right = buildVolumeLine1RightResponse();
textAscii = buildPowerAsciiResponse();
break;
case ZONE2_POWER_OFF:
- powerZone2 = false;
- text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- powerZone2, sourceZone2);
- showZone = 2;
- resetZone = false;
- break;
- case ZONE2_POWER_ON:
- powerZone2 = true;
- text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- powerZone2, sourceZone2);
- showZone = 2;
- resetZone = false;
- break;
case ZONE3_POWER_OFF:
- powerZone3 = false;
- text = textLine2 = buildZonePowerResponse("ZONE3", powerZone3, sourceZone3);
- showZone = 3;
- resetZone = false;
- break;
- case ZONE3_POWER_ON:
- powerZone3 = true;
- text = textLine2 = buildZonePowerResponse("ZONE3", powerZone3, sourceZone3);
- showZone = 3;
- resetZone = false;
- break;
case ZONE4_POWER_OFF:
- powerZone4 = false;
- text = textLine2 = buildZonePowerResponse("ZONE4", powerZone4, sourceZone4);
- showZone = 4;
+ powers[numZone] = false;
+ text = textLine2 = buildZonePowerResponse(numZone);
+ showZone = numZone;
resetZone = false;
break;
+ case ZONE2_POWER_ON:
+ case ZONE3_POWER_ON:
case ZONE4_POWER_ON:
- powerZone4 = true;
- text = textLine2 = buildZonePowerResponse("ZONE4", powerZone4, sourceZone4);
- showZone = 4;
+ powers[numZone] = true;
+ text = textLine2 = buildZonePowerResponse(numZone);
+ showZone = numZone;
resetZone = false;
break;
case RECORD_FONCTION_SELECT:
- if (model.getNbAdditionalZones() >= 1 && model.getZoneSelectCmd() == cmd) {
+ if (model.getNumberOfZones() > 1 && model.getZoneSelectCmd() == cmd) {
showZone++;
- if (showZone > model.getNbAdditionalZones()) {
+ if (showZone >= model.getNumberOfZones()) {
showZone = 1;
- if (!power) {
+ if (!powers[0]) {
showZone++;
}
}
showZone = 1;
}
if (showZone == 1) {
- selectingRecord = power;
+ selectingRecord = powers[0];
showTreble = false;
textLine2 = buildRecordResponse();
- } else if (showZone == 2) {
- selectingRecord = false;
- text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- powerZone2, sourceZone2);
- } else if (showZone == 3) {
- selectingRecord = false;
- text = textLine2 = buildZonePowerResponse("ZONE3", powerZone3, sourceZone3);
- } else if (showZone == 4) {
+ } else if (showZone >= 2 && showZone <= 4) {
selectingRecord = false;
- text = textLine2 = buildZonePowerResponse("ZONE4", powerZone4, sourceZone4);
+ text = textLine2 = buildZonePowerResponse(showZone);
}
resetZone = false;
break;
case ZONE_SELECT:
- if (model.getNbAdditionalZones() == 0
- || (model.getNbAdditionalZones() > 1 && model.getZoneSelectCmd() == cmd)
+ if (model.getNumberOfZones() == 1 || (model.getNumberOfZones() > 2 && model.getZoneSelectCmd() == cmd)
|| (showZone == 1 && model.getZoneSelectCmd() != cmd)) {
accepted = false;
} else {
if (model.getZoneSelectCmd() == cmd) {
- if (!power && !powerZone2) {
+ if (!powers[0] && !powers[2]) {
showZone = 2;
- powerZone2 = true;
+ powers[2] = true;
} else if (showZone == 2) {
- powerZone2 = !powerZone2;
+ powers[2] = !powers[2];
} else {
showZone = 2;
}
- } else {
- if (showZone == 2) {
- powerZone2 = !powerZone2;
- } else if (showZone == 3) {
- powerZone3 = !powerZone3;
- } else if (showZone == 4) {
- powerZone4 = !powerZone4;
- }
+ } else if (showZone >= 2 && showZone <= 4) {
+ powers[showZone] = !powers[showZone];
}
- if (showZone == 2) {
- text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- powerZone2, sourceZone2);
- } else if (showZone == 3) {
- text = textLine2 = buildZonePowerResponse("ZONE3", powerZone3, sourceZone3);
- } else if (showZone == 4) {
- text = textLine2 = buildZonePowerResponse("ZONE4", powerZone4, sourceZone4);
+ if (showZone >= 2 && showZone <= 4) {
+ text = textLine2 = buildZonePowerResponse(showZone);
}
resetZone = false;
}
accepted = false;
break;
}
- if (!accepted && powerZone2) {
+ if (!accepted && numZone > 0 && powers[numZone]) {
accepted = true;
switch (cmd) {
+ case ZONE1_VOLUME_UP:
case ZONE2_VOLUME_UP:
- if (volumeZone2 < maxVolume) {
- volumeZone2++;
+ case ZONE3_VOLUME_UP:
+ case ZONE4_VOLUME_UP:
+ if (volumes[numZone] < maxVolume) {
+ volumes[numZone]++;
}
- text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- muteZone2, volumeZone2);
+ text = textLine2 = buildZoneVolumeResponse(numZone);
+ textAscii = buildVolumeAsciiResponse();
break;
+ case ZONE1_VOLUME_DOWN:
case ZONE2_VOLUME_DOWN:
- if (volumeZone2 > minVolume) {
- volumeZone2--;
+ case ZONE3_VOLUME_DOWN:
+ case ZONE4_VOLUME_DOWN:
+ if (volumes[numZone] > minVolume) {
+ volumes[numZone]--;
}
- text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- muteZone2, volumeZone2);
+ text = textLine2 = buildZoneVolumeResponse(numZone);
+ textAscii = buildVolumeAsciiResponse();
break;
+ case ZONE1_VOLUME_SET:
case ZONE2_VOLUME_SET:
+ case ZONE3_VOLUME_SET:
+ case ZONE4_VOLUME_SET:
if (value != null) {
- volumeZone2 = value;
- }
- text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- muteZone2, volumeZone2);
- break;
- case VOLUME_UP:
- if (!model.hasZone2Commands() && model.getNbAdditionalZones() >= 1 && showZone == 2) {
- if (volumeZone2 < maxVolume) {
- volumeZone2++;
- }
- text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- muteZone2, volumeZone2);
- resetZone = false;
- } else {
- accepted = false;
- }
- break;
- case VOLUME_DOWN:
- if (!model.hasZone2Commands() && model.getNbAdditionalZones() >= 1 && showZone == 2) {
- if (volumeZone2 > minVolume) {
- volumeZone2--;
- }
- text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- muteZone2, volumeZone2);
- resetZone = false;
- } else {
- accepted = false;
- }
- break;
- case VOLUME_SET:
- if (!model.hasZone2Commands() && model.getNbAdditionalZones() >= 1 && showZone == 2) {
- if (value != null) {
- volumeZone2 = value;
- }
- text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- muteZone2, volumeZone2);
- resetZone = false;
- } else {
- accepted = false;
+ volumes[numZone] = value;
}
+ text = textLine2 = buildZoneVolumeResponse(numZone);
+ textAscii = buildVolumeAsciiResponse();
break;
+ case ZONE1_MUTE_TOGGLE:
case ZONE2_MUTE_TOGGLE:
- muteZone2 = !muteZone2;
- text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- muteZone2, volumeZone2);
+ case ZONE3_MUTE_TOGGLE:
+ case ZONE4_MUTE_TOGGLE:
+ mutes[numZone] = !mutes[numZone];
+ text = textLine2 = buildZoneVolumeResponse(numZone);
+ textAscii = buildMuteAsciiResponse();
break;
+ case ZONE1_MUTE_ON:
case ZONE2_MUTE_ON:
- muteZone2 = true;
- text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- muteZone2, volumeZone2);
+ case ZONE3_MUTE_ON:
+ case ZONE4_MUTE_ON:
+ mutes[numZone] = true;
+ text = textLine2 = buildZoneVolumeResponse(numZone);
+ textAscii = buildMuteAsciiResponse();
break;
+ case ZONE1_MUTE_OFF:
case ZONE2_MUTE_OFF:
- muteZone2 = false;
- text = textLine2 = buildZoneVolumeResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- muteZone2, volumeZone2);
+ case ZONE3_MUTE_OFF:
+ case ZONE4_MUTE_OFF:
+ mutes[numZone] = false;
+ text = textLine2 = buildZoneVolumeResponse(numZone);
+ textAscii = buildMuteAsciiResponse();
break;
- default:
- accepted = false;
+ case ZONE1_BASS_UP:
+ case ZONE2_BASS_UP:
+ case ZONE3_BASS_UP:
+ case ZONE4_BASS_UP:
+ if (!tcbypass && basses[numZone] < maxToneLevel) {
+ basses[numZone] += STEP_TONE_LEVEL;
+ }
+ textAscii = buildBassAsciiResponse();
break;
- }
- if (!accepted) {
- try {
- sourceZone2 = model.getZone2SourceFromCommand(cmd);
- powerZone2 = true;
- text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- powerZone2, sourceZone2);
- muteZone2 = false;
- accepted = true;
- showZone = 2;
- resetZone = false;
- } catch (RotelException e) {
- }
- }
- if (!accepted && !model.hasZone2Commands() && model.getNbAdditionalZones() >= 1 && showZone == 2) {
- try {
- sourceZone2 = model.getSourceFromCommand(cmd);
- powerZone2 = true;
- text = textLine2 = buildZonePowerResponse(model.getNbAdditionalZones() > 1 ? "ZONE2" : "ZONE",
- powerZone2, sourceZone2);
- muteZone2 = false;
- accepted = true;
- resetZone = false;
- } catch (RotelException e) {
- }
- }
- }
- if (!accepted && powerZone3) {
- accepted = true;
- switch (cmd) {
- case ZONE3_VOLUME_UP:
- if (volumeZone3 < maxVolume) {
- volumeZone3++;
+ case ZONE1_BASS_DOWN:
+ case ZONE2_BASS_DOWN:
+ case ZONE3_BASS_DOWN:
+ case ZONE4_BASS_DOWN:
+ if (!tcbypass && basses[numZone] > minToneLevel) {
+ basses[numZone] -= STEP_TONE_LEVEL;
}
- text = textLine2 = buildZoneVolumeResponse("ZONE3", muteZone3, volumeZone3);
+ textAscii = buildBassAsciiResponse();
break;
- case ZONE3_VOLUME_DOWN:
- if (volumeZone3 > minVolume) {
- volumeZone3--;
+ case ZONE1_BASS_SET:
+ case ZONE2_BASS_SET:
+ case ZONE3_BASS_SET:
+ case ZONE4_BASS_SET:
+ if (!tcbypass && value != null) {
+ basses[numZone] = value;
}
- text = textLine2 = buildZoneVolumeResponse("ZONE3", muteZone3, volumeZone3);
+ textAscii = buildBassAsciiResponse();
break;
- case ZONE3_VOLUME_SET:
- if (value != null) {
- volumeZone3 = value;
+ case ZONE1_TREBLE_UP:
+ case ZONE2_TREBLE_UP:
+ case ZONE3_TREBLE_UP:
+ case ZONE4_TREBLE_UP:
+ if (!tcbypass && trebles[numZone] < maxToneLevel) {
+ trebles[numZone] += STEP_TONE_LEVEL;
}
- text = textLine2 = buildZoneVolumeResponse("ZONE3", muteZone3, volumeZone3);
+ textAscii = buildTrebleAsciiResponse();
break;
- case ZONE3_MUTE_TOGGLE:
- muteZone3 = !muteZone3;
- text = textLine2 = buildZoneVolumeResponse("ZONE3", muteZone3, volumeZone3);
+ case ZONE1_TREBLE_DOWN:
+ case ZONE2_TREBLE_DOWN:
+ case ZONE3_TREBLE_DOWN:
+ case ZONE4_TREBLE_DOWN:
+ if (!tcbypass && trebles[numZone] > minToneLevel) {
+ trebles[numZone] -= STEP_TONE_LEVEL;
+ }
+ textAscii = buildTrebleAsciiResponse();
break;
- case ZONE3_MUTE_ON:
- muteZone3 = true;
- text = textLine2 = buildZoneVolumeResponse("ZONE3", muteZone3, volumeZone3);
+ case ZONE1_TREBLE_SET:
+ case ZONE2_TREBLE_SET:
+ case ZONE3_TREBLE_SET:
+ case ZONE4_TREBLE_SET:
+ if (!tcbypass && value != null) {
+ trebles[numZone] = value;
+ }
+ textAscii = buildTrebleAsciiResponse();
break;
- case ZONE3_MUTE_OFF:
- muteZone3 = false;
- text = textLine2 = buildZoneVolumeResponse("ZONE3", muteZone3, volumeZone3);
+ case ZONE1_BALANCE_LEFT:
+ case ZONE2_BALANCE_LEFT:
+ case ZONE3_BALANCE_LEFT:
+ case ZONE4_BALANCE_LEFT:
+ if (balances[numZone] > minBalance) {
+ balances[numZone]--;
+ }
+ textAscii = buildBalanceAsciiResponse();
+ break;
+ case ZONE1_BALANCE_RIGHT:
+ case ZONE2_BALANCE_RIGHT:
+ case ZONE3_BALANCE_RIGHT:
+ case ZONE4_BALANCE_RIGHT:
+ if (balances[numZone] < maxBalance) {
+ balances[numZone]++;
+ }
+ textAscii = buildBalanceAsciiResponse();
+ break;
+ case ZONE1_BALANCE_SET:
+ case ZONE2_BALANCE_SET:
+ case ZONE3_BALANCE_SET:
+ case ZONE4_BALANCE_SET:
+ if (value != null) {
+ balances[numZone] = value;
+ }
+ textAscii = buildBalanceAsciiResponse();
break;
default:
accepted = false;
break;
}
- if (!accepted) {
- try {
- sourceZone3 = model.getZone3SourceFromCommand(cmd);
- powerZone3 = true;
- text = textLine2 = buildZonePowerResponse("ZONE3", powerZone3, sourceZone3);
- muteZone3 = false;
- accepted = true;
- showZone = 3;
- resetZone = false;
- } catch (RotelException e) {
+ }
+ if (!accepted) {
+ // Check if command is a change of source input for a zone
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ if (powers[zone]) {
+ try {
+ sources[zone] = model.getZoneSourceFromCommand(cmd, zone);
+ text = textLine2 = buildZonePowerResponse(zone);
+ textAscii = buildSourceAsciiResponse();
+ mutes[zone] = false;
+ accepted = true;
+ showZone = zone;
+ resetZone = false;
+ break;
+ } catch (RotelException e) {
+ }
}
}
}
- if (!accepted && powerZone4) {
+ if (!accepted && powers[2] && !model.hasZoneCommands(2) && model.getNumberOfZones() > 1 && showZone == 2) {
accepted = true;
switch (cmd) {
- case ZONE4_VOLUME_UP:
- if (volumeZone4 < maxVolume) {
- volumeZone4++;
+ case VOLUME_UP:
+ if (volumes[2] < maxVolume) {
+ volumes[2]++;
}
- text = textLine2 = buildZoneVolumeResponse("ZONE4", muteZone4, volumeZone4);
+ text = textLine2 = buildZoneVolumeResponse(2);
+ resetZone = false;
break;
- case ZONE4_VOLUME_DOWN:
- if (volumeZone4 > minVolume) {
- volumeZone4--;
+ case VOLUME_DOWN:
+ if (volumes[2] > minVolume) {
+ volumes[2]--;
}
- text = textLine2 = buildZoneVolumeResponse("ZONE4", muteZone4, volumeZone4);
+ text = textLine2 = buildZoneVolumeResponse(2);
+ resetZone = false;
break;
- case ZONE4_VOLUME_SET:
+ case VOLUME_SET:
if (value != null) {
- volumeZone4 = value;
+ volumes[2] = value;
}
- text = textLine2 = buildZoneVolumeResponse("ZONE4", muteZone4, volumeZone4);
- break;
- case ZONE4_MUTE_TOGGLE:
- muteZone4 = !muteZone4;
- text = textLine2 = buildZoneVolumeResponse("ZONE4", muteZone4, volumeZone4);
- break;
- case ZONE4_MUTE_ON:
- muteZone4 = true;
- text = textLine2 = buildZoneVolumeResponse("ZONE4", muteZone4, volumeZone4);
- break;
- case ZONE4_MUTE_OFF:
- muteZone4 = false;
- text = textLine2 = buildZoneVolumeResponse("ZONE4", muteZone4, volumeZone4);
+ text = textLine2 = buildZoneVolumeResponse(2);
+ resetZone = false;
break;
default:
accepted = false;
}
if (!accepted) {
try {
- sourceZone4 = model.getZone4SourceFromCommand(cmd);
- powerZone4 = true;
- text = textLine2 = buildZonePowerResponse("ZONE4", powerZone4, sourceZone4);
- muteZone4 = false;
+ sources[2] = model.getSourceFromCommand(cmd);
+ text = textLine2 = buildZonePowerResponse(2);
+ mutes[2] = false;
accepted = true;
- showZone = 4;
resetZone = false;
} catch (RotelException e) {
}
}
}
- if (!accepted && power) {
+ if (!accepted && powers[0]) {
accepted = true;
switch (cmd) {
case UPDATE_AUTO:
break;
case VOLUME_UP:
case MAIN_ZONE_VOLUME_UP:
- if (volume < maxVolume) {
- volume++;
+ if (volumes[0] < maxVolume) {
+ volumes[0]++;
}
text = buildVolumeLine1Response();
textLine1Right = buildVolumeLine1RightResponse();
break;
case VOLUME_DOWN:
case MAIN_ZONE_VOLUME_DOWN:
- if (volume > minVolume) {
- volume--;
+ if (volumes[0] > minVolume) {
+ volumes[0]--;
}
text = buildVolumeLine1Response();
textLine1Right = buildVolumeLine1RightResponse();
break;
case VOLUME_SET:
if (value != null) {
- volume = value;
+ volumes[0] = value;
}
text = buildVolumeLine1Response();
textLine1Right = buildVolumeLine1RightResponse();
break;
case MUTE_TOGGLE:
case MAIN_ZONE_MUTE_TOGGLE:
- mute = !mute;
+ mutes[0] = !mutes[0];
text = buildSourceLine1Response();
textLine1Right = buildVolumeLine1RightResponse();
textAscii = buildMuteAsciiResponse();
break;
case MUTE_ON:
case MAIN_ZONE_MUTE_ON:
- mute = true;
+ mutes[0] = true;
text = buildSourceLine1Response();
textLine1Right = buildVolumeLine1RightResponse();
textAscii = buildMuteAsciiResponse();
break;
case MUTE_OFF:
case MAIN_ZONE_MUTE_OFF:
- mute = false;
+ mutes[0] = false;
text = buildSourceLine1Response();
textLine1Right = buildVolumeLine1RightResponse();
textAscii = buildMuteAsciiResponse();
textAscii = buildMuteAsciiResponse();
break;
case TONE_MAX:
- textAscii = buildAsciiResponse(KEY_TONE_MAX, "%02d", maxToneLevel);
+ textAscii = buildAsciiResponse(KEY_TONE_MAX, String.format("%02d", maxToneLevel));
+ break;
+ case TONE_CONTROLS_ON:
+ tcbypass = false;
+ textAscii = buildAsciiResponse(KEY_TONE, !tcbypass);
+ break;
+ case TONE_CONTROLS_OFF:
+ tcbypass = true;
+ textAscii = buildAsciiResponse(KEY_TONE, !tcbypass);
+ break;
+ case TONE_CONTROLS:
+ textAscii = buildAsciiResponse(KEY_TONE, !tcbypass);
+ break;
+ case TCBYPASS_ON:
+ tcbypass = true;
+ textAscii = buildAsciiResponse(KEY_TCBYPASS, tcbypass);
+ break;
+ case TCBYPASS_OFF:
+ tcbypass = false;
+ textAscii = buildAsciiResponse(KEY_TCBYPASS, tcbypass);
+ break;
+ case TCBYPASS:
+ textAscii = buildAsciiResponse(KEY_TCBYPASS, tcbypass);
break;
case BASS_UP:
- if (bass < maxToneLevel) {
- bass += STEP_TONE_LEVEL;
+ if (!tcbypass && basses[0] < maxToneLevel) {
+ basses[0] += STEP_TONE_LEVEL;
}
text = buildBassLine1Response();
textLine1Right = buildBassLine1RightResponse();
textAscii = buildBassAsciiResponse();
break;
case BASS_DOWN:
- if (bass > minToneLevel) {
- bass -= STEP_TONE_LEVEL;
+ if (!tcbypass && basses[0] > minToneLevel) {
+ basses[0] -= STEP_TONE_LEVEL;
}
text = buildBassLine1Response();
textLine1Right = buildBassLine1RightResponse();
textAscii = buildBassAsciiResponse();
break;
case BASS_SET:
- if (value != null) {
- bass = value;
+ if (!tcbypass && value != null) {
+ basses[0] = value;
}
text = buildBassLine1Response();
textLine1Right = buildBassLine1RightResponse();
textAscii = buildBassAsciiResponse();
break;
case TREBLE_UP:
- if (treble < maxToneLevel) {
- treble += STEP_TONE_LEVEL;
+ if (!tcbypass && trebles[0] < maxToneLevel) {
+ trebles[0] += STEP_TONE_LEVEL;
}
text = buildTrebleLine1Response();
textLine1Right = buildTrebleLine1RightResponse();
textAscii = buildTrebleAsciiResponse();
break;
case TREBLE_DOWN:
- if (treble > minToneLevel) {
- treble -= STEP_TONE_LEVEL;
+ if (!tcbypass && trebles[0] > minToneLevel) {
+ trebles[0] -= STEP_TONE_LEVEL;
}
text = buildTrebleLine1Response();
textLine1Right = buildTrebleLine1RightResponse();
textAscii = buildTrebleAsciiResponse();
break;
case TREBLE_SET:
- if (value != null) {
- treble = value;
+ if (!tcbypass && value != null) {
+ trebles[0] = value;
}
text = buildTrebleLine1Response();
textLine1Right = buildTrebleLine1RightResponse();
textLine1Right = buildBassLine1RightResponse();
}
break;
+ case BALANCE_LEFT:
+ if (balances[0] > minBalance) {
+ balances[0]--;
+ }
+ textAscii = buildBalanceAsciiResponse();
+ break;
+ case BALANCE_RIGHT:
+ if (balances[0] < maxBalance) {
+ balances[0]++;
+ }
+ textAscii = buildBalanceAsciiResponse();
+ break;
+ case BALANCE_SET:
+ if (value != null) {
+ balances[0] = value;
+ }
+ textAscii = buildBalanceAsciiResponse();
+ break;
+ case BALANCE:
+ textAscii = buildBalanceAsciiResponse();
+ break;
+ case SPEAKER_A_TOGGLE:
+ speakerA = !speakerA;
+ textAscii = buildSpeakerAsciiResponse();
+ break;
+ case SPEAKER_A_ON:
+ speakerA = true;
+ textAscii = buildSpeakerAsciiResponse();
+ break;
+ case SPEAKER_A_OFF:
+ speakerA = false;
+ textAscii = buildSpeakerAsciiResponse();
+ break;
+ case SPEAKER_B_TOGGLE:
+ speakerB = !speakerB;
+ textAscii = buildSpeakerAsciiResponse();
+ break;
+ case SPEAKER_B_ON:
+ speakerB = true;
+ textAscii = buildSpeakerAsciiResponse();
+ break;
+ case SPEAKER_B_OFF:
+ speakerB = false;
+ textAscii = buildSpeakerAsciiResponse();
+ break;
+ case SPEAKER:
+ textAscii = buildSpeakerAsciiResponse();
+ break;
case PLAY:
playStatus = RotelPlayStatus.PLAYING;
textAscii = buildPlayStatusAsciiResponse();
multiinput = !multiinput;
text = "MULTI IN " + (multiinput ? "ON" : "OFF");
try {
- source = model.getSourceFromCommand(cmd);
+ sources[0] = model.getSourceFromCommand(cmd);
textLine1Left = buildSourceLine1LeftResponse();
textAscii = buildSourceAsciiResponse();
- mute = false;
+ mutes[0] = false;
} catch (RotelException e) {
}
break;
case SOURCE:
+ case INPUT:
textAscii = buildSourceAsciiResponse();
break;
case STEREO:
textAscii = buildDspAsciiResponse();
break;
case FREQUENCY:
- textAscii = buildAsciiResponse(KEY_FREQ, "44.1");
+ textAscii = model.getNumberOfZones() > 1 ? buildAsciiResponse(KEY_FREQ, "44.1,48,none,176.4")
+ : buildAsciiResponse(KEY_FREQ, "44.1");
break;
case DIMMER_LEVEL_SET:
if (value != null) {
case DIMMER_LEVEL_GET:
textAscii = buildAsciiResponse(KEY_DIMMER, dimmer);
break;
+ case MODEL:
+ textAscii = buildAsciiResponse(KEY_MODEL, model.getName());
+ break;
+ case VERSION:
+ textAscii = buildAsciiResponse(KEY_VERSION, "1.00");
+ break;
default:
accepted = false;
break;
}
if (!accepted) {
+ // Check if command is a change of source input for the main zone
try {
- source = model.getMainZoneSourceFromCommand(cmd);
+ sources[0] = model.getZoneSourceFromCommand(cmd, 1);
text = buildSourceLine1Response();
textLine1Left = buildSourceLine1LeftResponse();
textAscii = buildSourceAsciiResponse();
}
}
if (!accepted) {
+ // Check if command is a change of source input
try {
if (selectingRecord && !model.hasOtherThanPrimaryCommands()) {
recordSource = model.getSourceFromCommand(cmd);
} else {
- source = model.getSourceFromCommand(cmd);
+ sources[0] = model.getSourceFromCommand(cmd);
}
text = buildSourceLine1Response();
textLine1Left = buildSourceLine1LeftResponse();
textAscii = buildSourceAsciiResponse();
- mute = false;
+ mutes[0] = false;
accepted = true;
} catch (RotelException e) {
}
}
if (!accepted) {
+ // Check if command is a change of record source
try {
recordSource = model.getRecordSourceFromCommand(cmd);
text = buildSourceLine1Response();
} catch (RotelException e) {
}
try {
- model.setZone2(flags, powerZone2);
+ model.setZone2(flags, powers[2]);
} catch (RotelException e) {
}
try {
- model.setZone3(flags, powerZone3);
+ model.setZone3(flags, powers[3]);
} catch (RotelException e) {
}
try {
- model.setZone4(flags, powerZone4);
+ model.setZone4(flags, powers[4]);
} catch (RotelException e) {
}
int size = 6 + model.getRespNbChars() + model.getRespNbFlags();
}
private String buildAsciiResponse(String key, int value) {
- return buildAsciiResponse(key, "%d", value);
+ return String.format("%s=%d", key, value);
}
- private String buildAsciiResponse(String key, String format, int value) {
- return String.format("%s=" + format, key, value);
+ private String buildAsciiResponse(String key, boolean value) {
+ return buildAsciiResponse(key, buildOnOffValue(value));
}
- private String buildAsciiResponse(String key, boolean value) {
- return buildAsciiResponse(key, value ? MSG_VALUE_ON : MSG_VALUE_OFF);
+ private String buildOnOffValue(boolean on) {
+ return on ? MSG_VALUE_ON : MSG_VALUE_OFF;
}
private String buildPowerAsciiResponse() {
- return buildAsciiResponse(KEY_POWER, power ? POWER_ON : STANDBY);
+ return buildAsciiResponse(KEY_POWER, powers[0] ? POWER_ON : STANDBY);
}
private String buildVolumeAsciiResponse() {
- return buildAsciiResponse(KEY_VOLUME, "%02d", volume);
+ if (model.getNumberOfZones() > 1) {
+ StringJoiner sj = new StringJoiner(",");
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ sj.add(String.format("%02d", volumes[zone]));
+ }
+ return buildAsciiResponse(KEY_VOLUME, sj.toString());
+ } else {
+ return buildAsciiResponse(KEY_VOLUME, String.format("%02d", volumes[0]));
+ }
}
private String buildMuteAsciiResponse() {
- return buildAsciiResponse(KEY_MUTE, mute);
+ if (model.getNumberOfZones() > 1) {
+ StringJoiner sj = new StringJoiner(",");
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ sj.add(buildOnOffValue(mutes[zone]));
+ }
+ return buildAsciiResponse(KEY_MUTE, sj.toString());
+ } else {
+ return buildAsciiResponse(KEY_MUTE, mutes[0]);
+ }
}
private String buildBassAsciiResponse() {
- String result;
- if (bass == 0) {
- result = buildAsciiResponse(KEY_BASS, "000");
- } else if (bass > 0) {
- result = buildAsciiResponse(KEY_BASS, "+%02d", bass);
+ if (model.getNumberOfZones() > 1) {
+ StringJoiner sj = new StringJoiner(",");
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ sj.add(buildBassTrebleValue(basses[zone]));
+ }
+ return buildAsciiResponse(KEY_BASS, sj.toString());
} else {
- result = buildAsciiResponse(KEY_BASS, "-%02d", -bass);
+ return buildAsciiResponse(KEY_BASS, buildBassTrebleValue(basses[0]));
}
- return result;
}
private String buildTrebleAsciiResponse() {
- String result;
- if (treble == 0) {
- result = buildAsciiResponse(KEY_TREBLE, "000");
- } else if (treble > 0) {
- result = buildAsciiResponse(KEY_TREBLE, "+%02d", treble);
+ if (model.getNumberOfZones() > 1) {
+ StringJoiner sj = new StringJoiner(",");
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ sj.add(buildBassTrebleValue(trebles[zone]));
+ }
+ return buildAsciiResponse(KEY_TREBLE, sj.toString());
+ } else {
+ return buildAsciiResponse(KEY_TREBLE, buildBassTrebleValue(trebles[0]));
+ }
+ }
+
+ private String buildBassTrebleValue(int value) {
+ if (tcbypass || value == 0) {
+ return "000";
+ } else if (value > 0) {
+ return String.format("+%02d", value);
} else {
- result = buildAsciiResponse(KEY_TREBLE, "-%02d", -treble);
+ return String.format("-%02d", -value);
}
- return result;
+ }
+
+ private String buildBalanceAsciiResponse() {
+ if (model.getNumberOfZones() > 1) {
+ StringJoiner sj = new StringJoiner(",");
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ sj.add(buildBalanceValue(balances[zone]));
+ }
+ return buildAsciiResponse(KEY_BALANCE, sj.toString());
+ } else {
+ return buildAsciiResponse(KEY_BALANCE, buildBalanceValue(balances[0]));
+ }
+ }
+
+ private String buildBalanceValue(int value) {
+ if (value == 0) {
+ return "000";
+ } else if (value > 0) {
+ return String.format("r%02d", value);
+ } else {
+ return String.format("l%02d", -value);
+ }
+ }
+
+ private String buildSpeakerAsciiResponse() {
+ String value;
+ if (speakerA && speakerB) {
+ value = MSG_VALUE_SPEAKER_AB;
+ } else if (speakerA && !speakerB) {
+ value = MSG_VALUE_SPEAKER_A;
+ } else if (!speakerA && speakerB) {
+ value = MSG_VALUE_SPEAKER_B;
+ } else {
+ value = MSG_VALUE_OFF;
+ }
+ return buildAsciiResponse(KEY_SPEAKER, value);
}
private String buildPlayStatusAsciiResponse() {
}
private String buildTrackAsciiResponse() {
- return buildAsciiResponse(KEY_TRACK, "%03d", track);
+ return buildAsciiResponse(KEY_TRACK, String.format("%03d", track));
}
private String buildSourceAsciiResponse() {
+ if (model.getNumberOfZones() > 1) {
+ StringJoiner sj = new StringJoiner(",");
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ sj.add(buildZoneSourceValue(sources[zone]));
+ }
+ return buildAsciiResponse(KEY_INPUT, sj.toString());
+ } else {
+ return buildAsciiResponse(KEY_SOURCE, buildSourceValue(sources[0]));
+ }
+ }
+
+ private String buildSourceValue(RotelSource source) {
String str = null;
RotelCommand command = source.getCommand();
if (command != null) {
- str = command.getAsciiCommandV2();
+ str = protocol == RotelProtocol.ASCII_V1 ? command.getAsciiCommandV1() : command.getAsciiCommandV2();
}
- return buildAsciiResponse(KEY_SOURCE, (str == null) ? "" : str);
+ return str == null ? "" : str;
+ }
+
+ private String buildZoneSourceValue(RotelSource source) {
+ String str = buildSourceValue(source);
+ int idx = str.indexOf("input_");
+ return idx < 0 ? str : str.substring(idx + 6);
}
private String buildDspAsciiResponse() {
private String buildSourceLine1Response() {
String text;
- if (!power) {
+ if (!powers[0]) {
text = "";
- } else if (mute) {
+ } else if (mutes[0]) {
text = "MUTE ON";
} else {
- text = getSourceLabel(source, false) + " " + getSourceLabel(recordSource, true);
+ text = getSourceLabel(sources[0], false) + " " + getSourceLabel(recordSource, true);
}
return text;
}
private String buildSourceLine1LeftResponse() {
String text;
- if (!power) {
+ if (!powers[0]) {
text = "";
} else {
- text = getSourceLabel(source, false);
+ text = getSourceLabel(sources[0], false);
}
return text;
}
private String buildRecordResponse() {
String text;
- if (!power) {
+ if (!powers[0]) {
text = "";
} else {
text = "REC " + getSourceLabel(recordSource, true);
return text;
}
- private String buildZonePowerResponse(String zone, boolean powerZone, RotelSource sourceZone) {
- String state = powerZone ? getSourceLabel(sourceZone, true) : "OFF";
+ private String buildZonePowerResponse(int numZone) {
+ String zone;
+ if (numZone == 2) {
+ zone = model.getNumberOfZones() > 2 ? "ZONE2" : "ZONE";
+ } else {
+ zone = String.format("ZONE%d", numZone);
+ }
+ String state = powers[numZone] ? getSourceLabel(sources[numZone], true) : "OFF";
return zone + " " + state;
}
private String buildVolumeLine1Response() {
String text;
- if (volume == minVolume) {
+ if (volumes[0] == minVolume) {
text = " VOLUME MIN ";
- } else if (volume == maxVolume) {
+ } else if (volumes[0] == maxVolume) {
text = " VOLUME MAX ";
} else {
- text = String.format(" VOLUME %02d ", volume);
+ text = String.format(" VOLUME %02d ", volumes[0]);
}
return text;
}
private String buildVolumeLine1RightResponse() {
String text;
- if (!power) {
+ if (!powers[0]) {
text = "";
- } else if (mute) {
+ } else if (mutes[0]) {
text = "MUTE ON";
- } else if (volume == minVolume) {
+ } else if (volumes[0] == minVolume) {
text = "VOL MIN";
- } else if (volume == maxVolume) {
+ } else if (volumes[0] == maxVolume) {
text = "VOL MAX";
} else {
- text = String.format("VOL %02d", volume);
+ text = String.format("VOL %02d", volumes[0]);
}
return text;
}
- private String buildZoneVolumeResponse(String zone, boolean muted, int vol) {
+ private String buildZoneVolumeResponse(int numZone) {
+ String zone;
+ if (numZone == 2) {
+ zone = model.getNumberOfZones() > 2 ? "ZONE2" : "ZONE";
+ } else {
+ zone = String.format("ZONE%d", numZone);
+ }
String text;
- if (muted) {
+ if (mutes[numZone]) {
text = zone + " MUTE ON";
- } else if (vol == minVolume) {
+ } else if (volumes[numZone] == minVolume) {
text = zone + " VOL MIN";
- } else if (vol == maxVolume) {
+ } else if (volumes[numZone] == maxVolume) {
text = zone + " VOL MAX";
} else {
- text = String.format("%s VOL %02d", zone, vol);
+ text = String.format("%s VOL %02d", zone, volumes[numZone]);
}
return text;
}
private String buildBassLine1Response() {
String text;
- if (bass == minToneLevel) {
+ if (basses[0] == minToneLevel) {
text = " BASS MIN ";
- } else if (bass == maxToneLevel) {
+ } else if (basses[0] == maxToneLevel) {
text = " BASS MAX ";
- } else if (bass == 0) {
+ } else if (basses[0] == 0) {
text = " BASS 0 ";
- } else if (bass > 0) {
- text = String.format(" BASS +%02d ", bass);
+ } else if (basses[0] > 0) {
+ text = String.format(" BASS +%02d ", basses[0]);
} else {
- text = String.format(" BASS -%02d ", -bass);
+ text = String.format(" BASS -%02d ", -basses[0]);
}
return text;
}
private String buildBassLine1RightResponse() {
String text;
- if (bass == minToneLevel) {
+ if (basses[0] == minToneLevel) {
text = "LF MIN";
- } else if (bass == maxToneLevel) {
+ } else if (basses[0] == maxToneLevel) {
text = "LF MAX";
- } else if (bass == 0) {
+ } else if (basses[0] == 0) {
text = "LF 0";
- } else if (bass > 0) {
- text = String.format("LF + %02d", bass);
+ } else if (basses[0] > 0) {
+ text = String.format("LF + %02d", basses[0]);
} else {
- text = String.format("LF - %02d", -bass);
+ text = String.format("LF - %02d", -basses[0]);
}
return text;
}
private String buildTrebleLine1Response() {
String text;
- if (treble == minToneLevel) {
+ if (trebles[0] == minToneLevel) {
text = " TREBLE MIN ";
- } else if (treble == maxToneLevel) {
+ } else if (trebles[0] == maxToneLevel) {
text = " TREBLE MAX ";
- } else if (treble == 0) {
+ } else if (trebles[0] == 0) {
text = " TREBLE 0 ";
- } else if (treble > 0) {
- text = String.format(" TREBLE +%02d ", treble);
+ } else if (trebles[0] > 0) {
+ text = String.format(" TREBLE +%02d ", trebles[0]);
} else {
- text = String.format(" TREBLE -%02d ", -treble);
+ text = String.format(" TREBLE -%02d ", -trebles[0]);
}
return text;
}
private String buildTrebleLine1RightResponse() {
String text;
- if (treble == minToneLevel) {
+ if (trebles[0] == minToneLevel) {
text = "HF MIN";
- } else if (treble == maxToneLevel) {
+ } else if (trebles[0] == maxToneLevel) {
text = "HF MAX";
- } else if (treble == 0) {
+ } else if (trebles[0] == 0) {
text = "HF 0";
- } else if (treble > 0) {
- text = String.format("HF + %02d", treble);
+ } else if (trebles[0] > 0) {
+ text = String.format("HF + %02d", trebles[0]);
} else {
- text = String.format("HF - %02d", -treble);
+ text = String.format("HF - %02d", -trebles[0]);
}
return text;
}
CAT20_BLUETOOTH(20, "BLUETOOTH", "Bluetooth", RotelCommand.SOURCE_BLUETOOTH),
CAT20_XLR1(20, "XLR1", "XLR 1", RotelCommand.SOURCE_XLR1),
CAT20_XLR2(20, "XLR2", "XLR 2", RotelCommand.SOURCE_XLR1),
- CAT20_PCUSB(20, "PCUSB", "PC USB", RotelCommand.SOURCE_PCUSB);
+ CAT20_PCUSB(20, "PCUSB", "PC USB", RotelCommand.SOURCE_PCUSB),
+
+ CAT21_INPUTA(21, "INPUTA", "Input A", RotelCommand.SOURCE_INPUT_A, null, RotelCommand.ZONE1_SOURCE_INPUT_A,
+ RotelCommand.ZONE2_SOURCE_INPUT_A, RotelCommand.ZONE3_SOURCE_INPUT_A, RotelCommand.ZONE4_SOURCE_INPUT_A),
+ CAT21_INPUTB(21, "INPUTB", "Input B", RotelCommand.SOURCE_INPUT_B, null, RotelCommand.ZONE1_SOURCE_INPUT_B,
+ RotelCommand.ZONE2_SOURCE_INPUT_B, RotelCommand.ZONE3_SOURCE_INPUT_B, RotelCommand.ZONE4_SOURCE_INPUT_B),
+ CAT21_INPUTC(21, "INPUTC", "Input C", RotelCommand.SOURCE_INPUT_C, null, RotelCommand.ZONE1_SOURCE_INPUT_C,
+ RotelCommand.ZONE2_SOURCE_INPUT_C, RotelCommand.ZONE3_SOURCE_INPUT_C, RotelCommand.ZONE4_SOURCE_INPUT_C),
+ CAT21_INPUTD(21, "INPUTD", "Input D", RotelCommand.SOURCE_INPUT_D, null, RotelCommand.ZONE1_SOURCE_INPUT_D,
+ RotelCommand.ZONE2_SOURCE_INPUT_D, RotelCommand.ZONE3_SOURCE_INPUT_D, RotelCommand.ZONE4_SOURCE_INPUT_D);
private int category;
private String name;
private String label;
private @Nullable RotelCommand command;
private @Nullable RotelCommand recordCommand;
- private @Nullable RotelCommand mainZoneCommand;
+ private @Nullable RotelCommand zone1Command;
private @Nullable RotelCommand zone2Command;
private @Nullable RotelCommand zone3Command;
private @Nullable RotelCommand zone4Command;
* @param label the label of the source
* @param command the command to select the source
* @param recordCommand the command to select the source as source to be recorded
- * @param mainZoneCommand the command to select the source in the main zone
+ * @param zone1Command the command to select the source in the zone 1 or main zone
* @param zone2Command the command to select the source in the zone 2
* @param zone3Command the command to select the source in the zone 3
* @param zone4Command the command to select the source in the zone 4
*/
private RotelSource(int category, String name, String label, @Nullable RotelCommand command,
- @Nullable RotelCommand recordCommand, @Nullable RotelCommand mainZoneCommand,
+ @Nullable RotelCommand recordCommand, @Nullable RotelCommand zone1Command,
@Nullable RotelCommand zone2Command, @Nullable RotelCommand zone3Command,
@Nullable RotelCommand zone4Command) {
this.category = category;
this.label = label;
this.command = command;
this.recordCommand = recordCommand;
- this.mainZoneCommand = mainZoneCommand;
+ this.zone1Command = zone1Command;
this.zone2Command = zone2Command;
this.zone3Command = zone3Command;
this.zone4Command = zone4Command;
}
/**
- * Get the command to select the source in the main zone
+ * Get the command to select the source in a zone
*
- * @return the command
- */
- public @Nullable RotelCommand getMainZoneCommand() {
- return mainZoneCommand;
- }
-
- /**
- * Get the command to select the source in the zone 2
+ * @param numZone the zone number, 1 for main zone or zone 1, 2 for zone 2, 3 for zone 3, 4 for zone 4
*
* @return the command
*/
- public @Nullable RotelCommand getZone2Command() {
- return zone2Command;
- }
-
- /**
- * Get the command to select the source in the zone 3
- *
- * @return the command
- */
- public @Nullable RotelCommand getZone3Command() {
- return zone3Command;
- }
-
- /**
- * Get the command to select the source in the zone 4
- *
- * @return the command
- */
- public @Nullable RotelCommand getZone4Command() {
- return zone4Command;
+ public @Nullable RotelCommand getZoneCommand(int numZone) {
+ switch (numZone) {
+ case 1:
+ return zone1Command;
+ case 2:
+ return zone2Command;
+ case 3:
+ return zone3Command;
+ case 4:
+ return zone4Command;
+ default:
+ throw new IllegalArgumentException("numZone must be a value between 1 and 4");
+ }
}
/**
* Get the list of {@link RotelSource} available for a particular category of models
*
* @param category a category of models
- * @param type a source type (0 for global source, 1 for main zone, 2 for zone 2, 3 for zone 3, 4 for zone 4 and 5
- * for record source)
+ * @param type a source type (0 for global source, 1 for main zone or zone 1, 2 for zone 2, 3 for zone 3, 4 for zone
+ * 4 and 5 for record source)
*
* @return the list of {@link RotelSource} available in a zone for a provided category of models
*/
List<RotelSource> sources = new ArrayList<>();
for (RotelSource value : RotelSource.values()) {
if (value.getCategory() == category && ((type == 0 && value.getCommand() != null)
- || (type == 1 && value.getMainZoneCommand() != null)
- || (type == 2 && value.getZone2Command() != null) || (type == 3 && value.getZone3Command() != null)
- || (type == 4 && value.getZone4Command() != null)
+ || (type == 1 && value.getZoneCommand(1) != null) || (type == 2 && value.getZoneCommand(2) != null)
+ || (type == 3 && value.getZoneCommand(3) != null) || (type == 4 && value.getZoneCommand(4) != null)
|| (type == 5 && value.getRecordCommand() != null))) {
sources.add(value);
}
*
* @param category a category of models
* @param command the command used to identify the source
- * @param type a source type (0 for global source, 1 for main zone, 2 for zone 2, 3 for zone 3, 4 for zone 4 and 5
- * for record source)
+ * @param type a source type (0 for global source, 1 for main zone or zone 1, 2 for zone 2, 3 for zone 3,
+ * 4 for zone 4 and 5 for record source)
*
* @return the source associated to the searched command for the provided category of models
*
public static RotelSource getFromCommand(int category, RotelCommand command, int type) throws RotelException {
for (RotelSource value : RotelSource.values()) {
if (value.getCategory() == category && ((type == 0 && value.getCommand() == command)
- || (type == 1 && value.getMainZoneCommand() == command)
- || (type == 2 && value.getZone2Command() == command)
- || (type == 3 && value.getZone3Command() == command)
- || (type == 4 && value.getZone4Command() == command)
+ || (type == 1 && value.getZoneCommand(1) == command)
+ || (type == 2 && value.getZoneCommand(2) == command)
+ || (type == 3 && value.getZoneCommand(3) == command)
+ || (type == 4 && value.getZoneCommand(4) == command)
|| (type == 5 && value.getRecordCommand() == command))) {
return value;
}
private static final int SLEEP_INTV = 30;
private @Nullable ScheduledFuture<?> reconnectJob;
- private @Nullable ScheduledFuture<?> powerOnJob;
private @Nullable ScheduledFuture<?> powerOffJob;
- private @Nullable ScheduledFuture<?> powerOnZone2Job;
- private @Nullable ScheduledFuture<?> powerOnZone3Job;
- private @Nullable ScheduledFuture<?> powerOnZone4Job;
+ private @Nullable ScheduledFuture<?>[] powerOnZoneJobs = { null, null, null, null, null };
private RotelStateDescriptionOptionProvider stateDescriptionProvider;
private SerialPortManager serialPortManager;
private int currentZone = 1;
private boolean selectingRecord;
- private @Nullable Boolean power;
- private boolean powerZone2;
- private boolean powerZone3;
- private boolean powerZone4;
- private RotelSource source = RotelSource.CAT0_CD;
+ private @Nullable Boolean[] powers = { null, false, false, false, false };
+ private boolean powerControlPerZone;
private @Nullable RotelSource recordSource;
- private @Nullable RotelSource sourceZone2;
- private @Nullable RotelSource sourceZone3;
- private @Nullable RotelSource sourceZone4;
+ private @Nullable RotelSource[] sources = { RotelSource.CAT0_CD, null, null, null, null };
private RotelDsp dsp = RotelDsp.CAT1_NONE;
- private int volume;
- private boolean mute;
- private boolean fixedVolumeZone2;
- private int volumeZone2;
- private boolean muteZone2;
- private boolean fixedVolumeZone3;
- private int volumeZone3;
- private boolean muteZone3;
- private boolean fixedVolumeZone4;
- private int volumeZone4;
- private boolean muteZone4;
- private int bass;
- private int treble;
+ private boolean[] fixedVolumeZones = { false, false, false, false, false };
+ private int[] volumes = { 0, 0, 0, 0, 0 };
+ private boolean[] mutes = { false, false, false, false, false };
+ private int[] basses = { 0, 0, 0, 0, 0 };
+ private int[] trebles = { 0, 0, 0, 0, 0 };
private RotelPlayStatus playStatus = RotelPlayStatus.STOPPED;
private int track;
- private double frequency;
+ private double[] frequencies = { 0.0, 0.0, 0.0, 0.0, 0.0 };
private String frontPanelLine1 = "";
private String frontPanelLine2 = "";
private int brightness;
private boolean tcbypass;
- private int balance;
+ private int[] balances = { 0, 0, 0, 0, 0 };
private int minBalanceLevel;
private int maxBalanceLevel;
private boolean speakera;
case THING_TYPE_ID_T14:
model = RotelModel.T14;
break;
+ case THING_TYPE_ID_C8:
+ model = RotelModel.C8;
+ break;
case THING_TYPE_ID_M8:
model = RotelModel.M8;
break;
minBalanceLevel, maxBalanceLevel);
}
+ powerControlPerZone = model.hasPowerControlPerZone();
+
// Check configuration settings
String configError = null;
if ((config.serialPort == null || config.serialPort.isEmpty())
new ChannelUID(getThing().getUID(), CHANNEL_MAIN_RECORD_SOURCE),
getStateOptions(model.getRecordSources(), sourcesCustomLabels));
}
- if (model.hasZone2SourceControl()) {
+ if (model.hasZoneSourceControl(1)) {
+ stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_ZONE1_SOURCE),
+ getStateOptions(model.getZoneSources(1), sourcesCustomLabels));
+ }
+ if (model.hasZoneSourceControl(2)) {
stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_ZONE2_SOURCE),
- getStateOptions(model.getZone2Sources(), sourcesCustomLabels));
+ getStateOptions(model.getZoneSources(2), sourcesCustomLabels));
}
- if (model.hasZone3SourceControl()) {
+ if (model.hasZoneSourceControl(3)) {
stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_ZONE3_SOURCE),
- getStateOptions(model.getZone3Sources(), sourcesCustomLabels));
+ getStateOptions(model.getZoneSources(3), sourcesCustomLabels));
}
- if (model.hasZone4SourceControl()) {
+ if (model.hasZoneSourceControl(4)) {
stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_ZONE4_SOURCE),
- getStateOptions(model.getZone4Sources(), sourcesCustomLabels));
+ getStateOptions(model.getZoneSources(4), sourcesCustomLabels));
}
if (model.hasDspControl()) {
stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_DSP),
public void dispose() {
logger.debug("Disposing handler for thing {}", getThing().getUID());
cancelPowerOffJob();
- cancelPowerOnJob();
- cancelPowerOnZone2Job();
- cancelPowerOnZone3Job();
- cancelPowerOnZone4Job();
+ for (int zone = 0; zone <= model.getNumberOfZones(); zone++) {
+ cancelPowerOnZoneJob(zone);
+ }
cancelReconnectJob();
closeConnection();
super.dispose();
return;
}
+ int numZone = 0;
+ switch (channel) {
+ case CHANNEL_ZONE1_SOURCE:
+ case CHANNEL_ZONE1_VOLUME:
+ case CHANNEL_ZONE1_MUTE:
+ case CHANNEL_ZONE1_BASS:
+ case CHANNEL_ZONE1_TREBLE:
+ case CHANNEL_ZONE1_BALANCE:
+ numZone = 1;
+ break;
+ case CHANNEL_ZONE2_POWER:
+ case CHANNEL_ZONE2_SOURCE:
+ case CHANNEL_ZONE2_VOLUME:
+ case CHANNEL_ZONE2_VOLUME_UP_DOWN:
+ case CHANNEL_ZONE2_MUTE:
+ case CHANNEL_ZONE2_BASS:
+ case CHANNEL_ZONE2_TREBLE:
+ case CHANNEL_ZONE2_BALANCE:
+ numZone = 2;
+ break;
+ case CHANNEL_ZONE3_POWER:
+ case CHANNEL_ZONE3_SOURCE:
+ case CHANNEL_ZONE3_VOLUME:
+ case CHANNEL_ZONE3_MUTE:
+ case CHANNEL_ZONE3_BASS:
+ case CHANNEL_ZONE3_TREBLE:
+ case CHANNEL_ZONE3_BALANCE:
+ numZone = 3;
+ break;
+ case CHANNEL_ZONE4_POWER:
+ case CHANNEL_ZONE4_SOURCE:
+ case CHANNEL_ZONE4_VOLUME:
+ case CHANNEL_ZONE4_MUTE:
+ case CHANNEL_ZONE4_BASS:
+ case CHANNEL_ZONE4_TREBLE:
+ case CHANNEL_ZONE4_BALANCE:
+ numZone = 4;
+ break;
+ default:
+ break;
+ }
+
RotelSource src;
RotelCommand cmd;
boolean success = true;
switch (channel) {
case CHANNEL_POWER:
case CHANNEL_MAIN_POWER:
- handlePowerCmd(channel, command, getPowerOnCommand(), getPowerOffCommand());
- break;
case CHANNEL_ZONE2_POWER:
- if (model.hasZone2Commands()) {
- handlePowerCmd(channel, command, RotelCommand.ZONE2_POWER_ON, RotelCommand.ZONE2_POWER_OFF);
- } else if (model.getNbAdditionalZones() == 1) {
- if (isPowerOn() || powerZone2) {
+ case CHANNEL_ZONE3_POWER:
+ case CHANNEL_ZONE4_POWER:
+ if (numZone == 0 || model.hasZoneCommands(numZone)) {
+ handlePowerCmd(channel, command, getPowerOnCommand(numZone), getPowerOffCommand(numZone));
+ } else if (numZone == 2 && model.getNumberOfZones() == 2) {
+ if (isPowerOn() || isPowerOn(numZone)) {
selectZone(2, model.getZoneSelectCmd());
}
sendCommand(RotelCommand.ZONE_SELECT);
logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
}
break;
- case CHANNEL_ZONE3_POWER:
- if (model.hasZone3Commands()) {
- handlePowerCmd(channel, command, RotelCommand.ZONE3_POWER_ON, RotelCommand.ZONE3_POWER_OFF);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
- case CHANNEL_ZONE4_POWER:
- if (model.hasZone4Commands()) {
- handlePowerCmd(channel, command, RotelCommand.ZONE4_POWER_ON, RotelCommand.ZONE4_POWER_OFF);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
+ case CHANNEL_ALL_POWER:
+ handlePowerCmd(channel, command, RotelCommand.POWER_ON, RotelCommand.POWER_OFF);
break;
case CHANNEL_SOURCE:
case CHANNEL_MAIN_SOURCE:
- if (!isPowerOn()) {
+ case CHANNEL_ZONE1_SOURCE:
+ case CHANNEL_ZONE2_SOURCE:
+ case CHANNEL_ZONE3_SOURCE:
+ case CHANNEL_ZONE4_SOURCE:
+ if (!isPowerOn(numZone)) {
success = false;
- logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
- } else {
+ logger.debug("Command {} from channel {} ignored: {} in standby", command, channel,
+ numZone == 0 ? "device" : "zone " + numZone);
+ } else if (numZone == 0 || model.hasZoneCommands(numZone)) {
src = model.getSourceFromName(command.toString());
- cmd = model.hasOtherThanPrimaryCommands() ? src.getMainZoneCommand() : src.getCommand();
+ if (numZone == 0) {
+ cmd = model.hasOtherThanPrimaryCommands() ? src.getZoneCommand(1) : src.getCommand();
+ } else {
+ cmd = src.getZoneCommand(numZone);
+ }
if (cmd != null) {
sendCommand(cmd);
if (model.canGetFrequency()) {
logger.debug("Command {} from channel {} failed: undefined source command", command,
channel);
}
- }
- break;
- case CHANNEL_MAIN_RECORD_SOURCE:
- if (!isPowerOn()) {
- success = false;
- logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
- } else if (model.hasOtherThanPrimaryCommands()) {
- src = model.getSourceFromName(command.toString());
- cmd = src.getRecordCommand();
- if (cmd != null) {
- sendCommand(cmd);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: undefined record source command",
- command, channel);
- }
- } else {
- src = model.getSourceFromName(command.toString());
- cmd = src.getCommand();
- if (cmd != null) {
- sendCommand(RotelCommand.RECORD_FONCTION_SELECT);
- Thread.sleep(100);
- sendCommand(cmd);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: undefined source command", command,
- channel);
- }
- }
- break;
- case CHANNEL_ZONE2_SOURCE:
- if (!powerZone2) {
- success = false;
- logger.debug("Command {} from channel {} ignored: zone 2 in standby", command, channel);
- } else if (model.hasZone2Commands()) {
- src = model.getSourceFromName(command.toString());
- cmd = src.getZone2Command();
- if (cmd != null) {
- sendCommand(cmd);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: undefined zone 2 source command",
- command, channel);
- }
- } else if (model.getNbAdditionalZones() >= 1) {
+ } else if (numZone == 2 && model.getNumberOfZones() > 1) {
src = model.getSourceFromName(command.toString());
cmd = src.getCommand();
if (cmd != null) {
selectZone(2, model.getZoneSelectCmd());
sendCommand(cmd);
+ if (model.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);
+ sendCommand(RotelCommand.FREQUENCY);
+ Thread.sleep(100);
+ updateChannelState(CHANNEL_FREQUENCY);
+ }
} else {
success = false;
logger.debug("Command {} from channel {} failed: undefined source command", command,
logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
}
break;
- case CHANNEL_ZONE3_SOURCE:
- if (!powerZone3) {
+ case CHANNEL_MAIN_RECORD_SOURCE:
+ if (!isPowerOn()) {
success = false;
- logger.debug("Command {} from channel {} ignored: zone 3 in standby", command, channel);
- } else if (model.hasZone3Commands()) {
+ logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+ } else if (model.hasOtherThanPrimaryCommands()) {
src = model.getSourceFromName(command.toString());
- cmd = src.getZone3Command();
+ cmd = src.getRecordCommand();
if (cmd != null) {
sendCommand(cmd);
} else {
success = false;
- logger.debug("Command {} from channel {} failed: undefined zone 3 source command",
+ logger.debug("Command {} from channel {} failed: undefined record source command",
command, channel);
}
} else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
- case CHANNEL_ZONE4_SOURCE:
- if (!powerZone4) {
- success = false;
- logger.debug("Command {} from channel {} ignored: zone 4 in standby", command, channel);
- } else if (model.hasZone4Commands()) {
src = model.getSourceFromName(command.toString());
- cmd = src.getZone4Command();
+ cmd = src.getCommand();
if (cmd != null) {
+ sendCommand(RotelCommand.RECORD_FONCTION_SELECT);
+ Thread.sleep(100);
sendCommand(cmd);
} else {
success = false;
- logger.debug("Command {} from channel {} failed: undefined zone 4 source command",
- command, channel);
+ logger.debug("Command {} from channel {} failed: undefined source command", command,
+ channel);
}
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
}
break;
case CHANNEL_DSP:
break;
case CHANNEL_VOLUME:
case CHANNEL_MAIN_VOLUME:
- if (!isPowerOn()) {
- success = false;
- logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
- } else if (model.hasVolumeControl()) {
- handleVolumeCmd(volume, channel, command, getVolumeUpCommand(), getVolumeDownCommand(),
- RotelCommand.VOLUME_SET);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
case CHANNEL_MAIN_VOLUME_UP_DOWN:
- if (!isPowerOn()) {
- success = false;
- logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
- } else if (model.hasVolumeControl()) {
- handleVolumeCmd(volume, channel, command, getVolumeUpCommand(), getVolumeDownCommand(),
- null);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
+ case CHANNEL_ZONE1_VOLUME:
case CHANNEL_ZONE2_VOLUME:
- if (!powerZone2) {
- success = false;
- logger.debug("Command {} from channel {} ignored: zone 2 in standby", command, channel);
- } else if (fixedVolumeZone2) {
- success = false;
- logger.debug("Command {} from channel {} ignored: fixed volume in zone 2", command,
- channel);
- } else if (model.hasVolumeControl() && model.getNbAdditionalZones() >= 1) {
- if (model.hasZone2Commands()) {
- handleVolumeCmd(volumeZone2, channel, command, RotelCommand.ZONE2_VOLUME_UP,
- RotelCommand.ZONE2_VOLUME_DOWN, RotelCommand.ZONE2_VOLUME_SET);
- } else {
- selectZone(2, model.getZoneSelectCmd());
- handleVolumeCmd(volumeZone2, channel, command, RotelCommand.VOLUME_UP,
- RotelCommand.VOLUME_DOWN, RotelCommand.VOLUME_SET);
- }
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
case CHANNEL_ZONE2_VOLUME_UP_DOWN:
- if (!powerZone2) {
- success = false;
- logger.debug("Command {} from channel {} ignored: zone 2 in standby", command, channel);
- } else if (fixedVolumeZone2) {
- success = false;
- logger.debug("Command {} from channel {} ignored: fixed volume in zone 2", command,
- channel);
- } else if (model.hasVolumeControl() && model.getNbAdditionalZones() >= 1) {
- if (model.hasZone2Commands()) {
- handleVolumeCmd(volumeZone2, channel, command, RotelCommand.ZONE2_VOLUME_UP,
- RotelCommand.ZONE2_VOLUME_DOWN, null);
- } else {
- selectZone(2, model.getZoneSelectCmd());
- handleVolumeCmd(volumeZone2, channel, command, RotelCommand.VOLUME_UP,
- RotelCommand.VOLUME_DOWN, null);
- }
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
case CHANNEL_ZONE3_VOLUME:
- if (!powerZone3) {
- success = false;
- logger.debug("Command {} from channel {} ignored: zone 3 in standby", command, channel);
- } else if (fixedVolumeZone3) {
- success = false;
- logger.debug("Command {} from channel {} ignored: fixed volume in zone 3", command,
- channel);
- } else if (model.hasVolumeControl() && model.hasZone3Commands()) {
- handleVolumeCmd(volumeZone3, channel, command, RotelCommand.ZONE3_VOLUME_UP,
- RotelCommand.ZONE3_VOLUME_DOWN, RotelCommand.ZONE3_VOLUME_SET);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
case CHANNEL_ZONE4_VOLUME:
- if (!powerZone4) {
+ if (!isPowerOn(numZone)) {
success = false;
- logger.debug("Command {} from channel {} ignored: zone 4 in standby", command, channel);
- } else if (fixedVolumeZone4) {
+ logger.debug("Command {} from channel {} ignored: zone {} in standby", command, channel,
+ numZone == 0 ? "device" : "zone " + numZone);
+ } else if (fixedVolumeZones[numZone]) {
success = false;
- logger.debug("Command {} from channel {} ignored: fixed volume in zone 4", command,
- channel);
- } else if (model.hasVolumeControl() && model.hasZone4Commands()) {
- handleVolumeCmd(volumeZone4, channel, command, RotelCommand.ZONE4_VOLUME_UP,
- RotelCommand.ZONE4_VOLUME_DOWN, RotelCommand.ZONE4_VOLUME_SET);
+ logger.debug("Command {} from channel {} ignored: fixed volume", command, channel);
+ } else if (model.hasVolumeControl() && (numZone == 0 || model.hasZoneCommands(numZone))) {
+ handleVolumeCmd(volumes[numZone], channel, command, getVolumeUpCommand(numZone),
+ getVolumeDownCommand(numZone),
+ CHANNEL_MAIN_VOLUME_UP_DOWN.equals(channel)
+ || CHANNEL_ZONE2_VOLUME_UP_DOWN.equals(channel) ? null
+ : getVolumeSetCommand(numZone));
+ } else if (numZone == 2 && model.hasVolumeControl() && model.getNumberOfZones() > 1) {
+ selectZone(2, model.getZoneSelectCmd());
+ handleVolumeCmd(volumes[numZone], channel, command, RotelCommand.VOLUME_UP,
+ RotelCommand.VOLUME_DOWN,
+ CHANNEL_ZONE2_VOLUME_UP_DOWN.equals(channel) ? null : RotelCommand.VOLUME_SET);
} else {
success = false;
logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
break;
case CHANNEL_MUTE:
case CHANNEL_MAIN_MUTE:
- if (!isPowerOn()) {
- success = false;
- logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
- } else if (model.hasVolumeControl()) {
- handleMuteCmd(protocol == RotelProtocol.HEX, channel, command, getMuteOnCommand(),
- getMuteOffCommand(), getMuteToggleCommand());
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
+ case CHANNEL_ZONE1_MUTE:
case CHANNEL_ZONE2_MUTE:
- if (!powerZone2) {
- success = false;
- logger.debug("Command {} from channel {} ignored: zone 2 in standby", command, channel);
- } else if (model.hasVolumeControl() && model.hasZone2Commands()) {
- handleMuteCmd(false, channel, command, RotelCommand.ZONE2_MUTE_ON,
- RotelCommand.ZONE2_MUTE_OFF, RotelCommand.ZONE2_MUTE_TOGGLE);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
case CHANNEL_ZONE3_MUTE:
- if (!powerZone3) {
- success = false;
- logger.debug("Command {} from channel {} ignored: zone 3 in standby", command, channel);
- } else if (model.hasVolumeControl() && model.hasZone3Commands()) {
- handleMuteCmd(false, channel, command, RotelCommand.ZONE3_MUTE_ON,
- RotelCommand.ZONE3_MUTE_OFF, RotelCommand.ZONE3_MUTE_TOGGLE);
- } else {
- success = false;
- logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
- }
- break;
case CHANNEL_ZONE4_MUTE:
- if (!powerZone4) {
+ if (!isPowerOn(numZone)) {
success = false;
- logger.debug("Command {} from channel {} ignored: zone 4 in standby", command, channel);
- } else if (model.hasVolumeControl() && model.hasZone4Commands()) {
- handleMuteCmd(false, channel, command, RotelCommand.ZONE4_MUTE_ON,
- RotelCommand.ZONE4_MUTE_OFF, RotelCommand.ZONE4_MUTE_TOGGLE);
+ logger.debug("Command {} from channel {} ignored: zone {} in standby", command, channel,
+ numZone == 0 ? "device" : "zone " + numZone);
+ } else if (model.hasVolumeControl() && (numZone == 0 || model.hasZoneCommands(numZone))) {
+ handleMuteCmd(numZone == 0 && protocol == RotelProtocol.HEX, channel, command,
+ getMuteOnCommand(numZone), getMuteOffCommand(numZone),
+ getMuteToggleCommand(numZone));
} else {
success = false;
logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
break;
case CHANNEL_BASS:
case CHANNEL_MAIN_BASS:
- if (!isPowerOn()) {
+ case CHANNEL_ZONE1_BASS:
+ case CHANNEL_ZONE2_BASS:
+ case CHANNEL_ZONE3_BASS:
+ case CHANNEL_ZONE4_BASS:
+ if (!isPowerOn(numZone)) {
success = false;
- logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+ logger.debug("Command {} from channel {} ignored: zone {} in standby", command, channel,
+ numZone == 0 ? "device" : "zone " + numZone);
} else if (tcbypass) {
+ success = false;
logger.debug("Command {} from channel {} ignored: tone control bypass is ON", command,
channel);
- updateChannelState(CHANNEL_BASS);
+ } else if (model.hasToneControl() && (numZone == 0 || model.hasZoneCommands(numZone))) {
+ handleToneCmd(basses[numZone], channel, command, 2, getBassUpCommand(numZone),
+ getBassDownCommand(numZone), getBassSetCommand(numZone));
} else {
- handleToneCmd(bass, channel, command, 2, RotelCommand.BASS_UP, RotelCommand.BASS_DOWN,
- RotelCommand.BASS_SET);
+ success = false;
+ logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
}
break;
case CHANNEL_TREBLE:
case CHANNEL_MAIN_TREBLE:
- if (!isPowerOn()) {
+ case CHANNEL_ZONE1_TREBLE:
+ case CHANNEL_ZONE2_TREBLE:
+ case CHANNEL_ZONE3_TREBLE:
+ case CHANNEL_ZONE4_TREBLE:
+ if (!isPowerOn(numZone)) {
success = false;
- logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+ logger.debug("Command {} from channel {} ignored: zone {} in standby", command, channel,
+ numZone == 0 ? "device" : "zone " + numZone);
} else if (tcbypass) {
+ success = false;
logger.debug("Command {} from channel {} ignored: tone control bypass is ON", command,
channel);
- updateChannelState(CHANNEL_TREBLE);
+ } else if (model.hasToneControl() && (numZone == 0 || model.hasZoneCommands(numZone))) {
+ handleToneCmd(trebles[numZone], channel, command, 1, getTrebleUpCommand(numZone),
+ getTrebleDownCommand(numZone), getTrebleSetCommand(numZone));
} else {
- handleToneCmd(treble, channel, command, 1, RotelCommand.TREBLE_UP, RotelCommand.TREBLE_DOWN,
- RotelCommand.TREBLE_SET);
+ success = false;
+ logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
}
break;
case CHANNEL_PLAY_CONTROL:
}
break;
case CHANNEL_BRIGHTNESS:
+ case CHANNEL_ALL_BRIGHTNESS:
if (!isPowerOn()) {
success = false;
logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
}
break;
case CHANNEL_BALANCE:
- if (!isPowerOn()) {
+ case CHANNEL_ZONE1_BALANCE:
+ case CHANNEL_ZONE2_BALANCE:
+ case CHANNEL_ZONE3_BALANCE:
+ case CHANNEL_ZONE4_BALANCE:
+ if (!isPowerOn(numZone)) {
success = false;
- logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+ logger.debug("Command {} from channel {} ignored: zone {} in standby", command, channel,
+ numZone == 0 ? "device" : "zone " + numZone);
} else if (!model.hasBalanceControl() || protocol == RotelProtocol.HEX) {
success = false;
logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
} else {
- handleBalanceCmd(channel, command, RotelCommand.BALANCE_LEFT, RotelCommand.BALANCE_RIGHT,
- RotelCommand.BALANCE_SET);
+ handleBalanceCmd(channel, command, getBalanceLeftCommand(numZone),
+ getBalanceRightCommand(numZone), getBalanceSetCommand(numZone));
}
break;
case CHANNEL_SPEAKER_A:
if (command instanceof OnOffType) {
if (command == OnOffType.ON) {
sendCommand(onCmd);
- bass = 0;
- treble = 0;
+ basses[0] = 0;
+ trebles[0] = 0;
updateChannelState(CHANNEL_BASS);
updateChannelState(CHANNEL_TREBLE);
} else if (command == OnOffType.OFF) {
*/
private void selectZone(int zone, @Nullable RotelCommand selectCommand)
throws RotelException, InterruptedException {
- if (protocol == RotelProtocol.HEX && model.getNbAdditionalZones() >= 1 && zone >= 1 && zone != currentZone
+ if (protocol == RotelProtocol.HEX && model.getNumberOfZones() > 1 && zone >= 1 && zone != currentZone
&& selectCommand != null) {
int nbSelect;
if (zone < currentZone) {
- nbSelect = zone + model.getNbAdditionalZones() - currentZone;
+ nbSelect = zone + model.getNumberOfZones() - 1 - currentZone;
if (isPowerOn() && selectCommand == RotelCommand.RECORD_FONCTION_SELECT) {
nbSelect++;
}
if (!KEY_ERROR.equals(key)) {
updateStatus(ThingStatus.ONLINE);
}
+ int numZone = 0;
+ switch (key) {
+ case KEY_INPUT_ZONE1:
+ case KEY_VOLUME_ZONE1:
+ case KEY_MUTE_ZONE1:
+ case KEY_BASS_ZONE1:
+ case KEY_TREBLE_ZONE1:
+ case KEY_BALANCE_ZONE1:
+ case KEY_FREQ_ZONE1:
+ numZone = 1;
+ break;
+ case KEY_POWER_ZONE2:
+ case KEY_SOURCE_ZONE2:
+ case KEY_INPUT_ZONE2:
+ case KEY_VOLUME_ZONE2:
+ case KEY_MUTE_ZONE2:
+ case KEY_BASS_ZONE2:
+ case KEY_TREBLE_ZONE2:
+ case KEY_BALANCE_ZONE2:
+ case KEY_FREQ_ZONE2:
+ numZone = 2;
+ break;
+ case KEY_POWER_ZONE3:
+ case KEY_SOURCE_ZONE3:
+ case KEY_INPUT_ZONE3:
+ case KEY_VOLUME_ZONE3:
+ case KEY_MUTE_ZONE3:
+ case KEY_BASS_ZONE3:
+ case KEY_TREBLE_ZONE3:
+ case KEY_BALANCE_ZONE3:
+ case KEY_FREQ_ZONE3:
+ numZone = 3;
+ break;
+ case KEY_POWER_ZONE4:
+ case KEY_SOURCE_ZONE4:
+ case KEY_INPUT_ZONE4:
+ case KEY_VOLUME_ZONE4:
+ case KEY_MUTE_ZONE4:
+ case KEY_BASS_ZONE4:
+ case KEY_TREBLE_ZONE4:
+ case KEY_BALANCE_ZONE4:
+ case KEY_FREQ_ZONE4:
+ numZone = 4;
+ break;
+ default:
+ break;
+ }
try {
switch (key) {
case KEY_ERROR:
handlePowerOn();
} else if (STANDBY.equalsIgnoreCase(value)) {
handlePowerOff();
+ if (model.getNumberOfZones() > 1 && !powerControlPerZone) {
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ handlePowerOffZone(zone);
+ }
+ }
} else if (POWER_OFF_DELAYED.equalsIgnoreCase(value)) {
schedulePowerOffJob(false);
} else {
}
break;
case KEY_POWER_ZONE2:
- if (POWER_ON.equalsIgnoreCase(value)) {
- handlePowerOnZone2();
- } else if (STANDBY.equalsIgnoreCase(value)) {
- handlePowerOffZone2();
- } else {
- throw new RotelException("Invalid value");
- }
- break;
case KEY_POWER_ZONE3:
- if (POWER_ON.equalsIgnoreCase(value)) {
- handlePowerOnZone3();
- } else if (STANDBY.equalsIgnoreCase(value)) {
- handlePowerOffZone3();
- } else {
- throw new RotelException("Invalid value");
- }
- break;
case KEY_POWER_ZONE4:
if (POWER_ON.equalsIgnoreCase(value)) {
- handlePowerOnZone4();
+ handlePowerOnZone(numZone);
} else if (STANDBY.equalsIgnoreCase(value)) {
- handlePowerOffZone4();
+ handlePowerOffZone(numZone);
} else {
throw new RotelException("Invalid value");
}
}
break;
case KEY_VOLUME:
- if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
- volume = minVolume;
+ case KEY_VOLUME_ZONE1:
+ case KEY_VOLUME_ZONE2:
+ case KEY_VOLUME_ZONE3:
+ case KEY_VOLUME_ZONE4:
+ fixedVolumeZones[numZone] = false;
+ if (MSG_VALUE_FIX.equalsIgnoreCase(value)) {
+ fixedVolumeZones[numZone] = true;
+ } else if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
+ volumes[numZone] = minVolume;
} else if (MSG_VALUE_MAX.equalsIgnoreCase(value)) {
- volume = maxVolume;
+ volumes[numZone] = maxVolume;
} else {
- volume = Integer.parseInt(value);
+ volumes[numZone] = Integer.parseInt(value);
+ }
+ if (numZone == 0) {
+ updateChannelState(CHANNEL_VOLUME);
+ updateChannelState(CHANNEL_MAIN_VOLUME);
+ updateChannelState(CHANNEL_MAIN_VOLUME_UP_DOWN);
+ } else {
+ updateGroupChannelState(numZone, CHANNEL_VOLUME);
+ updateGroupChannelState(numZone, CHANNEL_VOLUME_UP_DOWN);
}
- updateChannelState(CHANNEL_VOLUME);
- updateChannelState(CHANNEL_MAIN_VOLUME);
- updateChannelState(CHANNEL_MAIN_VOLUME_UP_DOWN);
break;
case KEY_MUTE:
+ case KEY_MUTE_ZONE1:
+ case KEY_MUTE_ZONE2:
+ case KEY_MUTE_ZONE3:
+ case KEY_MUTE_ZONE4:
if (MSG_VALUE_ON.equalsIgnoreCase(value)) {
- mute = true;
- updateChannelState(CHANNEL_MUTE);
- updateChannelState(CHANNEL_MAIN_MUTE);
+ mutes[numZone] = true;
+ if (numZone == 0) {
+ updateChannelState(CHANNEL_MUTE);
+ updateChannelState(CHANNEL_MAIN_MUTE);
+ } else {
+ updateGroupChannelState(numZone, CHANNEL_MUTE);
+ }
} else if (MSG_VALUE_OFF.equalsIgnoreCase(value)) {
- mute = false;
- updateChannelState(CHANNEL_MUTE);
- updateChannelState(CHANNEL_MAIN_MUTE);
+ mutes[numZone] = false;
+ if (numZone == 0) {
+ updateChannelState(CHANNEL_MUTE);
+ updateChannelState(CHANNEL_MAIN_MUTE);
+ } else {
+ updateGroupChannelState(numZone, CHANNEL_MUTE);
+ }
} else {
throw new RotelException("Invalid value");
}
break;
- case KEY_VOLUME_ZONE2:
- fixedVolumeZone2 = false;
- if (MSG_VALUE_FIX.equalsIgnoreCase(value)) {
- fixedVolumeZone2 = true;
- } else if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
- volumeZone2 = minVolume;
+ case KEY_TONE_MAX:
+ maxToneLevel = Integer.parseInt(value);
+ minToneLevel = -maxToneLevel;
+ logger.info(
+ "Set minValue to {} and maxValue to {} for your sitemap widget attached to your bass or treble item.",
+ minToneLevel, maxToneLevel);
+ break;
+ case KEY_BASS:
+ case KEY_BASS_ZONE1:
+ case KEY_BASS_ZONE2:
+ case KEY_BASS_ZONE3:
+ case KEY_BASS_ZONE4:
+ if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
+ basses[numZone] = minToneLevel;
} else if (MSG_VALUE_MAX.equalsIgnoreCase(value)) {
- volumeZone2 = maxVolume;
+ basses[numZone] = maxToneLevel;
} else {
- volumeZone2 = Integer.parseInt(value);
+ basses[numZone] = Integer.parseInt(value);
}
- updateChannelState(CHANNEL_ZONE2_VOLUME);
- updateChannelState(CHANNEL_ZONE2_VOLUME_UP_DOWN);
- break;
- case KEY_VOLUME_ZONE3:
- fixedVolumeZone3 = false;
- if (MSG_VALUE_FIX.equalsIgnoreCase(value)) {
- fixedVolumeZone3 = true;
- } else if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
- volumeZone3 = minVolume;
- } else if (MSG_VALUE_MAX.equalsIgnoreCase(value)) {
- volumeZone3 = maxVolume;
+ if (numZone == 0) {
+ updateChannelState(CHANNEL_BASS);
+ updateChannelState(CHANNEL_MAIN_BASS);
} else {
- volumeZone3 = Integer.parseInt(value);
+ updateGroupChannelState(numZone, CHANNEL_BASS);
}
- updateChannelState(CHANNEL_ZONE3_VOLUME);
break;
- case KEY_VOLUME_ZONE4:
- fixedVolumeZone4 = false;
- if (MSG_VALUE_FIX.equalsIgnoreCase(value)) {
- fixedVolumeZone4 = true;
- } else if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
- volumeZone4 = minVolume;
+ case KEY_TREBLE:
+ case KEY_TREBLE_ZONE1:
+ case KEY_TREBLE_ZONE2:
+ case KEY_TREBLE_ZONE3:
+ case KEY_TREBLE_ZONE4:
+ if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
+ trebles[numZone] = minToneLevel;
} else if (MSG_VALUE_MAX.equalsIgnoreCase(value)) {
- volumeZone4 = maxVolume;
+ trebles[numZone] = maxToneLevel;
} else {
- volumeZone4 = Integer.parseInt(value);
+ trebles[numZone] = Integer.parseInt(value);
}
- updateChannelState(CHANNEL_ZONE4_VOLUME);
- break;
- case KEY_MUTE_ZONE2:
- if (MSG_VALUE_ON.equalsIgnoreCase(value)) {
- muteZone2 = true;
- updateChannelState(CHANNEL_ZONE2_MUTE);
- } else if (MSG_VALUE_OFF.equalsIgnoreCase(value)) {
- muteZone2 = false;
- updateChannelState(CHANNEL_ZONE2_MUTE);
+ if (numZone == 0) {
+ updateChannelState(CHANNEL_TREBLE);
+ updateChannelState(CHANNEL_MAIN_TREBLE);
} else {
- throw new RotelException("Invalid value");
- }
- break;
- case KEY_MUTE_ZONE3:
- if (MSG_VALUE_ON.equalsIgnoreCase(value)) {
- muteZone3 = true;
- updateChannelState(CHANNEL_ZONE3_MUTE);
- } else if (MSG_VALUE_OFF.equalsIgnoreCase(value)) {
- muteZone3 = false;
- updateChannelState(CHANNEL_ZONE3_MUTE);
- } else {
- throw new RotelException("Invalid value");
+ updateGroupChannelState(numZone, CHANNEL_TREBLE);
}
break;
- case KEY_MUTE_ZONE4:
- if (MSG_VALUE_ON.equalsIgnoreCase(value)) {
- muteZone4 = true;
- updateChannelState(CHANNEL_ZONE4_MUTE);
- } else if (MSG_VALUE_OFF.equalsIgnoreCase(value)) {
- muteZone4 = false;
- updateChannelState(CHANNEL_ZONE4_MUTE);
- } else {
- throw new RotelException("Invalid value");
- }
- break;
- case KEY_TONE_MAX:
- maxToneLevel = Integer.parseInt(value);
- minToneLevel = -maxToneLevel;
- logger.info(
- "Set minValue to {} and maxValue to {} for your sitemap widget attached to your bass or treble item.",
- minToneLevel, maxToneLevel);
- break;
- case KEY_BASS:
- if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
- bass = minToneLevel;
- } else if (MSG_VALUE_MAX.equalsIgnoreCase(value)) {
- bass = maxToneLevel;
- } else {
- bass = Integer.parseInt(value);
- }
- updateChannelState(CHANNEL_BASS);
- updateChannelState(CHANNEL_MAIN_BASS);
- break;
- case KEY_TREBLE:
- if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
- treble = minToneLevel;
- } else if (MSG_VALUE_MAX.equalsIgnoreCase(value)) {
- treble = maxToneLevel;
- } else {
- treble = Integer.parseInt(value);
- }
- updateChannelState(CHANNEL_TREBLE);
- updateChannelState(CHANNEL_MAIN_TREBLE);
- break;
case KEY_SOURCE:
- source = model.getSourceFromCommand(RotelCommand.getFromAsciiCommand(value));
+ sources[0] = model.getSourceFromCommand(RotelCommand.getFromAsciiCommand(value));
updateChannelState(CHANNEL_SOURCE);
updateChannelState(CHANNEL_MAIN_SOURCE);
break;
updateChannelState(CHANNEL_MAIN_RECORD_SOURCE);
break;
case KEY_SOURCE_ZONE2:
- sourceZone2 = model.getZone2SourceFromCommand(RotelCommand.getFromAsciiCommand(value));
- updateChannelState(CHANNEL_ZONE2_SOURCE);
- break;
case KEY_SOURCE_ZONE3:
- sourceZone3 = model.getZone3SourceFromCommand(RotelCommand.getFromAsciiCommand(value));
- updateChannelState(CHANNEL_ZONE3_SOURCE);
- break;
case KEY_SOURCE_ZONE4:
- sourceZone4 = model.getZone4SourceFromCommand(RotelCommand.getFromAsciiCommand(value));
- updateChannelState(CHANNEL_ZONE4_SOURCE);
+ case KEY_INPUT_ZONE1:
+ case KEY_INPUT_ZONE2:
+ case KEY_INPUT_ZONE3:
+ case KEY_INPUT_ZONE4:
+ sources[numZone] = model.getZoneSourceFromCommand(RotelCommand.getFromAsciiCommand(value), numZone);
+ updateGroupChannelState(numZone, CHANNEL_SOURCE);
break;
case KEY_DSP_MODE:
if ("dolby_pliix_movie".equals(value)) {
}
break;
case KEY_TRACK:
- if (source.getName().equals("CD") && !model.hasSourceControl()) {
+ RotelSource source = sources[0];
+ if (source != null && source.getName().equals("CD") && !model.hasSourceControl()) {
track = Integer.parseInt(value);
updateChannelState(CHANNEL_TRACK);
}
break;
case KEY_FREQ:
- if (MSG_VALUE_OFF.equalsIgnoreCase(value)) {
- frequency = 0.0;
+ case KEY_FREQ_ZONE1:
+ case KEY_FREQ_ZONE2:
+ case KEY_FREQ_ZONE3:
+ case KEY_FREQ_ZONE4:
+ if (MSG_VALUE_OFF.equalsIgnoreCase(value) || MSG_VALUE_NONE.equalsIgnoreCase(value)) {
+ frequencies[numZone] = 0.0;
} else {
// Suppress a potential ending "k" or "K"
if (value.toUpperCase().endsWith("K")) {
value = value.substring(0, value.length() - 1);
}
- frequency = Double.parseDouble(value);
+ frequencies[numZone] = Double.parseDouble(value);
+ }
+ if (numZone == 0) {
+ updateChannelState(CHANNEL_FREQUENCY);
+ } else {
+ updateGroupChannelState(numZone, CHANNEL_FREQUENCY);
}
- updateChannelState(CHANNEL_FREQUENCY);
break;
case KEY_DIMMER:
brightness = Integer.parseInt(value);
updateChannelState(CHANNEL_BRIGHTNESS);
+ updateChannelState(CHANNEL_ALL_BRIGHTNESS);
break;
case KEY_UPDATE_MODE:
case KEY_DISPLAY_UPDATE:
}
break;
case KEY_BALANCE:
+ case KEY_BALANCE_ZONE1:
+ case KEY_BALANCE_ZONE2:
+ case KEY_BALANCE_ZONE3:
+ case KEY_BALANCE_ZONE4:
if (MSG_VALUE_MIN.equalsIgnoreCase(value)) {
- balance = minBalanceLevel;
+ balances[numZone] = minBalanceLevel;
} else if (MSG_VALUE_MAX.equalsIgnoreCase(value)) {
- balance = maxBalanceLevel;
+ balances[numZone] = maxBalanceLevel;
} else if (value.toUpperCase().startsWith("L")) {
- balance = -Integer.parseInt(value.substring(1));
+ balances[numZone] = -Integer.parseInt(value.substring(1));
} else if (value.toUpperCase().startsWith("R")) {
- balance = Integer.parseInt(value.substring(1));
+ balances[numZone] = Integer.parseInt(value.substring(1));
} else {
- balance = Integer.parseInt(value);
+ balances[numZone] = Integer.parseInt(value);
+ }
+ if (numZone == 0) {
+ updateChannelState(CHANNEL_BALANCE);
+ } else {
+ updateGroupChannelState(numZone, CHANNEL_BALANCE);
}
- updateChannelState(CHANNEL_BALANCE);
break;
case KEY_SPEAKER:
if (MSG_VALUE_SPEAKER_A.equalsIgnoreCase(value)) {
throw new RotelException("Invalid value");
}
break;
+ case KEY_MODEL:
+ getThing().setProperty(Thing.PROPERTY_MODEL_ID, value);
+ break;
+ case KEY_VERSION:
+ getThing().setProperty(Thing.PROPERTY_FIRMWARE_VERSION, value);
+ break;
default:
logger.debug("onNewMessageEvent: unhandled key {}", key);
break;
* Handle the received information that device power (main zone) is ON
*/
private void handlePowerOn() {
- Boolean prev = power;
- power = true;
+ Boolean prev = powers[0];
+ powers[0] = true;
updateChannelState(CHANNEL_POWER);
updateChannelState(CHANNEL_MAIN_POWER);
+ updateChannelState(CHANNEL_ALL_POWER);
if ((prev == null) || !prev) {
schedulePowerOnJob();
}
* Handle the received information that device power (main zone) is OFF
*/
private void handlePowerOff() {
- cancelPowerOnJob();
- power = false;
+ cancelPowerOnZoneJob(0);
+ powers[0] = false;
updateChannelState(CHANNEL_POWER);
- updateChannelState(CHANNEL_MAIN_POWER);
updateChannelState(CHANNEL_SOURCE);
- updateChannelState(CHANNEL_MAIN_SOURCE);
- updateChannelState(CHANNEL_MAIN_RECORD_SOURCE);
updateChannelState(CHANNEL_DSP);
- updateChannelState(CHANNEL_MAIN_DSP);
updateChannelState(CHANNEL_VOLUME);
- updateChannelState(CHANNEL_MAIN_VOLUME);
- updateChannelState(CHANNEL_MAIN_VOLUME_UP_DOWN);
updateChannelState(CHANNEL_MUTE);
- updateChannelState(CHANNEL_MAIN_MUTE);
updateChannelState(CHANNEL_BASS);
- updateChannelState(CHANNEL_MAIN_BASS);
updateChannelState(CHANNEL_TREBLE);
- updateChannelState(CHANNEL_MAIN_TREBLE);
updateChannelState(CHANNEL_PLAY_CONTROL);
updateChannelState(CHANNEL_TRACK);
updateChannelState(CHANNEL_FREQUENCY);
updateChannelState(CHANNEL_BALANCE);
updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B);
- }
-
- /**
- * Handle the received information that zone 2 power is ON
- */
- private void handlePowerOnZone2() {
- boolean prev = powerZone2;
- powerZone2 = true;
- updateChannelState(CHANNEL_ZONE2_POWER);
- if (!prev) {
- schedulePowerOnZone2Job();
- }
- }
- /**
- * Handle the received information that zone 2 power is OFF
- */
- private void handlePowerOffZone2() {
- cancelPowerOnZone2Job();
- powerZone2 = false;
- updateChannelState(CHANNEL_ZONE2_POWER);
- updateChannelState(CHANNEL_ZONE2_SOURCE);
- updateChannelState(CHANNEL_ZONE2_VOLUME);
- updateChannelState(CHANNEL_ZONE2_VOLUME_UP_DOWN);
- updateChannelState(CHANNEL_ZONE2_MUTE);
- }
-
- /**
- * Handle the received information that zone 3 power is ON
- */
- private void handlePowerOnZone3() {
- boolean prev = powerZone3;
- powerZone3 = true;
- updateChannelState(CHANNEL_ZONE3_POWER);
- if (!prev) {
- schedulePowerOnZone3Job();
- }
- }
+ updateChannelState(CHANNEL_MAIN_POWER);
+ updateChannelState(CHANNEL_MAIN_SOURCE);
+ updateChannelState(CHANNEL_MAIN_RECORD_SOURCE);
+ updateChannelState(CHANNEL_MAIN_DSP);
+ updateChannelState(CHANNEL_MAIN_VOLUME);
+ updateChannelState(CHANNEL_MAIN_VOLUME_UP_DOWN);
+ updateChannelState(CHANNEL_MAIN_MUTE);
+ updateChannelState(CHANNEL_MAIN_BASS);
+ updateChannelState(CHANNEL_MAIN_TREBLE);
- /**
- * Handle the received information that zone 3 power is OFF
- */
- private void handlePowerOffZone3() {
- cancelPowerOnZone3Job();
- powerZone3 = false;
- updateChannelState(CHANNEL_ZONE3_POWER);
- updateChannelState(CHANNEL_ZONE3_SOURCE);
- updateChannelState(CHANNEL_ZONE3_VOLUME);
- updateChannelState(CHANNEL_ZONE3_MUTE);
+ updateChannelState(CHANNEL_ALL_POWER);
+ updateChannelState(CHANNEL_ALL_BRIGHTNESS);
}
/**
- * Handle the received information that zone 4 power is ON
+ * Handle the received information that a zone power is ON
*/
- private void handlePowerOnZone4() {
- boolean prev = powerZone4;
- powerZone4 = true;
- updateChannelState(CHANNEL_ZONE4_POWER);
- if (!prev) {
- schedulePowerOnZone4Job();
+ private void handlePowerOnZone(int numZone) {
+ Boolean prev = powers[numZone];
+ powers[numZone] = true;
+ updateGroupChannelState(numZone, CHANNEL_POWER);
+ if ((prev == null) || !prev) {
+ schedulePowerOnZoneJob(numZone, getVolumeDownCommand(numZone), getVolumeUpCommand(numZone));
}
}
/**
- * Handle the received information that zone 4 power is OFF
+ * Handle the received information that a zone power is OFF
*/
- private void handlePowerOffZone4() {
- cancelPowerOnZone4Job();
- powerZone4 = false;
- updateChannelState(CHANNEL_ZONE4_POWER);
- updateChannelState(CHANNEL_ZONE4_SOURCE);
- updateChannelState(CHANNEL_ZONE4_VOLUME);
- updateChannelState(CHANNEL_ZONE4_MUTE);
+ private void handlePowerOffZone(int numZone) {
+ cancelPowerOnZoneJob(numZone);
+ powers[numZone] = false;
+ updateGroupChannelState(numZone, CHANNEL_POWER);
+ updateGroupChannelState(numZone, CHANNEL_SOURCE);
+ updateGroupChannelState(numZone, CHANNEL_VOLUME);
+ updateGroupChannelState(numZone, CHANNEL_MUTE);
+ updateGroupChannelState(numZone, CHANNEL_BASS);
+ updateGroupChannelState(numZone, CHANNEL_TREBLE);
+ updateGroupChannelState(numZone, CHANNEL_BALANCE);
+ updateGroupChannelState(numZone, CHANNEL_FREQUENCY);
+ updateGroupChannelState(numZone, CHANNEL_VOLUME_UP_DOWN);
}
/**
logger.debug("Power OFF job");
handlePowerOff();
if (switchOffAllZones) {
- handlePowerOffZone2();
- handlePowerOffZone3();
- handlePowerOffZone4();
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ handlePowerOffZone(zone);
+ }
}
}, 2000, TimeUnit.MILLISECONDS);
}
*/
private void schedulePowerOnJob() {
logger.debug("Schedule power ON job");
- cancelPowerOnJob();
- powerOnJob = scheduler.schedule(() -> {
+ cancelPowerOnZoneJob(0);
+ powerOnZoneJobs[0] = scheduler.schedule(() -> {
synchronized (sequenceLock) {
logger.debug("Power ON job");
try {
switch (protocol) {
case HEX:
if (model.getRespNbChars() <= 13 && model.hasVolumeControl()) {
- sendCommand(getVolumeDownCommand());
+ sendCommand(getVolumeDownCommand(0));
Thread.sleep(100);
- sendCommand(getVolumeUpCommand());
+ sendCommand(getVolumeUpCommand(0));
Thread.sleep(100);
}
- if (model.getNbAdditionalZones() >= 1) {
+ if (model.getNumberOfZones() > 1) {
if (currentZone != 1
&& model.getZoneSelectCmd() == RotelCommand.RECORD_FONCTION_SELECT) {
selectZone(1, model.getZoneSelectCmd());
Thread.sleep(SLEEP_INTV);
sendCommand(RotelCommand.TREBLE);
Thread.sleep(SLEEP_INTV);
- sendCommand(RotelCommand.TONE_CONTROLS);
- Thread.sleep(SLEEP_INTV);
+ if (model.canGetBypassStatus()) {
+ sendCommand(RotelCommand.TONE_CONTROLS);
+ Thread.sleep(SLEEP_INTV);
+ }
}
}
if (model.hasBalanceControl()) {
Thread.sleep(SLEEP_INTV);
}
if (model.hasPlayControl()) {
+ RotelSource source = sources[0];
if (model != RotelModel.RCD1570 && model != RotelModel.RCD1572
- && (model != RotelModel.RCX1500 || !source.getName().equals("CD"))) {
+ && (model != RotelModel.RCX1500 || source == null
+ || !source.getName().equals("CD"))) {
sendCommand(RotelCommand.PLAY_STATUS);
Thread.sleep(SLEEP_INTV);
} else {
sendCommand(RotelCommand.UPDATE_AUTO);
Thread.sleep(SLEEP_INTV);
if (model.hasSourceControl()) {
- sendCommand(RotelCommand.SOURCE);
+ if (model.getNumberOfZones() > 1) {
+ sendCommand(RotelCommand.INPUT);
+ } else {
+ sendCommand(RotelCommand.SOURCE);
+ }
Thread.sleep(SLEEP_INTV);
}
if (model.hasVolumeControl()) {
Thread.sleep(SLEEP_INTV);
sendCommand(RotelCommand.TREBLE);
Thread.sleep(SLEEP_INTV);
- sendCommand(RotelCommand.TCBYPASS);
- Thread.sleep(SLEEP_INTV);
+ if (model.canGetBypassStatus()) {
+ sendCommand(RotelCommand.TCBYPASS);
+ Thread.sleep(SLEEP_INTV);
+ }
}
if (model.hasBalanceControl()) {
sendCommand(RotelCommand.BALANCE);
if (model.hasPlayControl()) {
sendCommand(RotelCommand.PLAY_STATUS);
Thread.sleep(SLEEP_INTV);
- if (source.getName().equals("CD") && !model.hasSourceControl()) {
+ RotelSource source = sources[0];
+ if (source != null && source.getName().equals("CD") && !model.hasSourceControl()) {
sendCommand(RotelCommand.TRACK);
Thread.sleep(SLEEP_INTV);
}
sendCommand(RotelCommand.SPEAKER);
Thread.sleep(SLEEP_INTV);
}
+ sendCommand(RotelCommand.MODEL);
+ Thread.sleep(SLEEP_INTV);
+ sendCommand(RotelCommand.VERSION);
+ Thread.sleep(SLEEP_INTV);
break;
}
} catch (RotelException e) {
}
/**
- * Cancel the job scheduled when the device power (main zone) switched ON
- */
- private void cancelPowerOnJob() {
- ScheduledFuture<?> powerOnJob = this.powerOnJob;
- if (powerOnJob != null && !powerOnJob.isCancelled()) {
- powerOnJob.cancel(true);
- this.powerOnJob = null;
- }
- }
-
- /**
- * Schedule the job to run with a few seconds delay when the zone 2 power switched ON
- */
- private void schedulePowerOnZone2Job() {
- logger.debug("Schedule power ON zone 2 job");
- cancelPowerOnZone2Job();
- powerOnZone2Job = scheduler.schedule(() -> {
- synchronized (sequenceLock) {
- logger.debug("Power ON zone 2 job");
- try {
- if (protocol == RotelProtocol.HEX && model.getNbAdditionalZones() >= 1) {
- selectZone(2, model.getZoneSelectCmd());
- sendCommand(
- model.hasZone2Commands() ? RotelCommand.ZONE2_VOLUME_DOWN : RotelCommand.VOLUME_DOWN);
- Thread.sleep(100);
- sendCommand(model.hasZone2Commands() ? RotelCommand.ZONE2_VOLUME_UP : RotelCommand.VOLUME_UP);
- Thread.sleep(100);
- }
- } catch (RotelException e) {
- logger.debug("Init sequence zone 2 failed: {}", e.getMessage());
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.comm-error-init-sequence-zone [\"2\"]");
- closeConnection();
- } catch (InterruptedException e) {
- logger.debug("Init sequence zone 2 interrupted: {}", e.getMessage());
- Thread.currentThread().interrupt();
- }
- }
- }, 2500, TimeUnit.MILLISECONDS);
- }
-
- /**
- * Cancel the job scheduled when the zone 2 power switched ON
- */
- private void cancelPowerOnZone2Job() {
- ScheduledFuture<?> powerOnZone2Job = this.powerOnZone2Job;
- if (powerOnZone2Job != null && !powerOnZone2Job.isCancelled()) {
- powerOnZone2Job.cancel(true);
- this.powerOnZone2Job = null;
- }
- }
-
- /**
- * Schedule the job to run with a few seconds delay when the zone 3 power switched ON
- */
- private void schedulePowerOnZone3Job() {
- logger.debug("Schedule power ON zone 3 job");
- cancelPowerOnZone3Job();
- powerOnZone3Job = scheduler.schedule(() -> {
- synchronized (sequenceLock) {
- logger.debug("Power ON zone 3 job");
- try {
- if (protocol == RotelProtocol.HEX && model.getNbAdditionalZones() >= 2) {
- selectZone(3, model.getZoneSelectCmd());
- sendCommand(
- model.hasZone3Commands() ? RotelCommand.ZONE3_VOLUME_DOWN : RotelCommand.VOLUME_DOWN);
- Thread.sleep(100);
- sendCommand(model.hasZone3Commands() ? RotelCommand.ZONE3_VOLUME_UP : RotelCommand.VOLUME_UP);
- Thread.sleep(100);
- }
- } catch (RotelException e) {
- logger.debug("Init sequence zone 3 failed: {}", e.getMessage());
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.comm-error-init-sequence-zone [\"3\"]");
- closeConnection();
- } catch (InterruptedException e) {
- logger.debug("Init sequence zone 3 interrupted: {}", e.getMessage());
- Thread.currentThread().interrupt();
- }
- }
- }, 2500, TimeUnit.MILLISECONDS);
- }
-
- /**
- * Cancel the job scheduled when the zone 3 power switched ON
- */
- private void cancelPowerOnZone3Job() {
- ScheduledFuture<?> powerOnZone3Job = this.powerOnZone3Job;
- if (powerOnZone3Job != null && !powerOnZone3Job.isCancelled()) {
- powerOnZone3Job.cancel(true);
- this.powerOnZone3Job = null;
- }
- }
-
- /**
- * Schedule the job to run with a few seconds delay when the zone 4 power switched ON
+ * Schedule the job to run with a few seconds delay when the zone power switched ON
*/
- private void schedulePowerOnZone4Job() {
- logger.debug("Schedule power ON zone 4 job");
- cancelPowerOnZone4Job();
- powerOnZone4Job = scheduler.schedule(() -> {
+ private void schedulePowerOnZoneJob(int numZone, RotelCommand volumeDown, RotelCommand volumeUp) {
+ logger.debug("Schedule power ON zone {} job", numZone);
+ cancelPowerOnZoneJob(numZone);
+ powerOnZoneJobs[numZone] = scheduler.schedule(() -> {
synchronized (sequenceLock) {
- logger.debug("Power ON zone 4 job");
+ logger.debug("Power ON zone {} job", numZone);
try {
- if (protocol == RotelProtocol.HEX && model.getNbAdditionalZones() >= 3) {
- selectZone(4, model.getZoneSelectCmd());
- sendCommand(
- model.hasZone4Commands() ? RotelCommand.ZONE4_VOLUME_DOWN : RotelCommand.VOLUME_DOWN);
+ if (protocol == RotelProtocol.HEX && model.getNumberOfZones() >= numZone) {
+ selectZone(numZone, model.getZoneSelectCmd());
+ sendCommand(model.hasZoneCommands(numZone) ? volumeDown : RotelCommand.VOLUME_DOWN);
Thread.sleep(100);
- sendCommand(model.hasZone4Commands() ? RotelCommand.ZONE4_VOLUME_UP : RotelCommand.VOLUME_UP);
+ sendCommand(model.hasZoneCommands(numZone) ? volumeUp : RotelCommand.VOLUME_UP);
Thread.sleep(100);
}
} catch (RotelException e) {
- logger.debug("Init sequence zone 4 failed: {}", e.getMessage());
+ logger.debug("Init sequence zone {} failed: {}", numZone, e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.comm-error-init-sequence-zone [\"4\"]");
+ String.format("@text/offline.comm-error-init-sequence-zone [\"%d\"]", numZone));
closeConnection();
} catch (InterruptedException e) {
- logger.debug("Init sequence zone 4 interrupted: {}", e.getMessage());
+ logger.debug("Init sequence zone {} interrupted: {}", numZone, e.getMessage());
Thread.currentThread().interrupt();
}
}
}
/**
- * Cancel the job scheduled when the zone 4 power switched ON
+ * Cancel the job scheduled when the device power (main zone) or a zone power switched ON
*/
- private void cancelPowerOnZone4Job() {
- ScheduledFuture<?> powerOnZone4Job = this.powerOnZone4Job;
- if (powerOnZone4Job != null && !powerOnZone4Job.isCancelled()) {
- powerOnZone4Job.cancel(true);
- this.powerOnZone4Job = null;
+ private void cancelPowerOnZoneJob(int numZone) {
+ ScheduledFuture<?> powerOnZoneJob = powerOnZoneJobs[numZone];
+ if (powerOnZoneJob != null && !powerOnZoneJob.isCancelled()) {
+ powerOnZoneJob.cancel(true);
+ powerOnZoneJobs[numZone] = null;
}
}
if (!connector.isConnected()) {
logger.debug("Trying to reconnect...");
closeConnection();
- power = null;
+ powers[0] = null;
String error = null;
if (openConnection()) {
synchronized (sequenceLock) {
}
if (error != null) {
handlePowerOff();
- handlePowerOffZone2();
- handlePowerOffZone3();
- handlePowerOffZone4();
+ for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
+ handlePowerOffZone(zone);
+ }
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, error);
} else {
updateStatus(ThingStatus.ONLINE);
}
}
+ private void updateGroupChannelState(int numZone, String channel) {
+ updateChannelState(String.format("zone%d#%s", numZone, channel));
+ }
+
/**
* Update the state of a channel
*
return;
}
State state = UnDefType.UNDEF;
+ RotelSource localSource;
+ int numZone = 0;
switch (channel) {
- case CHANNEL_POWER:
- case CHANNEL_MAIN_POWER:
- Boolean po = power;
- if (po != null) {
- state = OnOffType.from(po.booleanValue());
- }
+ case CHANNEL_ZONE1_SOURCE:
+ case CHANNEL_ZONE1_VOLUME:
+ case CHANNEL_ZONE1_MUTE:
+ case CHANNEL_ZONE1_BASS:
+ case CHANNEL_ZONE1_TREBLE:
+ case CHANNEL_ZONE1_BALANCE:
+ case CHANNEL_ZONE1_FREQUENCY:
+ numZone = 1;
break;
case CHANNEL_ZONE2_POWER:
- state = OnOffType.from(powerZone2);
+ case CHANNEL_ZONE2_SOURCE:
+ case CHANNEL_ZONE2_VOLUME:
+ case CHANNEL_ZONE2_VOLUME_UP_DOWN:
+ case CHANNEL_ZONE2_MUTE:
+ case CHANNEL_ZONE2_BASS:
+ case CHANNEL_ZONE2_TREBLE:
+ case CHANNEL_ZONE2_BALANCE:
+ case CHANNEL_ZONE2_FREQUENCY:
+ numZone = 2;
break;
case CHANNEL_ZONE3_POWER:
- state = OnOffType.from(powerZone3);
+ case CHANNEL_ZONE3_SOURCE:
+ case CHANNEL_ZONE3_VOLUME:
+ case CHANNEL_ZONE3_MUTE:
+ case CHANNEL_ZONE3_BASS:
+ case CHANNEL_ZONE3_TREBLE:
+ case CHANNEL_ZONE3_BALANCE:
+ case CHANNEL_ZONE3_FREQUENCY:
+ numZone = 3;
break;
case CHANNEL_ZONE4_POWER:
- state = OnOffType.from(powerZone4);
+ case CHANNEL_ZONE4_SOURCE:
+ case CHANNEL_ZONE4_VOLUME:
+ case CHANNEL_ZONE4_MUTE:
+ case CHANNEL_ZONE4_BASS:
+ case CHANNEL_ZONE4_TREBLE:
+ case CHANNEL_ZONE4_BALANCE:
+ case CHANNEL_ZONE4_FREQUENCY:
+ numZone = 4;
break;
- case CHANNEL_SOURCE:
- case CHANNEL_MAIN_SOURCE:
- if (isPowerOn()) {
- state = new StringType(source.getName());
- }
+ default:
break;
- case CHANNEL_MAIN_RECORD_SOURCE:
- RotelSource recordSource = this.recordSource;
- if (isPowerOn() && recordSource != null) {
- state = new StringType(recordSource.getName());
+ }
+ switch (channel) {
+ case CHANNEL_POWER:
+ case CHANNEL_MAIN_POWER:
+ case CHANNEL_ALL_POWER:
+ case CHANNEL_ZONE2_POWER:
+ case CHANNEL_ZONE3_POWER:
+ case CHANNEL_ZONE4_POWER:
+ Boolean powerZone = powers[numZone];
+ if (powerZone != null) {
+ state = OnOffType.from(powerZone.booleanValue());
}
break;
+ case CHANNEL_SOURCE:
+ case CHANNEL_MAIN_SOURCE:
+ case CHANNEL_ZONE1_SOURCE:
case CHANNEL_ZONE2_SOURCE:
- RotelSource sourceZone2 = this.sourceZone2;
- if (powerZone2 && sourceZone2 != null) {
- state = new StringType(sourceZone2.getName());
- }
- break;
case CHANNEL_ZONE3_SOURCE:
- RotelSource sourceZone3 = this.sourceZone3;
- if (powerZone3 && sourceZone3 != null) {
- state = new StringType(sourceZone3.getName());
+ case CHANNEL_ZONE4_SOURCE:
+ localSource = sources[numZone];
+ if (isPowerOn(numZone) && localSource != null) {
+ state = new StringType(localSource.getName());
}
break;
- case CHANNEL_ZONE4_SOURCE:
- RotelSource sourceZone4 = this.sourceZone4;
- if (powerZone4 && sourceZone4 != null) {
- state = new StringType(sourceZone4.getName());
+ case CHANNEL_MAIN_RECORD_SOURCE:
+ localSource = recordSource;
+ if (isPowerOn() && localSource != null) {
+ state = new StringType(localSource.getName());
}
break;
case CHANNEL_DSP:
break;
case CHANNEL_VOLUME:
case CHANNEL_MAIN_VOLUME:
- if (isPowerOn()) {
- long volumePct = Math
- .round((double) (volume - minVolume) / (double) (maxVolume - minVolume) * 100.0);
- state = new PercentType(BigDecimal.valueOf(volumePct));
- }
- break;
- case CHANNEL_MAIN_VOLUME_UP_DOWN:
- if (isPowerOn()) {
- state = new DecimalType(volume);
- }
- break;
+ case CHANNEL_ZONE1_VOLUME:
case CHANNEL_ZONE2_VOLUME:
- if (powerZone2 && !fixedVolumeZone2) {
- long volumePct = Math
- .round((double) (volumeZone2 - minVolume) / (double) (maxVolume - minVolume) * 100.0);
- state = new PercentType(BigDecimal.valueOf(volumePct));
- }
- break;
- case CHANNEL_ZONE2_VOLUME_UP_DOWN:
- if (powerZone2 && !fixedVolumeZone2) {
- state = new DecimalType(volumeZone2);
- }
- break;
case CHANNEL_ZONE3_VOLUME:
- if (powerZone3 && !fixedVolumeZone3) {
+ case CHANNEL_ZONE4_VOLUME:
+ if (isPowerOn(numZone) && !fixedVolumeZones[numZone]) {
long volumePct = Math
- .round((double) (volumeZone3 - minVolume) / (double) (maxVolume - minVolume) * 100.0);
+ .round((double) (volumes[numZone] - minVolume) / (double) (maxVolume - minVolume) * 100.0);
state = new PercentType(BigDecimal.valueOf(volumePct));
}
break;
- case CHANNEL_ZONE4_VOLUME:
- if (powerZone4 && !fixedVolumeZone4) {
- long volumePct = Math
- .round((double) (volumeZone4 - minVolume) / (double) (maxVolume - minVolume) * 100.0);
- state = new PercentType(BigDecimal.valueOf(volumePct));
+ case CHANNEL_MAIN_VOLUME_UP_DOWN:
+ case CHANNEL_ZONE2_VOLUME_UP_DOWN:
+ if (isPowerOn(numZone) && !fixedVolumeZones[numZone]) {
+ state = new DecimalType(volumes[numZone]);
}
break;
case CHANNEL_MUTE:
case CHANNEL_MAIN_MUTE:
- if (isPowerOn()) {
- state = OnOffType.from(mute);
- }
- break;
+ case CHANNEL_ZONE1_MUTE:
case CHANNEL_ZONE2_MUTE:
- if (powerZone2) {
- state = OnOffType.from(muteZone2);
- }
- break;
case CHANNEL_ZONE3_MUTE:
- if (powerZone3) {
- state = OnOffType.from(muteZone3);
- }
- break;
case CHANNEL_ZONE4_MUTE:
- if (powerZone4) {
- state = OnOffType.from(muteZone4);
+ if (isPowerOn(numZone)) {
+ state = OnOffType.from(mutes[numZone]);
}
break;
case CHANNEL_BASS:
case CHANNEL_MAIN_BASS:
- if (isPowerOn()) {
- state = new DecimalType(bass);
+ case CHANNEL_ZONE1_BASS:
+ case CHANNEL_ZONE2_BASS:
+ case CHANNEL_ZONE3_BASS:
+ case CHANNEL_ZONE4_BASS:
+ if (isPowerOn(numZone)) {
+ state = new DecimalType(basses[numZone]);
}
break;
case CHANNEL_TREBLE:
case CHANNEL_MAIN_TREBLE:
- if (isPowerOn()) {
- state = new DecimalType(treble);
+ case CHANNEL_ZONE1_TREBLE:
+ case CHANNEL_ZONE2_TREBLE:
+ case CHANNEL_ZONE3_TREBLE:
+ case CHANNEL_ZONE4_TREBLE:
+ if (isPowerOn(numZone)) {
+ state = new DecimalType(trebles[numZone]);
}
break;
case CHANNEL_TRACK:
- if (track > 0 && isPowerOn()) {
+ if (isPowerOn() && track > 0) {
state = new DecimalType(track);
}
break;
}
break;
case CHANNEL_FREQUENCY:
- if (frequency > 0.0 && isPowerOn()) {
- state = new DecimalType(frequency);
+ case CHANNEL_ZONE1_FREQUENCY:
+ case CHANNEL_ZONE2_FREQUENCY:
+ case CHANNEL_ZONE3_FREQUENCY:
+ case CHANNEL_ZONE4_FREQUENCY:
+ if (isPowerOn(numZone) && frequencies[numZone] > 0.0) {
+ state = new DecimalType(frequencies[numZone]);
}
break;
case CHANNEL_LINE1:
state = new StringType(frontPanelLine2);
break;
case CHANNEL_BRIGHTNESS:
+ case CHANNEL_ALL_BRIGHTNESS:
if (isPowerOn() && model.hasDimmerControl()) {
long dimmerPct = Math.round((double) (brightness - model.getDimmerLevelMin())
/ (double) (model.getDimmerLevelMax() - model.getDimmerLevelMin()) * 100.0);
}
break;
case CHANNEL_BALANCE:
- if (isPowerOn()) {
- state = new DecimalType(balance);
+ case CHANNEL_ZONE1_BALANCE:
+ case CHANNEL_ZONE2_BALANCE:
+ case CHANNEL_ZONE3_BALANCE:
+ case CHANNEL_ZONE4_BALANCE:
+ if (isPowerOn(numZone)) {
+ state = new DecimalType(balances[numZone]);
}
break;
case CHANNEL_SPEAKER_A:
}
/**
- * Inform about the main zone power state
+ * Inform about the device / main zone power state
*
- * @return true if main zone power state is known and known as ON
+ * @return true if device / main zone power state is known and known as ON
*/
private boolean isPowerOn() {
- Boolean power = this.power;
- return power != null && power.booleanValue();
+ return isPowerOn(0);
+ }
+
+ /**
+ * Inform about the power state
+ *
+ * @param numZone the zone number (1-4) or 0 for the device or main zone
+ *
+ * @return true if power state is known and known as ON
+ */
+ private boolean isPowerOn(int numZone) {
+ if (numZone < 0 || numZone > MAX_NUMBER_OF_ZONES) {
+ throw new IllegalArgumentException("numZone must be in range 0-" + MAX_NUMBER_OF_ZONES);
+ }
+ Boolean power = powers[numZone];
+ return (numZone > 0 && !powerControlPerZone) ? isPowerOn(0) : power != null && power.booleanValue();
}
/**
- * Get the command to be used for main zone POWER ON
+ * Get the command to be used for POWER ON
+ *
+ * @param numZone the zone number (2-4) or 0 for the device or main zone
*
* @return the command
*/
- private RotelCommand getPowerOnCommand() {
- return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_POWER_ON : RotelCommand.POWER_ON;
+ private RotelCommand getPowerOnCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_POWER_ON : RotelCommand.POWER_ON;
+ case 2:
+ return RotelCommand.ZONE2_POWER_ON;
+ case 3:
+ return RotelCommand.ZONE3_POWER_ON;
+ case 4:
+ return RotelCommand.ZONE4_POWER_ON;
+ default:
+ throw new IllegalArgumentException("No power ON command defined for zone " + numZone);
+ }
}
/**
- * Get the command to be used for main zone POWER OFF
+ * Get the command to be used for POWER OFF
+ *
+ * @param numZone the zone number (2-4) or 0 for the device or main zone
*
* @return the command
*/
- private RotelCommand getPowerOffCommand() {
- return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_POWER_OFF : RotelCommand.POWER_OFF;
+ private RotelCommand getPowerOffCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_POWER_OFF : RotelCommand.POWER_OFF;
+ case 2:
+ return RotelCommand.ZONE2_POWER_OFF;
+ case 3:
+ return RotelCommand.ZONE3_POWER_OFF;
+ case 4:
+ return RotelCommand.ZONE4_POWER_OFF;
+ default:
+ throw new IllegalArgumentException("No power OFF command defined for zone " + numZone);
+ }
}
/**
- * Get the command to be used for main zone VOLUME UP
+ * Get the command to be used for VOLUME UP
+ *
+ * @param numZone the zone number (1-4) or 0 for the device or main zone
*
* @return the command
*/
- private RotelCommand getVolumeUpCommand() {
- return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_VOLUME_UP : RotelCommand.VOLUME_UP;
+ private RotelCommand getVolumeUpCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_VOLUME_UP : RotelCommand.VOLUME_UP;
+ case 1:
+ return RotelCommand.ZONE1_VOLUME_UP;
+ case 2:
+ return RotelCommand.ZONE2_VOLUME_UP;
+ case 3:
+ return RotelCommand.ZONE3_VOLUME_UP;
+ case 4:
+ return RotelCommand.ZONE4_VOLUME_UP;
+ default:
+ throw new IllegalArgumentException("No VOLUME UP command defined for zone " + numZone);
+ }
}
/**
- * Get the command to be used for main zone VOLUME DOWN
+ * Get the command to be used for VOLUME DOWN
+ *
+ * @param numZone the zone number (1-4) or 0 for the device or main zone
*
* @return the command
*/
- private RotelCommand getVolumeDownCommand() {
- return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_VOLUME_DOWN : RotelCommand.VOLUME_DOWN;
+ private RotelCommand getVolumeDownCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_VOLUME_DOWN
+ : RotelCommand.VOLUME_DOWN;
+ case 1:
+ return RotelCommand.ZONE1_VOLUME_DOWN;
+ case 2:
+ return RotelCommand.ZONE2_VOLUME_DOWN;
+ case 3:
+ return RotelCommand.ZONE3_VOLUME_DOWN;
+ case 4:
+ return RotelCommand.ZONE4_VOLUME_DOWN;
+ default:
+ throw new IllegalArgumentException("No VOLUME DOWN command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for VOLUME SET
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getVolumeSetCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.VOLUME_SET;
+ case 1:
+ return RotelCommand.ZONE1_VOLUME_SET;
+ case 2:
+ return RotelCommand.ZONE2_VOLUME_SET;
+ case 3:
+ return RotelCommand.ZONE3_VOLUME_SET;
+ case 4:
+ return RotelCommand.ZONE4_VOLUME_SET;
+ default:
+ throw new IllegalArgumentException("No VOLUME SET command defined for zone " + numZone);
+ }
}
/**
- * Get the command to be used for main zone MUTE ON
+ * Get the command to be used for MUTE ON
+ *
+ * @param numZone the zone number (1-4) or 0 for the device or main zone
*
* @return the command
*/
- private RotelCommand getMuteOnCommand() {
- return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_MUTE_ON : RotelCommand.MUTE_ON;
+ private RotelCommand getMuteOnCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_MUTE_ON : RotelCommand.MUTE_ON;
+ case 1:
+ return RotelCommand.ZONE1_MUTE_ON;
+ case 2:
+ return RotelCommand.ZONE2_MUTE_ON;
+ case 3:
+ return RotelCommand.ZONE3_MUTE_ON;
+ case 4:
+ return RotelCommand.ZONE4_MUTE_ON;
+ default:
+ throw new IllegalArgumentException("No MUTE ON command defined for zone " + numZone);
+ }
}
/**
- * Get the command to be used for main zone MUTE OFF
+ * Get the command to be used for MUTE OFF
+ *
+ * @param numZone the zone number (1-4) or 0 for the device or main zone
*
* @return the command
*/
- private RotelCommand getMuteOffCommand() {
- return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_MUTE_OFF : RotelCommand.MUTE_OFF;
+ private RotelCommand getMuteOffCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_MUTE_OFF : RotelCommand.MUTE_OFF;
+ case 1:
+ return RotelCommand.ZONE1_MUTE_OFF;
+ case 2:
+ return RotelCommand.ZONE2_MUTE_OFF;
+ case 3:
+ return RotelCommand.ZONE3_MUTE_OFF;
+ case 4:
+ return RotelCommand.ZONE4_MUTE_OFF;
+ default:
+ throw new IllegalArgumentException("No MUTE OFF command defined for zone " + numZone);
+ }
}
/**
- * Get the command to be used for main zone MUTE TOGGLE
+ * Get the command to be used for MUTE TOGGLE
+ *
+ * @param numZone the zone number (1-4) or 0 for the device or main zone
*
* @return the command
*/
- private RotelCommand getMuteToggleCommand() {
- return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_MUTE_TOGGLE : RotelCommand.MUTE_TOGGLE;
+ private RotelCommand getMuteToggleCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_MUTE_TOGGLE
+ : RotelCommand.MUTE_TOGGLE;
+ case 1:
+ return RotelCommand.ZONE1_MUTE_TOGGLE;
+ case 2:
+ return RotelCommand.ZONE2_MUTE_TOGGLE;
+ case 3:
+ return RotelCommand.ZONE3_MUTE_TOGGLE;
+ case 4:
+ return RotelCommand.ZONE4_MUTE_TOGGLE;
+ default:
+ throw new IllegalArgumentException("No MUTE TOGGLE command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for BASS UP
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getBassUpCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.BASS_UP;
+ case 1:
+ return RotelCommand.ZONE1_BASS_UP;
+ case 2:
+ return RotelCommand.ZONE2_BASS_UP;
+ case 3:
+ return RotelCommand.ZONE3_BASS_UP;
+ case 4:
+ return RotelCommand.ZONE4_BASS_UP;
+ default:
+ throw new IllegalArgumentException("No BASS UP command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for BASS DOWN
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getBassDownCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.BASS_DOWN;
+ case 1:
+ return RotelCommand.ZONE1_BASS_DOWN;
+ case 2:
+ return RotelCommand.ZONE2_BASS_DOWN;
+ case 3:
+ return RotelCommand.ZONE3_BASS_DOWN;
+ case 4:
+ return RotelCommand.ZONE4_BASS_DOWN;
+ default:
+ throw new IllegalArgumentException("No BASS DOWN command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for BASS SET
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getBassSetCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.BASS_SET;
+ case 1:
+ return RotelCommand.ZONE1_BASS_SET;
+ case 2:
+ return RotelCommand.ZONE2_BASS_SET;
+ case 3:
+ return RotelCommand.ZONE3_BASS_SET;
+ case 4:
+ return RotelCommand.ZONE4_BASS_SET;
+ default:
+ throw new IllegalArgumentException("No BASS SET command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for TREBLE UP
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getTrebleUpCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.TREBLE_UP;
+ case 1:
+ return RotelCommand.ZONE1_TREBLE_UP;
+ case 2:
+ return RotelCommand.ZONE2_TREBLE_UP;
+ case 3:
+ return RotelCommand.ZONE3_TREBLE_UP;
+ case 4:
+ return RotelCommand.ZONE4_TREBLE_UP;
+ default:
+ throw new IllegalArgumentException("No TREBLE UP command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for TREBLE DOWN
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getTrebleDownCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.TREBLE_DOWN;
+ case 1:
+ return RotelCommand.ZONE1_TREBLE_DOWN;
+ case 2:
+ return RotelCommand.ZONE2_TREBLE_DOWN;
+ case 3:
+ return RotelCommand.ZONE3_TREBLE_DOWN;
+ case 4:
+ return RotelCommand.ZONE4_TREBLE_DOWN;
+ default:
+ throw new IllegalArgumentException("No TREBLE DOWN command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for TREBLE SET
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getTrebleSetCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.TREBLE_SET;
+ case 1:
+ return RotelCommand.ZONE1_TREBLE_SET;
+ case 2:
+ return RotelCommand.ZONE2_TREBLE_SET;
+ case 3:
+ return RotelCommand.ZONE3_TREBLE_SET;
+ case 4:
+ return RotelCommand.ZONE4_TREBLE_SET;
+ default:
+ throw new IllegalArgumentException("No TREBLE SET command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for BALANCE LEFT
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getBalanceLeftCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.BALANCE_LEFT;
+ case 1:
+ return RotelCommand.ZONE1_BALANCE_LEFT;
+ case 2:
+ return RotelCommand.ZONE2_BALANCE_LEFT;
+ case 3:
+ return RotelCommand.ZONE3_BALANCE_LEFT;
+ case 4:
+ return RotelCommand.ZONE4_BALANCE_LEFT;
+ default:
+ throw new IllegalArgumentException("No BALANCE LEFT command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for BALANCE RIGHT
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getBalanceRightCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.BALANCE_RIGHT;
+ case 1:
+ return RotelCommand.ZONE1_BALANCE_RIGHT;
+ case 2:
+ return RotelCommand.ZONE2_BALANCE_RIGHT;
+ case 3:
+ return RotelCommand.ZONE3_BALANCE_RIGHT;
+ case 4:
+ return RotelCommand.ZONE4_BALANCE_RIGHT;
+ default:
+ throw new IllegalArgumentException("No BALANCE RIGHT command defined for zone " + numZone);
+ }
+ }
+
+ /**
+ * Get the command to be used for BALANCE SET
+ *
+ * @param numZone the zone number (1-4) or 0 for the device
+ *
+ * @return the command
+ */
+ private RotelCommand getBalanceSetCommand(int numZone) {
+ switch (numZone) {
+ case 0:
+ return RotelCommand.BALANCE_SET;
+ case 1:
+ return RotelCommand.ZONE1_BALANCE_SET;
+ case 2:
+ return RotelCommand.ZONE2_BALANCE_SET;
+ case 3:
+ return RotelCommand.ZONE3_BALANCE_SET;
+ case 4:
+ return RotelCommand.ZONE4_BALANCE_SET;
+ default:
+ throw new IllegalArgumentException("No BALANCE SET command defined for zone " + numZone);
+ }
}
private void sendCommand(RotelCommand cmd) throws RotelException {
*/
package org.openhab.binding.rotel.internal.protocol.ascii;
+import static org.openhab.binding.rotel.internal.RotelBindingConstants.*;
+
import java.nio.charset.StandardCharsets;
import org.eclipse.jdt.annotation.NonNullByDefault;
if (value != null) {
switch (cmd) {
case VOLUME_SET:
+ case ZONE1_VOLUME_SET:
+ case ZONE2_VOLUME_SET:
+ case ZONE3_VOLUME_SET:
+ case ZONE4_VOLUME_SET:
messageStr += String.format("%02d", value);
break;
case BASS_SET:
+ case ZONE1_BASS_SET:
+ case ZONE2_BASS_SET:
+ case ZONE3_BASS_SET:
+ case ZONE4_BASS_SET:
case TREBLE_SET:
+ case ZONE1_TREBLE_SET:
+ case ZONE2_TREBLE_SET:
+ case ZONE3_TREBLE_SET:
+ case ZONE4_TREBLE_SET:
if (value == 0) {
messageStr += "000";
} else if (value > 0) {
}
break;
case BALANCE_SET:
+ case ZONE1_BALANCE_SET:
+ case ZONE2_BALANCE_SET:
+ case ZONE3_BALANCE_SET:
+ case ZONE4_BALANCE_SET:
if (value == 0) {
messageStr += "000";
} else if (value > 0) {
logger.debug("Command \"{}\" => {}", cmd.getName(), messageStr);
return message;
}
+
+ @Override
+ protected void dispatchKeyValue(String key, String value) {
+ // For distribution amplifiers, we need to split certain values to get the value for each zone
+ if (model == RotelModel.C8 && value.contains(",")) {
+ switch (key) {
+ case KEY_INPUT:
+ case KEY_VOLUME:
+ case KEY_MUTE:
+ case KEY_BASS:
+ case KEY_TREBLE:
+ case KEY_BALANCE:
+ case KEY_FREQ:
+ String[] splitValues = value.split(",");
+ int nb = splitValues.length;
+ if (nb > MAX_NUMBER_OF_ZONES) {
+ nb = MAX_NUMBER_OF_ZONES;
+ }
+ for (int i = 1; i <= nb; i++) {
+ String val = KEY_INPUT.equals(key) ? String.format("z%d:input_%s", i, splitValues[i - 1])
+ : splitValues[i - 1];
+ dispatchKeyValue(String.format("%s_zone%d", key, i), val);
+ }
+ break;
+ default:
+ super.dispatchKeyValue(key, value);
+ break;
+ }
+ } else {
+ super.dispatchKeyValue(key, value);
+ }
+ }
}
} else if (!MSG_VALUE_OFF.equalsIgnoreCase(value)) {
RotelSource source = parseSource(value, true);
if (source != null) {
- RotelCommand cmd = source.getZone2Command();
+ RotelCommand cmd = source.getZoneCommand(2);
if (cmd != null) {
value = cmd.getAsciiCommandV2();
if (value != null) {
} else if (!MSG_VALUE_OFF.equalsIgnoreCase(value)) {
RotelSource source = parseSource(value, true);
if (source != null) {
- RotelCommand cmd = source.getZone3Command();
+ RotelCommand cmd = source.getZoneCommand(3);
if (cmd != null) {
value = cmd.getAsciiCommandV2();
if (value != null) {
} else if (!MSG_VALUE_OFF.equalsIgnoreCase(value)) {
RotelSource source = parseSource(value, true);
if (source != null) {
- RotelCommand cmd = source.getZone4Command();
+ RotelCommand cmd = source.getZoneCommand(4);
if (cmd != null) {
value = cmd.getAsciiCommandV2();
if (value != null) {
# channel group types
+channel-group.allZones.label = All Zones
+channel-group.allZones.description = The controls applied to all zones
channel-group.mainZone.label = Main Zone
channel-group.mainZone.description = The controls of the main zone
+channel-group.zone.label = Zone
+channel-group.zone.description = The controls of the zone
+channel-group.zone1.label = Zone 1
+channel-group.zone1.description = The controls of the zone 1
channel-group.zone2.label = Zone 2
channel-group.zone2.description = The controls of the zone 2
channel-group.zone3.label = Zone 3
source.PLAYFI = PlayFi
source.IRADIO = iRadio
source.NETWORK = Network
+source.INPUTA = Input A
+source.INPUTB = Input B
+source.INPUTC = Input C
+source.INPUTD = Input D
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="rotel"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
+ xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
+
+ <!-- Rotel C8 Connection Thing Type -->
+ <thing-type id="c8">
+ <label>C8 Distribution Amplifier</label>
+ <description>Connection to the Rotel C8 or C8+ distribution amplifier</description>
+
+ <channel-groups>
+ <channel-group id="allZones" typeId="allZones"/>
+ <channel-group id="zone1" typeId="zone">
+ <label>@text/channel-group.zone1.label</label>
+ <description>@text/channel-group.zone1.description</description>
+ </channel-group>
+ <channel-group id="zone2" typeId="zone">
+ <label>@text/channel-group.zone2.label</label>
+ <description>@text/channel-group.zone2.description</description>
+ </channel-group>
+ <channel-group id="zone3" typeId="zone">
+ <label>@text/channel-group.zone3.label</label>
+ <description>@text/channel-group.zone3.description</description>
+ </channel-group>
+ <channel-group id="zone4" typeId="zone">
+ <label>@text/channel-group.zone4.label</label>
+ <description>@text/channel-group.zone4.description</description>
+ </channel-group>
+ </channel-groups>
+
+ <properties>
+ <property name="protocol">ASCII_V2</property>
+ </properties>
+
+ <config-description-ref uri="thing-type:rotel:serialandip2"/>
+ </thing-type>
+
+</thing:thing-descriptions>
</channels>
</channel-group-type>
+ <channel-group-type id="allZones">
+ <label>@text/channel-group.allZones.label</label>
+ <description>@text/channel-group.allZones.description</description>
+ <channels>
+ <channel id="power" typeId="system.power"/>
+ <channel id="brightness" typeId="brightness"/>
+ </channels>
+ </channel-group-type>
+
+ <channel-group-type id="zone">
+ <label>@text/channel-group.zone.label</label>
+ <description>@text/channel-group.zone.description</description>
+ <channels>
+ <channel id="source" typeId="source"/>
+ <channel id="volume" typeId="system.volume"/>
+ <channel id="mute" typeId="system.mute"/>
+ <channel id="bass" typeId="bass"/>
+ <channel id="treble" typeId="treble"/>
+ <channel id="balance" typeId="balance"/>
+ <channel id="frequency" typeId="frequency"/>
+ </channels>
+ </channel-group-type>
+
<channel-type id="source">
<item-type>String</item-type>
<label>Source Input</label>