From b347491d602e7556295d3619f17dde1f52341561 Mon Sep 17 00:00:00 2001 From: tonwi Date: Tue, 22 Mar 2022 20:48:18 +0100 Subject: [PATCH] [rotel] Extension of amplifier A14's channel list (#12447) * A14: new channels: tcbypass, balance, speakera and speakerb * Specific balance set command for models A1x * Channels added on other models * In state TCBYPASS ON: 1) Ignore user adjustments on BASS/TREBLE. 2) Reset BASS/TREBLE to 0. Signed-off-by: Wilhelm Tonsern Also-by: Laurent Garnier --- bundles/org.openhab.binding.rotel/README.md | 67 ++-- .../rotel/internal/RotelBindingConstants.java | 4 + .../binding/rotel/internal/RotelModel.java | 104 +++++- .../internal/communication/RotelCommand.java | 24 +- .../communication/RotelConnector.java | 28 ++ .../rotel/internal/handler/RotelHandler.java | 348 ++++++++++++++++-- .../main/resources/OH-INF/config/config.xml | 1 + .../resources/OH-INF/i18n/rotel.properties | 8 + .../src/main/resources/OH-INF/thing/a11.xml | 4 + .../src/main/resources/OH-INF/thing/a12.xml | 4 + .../src/main/resources/OH-INF/thing/a14.xml | 4 + .../main/resources/OH-INF/thing/channels.xml | 23 ++ .../src/main/resources/OH-INF/thing/ra11.xml | 2 + .../src/main/resources/OH-INF/thing/ra12.xml | 2 + .../main/resources/OH-INF/thing/ra1570.xml | 4 + .../main/resources/OH-INF/thing/ra1572.xml | 4 + .../main/resources/OH-INF/thing/ra1592.xml | 4 + .../main/resources/OH-INF/thing/rc1570.xml | 2 + .../main/resources/OH-INF/thing/rc1572.xml | 2 + .../main/resources/OH-INF/thing/rc1590.xml | 2 + 20 files changed, 558 insertions(+), 83 deletions(-) diff --git a/bundles/org.openhab.binding.rotel/README.md b/bundles/org.openhab.binding.rotel/README.md index 1204fc804..ad3a2703e 100644 --- a/bundles/org.openhab.binding.rotel/README.md +++ b/bundles/org.openhab.binding.rotel/README.md @@ -162,38 +162,42 @@ The following channels are available: | mainZone#line2 | Front Panel Line 2 | String | The second line displayed on the device front panel | | | frequency | Current Frequency | Number | The current frequency (in kHz) for digital source input | | | brightness | Front Panel Display Brightness | Dimmer | The backlight brightness level (in %) of the device front panel | | +| tcbypass | Tone Control Bypass | Switch | The user's bass-/treble-settings are bypassed | ON, OFF | +| balance | Stereo Balance Adjustment | Number | Adjust the balance | INCREASE, DECREASE, value | +| speakera | Speaker-A Adjustment | Switch | Turn on/off the speaker group A | ON, OFF | +| speakerb | Speaker-B Adjustment | Switch | Turn on/off the speaker group B | ON, OFF | Here are the list of channels available for each thing type: -| Thing Type | Available channels | -|------------|---------------------------------------------------------------------------------------| -| a11 | power, source, volume, mute, bass, treble, brightness | -| a12 | power, source, volume, mute, bass, treble, frequency, brightness | -| a14 | power, source, volume, mute, bass, treble, frequency, brightness | -| cd11 | power, playControl, track, brightness | -| cd14 | power, playControl, track, brightness | -| ra11 | power, source, volume, mute, bass, treble, playControl, frequency, brightness | -| ra12 | power, source, volume, mute, bass, treble, playControl, frequency, brightness | -| ra1570 | power, source, volume, mute, bass, treble, playControl, frequency, brightness | -| ra1572 | power, source, volume, mute, bass, treble, frequency, brightness | -| ra1592 | power, source, volume, mute, bass, treble, frequency, brightness | -| rap1580 | power, source, dsp, volume, mute, brightness | -| rc1570 | power, source, volume, mute, bass, treble, playControl, frequency, brightness | -| rc1572 | power, source, volume, mute, bass, treble, frequency, brightness | -| rc1590 | power, source, volume, mute, bass, treble, frequency, brightness | -| rcd1570 | power, playControl, brightness | -| rcd1572 | power, playControl, track, brightness | -| rcx1500 | power, source, volume, mute, playControl | -| rdd1580 | power, source, playControl, frequency | -| rdg1520 | power, source, playControl | +| Thing Type | Available channels | +|------------|---------------------------------------------------------------------------------------------------------| +| a11 | power, source, volume, mute, bass, treble, brightness, tcbypass, balance, speakera, speakerb | +| a12 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb | +| a14 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb | +| cd11 | power, playControl, track, brightness | +| cd14 | power, playControl, track, brightness | +| ra11 | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance | +| ra12 | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance | +| ra1570 | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance, speakera, speakerb | +| ra1572 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb | +| ra1592 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb | +| rap1580 | power, source, dsp, volume, mute, brightness | +| rc1570 | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance | +| rc1572 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance | +| rc1590 | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance | +| rcd1570 | power, playControl, brightness | +| rcd1572 | power, playControl, track, brightness | +| rcx1500 | power, source, volume, mute, playControl | +| rdd1580 | power, source, playControl, frequency | +| rdg1520 | power, source, playControl | | rsp1066 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volumeUpDown, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volumeUpDown | | rsp1068 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute | | rsp1069 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute | | rsp1098 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volume, zone2#mute | | rsp1570 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute | | rsp1572 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute | -| rsp1576 | power, source, dsp, volume, mute, brightness | -| rsp1582 | power, source, dsp, volume, mute, brightness | +| rsp1576 | power, source, dsp, volume, mute, brightness | +| rsp1582 | power, source, dsp, volume, mute, brightness | | rsx1055 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volumeUpDown, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volumeUpDown | | rsx1056 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volume, zone2#mute | | rsx1057 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volume, zone2#mute | @@ -203,11 +207,11 @@ Here are the list of channels available for each thing type: | rsx1550 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute | | rsx1560 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute | | rsx1562 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute | -| rt09 | power, source, playControl, brightness | -| rt11 | power, source, brightness | -| rt1570 | power, source, brightness | -| t11 | power, source, brightness | -| t14 | power, source, brightness | +| rt09 | power, source, playControl, brightness | +| rt11 | power, source, brightness | +| rt1570 | power, source, brightness | +| t11 | power, source, brightness | +| t14 | power, source, brightness | ## Full Example @@ -221,6 +225,8 @@ Thing rotel:rsp1570:preamp "RSP-1570" [ serialPort="COM2" ] Thing rotel:ra1592:preamp "RA-1592" [ serialPort="COM3" ] Thing rotel:cd14:cd "CD14" [ serialPort="COM4" ] + +Thing rotel:a14:amp "A14" [ serialPort="/dev/ttyUSB0" ] ``` example.things using serial over IP connection: @@ -282,6 +288,11 @@ Number amp_bass "Bass Adjustment [%d]" { channel="rotel:ra1592:preamp:bass" } Number amp_treble "Treble Adjustment [%d]" { channel="rotel:ra1592:preamp:treble" } Dimmer amp_brightness "Display brightness" { channel="rotel:ra1592:preamp:brightness" } +Switch amp_bypass "TCBypass" { channel="rotel:a14:amp:tcbypass" } +Number amp_balance "Balance Adjustment [%d]" { channel="rotel:a14:amp:balance" } +Switch amp_speakera "Speaker A" { channel="rotel:a14:amp:speakera" } +Switch amp_speakerb "Speaker B" { channel="rotel:a14:amp:speakerb" } + Switch cd_power "Power" { channel="rotel:cd14:cd:power" } Player cd_control "Playback" { channel="rotel:cd14:cd:power" } Number cd_track "Track [%d]" { channel="rotel:cd14:cd:power" } diff --git a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelBindingConstants.java b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelBindingConstants.java index 559c6c405..651296b70 100644 --- a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelBindingConstants.java +++ b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelBindingConstants.java @@ -148,6 +148,10 @@ public class RotelBindingConstants { public static final String CHANNEL_ZONE4_SOURCE = "zone4#source"; public static final String CHANNEL_ZONE4_VOLUME = "zone4#volume"; public static final String CHANNEL_ZONE4_MUTE = "zone4#mute"; + public static final String CHANNEL_TCBYPASS = "tcbypass"; + public static final String CHANNEL_BALANCE = "balance"; + public static final String CHANNEL_SPEAKER_A = "speakera"; + public static final String CHANNEL_SPEAKER_B = "speakerb"; // List of all properties public static final String PROPERTY_PROTOCOL = "protocol"; diff --git a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelModel.java b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelModel.java index 31039c3de..ec7c236c1 100644 --- a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelModel.java +++ b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelModel.java @@ -62,21 +62,27 @@ public enum RotelModel { 5, true, RotelFlagsMapping.MAPPING5), RSX1562("RSX-1562", 115200, 2, 3, true, 96, true, null, false, RotelCommand.RECORD_FONCTION_SELECT, 4, (byte) 0xCC, 42, 5, true, RotelFlagsMapping.MAPPING5), - A11("A11", 115200, 4, 96, true, 10, false, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS), - A12("A12", 115200, 5, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS), - A14("A14", 115200, 5, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS), + A11("A11", 115200, 4, 96, true, 10, 15, false, -1, false, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS), + A12("A12", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS), + A14("A14", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS), CD11("CD11", 57600, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS), CD14("CD14", 57600, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS), - RA11("RA-11", 115200, 6, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS), - RA12("RA-12", 115200, 6, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS), - RA1570("RA-1570", 115200, 7, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS), - RA1572("RA-1572", 115200, 8, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS), - RA1592("RA-1592", 115200, 9, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS), + RA11("RA-11", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS), + RA12("RA-12", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS), + RA1570("RA-1570", 115200, 7, 96, true, 10, 15, true, -1, true, true, false, 6, 0, + RotelConnector.SPECIAL_CHARACTERS), + RA1572("RA-1572", 115200, 8, 96, true, 10, 15, false, -1, true, true, true, 6, 0, + RotelConnector.SPECIAL_CHARACTERS), + RA1592("RA-1592", 115200, 9, 96, true, 10, 15, false, -1, true, true, true, 6, 0, + RotelConnector.SPECIAL_CHARACTERS), RAP1580("RAP-1580", 115200, 11, 96, true, null, false, 5, false, false, -10, 10, RotelConnector.NO_SPECIAL_CHARACTERS), - RC1570("RC-1570", 115200, 7, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS), - RC1572("RC-1572", 115200, 8, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS), - RC1590("RC-1590", 115200, 9, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS), + RC1570("RC-1570", 115200, 7, 96, true, 10, 15, true, -1, true, false, false, 6, 0, + RotelConnector.SPECIAL_CHARACTERS), + RC1572("RC-1572", 115200, 8, 96, true, 10, 15, false, -1, true, false, true, 6, 0, + RotelConnector.SPECIAL_CHARACTERS), + RC1590("RC-1590", 115200, 9, 96, true, 10, 15, false, -1, true, false, true, 6, 0, + RotelConnector.SPECIAL_CHARACTERS), RCD1570("RCD-1570", 115200, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS), RCD1572("RCD-1572", 57600, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS_RCD1572), @@ -118,6 +124,8 @@ public enum RotelModel { private boolean charsBeforeFlags; private RotelFlagsMapping flagsMapping; private byte[][] specialCharacters; + private @Nullable Integer balanceLevelMax; + private boolean getSpeakerGroupsAvailable; /** * Constructor @@ -144,8 +152,8 @@ public enum RotelModel { @Nullable RotelCommand zoneSelectCmd, int dspCategory, byte deviceId, int respNbChars, int respNbFlags, boolean charsBeforeFlags, RotelFlagsMapping flagsMapping) { this(name, baudRate, RotelCommand.DISPLAY_REFRESH, sourceCategory, nbAdditionalZones, additionalCommands, - volumeMax, directVolume, toneLevelMax, playControl, zoneSelectCmd, dspCategory, false, false, null, - null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping, + volumeMax, directVolume, toneLevelMax, null, playControl, zoneSelectCmd, dspCategory, false, false, + false, null, null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping, RotelConnector.NO_SPECIAL_CHARACTERS); } @@ -170,11 +178,40 @@ public enum RotelModel { @Nullable Integer toneLevelMax, boolean playControl, int dspCategory, boolean getFrequencyAvailable, boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax, byte[][] specialCharacters) { - this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax, - playControl, null, dspCategory, getFrequencyAvailable, getDimmerLevelAvailable, diummerLevelMin, + this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax, null, + playControl, null, dspCategory, getFrequencyAvailable, false, getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, (byte) 0, 0, 0, false, RotelFlagsMapping.NO_MAPPING, specialCharacters); } + /** + * Constructor + * + * @param name the model name + * @param baudRate the baud rate to be used for the RS232 communication + * @param sourceCategory the category from {@link RotelSource} + * @param volumeMax the maximum volume or null if no volume management is available + * @param directVolume true if a command to set the volume with a value is available + * @param toneLevelMax the maximum tone level or null if no bass/treble management is available + * @param balanceLevelMax the maximum balance level or null if no balance management is available + * @param playControl true if control of source playback is available + * @param dspCategory the category from {@link RotelDsp} + * @param getFrequencyAvailable true if the command to get the frequency for digital source input is available + * @param getSpeakerGroupsAvailable true if the command to switch speaker groups is available + * @param getDimmerLevelAvailable true if the command to get the front display dimmer level is available + * @param diummerLevelMin the minimum front display dimmer level or null if dimmer control is unavailable + * @param diummerLevelMax the maximum front display dimmer level or null if dimmer control is unavailable + * @param specialCharacters the table of special characters that can be found in the standard response message + */ + private RotelModel(String name, int baudRate, int sourceCategory, @Nullable Integer volumeMax, boolean directVolume, + @Nullable Integer toneLevelMax, @Nullable Integer balanceLevelMax, boolean playControl, int dspCategory, + boolean getFrequencyAvailable, boolean getSpeakerGroupsAvailable, boolean getDimmerLevelAvailable, + @Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax, byte[][] specialCharacters) { + this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax, + balanceLevelMax, playControl, null, dspCategory, getFrequencyAvailable, getSpeakerGroupsAvailable, + getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, (byte) 0, 0, 0, false, + RotelFlagsMapping.NO_MAPPING, specialCharacters); + } + /** * Constructor * @@ -187,10 +224,12 @@ public enum RotelModel { * @param volumeMax the maximum volume or null if no volume management is available * @param directVolume true if a command to set the volume with a value is available * @param toneLevelMax the maximum tone level or null if no bass/treble management is available + * @param balanceLevelMax the maximum balance level or null if no balance management is available * @param playControl true if control of source playback is available * @param zoneSelectCmd the command to be used to select a zone * @param dspCategory the category from {@link RotelDsp} * @param getFrequencyAvailable true if the command to get the frequency for digital source input is available + * @param getSpeakerGroupsAvailable true if the command to switch speaker groups is available * @param getDimmerLevelAvailable true if the command to get the front display dimmer level is available * @param diummerLevelMin the minimum front display dimmer level or null if dimmer control is unavailable * @param diummerLevelMax the maximum front display dimmer level or null if dimmer control is unavailable @@ -203,8 +242,9 @@ public enum RotelModel { */ private RotelModel(String name, int baudRate, RotelCommand powerStateCmd, int sourceCategory, int nbAdditionalZones, boolean additionalCommands, @Nullable Integer volumeMax, boolean directVolume, - @Nullable Integer toneLevelMax, boolean playControl, @Nullable RotelCommand zoneSelectCmd, int dspCategory, - boolean getFrequencyAvailable, boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin, + @Nullable Integer toneLevelMax, @Nullable Integer balanceLevelMax, boolean playControl, + @Nullable RotelCommand zoneSelectCmd, int dspCategory, boolean getFrequencyAvailable, + boolean getSpeakerGroupsAvailable, boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax, byte deviceId, int respNbChars, int respNbFlags, boolean charsBeforeFlags, RotelFlagsMapping flagsMapping, byte[][] specialCharacters) { this.name = name; @@ -216,10 +256,12 @@ public enum RotelModel { this.volumeMax = volumeMax; this.directVolume = directVolume; this.toneLevelMax = toneLevelMax; + this.balanceLevelMax = balanceLevelMax; this.playControl = playControl; this.zoneSelectCmd = zoneSelectCmd; this.dspCategory = dspCategory; this.getFrequencyAvailable = getFrequencyAvailable; + this.getSpeakerGroupsAvailable = getSpeakerGroupsAvailable; this.getDimmerLevelAvailable = getDimmerLevelAvailable; this.diummerLevelMin = diummerLevelMin; this.diummerLevelMax = diummerLevelMax; @@ -386,6 +428,34 @@ public enum RotelModel { return toneLevelMax != null ? toneLevelMax.intValue() : 0; } + /** + * Inform whether balance control is available + * + * @return true if balance control is available + */ + public boolean hasBalanceControl() { + return balanceLevelMax != null; + } + + /** + * Get the maximum balance level + * + * @return the maximum balance level or 0 + */ + public int getBalanceLevelMax() { + Integer balanceLevelMax = this.balanceLevelMax; + return balanceLevelMax != null ? balanceLevelMax.intValue() : 0; + } + + /** + * Inform whether the command to switch speaker groups is available + * + * @return true if the command is available + */ + public boolean hasSpeakerGroups() { + return getSpeakerGroupsAvailable; + } + /** * Inform whether the command to get the current frequency for digital source input is available * diff --git a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelCommand.java b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelCommand.java index 0924f9f87..bfbefd1ab 100644 --- a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelCommand.java +++ b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelCommand.java @@ -227,12 +227,30 @@ public enum RotelCommand { TRACK_FORWARD("Track Forward", RotelConnector.PRIMARY_CMD, (byte) 0x09, "track_fwd", "trkf"), TRACK_BACKWORD("Track Backward", RotelConnector.PRIMARY_CMD, (byte) 0x08, "track_back", "trkb"), TRACK("Request current CD track number", null, "track"), - FREQUENCY("Request current frequency for digital source input", "get_current_freq", "freq"), + FREQUENCY("Request current frequency for digital source input", "get_current_freq", "freq?"), DISPLAY_REFRESH("Display Refresh", RotelConnector.PRIMARY_CMD, (byte) 0xFF), - DIMMER_LEVEL_GET("Request current front display dimmer level", "get_current_dimmer", "dimmer"), + DIMMER_LEVEL_GET("Request current front display dimmer level", "get_current_dimmer", "dimmer?"), DIMMER_LEVEL_SET("Set front display dimmer to level", "dimmer_", "dimmer_"), UPDATE_AUTO("Set Update to Auto", "display_update_auto", "rs232_update_on"), - UPDATE_MANUAL("Set Update to Manual", "display_update_manual", "rs232_update_off"); + UPDATE_MANUAL("Set Update to Manual", "display_update_manual", "rs232_update_off"), + TONE_CONTROLS_ON("Tone Controls On", "tone_on", null), + TONE_CONTROLS_OFF("Tone Controls Off", "tone_off", null), + TONE_CONTROLS("Request current tone control state", "get_tone", null), + TCBYPASS_ON("Bypass On", null, "bypass_on"), + TCBYPASS_OFF("Bypass Off", null, "bypass_off"), + TCBYPASS("Request current tone bypass state", null, "bypass?"), + BALANCE_RIGHT("Balance Right", "balance_right", "balance_r"), + BALANCE_LEFT("Balance Left", "balance_left", "balance_l"), + BALANCE_SET("Set Balance to level", "balance_", "balance_"), + BALANCE_SET_FIX("Set Balance to level", "balance_", "balance_"), + BALANCE("Request current balance setting", "get_balance", "balance?"), + SPEAKER_A_TOGGLE("Toggle Speaker A Output", RotelConnector.PRIMARY_CMD, (byte) 0x50, "speaker_a", "speaker_a"), + SPEAKER_A_ON("Set Speaker A Output", "speaker_a_on", "speaker_a_on"), + SPEAKER_A_OFF("Unset Speaker A Output", "speaker_a_off", "speaker_a_off"), + SPEAKER_B_TOGGLE("Toggle Speaker B Output", RotelConnector.PRIMARY_CMD, (byte) 0x51, "speaker_b", "speaker_b"), + SPEAKER_B_ON("Set Speaker B Output", "speaker_b_on", "speaker_b_on"), + SPEAKER_B_OFF("Unset Speaker B Output", "speaker_b_off", "speaker_b_off"), + SPEAKER("Request current active speaker outputs", "get_current_speaker", "speaker?"); public static final byte PRIMARY_COMMAND = (byte) 0x10; diff --git a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelConnector.java b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelConnector.java index de749ff6f..fec2effc2 100644 --- a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelConnector.java +++ b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelConnector.java @@ -136,6 +136,10 @@ public abstract class RotelConnector { public static final String KEY_DSP_MODE = "dsp_mode"; public static final String KEY_DIMMER = "dimmer"; public static final String KEY_FREQ = "freq"; + public static final String KEY_TONE = "tone"; + public static final String KEY_TCBYPASS = "bypass"; + public static final String KEY_BALANCE = "balance"; + public static final String KEY_SPEAKER = "speaker"; // Special keys used by the binding public static final String KEY_LINE1 = "line1"; @@ -171,6 +175,9 @@ public abstract class RotelConnector { public static final String PAUSE = "pause"; public static final String STOP = "stop"; private static final String SOURCE = "source"; + public static final String MSG_VALUE_SPEAKER_A = "a"; + public static final String MSG_VALUE_SPEAKER_B = "b"; + public static final String MSG_VALUE_SPEAKER_AB = "a_b"; private RotelModel model; private RotelProtocol protocol; @@ -458,6 +465,27 @@ public abstract class RotelConnector { messageStr += String.format("-%02d", -value); } break; + case BALANCE_SET: + if (value == 0) { + messageStr += "000"; + } else if (value > 0) { + messageStr += String.format("R%02d", value); + } else { + messageStr += String.format("L%02d", -value); + } + break; + case BALANCE_SET_FIX: + // Firmware for models A1x does not follow strictly the Rotel specification + // The firmware expects values like r05 or l04 while the specification mentions + // R05 and L04 + if (value == 0) { + messageStr += "000"; + } else if (value > 0) { + messageStr += String.format("r%02d", value); + } else { + messageStr += String.format("l%02d", -value); + } + break; case DIMMER_LEVEL_SET: if (value > 0 && model.getDimmerLevelMin() < 0) { messageStr += String.format("+%d", value); diff --git a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/handler/RotelHandler.java b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/handler/RotelHandler.java index f07db499e..01c8ed055 100644 --- a/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/handler/RotelHandler.java +++ b/bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/handler/RotelHandler.java @@ -75,6 +75,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL private static final RotelModel DEFAULT_MODEL = RotelModel.RSP1066; private static final long POLLING_INTERVAL = TimeUnit.SECONDS.toSeconds(60); private static final boolean USE_SIMULATED_DEVICE = false; + private static final int SLEEP_INTV = 30; private @Nullable ScheduledFuture reconnectJob; private @Nullable ScheduledFuture powerOnJob; @@ -125,6 +126,13 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL private String frontPanelLine1 = ""; private String frontPanelLine2 = ""; private int brightness; + private boolean tcbypass; + private int balance; + private int minBalanceLevel; + private int maxBalanceLevel; + private boolean speakera; + private boolean speakerb; + private boolean useFixedBalanceCmd; private Object sequenceLock = new Object(); @@ -191,12 +199,15 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL break; case THING_TYPE_ID_A11: rotelModel = RotelModel.A11; + useFixedBalanceCmd = true; break; case THING_TYPE_ID_A12: rotelModel = RotelModel.A12; + useFixedBalanceCmd = true; break; case THING_TYPE_ID_A14: rotelModel = RotelModel.A14; + useFixedBalanceCmd = true; break; case THING_TYPE_ID_CD11: rotelModel = RotelModel.CD11; @@ -312,6 +323,12 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL "Set minValue to {} and maxValue to {} for your sitemap widget attached to your bass or treble item.", minToneLevel, maxToneLevel); } + if (rotelModel.hasBalanceControl()) { + maxBalanceLevel = rotelModel.getBalanceLevelMax(); + minBalanceLevel = -maxBalanceLevel; + logger.info("Set minValue to {} and maxValue to {} for your sitemap widget attached to your balance item.", + minBalanceLevel, maxBalanceLevel); + } // Check configuration settings String configError = null; @@ -519,6 +536,18 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL : src.getCommand(); if (cmd != null) { connector.sendCommand(cmd); + if (connector.getModel().canGetFrequency()) { + // send returns + // 1.) the selected + // 2.) the used frequency + // BUT: + // at response-time the frequency has the value of + // so we must wait a short moment to get the frequency of + Thread.sleep(1000); + connector.sendCommand(RotelCommand.FREQUENCY); + Thread.sleep(100); + updateChannelState(CHANNEL_FREQUENCY); + } } else { success = false; logger.debug("Command {} from channel {} failed: undefined source command", command, @@ -788,6 +817,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL if (!isPowerOn()) { success = false; logger.debug("Command {} from channel {} ignored: device in standby", command, channel); + } else if (tcbypass) { + logger.debug("Command {} from channel {} ignored: tone control bypass is ON", command, + channel); + updateChannelState(CHANNEL_BASS); } else { handleToneCmd(bass, channel, command, 2, RotelCommand.BASS_UP, RotelCommand.BASS_DOWN, RotelCommand.BASS_SET); @@ -798,6 +831,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL if (!isPowerOn()) { success = false; logger.debug("Command {} from channel {} ignored: device in standby", command, channel); + } else if (tcbypass) { + logger.debug("Command {} from channel {} ignored: tone control bypass is ON", command, + channel); + updateChannelState(CHANNEL_TREBLE); } else { handleToneCmd(treble, channel, command, 1, RotelCommand.TREBLE_UP, RotelCommand.TREBLE_DOWN, RotelCommand.TREBLE_SET); @@ -815,7 +852,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL && connector.getModel() != RotelModel.RCD1570 && connector.getModel() != RotelModel.RCD1572 && connector.getModel() != RotelModel.RCX1500) { - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); connector.sendCommand(RotelCommand.PLAY_STATUS); } } else if (command instanceof NextPreviousType && command == NextPreviousType.NEXT) { @@ -845,6 +882,55 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL logger.debug("Command {} from channel {} failed: invalid command value", command, channel); } break; + case CHANNEL_TCBYPASS: + if (!isPowerOn()) { + success = false; + logger.debug("Command {} from channel {} ignored: device in standby", command, channel); + } else if (!connector.getModel().hasToneControl() + || connector.getProtocol() == RotelProtocol.HEX) { + success = false; + logger.debug("Command {} from channel {} failed: unavailable feature", command, channel); + } else { + handleTcbypassCmd(channel, command, + connector.getProtocol() == RotelProtocol.ASCII_V1 ? RotelCommand.TONE_CONTROLS_OFF + : RotelCommand.TCBYPASS_ON, + connector.getProtocol() == RotelProtocol.ASCII_V1 ? RotelCommand.TONE_CONTROLS_ON + : RotelCommand.TCBYPASS_OFF); + } + break; + case CHANNEL_BALANCE: + if (!isPowerOn()) { + success = false; + logger.debug("Command {} from channel {} ignored: device in standby", command, channel); + } else if (!connector.getModel().hasBalanceControl() + || connector.getProtocol() == RotelProtocol.HEX) { + success = false; + logger.debug("Command {} from channel {} failed: unavailable feature", command, channel); + } else { + handleBalanceCmd(channel, command, RotelCommand.BALANCE_LEFT, RotelCommand.BALANCE_RIGHT, + useFixedBalanceCmd ? RotelCommand.BALANCE_SET_FIX : RotelCommand.BALANCE_SET); + } + break; + case CHANNEL_SPEAKER_A: + if (!isPowerOn()) { + success = false; + logger.debug("Command {} from channel {} ignored: device in standby", command, channel); + } else { + handleSpeakerCmd(connector.getProtocol() == RotelProtocol.HEX, channel, command, + RotelCommand.SPEAKER_A_ON, RotelCommand.SPEAKER_A_OFF, + RotelCommand.SPEAKER_A_TOGGLE); + } + break; + case CHANNEL_SPEAKER_B: + if (!isPowerOn()) { + success = false; + logger.debug("Command {} from channel {} ignored: device in standby", command, channel); + } else { + handleSpeakerCmd(connector.getProtocol() == RotelProtocol.HEX, channel, command, + RotelCommand.SPEAKER_B_ON, RotelCommand.SPEAKER_B_OFF, + RotelCommand.SPEAKER_B_TOGGLE); + } + break; default: success = false; logger.debug("Command {} from channel {} failed: nnexpected command", command, channel); @@ -992,6 +1078,92 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL } } + /** + * Handle a tcbypass command (only for ASCII protocol) + * + * @param channel the channel + * @param command the received channel command (OnOffType) + * @param onCmd the command to be sent to the device to bypass_on + * @param offCmd the command to be sent to the device to bypass_off + * + * @throws RotelException in case of communication error with the device + */ + private void handleTcbypassCmd(String channel, Command command, RotelCommand onCmd, RotelCommand offCmd) + throws RotelException, InterruptedException { + if (command instanceof OnOffType) { + if (command == OnOffType.ON) { + connector.sendCommand(onCmd); + bass = 0; + treble = 0; + updateChannelState(CHANNEL_BASS); + updateChannelState(CHANNEL_TREBLE); + } else if (command == OnOffType.OFF) { + connector.sendCommand(offCmd); + Thread.sleep(200); + connector.sendCommand(RotelCommand.BASS); + Thread.sleep(200); + connector.sendCommand(RotelCommand.TREBLE); + } + } else { + logger.debug("Command {} from channel {} failed: invalid command value", command, channel); + } + } + + /** + * Handle a speaker command + * + * @param onlyToggle true if only the toggle command must be used + * @param channel the channel + * @param command the received channel command (OnOffType) + * @param onCmd the command to be sent to the device to speaker_x_on + * @param offCmd the command to be sent to the device to speaker_x_off + * @param toggleCmd the command to be sent to the device to toggle the speaker_x state + * + * @throws RotelException in case of communication error with the device + */ + private void handleSpeakerCmd(boolean onlyToggle, String channel, Command command, RotelCommand onCmd, + RotelCommand offCmd, RotelCommand toggleCmd) throws RotelException { + if (command instanceof OnOffType) { + if (onlyToggle) { + connector.sendCommand(toggleCmd); + } else if (command == OnOffType.ON) { + connector.sendCommand(onCmd); + } else if (command == OnOffType.OFF) { + connector.sendCommand(offCmd); + } + } else { + logger.debug("Command {} from channel {} failed: invalid command value", command, channel); + } + } + + /** + * Handle a tone balance adjustment command (left or right) (only for ASCII protocol) + * + * @param channel the channel + * @param command the received channel command (IncreaseDecreaseType or DecimalType) + * @param rightCmd the command to be sent to the device to "increase" balance (shift to the right side) + * @param leftCmd the command to be sent to the device to "decrease" balance (shift to the left side) + * @param setCmd the command to be sent to the device to set the balance at a value + * + * @throws RotelException in case of communication error with the device + * @throws InterruptedException in case of interruption during a thread sleep + */ + private void handleBalanceCmd(String channel, Command command, RotelCommand leftCmd, RotelCommand rightCmd, + RotelCommand setCmd) throws RotelException, InterruptedException { + if (command instanceof IncreaseDecreaseType && command == IncreaseDecreaseType.INCREASE) { + connector.sendCommand(rightCmd); + } else if (command instanceof IncreaseDecreaseType && command == IncreaseDecreaseType.DECREASE) { + connector.sendCommand(leftCmd); + } else if (command instanceof DecimalType) { + int value = ((DecimalType) command).intValue(); + if (value >= minBalanceLevel && value <= maxBalanceLevel) { + connector.sendCommand(setCmd, value); + } + } else { + logger.debug("Command {} from channel {} failed: invalid command value", command, channel); + } + } + /** * Run a sequence of commands to display the current tone level (bass or treble) on the device front panel * @@ -1377,6 +1549,67 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL case RotelConnector.KEY_UPDATE_MODE: case RotelConnector.KEY_DISPLAY_UPDATE: break; + case RotelConnector.KEY_TONE: + if (RotelConnector.MSG_VALUE_ON.equalsIgnoreCase(value)) { + tcbypass = false; + updateChannelState(CHANNEL_TCBYPASS); + } else if (RotelConnector.MSG_VALUE_OFF.equalsIgnoreCase(value)) { + tcbypass = true; + updateChannelState(CHANNEL_TCBYPASS); + } else { + throw new RotelException("Invalid value"); + } + break; + case RotelConnector.KEY_TCBYPASS: + if (RotelConnector.MSG_VALUE_ON.equalsIgnoreCase(value)) { + tcbypass = true; + updateChannelState(CHANNEL_TCBYPASS); + } else if (RotelConnector.MSG_VALUE_OFF.equalsIgnoreCase(value)) { + tcbypass = false; + updateChannelState(CHANNEL_TCBYPASS); + } else { + throw new RotelException("Invalid value"); + } + break; + case RotelConnector.KEY_BALANCE: + if (RotelConnector.MSG_VALUE_MIN.equalsIgnoreCase(value)) { + balance = minBalanceLevel; + } else if (RotelConnector.MSG_VALUE_MAX.equalsIgnoreCase(value)) { + balance = maxBalanceLevel; + } else if (value.toUpperCase().startsWith("L")) { + balance = -Integer.parseInt(value.substring(1)); + } else if (value.toLowerCase().startsWith("R")) { + balance = Integer.parseInt(value.substring(1)); + } else { + balance = Integer.parseInt(value); + } + updateChannelState(CHANNEL_BALANCE); + break; + case RotelConnector.KEY_SPEAKER: + if (RotelConnector.MSG_VALUE_SPEAKER_A.equalsIgnoreCase(value)) { + speakera = true; + speakerb = false; + updateChannelState(CHANNEL_SPEAKER_A); + updateChannelState(CHANNEL_SPEAKER_B); + } else if (RotelConnector.MSG_VALUE_SPEAKER_B.equalsIgnoreCase(value)) { + speakera = false; + speakerb = true; + updateChannelState(CHANNEL_SPEAKER_A); + updateChannelState(CHANNEL_SPEAKER_B); + } else if (RotelConnector.MSG_VALUE_SPEAKER_AB.equalsIgnoreCase(value)) { + speakera = true; + speakerb = true; + updateChannelState(CHANNEL_SPEAKER_A); + updateChannelState(CHANNEL_SPEAKER_B); + } else if (RotelConnector.MSG_VALUE_OFF.equalsIgnoreCase(value)) { + speakera = false; + speakerb = false; + updateChannelState(CHANNEL_SPEAKER_A); + updateChannelState(CHANNEL_SPEAKER_B); + } else { + throw new RotelException("Invalid value"); + } + break; default: logger.debug("onNewMessageEvent: unhandled key {}", key); break; @@ -1425,6 +1658,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL updateChannelState(CHANNEL_TRACK); updateChannelState(CHANNEL_FREQUENCY); updateChannelState(CHANNEL_BRIGHTNESS); + updateChannelState(CHANNEL_TCBYPASS); + updateChannelState(CHANNEL_BALANCE); + updateChannelState(CHANNEL_SPEAKER_A); + updateChannelState(CHANNEL_SPEAKER_B); } /** @@ -1582,11 +1819,11 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL && connector.getModel() != RotelModel.RSP1576 && connector.getModel() != RotelModel.RSP1582) { connector.sendCommand(RotelCommand.UPDATE_AUTO); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().hasSourceControl()) { connector.sendCommand(RotelCommand.SOURCE); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().hasVolumeControl() || connector.getModel().hasToneControl()) { if (connector.getModel().hasVolumeControl() @@ -1594,96 +1831,116 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL && connector.getModel() != RotelModel.RSP1576 && connector.getModel() != RotelModel.RSP1582) { connector.sendCommand(RotelCommand.VOLUME_GET_MIN); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); connector.sendCommand(RotelCommand.VOLUME_GET_MAX); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().hasToneControl()) { connector.sendCommand(RotelCommand.TONE_MAX); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } // Wait enough to be sure to get the min/max values requested just before Thread.sleep(250); if (connector.getModel().hasVolumeControl()) { connector.sendCommand(RotelCommand.VOLUME_GET); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); if (connector.getModel() != RotelModel.RA11 && connector.getModel() != RotelModel.RA12 && connector.getModel() != RotelModel.RCX1500) { connector.sendCommand(RotelCommand.MUTE); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } } if (connector.getModel().hasToneControl()) { connector.sendCommand(RotelCommand.BASS); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); connector.sendCommand(RotelCommand.TREBLE); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); + connector.sendCommand(RotelCommand.TONE_CONTROLS); + Thread.sleep(SLEEP_INTV); } } + if (connector.getModel().hasBalanceControl()) { + connector.sendCommand(RotelCommand.BALANCE); + Thread.sleep(SLEEP_INTV); + } if (connector.getModel().hasPlayControl()) { if (connector.getModel() != RotelModel.RCD1570 && connector.getModel() != RotelModel.RCD1572 && (connector.getModel() != RotelModel.RCX1500 || !source.getName().equals("CD"))) { connector.sendCommand(RotelCommand.PLAY_STATUS); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } else { connector.sendCommand(RotelCommand.CD_PLAY_STATUS); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } } if (connector.getModel().hasDspControl()) { connector.sendCommand(RotelCommand.DSP_MODE); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().canGetFrequency()) { connector.sendCommand(RotelCommand.FREQUENCY); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().hasDimmerControl() && connector.getModel().canGetDimmerLevel()) { connector.sendCommand(RotelCommand.DIMMER_LEVEL_GET); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); + } + if (connector.getModel().hasSpeakerGroups()) { + connector.sendCommand(RotelCommand.SPEAKER); + Thread.sleep(SLEEP_INTV); } break; case ASCII_V2: connector.sendCommand(RotelCommand.UPDATE_AUTO); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); if (connector.getModel().hasSourceControl()) { connector.sendCommand(RotelCommand.SOURCE); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().hasVolumeControl()) { connector.sendCommand(RotelCommand.VOLUME_GET); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); connector.sendCommand(RotelCommand.MUTE); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().hasToneControl()) { connector.sendCommand(RotelCommand.BASS); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); connector.sendCommand(RotelCommand.TREBLE); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); + connector.sendCommand(RotelCommand.TCBYPASS); + Thread.sleep(SLEEP_INTV); + } + if (connector.getModel().hasBalanceControl()) { + connector.sendCommand(RotelCommand.BALANCE); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().hasPlayControl()) { connector.sendCommand(RotelCommand.PLAY_STATUS); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); if (source.getName().equals("CD") && !connector.getModel().hasSourceControl()) { connector.sendCommand(RotelCommand.TRACK); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } } if (connector.getModel().hasDspControl()) { connector.sendCommand(RotelCommand.DSP_MODE); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().canGetFrequency()) { connector.sendCommand(RotelCommand.FREQUENCY); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); } if (connector.getModel().hasDimmerControl() && connector.getModel().canGetDimmerLevel()) { connector.sendCommand(RotelCommand.DIMMER_LEVEL_GET); - Thread.sleep(50); + Thread.sleep(SLEEP_INTV); + } + if (connector.getModel().hasSpeakerGroups()) { + connector.sendCommand(RotelCommand.SPEAKER); + Thread.sleep(SLEEP_INTV); } break; } @@ -1907,18 +2164,19 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL switch (channel) { case CHANNEL_POWER: case CHANNEL_MAIN_POWER: - if (power != null) { - state = power ? OnOffType.ON : OnOffType.OFF; + Boolean po = power; + if (po != null) { + state = OnOffType.from(po.booleanValue()); } break; case CHANNEL_ZONE2_POWER: - state = powerZone2 ? OnOffType.ON : OnOffType.OFF; + state = OnOffType.from(powerZone2); break; case CHANNEL_ZONE3_POWER: - state = powerZone3 ? OnOffType.ON : OnOffType.OFF; + state = OnOffType.from(powerZone3); break; case CHANNEL_ZONE4_POWER: - state = powerZone4 ? OnOffType.ON : OnOffType.OFF; + state = OnOffType.from(powerZone4); break; case CHANNEL_SOURCE: case CHANNEL_MAIN_SOURCE: @@ -1998,22 +2256,22 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL case CHANNEL_MUTE: case CHANNEL_MAIN_MUTE: if (isPowerOn()) { - state = mute ? OnOffType.ON : OnOffType.OFF; + state = OnOffType.from(mute); } break; case CHANNEL_ZONE2_MUTE: if (powerZone2) { - state = muteZone2 ? OnOffType.ON : OnOffType.OFF; + state = OnOffType.from(muteZone2); } break; case CHANNEL_ZONE3_MUTE: if (powerZone3) { - state = muteZone3 ? OnOffType.ON : OnOffType.OFF; + state = OnOffType.from(muteZone3); } break; case CHANNEL_ZONE4_MUTE: if (powerZone4) { - state = muteZone4 ? OnOffType.ON : OnOffType.OFF; + state = OnOffType.from(muteZone4); } break; case CHANNEL_BASS: @@ -2066,6 +2324,26 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL state = new PercentType(BigDecimal.valueOf(dimmerPct)); } break; + case CHANNEL_TCBYPASS: + if (isPowerOn()) { + state = OnOffType.from(tcbypass); + } + break; + case CHANNEL_BALANCE: + if (isPowerOn()) { + state = new DecimalType(balance); + } + break; + case CHANNEL_SPEAKER_A: + if (isPowerOn()) { + state = OnOffType.from(speakera); + } + break; + case CHANNEL_SPEAKER_B: + if (isPowerOn()) { + state = OnOffType.from(speakerb); + } + break; default: break; } diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/config/config.xml index 382320b39..197817913 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/config/config.xml @@ -319,4 +319,5 @@ @text/config.inputLabelMulti.description + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/i18n/rotel.properties b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/i18n/rotel.properties index 5c453bb2f..ae086f428 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/i18n/rotel.properties +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/i18n/rotel.properties @@ -110,6 +110,14 @@ channel-type.rotel.treble.label = Treble Adjustment channel-type.rotel.treble.description = Adjust the treble channel-type.rotel.volumeUpDown.label = Volume channel-type.rotel.volumeUpDown.description = Increase or decrease the volume +channel-type.rotel.tcbypass.label = Tone Control Bypass +channel-type.rotel.tcbypass.description = The user's bass-/treble-settings are bypassed +channel-type.rotel.balance.label = Balance Adjustment +channel-type.rotel.balance.description = Adjust the speakers left-right balance +channel-type.rotel.speakera.label = Speaker-A Adjustment +channel-type.rotel.speakera.description = Turn on/off the speaker group A +channel-type.rotel.speakerb.label = Speaker-B Adjustment +channel-type.rotel.speakerb.description = Turn on/off the speaker group B # thing type configuration diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a11.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a11.xml index 824261a7c..7a8a74216 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a11.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a11.xml @@ -17,6 +17,10 @@ + + + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a12.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a12.xml index a8aec80d6..ba667de64 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a12.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a12.xml @@ -18,6 +18,10 @@ + + + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a14.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a14.xml index e69b81110..23a41ad39 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a14.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a14.xml @@ -18,6 +18,10 @@ + + + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/channels.xml index 79c714446..261e3d9f6 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/channels.xml @@ -201,4 +201,27 @@ The backlight brightness level (in %) of the device front panel + + Switch + + The user's bass-/treble-settings are bypassed + + + + Number + + Adjust the speakers left-right balance + + + + Switch + + Turn on/off the speaker group A + + + + Switch + + Turn on/off the speaker group B + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra11.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra11.xml index b2480d37d..0ff59b1e9 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra11.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra11.xml @@ -19,6 +19,8 @@ + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra12.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra12.xml index 8435e3fe5..0330c19d2 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra12.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra12.xml @@ -19,6 +19,8 @@ + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1570.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1570.xml index 636b985fa..dd38072af 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1570.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1570.xml @@ -19,6 +19,10 @@ + + + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1572.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1572.xml index d3e671a71..8bfbf0730 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1572.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1572.xml @@ -18,6 +18,10 @@ + + + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1592.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1592.xml index 437fd8861..bb431ee2a 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1592.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1592.xml @@ -18,6 +18,10 @@ + + + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1570.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1570.xml index b28f8f33e..449f6d612 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1570.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1570.xml @@ -19,6 +19,8 @@ + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1572.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1572.xml index 0fb3417f3..09e66055a 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1572.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1572.xml @@ -18,6 +18,8 @@ + + diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1590.xml b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1590.xml index 86930aa91..75c24867f 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1590.xml +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1590.xml @@ -18,6 +18,8 @@ + +