[rotel] Support added for model RX-1052 (#16486)

* Two new channels to enable/disable speaker A and speaker B

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2024-03-21 22:14:03 +01:00 committed by GitHub
parent d68adfab21
commit 0d308665c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 661 additions and 390 deletions

View File

@ -22,7 +22,7 @@ You can connect it for example to a Raspberry Pi and use [ser2net Linux tool](ht
Recent devices provide a network interface (RJ45 connector). Recent devices provide a network interface (RJ45 connector).
So you can use the device IP to connect to the device, keeping 9590 as default port. So you can use the device IP to connect to the device, keeping 9590 as default port.
The binding has been tested with a RSP-1066 and a RSP-1570. The binding has been tested with an RSP-1066, an RSP-1570 and an RX-1052.
## Supported Things ## Supported Things
@ -72,6 +72,7 @@ This binding supports the following thing types:
| rt09 | Connection to the Rotel RT-09 tuner | | rt09 | Connection to the Rotel RT-09 tuner |
| rt11 | Connection to the Rotel RT-11 tuner | | rt11 | Connection to the Rotel RT-11 tuner |
| rt1570 | Connection to the Rotel RT-1570 tuner | | rt1570 | Connection to the Rotel RT-1570 tuner |
| rx1052 | Connection to the Rotel RX-1052 stereo receiver |
| s5 | Connection to the Rotel Michi S5 stereo amplifier | | s5 | Connection to the Rotel Michi S5 stereo amplifier |
| t11 | Connection to the Rotel T11 tuner | | t11 | Connection to the Rotel T11 tuner |
| t14 | Connection to the Rotel T14 tuner | | t14 | Connection to the Rotel T14 tuner |
@ -95,6 +96,7 @@ The thing requires the following configuration parameters:
| Parameter Label | Parameter ID | Description | Accepted values | | Parameter Label | Parameter ID | Description | Accepted values |
|-------------------------|------------------|-------------------------------------------------------|-----------------| |-------------------------|------------------|-------------------------------------------------------|-----------------|
| Serial Port | serialPort | Serial port to use for connecting to the Rotel device | | | Serial Port | serialPort | Serial port to use for connecting to the Rotel device | |
| Baud Rate | baudRate | Baud rate to use for connecting to the Rotel device | 19200, 38400 |
| Address | host | Host name or IP address of the Rotel device (IP connection) or the machine connected to the Rotel device (serial over IP) | | | Address | host | Host name or IP address of the Rotel device (IP connection) or the machine connected to the Rotel device (serial over IP) | |
| Port | port | Communication port (IP or serial over IP). For IP connection to the Rotel device, keep the default port (9590) | | | Port | port | Communication port (IP or serial over IP). For IP connection to the Rotel device, keep the default port (9590) | |
| Protocol Version | Protocol | Choose one of the two protocol versions (depends on your device firmware). Default is ASCII_V2 | ASCII_V1 or ASCII_V2 | | Protocol Version | Protocol | Choose one of the two protocol versions (depends on your device firmware). Default is ASCII_V2 | ASCII_V1 or ASCII_V2 |
@ -135,7 +137,7 @@ Some have additional parameters listed in the next table:
| rsx1550 | inputLabelCd, inputLabelTuner, inputLabelTape, inputLabelVideo1, inputLabelVideo2, inputLabelVideo3, inputLabelVideo4, inputLabelVideo5, inputLabelMulti | | rsx1550 | inputLabelCd, inputLabelTuner, inputLabelTape, inputLabelVideo1, inputLabelVideo2, inputLabelVideo3, inputLabelVideo4, inputLabelVideo5, inputLabelMulti |
| rsx1560 | inputLabelCd, inputLabelTuner, inputLabelTape, inputLabelVideo1, inputLabelVideo2, inputLabelVideo3, inputLabelVideo4, inputLabelVideo5, inputLabelMulti | | rsx1560 | inputLabelCd, inputLabelTuner, inputLabelTape, inputLabelVideo1, inputLabelVideo2, inputLabelVideo3, inputLabelVideo4, inputLabelVideo5, inputLabelMulti |
| rsx1562 | inputLabelCd, inputLabelTuner, inputLabelUsb, inputLabelVideo1, inputLabelVideo2, inputLabelVideo3, inputLabelVideo4, inputLabelVideo5, inputLabelVideo6, inputLabelMulti | | rsx1562 | inputLabelCd, inputLabelTuner, inputLabelUsb, inputLabelVideo1, inputLabelVideo2, inputLabelVideo3, inputLabelVideo4, inputLabelVideo5, inputLabelVideo6, inputLabelMulti |
| rx1052 | baudRate, inputLabelVideo1, inputLabelVideo2, inputLabelVideo3, inputLabelVideo4 |
Some notes: Some notes:
- On Linux, you may get an error stating the serial port cannot be opened when the Rotel binding tries to load. You can get around this by adding the `openhab` user to the `dialout` group like this: `usermod -a -G dialout openhab`. - On Linux, you may get an error stating the serial port cannot be opened when the Rotel binding tries to load. You can get around this by adding the `openhab` user to the `dialout` group like this: `usermod -a -G dialout openhab`.
@ -154,7 +156,7 @@ The following channels are available:
|--------------|---------------------|-----------|---------------------------------------|------------------------------------| |--------------|---------------------|-----------|---------------------------------------|------------------------------------|
| power, mainZone#power, allZones#power, zone2#power, zone3#power, zone4#power | Power | Switch | Power ON/OFF the equipment or the zone | ON, OFF | | power, mainZone#power, allZones#power, zone2#power, zone3#power, zone4#power | Power | Switch | Power ON/OFF the equipment or the zone | ON, OFF |
| source, mainZone#source, zone1#source, zone2#source, zone3#source, zone4#source | Source Input | String | Select the source input | CD, TUNER, TAPE, VIDEO1, VIDEO2, VIDEO3, VIDEO4, VIDEO5, VIDEO6, VIDEO7, VIDEO8, USB, PCUSB, MULTI, PHONO, BLUETOOTH, AUX, AUX1, AUX2, AUX1_COAX, AUX1_OPTICAL, COAX1, COAX2, COAX3, OPTICAL1, OPTICAL2, OPTICAL3, XLR, RCD, FM, DAB, PLAYFI, IRADIO, NETWORK, INPUTA, INPUTB, INPUTC, INPUTD | | source, mainZone#source, zone1#source, zone2#source, zone3#source, zone4#source | Source Input | String | Select the source input | CD, TUNER, TAPE, VIDEO1, VIDEO2, VIDEO3, VIDEO4, VIDEO5, VIDEO6, VIDEO7, VIDEO8, USB, PCUSB, MULTI, PHONO, BLUETOOTH, AUX, AUX1, AUX2, AUX1_COAX, AUX1_OPTICAL, COAX1, COAX2, COAX3, OPTICAL1, OPTICAL2, OPTICAL3, XLR, RCD, FM, DAB, PLAYFI, IRADIO, NETWORK, INPUTA, INPUTB, INPUTC, INPUTD |
| mainZone#recordSource | Record Source | String | Select the source to be recorded | CD, TUNER, TAPE, VIDEO1, VIDEO2, VIDEO3, VIDEO4, VIDEO5, VIDEO6, USB, MAIN | | mainZone#recordSource | Record Source | String | Select the source to be recorded | CD, TUNER, TAPE, VIDEO1, VIDEO2, VIDEO3, VIDEO4, VIDEO5, VIDEO6, USB, PHONO, MAIN |
| dsp, mainZone#dsp | DSP Mode | String | Select the DSP mode | NONE, STEREO3, STEREO5, STEREO7, STEREO9, STEREO11, MUSIC1, MUSIC2, MUSIC3, MUSIC4, PROLOGIC, PLIICINEMA, PLIIMUSIC, PLIIGAME, PLIIXCINEMA, PLIIXMUSIC, PLIIXGAME, PLIIZ, NEO6MUSIC, NEO6CINEMA, ATMOS, NEURALX, BYPASS | | dsp, mainZone#dsp | DSP Mode | String | Select the DSP mode | NONE, STEREO3, STEREO5, STEREO7, STEREO9, STEREO11, MUSIC1, MUSIC2, MUSIC3, MUSIC4, PROLOGIC, PLIICINEMA, PLIIMUSIC, PLIIGAME, PLIIXCINEMA, PLIIXMUSIC, PLIIXGAME, PLIIZ, NEO6MUSIC, NEO6CINEMA, ATMOS, NEURALX, BYPASS |
| mainZone#volumeUpDown, zone2#volumeUpDown | Volume | Number | Increase or decrease the volume | INCREASE, DECREASE, value | | mainZone#volumeUpDown, zone2#volumeUpDown | Volume | Number | Increase or decrease the volume | INCREASE, DECREASE, value |
| volume, mainZone#volume, zone1#volume, zone2#volume, zone3#volume, zone4#volume | Volume | Dimmer | Adjust the volume | value between 0 and 100 | | volume, mainZone#volume, zone1#volume, zone2#volume, zone3#volume, zone4#volume | Volume | Dimmer | Adjust the volume | value between 0 and 100 |
@ -221,6 +223,7 @@ Here are the list of channels available for each thing type:
| rt09 | power, source, playControl, brightness | | rt09 | power, source, playControl, brightness |
| rt11 | power, source, radioPreset, brightness | | rt11 | power, source, radioPreset, brightness |
| rt1570 | power, source, radioPreset, brightness | | rt1570 | power, source, radioPreset, brightness |
| rx1052 | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#speakera, mainZone#speakerb, mainZone#line1, mainZone#otherCommand, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute |
| s5 | power, brightness | | s5 | power, brightness |
| t11 | power, source, radioPreset, brightness | | t11 | power, source, radioPreset, brightness |
| t14 | power, source, radioPreset, brightness | | t14 | power, source, radioPreset, brightness |
@ -270,6 +273,7 @@ Here are the available commands for the otherCommand channel depending on the th
| rsx1550 | DSP_TOGGLE, PROLOGIC_TOGGLE, DOLBY_TOGGLE, PLII_PANORAMA_TOGGLE, PLII_DIMENSION_UP, PLII_DIMENSION_DOWN, PLII_CENTER_WIDTH_UP, PLII_CENTER_WIDTH_DOWN, DDEX_TOGGLE, NEO6_TOGGLE, NEXT_MODE, TUNE_UP, TUNE_DOWN, PRESET_UP, PRESET_DOWN, FREQUENCY_UP, FREQUENCY_DOWN, MEMORY, BAND_TOGGLE, AM, FM, TUNE_PRESET_TOGGLE, TUNING_MODE_SELECT, PRESET_MODE_SELECT, FREQUENCY_DIRECT, PRESET_SCAN, TUNER_DISPLAY, RDS_PTY, RDS_TP, RDS_TA, FM_MONO_TOGGLE, ZONE2_TUNE_UP, ZONE2_TUNE_DOWN, ZONE2_PRESET_UP, ZONE2_PRESET_DOWN, ZONE2_FREQUENCY_UP, ZONE2_FREQUENCY_DOWN, ZONE2_BAND_TOGGLE, ZONE2_AM, ZONE2_FM, ZONE2_TUNE_PRESET_TOGGLE, ZONE2_TUNING_MODE_SELECT, ZONE2_PRESET_MODE_SELECT, ZONE2_PRESET_SCAN, ZONE2_FM_MONO_TOGGLE, ZONE3_TUNE_UP, ZONE3_TUNE_DOWN, ZONE3_PRESET_UP, ZONE3_PRESET_DOWN, ZONE3_FREQUENCY_UP, ZONE3_FREQUENCY_DOWN, ZONE3_BAND_TOGGLE, ZONE3_AM, ZONE3_FM, ZONE3_TUNE_PRESET_TOGGLE, ZONE3_TUNING_MODE_SELECT, ZONE3_PRESET_MODE_SELECT, ZONE3_PRESET_SCAN, ZONE3_FM_MONO_TOGGLE, ZONE4_TUNE_UP, ZONE4_TUNE_DOWN, ZONE4_PRESET_UP, ZONE4_PRESET_DOWN, ZONE4_FREQUENCY_UP, ZONE4_FREQUENCY_DOWN, ZONE4_BAND_TOGGLE, ZONE4_AM, ZONE4_FM, ZONE4_TUNE_PRESET_TOGGLE, ZONE4_TUNING_MODE_SELECT, ZONE4_PRESET_MODE_SELECT, ZONE4_PRESET_SCAN, ZONE4_FM_MONO_TOGGLE, KEY1, KEY2, KEY3, KEY4, KEY5, KEY6, KEY7, KEY8, KEY9, KEY0, ZONE2_KEY1, ZONE2_KEY2, ZONE2_KEY3, ZONE2_KEY4, ZONE2_KEY5, ZONE2_KEY6, ZONE2_KEY7, ZONE2_KEY8, ZONE2_KEY9, ZONE2_KEY0, ZONE3_KEY1, ZONE3_KEY2, ZONE3_KEY3, ZONE3_KEY4, ZONE3_KEY5, ZONE3_KEY6, ZONE3_KEY7, ZONE3_KEY8, ZONE3_KEY9, ZONE3_KEY0, ZONE4_KEY1, ZONE4_KEY2, ZONE4_KEY3, ZONE4_KEY4, ZONE4_KEY5, ZONE4_KEY6, ZONE4_KEY7, ZONE4_KEY8, ZONE4_KEY9, ZONE4_KEY0, MENU, UP, DOWN, LEFT, RIGHT, ENTER, RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT, DYNAMIC_RANGE, DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE, POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE, ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE, OUTPUT_RESOLUTION, HDMI_AMP_MODE, HDMI_TV_MODE, RESET_FACTORY | | rsx1550 | DSP_TOGGLE, PROLOGIC_TOGGLE, DOLBY_TOGGLE, PLII_PANORAMA_TOGGLE, PLII_DIMENSION_UP, PLII_DIMENSION_DOWN, PLII_CENTER_WIDTH_UP, PLII_CENTER_WIDTH_DOWN, DDEX_TOGGLE, NEO6_TOGGLE, NEXT_MODE, TUNE_UP, TUNE_DOWN, PRESET_UP, PRESET_DOWN, FREQUENCY_UP, FREQUENCY_DOWN, MEMORY, BAND_TOGGLE, AM, FM, TUNE_PRESET_TOGGLE, TUNING_MODE_SELECT, PRESET_MODE_SELECT, FREQUENCY_DIRECT, PRESET_SCAN, TUNER_DISPLAY, RDS_PTY, RDS_TP, RDS_TA, FM_MONO_TOGGLE, ZONE2_TUNE_UP, ZONE2_TUNE_DOWN, ZONE2_PRESET_UP, ZONE2_PRESET_DOWN, ZONE2_FREQUENCY_UP, ZONE2_FREQUENCY_DOWN, ZONE2_BAND_TOGGLE, ZONE2_AM, ZONE2_FM, ZONE2_TUNE_PRESET_TOGGLE, ZONE2_TUNING_MODE_SELECT, ZONE2_PRESET_MODE_SELECT, ZONE2_PRESET_SCAN, ZONE2_FM_MONO_TOGGLE, ZONE3_TUNE_UP, ZONE3_TUNE_DOWN, ZONE3_PRESET_UP, ZONE3_PRESET_DOWN, ZONE3_FREQUENCY_UP, ZONE3_FREQUENCY_DOWN, ZONE3_BAND_TOGGLE, ZONE3_AM, ZONE3_FM, ZONE3_TUNE_PRESET_TOGGLE, ZONE3_TUNING_MODE_SELECT, ZONE3_PRESET_MODE_SELECT, ZONE3_PRESET_SCAN, ZONE3_FM_MONO_TOGGLE, ZONE4_TUNE_UP, ZONE4_TUNE_DOWN, ZONE4_PRESET_UP, ZONE4_PRESET_DOWN, ZONE4_FREQUENCY_UP, ZONE4_FREQUENCY_DOWN, ZONE4_BAND_TOGGLE, ZONE4_AM, ZONE4_FM, ZONE4_TUNE_PRESET_TOGGLE, ZONE4_TUNING_MODE_SELECT, ZONE4_PRESET_MODE_SELECT, ZONE4_PRESET_SCAN, ZONE4_FM_MONO_TOGGLE, KEY1, KEY2, KEY3, KEY4, KEY5, KEY6, KEY7, KEY8, KEY9, KEY0, ZONE2_KEY1, ZONE2_KEY2, ZONE2_KEY3, ZONE2_KEY4, ZONE2_KEY5, ZONE2_KEY6, ZONE2_KEY7, ZONE2_KEY8, ZONE2_KEY9, ZONE2_KEY0, ZONE3_KEY1, ZONE3_KEY2, ZONE3_KEY3, ZONE3_KEY4, ZONE3_KEY5, ZONE3_KEY6, ZONE3_KEY7, ZONE3_KEY8, ZONE3_KEY9, ZONE3_KEY0, ZONE4_KEY1, ZONE4_KEY2, ZONE4_KEY3, ZONE4_KEY4, ZONE4_KEY5, ZONE4_KEY6, ZONE4_KEY7, ZONE4_KEY8, ZONE4_KEY9, ZONE4_KEY0, MENU, UP, DOWN, LEFT, RIGHT, ENTER, RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT, DYNAMIC_RANGE, DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE, POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE, ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE, OUTPUT_RESOLUTION, HDMI_AMP_MODE, HDMI_TV_MODE, RESET_FACTORY |
| rsx1560 | DSP_TOGGLE, PROLOGIC_TOGGLE, DOLBY_TOGGLE, PLII_PANORAMA_TOGGLE, PLII_DIMENSION_UP, PLII_DIMENSION_DOWN, PLII_CENTER_WIDTH_UP, PLII_CENTER_WIDTH_DOWN, DDEX_TOGGLE, NEO6_TOGGLE, NEXT_MODE, TUNE_UP, TUNE_DOWN, PRESET_UP, PRESET_DOWN, FREQUENCY_UP, FREQUENCY_DOWN, MEMORY, BAND_TOGGLE, AM, FM, TUNE_PRESET_TOGGLE, TUNING_MODE_SELECT, PRESET_MODE_SELECT, FREQUENCY_DIRECT, PRESET_SCAN, TUNER_DISPLAY, RDS_PTY, RDS_TP, RDS_TA, FM_MONO_TOGGLE, ZONE2_TUNE_UP, ZONE2_TUNE_DOWN, ZONE2_PRESET_UP, ZONE2_PRESET_DOWN, ZONE2_FREQUENCY_UP, ZONE2_FREQUENCY_DOWN, ZONE2_BAND_TOGGLE, ZONE2_AM, ZONE2_FM, ZONE2_TUNE_PRESET_TOGGLE, ZONE2_TUNING_MODE_SELECT, ZONE2_PRESET_MODE_SELECT, ZONE2_PRESET_SCAN, ZONE2_FM_MONO_TOGGLE, ZONE3_TUNE_UP, ZONE3_TUNE_DOWN, ZONE3_PRESET_UP, ZONE3_PRESET_DOWN, ZONE3_FREQUENCY_UP, ZONE3_FREQUENCY_DOWN, ZONE3_BAND_TOGGLE, ZONE3_AM, ZONE3_FM, ZONE3_TUNE_PRESET_TOGGLE, ZONE3_TUNING_MODE_SELECT, ZONE3_PRESET_MODE_SELECT, ZONE3_PRESET_SCAN, ZONE3_FM_MONO_TOGGLE, ZONE4_TUNE_UP, ZONE4_TUNE_DOWN, ZONE4_PRESET_UP, ZONE4_PRESET_DOWN, ZONE4_FREQUENCY_UP, ZONE4_FREQUENCY_DOWN, ZONE4_BAND_TOGGLE, ZONE4_AM, ZONE4_FM, ZONE4_TUNE_PRESET_TOGGLE, ZONE4_TUNING_MODE_SELECT, ZONE4_PRESET_MODE_SELECT, ZONE4_PRESET_SCAN, ZONE4_FM_MONO_TOGGLE, KEY1, KEY2, KEY3, KEY4, KEY5, KEY6, KEY7, KEY8, KEY9, KEY0, ZONE2_KEY1, ZONE2_KEY2, ZONE2_KEY3, ZONE2_KEY4, ZONE2_KEY5, ZONE2_KEY6, ZONE2_KEY7, ZONE2_KEY8, ZONE2_KEY9, ZONE2_KEY0, ZONE3_KEY1, ZONE3_KEY2, ZONE3_KEY3, ZONE3_KEY4, ZONE3_KEY5, ZONE3_KEY6, ZONE3_KEY7, ZONE3_KEY8, ZONE3_KEY9, ZONE3_KEY0, ZONE4_KEY1, ZONE4_KEY2, ZONE4_KEY3, ZONE4_KEY4, ZONE4_KEY5, ZONE4_KEY6, ZONE4_KEY7, ZONE4_KEY8, ZONE4_KEY9, ZONE4_KEY0, MENU, UP, DOWN, LEFT, RIGHT, ENTER, RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT, DYNAMIC_RANGE, DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE, POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE, ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE, OUTPUT_RESOLUTION, HDMI_AMP_MODE, HDMI_TV_MODE, RESET_FACTORY | | rsx1560 | DSP_TOGGLE, PROLOGIC_TOGGLE, DOLBY_TOGGLE, PLII_PANORAMA_TOGGLE, PLII_DIMENSION_UP, PLII_DIMENSION_DOWN, PLII_CENTER_WIDTH_UP, PLII_CENTER_WIDTH_DOWN, DDEX_TOGGLE, NEO6_TOGGLE, NEXT_MODE, TUNE_UP, TUNE_DOWN, PRESET_UP, PRESET_DOWN, FREQUENCY_UP, FREQUENCY_DOWN, MEMORY, BAND_TOGGLE, AM, FM, TUNE_PRESET_TOGGLE, TUNING_MODE_SELECT, PRESET_MODE_SELECT, FREQUENCY_DIRECT, PRESET_SCAN, TUNER_DISPLAY, RDS_PTY, RDS_TP, RDS_TA, FM_MONO_TOGGLE, ZONE2_TUNE_UP, ZONE2_TUNE_DOWN, ZONE2_PRESET_UP, ZONE2_PRESET_DOWN, ZONE2_FREQUENCY_UP, ZONE2_FREQUENCY_DOWN, ZONE2_BAND_TOGGLE, ZONE2_AM, ZONE2_FM, ZONE2_TUNE_PRESET_TOGGLE, ZONE2_TUNING_MODE_SELECT, ZONE2_PRESET_MODE_SELECT, ZONE2_PRESET_SCAN, ZONE2_FM_MONO_TOGGLE, ZONE3_TUNE_UP, ZONE3_TUNE_DOWN, ZONE3_PRESET_UP, ZONE3_PRESET_DOWN, ZONE3_FREQUENCY_UP, ZONE3_FREQUENCY_DOWN, ZONE3_BAND_TOGGLE, ZONE3_AM, ZONE3_FM, ZONE3_TUNE_PRESET_TOGGLE, ZONE3_TUNING_MODE_SELECT, ZONE3_PRESET_MODE_SELECT, ZONE3_PRESET_SCAN, ZONE3_FM_MONO_TOGGLE, ZONE4_TUNE_UP, ZONE4_TUNE_DOWN, ZONE4_PRESET_UP, ZONE4_PRESET_DOWN, ZONE4_FREQUENCY_UP, ZONE4_FREQUENCY_DOWN, ZONE4_BAND_TOGGLE, ZONE4_AM, ZONE4_FM, ZONE4_TUNE_PRESET_TOGGLE, ZONE4_TUNING_MODE_SELECT, ZONE4_PRESET_MODE_SELECT, ZONE4_PRESET_SCAN, ZONE4_FM_MONO_TOGGLE, KEY1, KEY2, KEY3, KEY4, KEY5, KEY6, KEY7, KEY8, KEY9, KEY0, ZONE2_KEY1, ZONE2_KEY2, ZONE2_KEY3, ZONE2_KEY4, ZONE2_KEY5, ZONE2_KEY6, ZONE2_KEY7, ZONE2_KEY8, ZONE2_KEY9, ZONE2_KEY0, ZONE3_KEY1, ZONE3_KEY2, ZONE3_KEY3, ZONE3_KEY4, ZONE3_KEY5, ZONE3_KEY6, ZONE3_KEY7, ZONE3_KEY8, ZONE3_KEY9, ZONE3_KEY0, ZONE4_KEY1, ZONE4_KEY2, ZONE4_KEY3, ZONE4_KEY4, ZONE4_KEY5, ZONE4_KEY6, ZONE4_KEY7, ZONE4_KEY8, ZONE4_KEY9, ZONE4_KEY0, MENU, UP, DOWN, LEFT, RIGHT, ENTER, RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT, DYNAMIC_RANGE, DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE, POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE, ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE, OUTPUT_RESOLUTION, HDMI_AMP_MODE, HDMI_TV_MODE, RESET_FACTORY |
| rsx1562 | STEREO_BYPASS_TOGGLE, DSP_TOGGLE, PROLOGIC_TOGGLE, DOLBY_TOGGLE, PLII_PANORAMA_TOGGLE, PLII_DIMENSION_UP, PLII_DIMENSION_DOWN, PLII_CENTER_WIDTH_UP, PLII_CENTER_WIDTH_DOWN, DDEX_TOGGLE, NEO6_TOGGLE, NEXT_MODE, TUNE_UP, TUNE_DOWN, PRESET_UP, PRESET_DOWN, FREQUENCY_UP, FREQUENCY_DOWN, MEMORY, BAND_TOGGLE, AM, FM, TUNE_PRESET_TOGGLE, TUNING_MODE_SELECT, PRESET_MODE_SELECT, FREQUENCY_DIRECT, PRESET_SCAN, TUNER_DISPLAY, RDS_PTY, RDS_TP, RDS_TA, FM_MONO_TOGGLE, ZONE2_TUNE_UP, ZONE2_TUNE_DOWN, ZONE2_PRESET_UP, ZONE2_PRESET_DOWN, ZONE2_FREQUENCY_UP, ZONE2_FREQUENCY_DOWN, ZONE2_BAND_TOGGLE, ZONE2_AM, ZONE2_FM, ZONE2_TUNE_PRESET_TOGGLE, ZONE2_TUNING_MODE_SELECT, ZONE2_PRESET_MODE_SELECT, ZONE2_PRESET_SCAN, ZONE2_FM_MONO_TOGGLE, ZONE3_TUNE_UP, ZONE3_TUNE_DOWN, ZONE3_PRESET_UP, ZONE3_PRESET_DOWN, ZONE3_FREQUENCY_UP, ZONE3_FREQUENCY_DOWN, ZONE3_BAND_TOGGLE, ZONE3_AM, ZONE3_FM, ZONE3_TUNE_PRESET_TOGGLE, ZONE3_TUNING_MODE_SELECT, ZONE3_PRESET_MODE_SELECT, ZONE3_PRESET_SCAN, ZONE3_FM_MONO_TOGGLE, ZONE4_TUNE_UP, ZONE4_TUNE_DOWN, ZONE4_PRESET_UP, ZONE4_PRESET_DOWN, ZONE4_FREQUENCY_UP, ZONE4_FREQUENCY_DOWN, ZONE4_BAND_TOGGLE, ZONE4_AM, ZONE4_FM, ZONE4_TUNE_PRESET_TOGGLE, ZONE4_TUNING_MODE_SELECT, ZONE4_PRESET_MODE_SELECT, ZONE4_PRESET_SCAN, ZONE4_FM_MONO_TOGGLE, KEY1, KEY2, KEY3, KEY4, KEY5, KEY6, KEY7, KEY8, KEY9, KEY0, ZONE2_KEY1, ZONE2_KEY2, ZONE2_KEY3, ZONE2_KEY4, ZONE2_KEY5, ZONE2_KEY6, ZONE2_KEY7, ZONE2_KEY8, ZONE2_KEY9, ZONE2_KEY0, ZONE3_KEY1, ZONE3_KEY2, ZONE3_KEY3, ZONE3_KEY4, ZONE3_KEY5, ZONE3_KEY6, ZONE3_KEY7, ZONE3_KEY8, ZONE3_KEY9, ZONE3_KEY0, ZONE4_KEY1, ZONE4_KEY2, ZONE4_KEY3, ZONE4_KEY4, ZONE4_KEY5, ZONE4_KEY6, ZONE4_KEY7, ZONE4_KEY8, ZONE4_KEY9, ZONE4_KEY0, MENU, EXIT, UP_PRESSED, UP_RELEASED, DOWN_PRESSED, DOWN_RELEASED, LEFT_PRESSED, LEFT_RELEASED, RIGHT_PRESSED, RIGHT_RELEASED, ENTER, RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT, DYNAMIC_RANGE, DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE, POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE, ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE, OUTPUT_RESOLUTION, HDMI_AMP_MODE, HDMI_TV_MODE, ROOM_EQ_TOGGLE, SPEAKER_SETTING_TOGGLE, RESET_FACTORY | | rsx1562 | STEREO_BYPASS_TOGGLE, DSP_TOGGLE, PROLOGIC_TOGGLE, DOLBY_TOGGLE, PLII_PANORAMA_TOGGLE, PLII_DIMENSION_UP, PLII_DIMENSION_DOWN, PLII_CENTER_WIDTH_UP, PLII_CENTER_WIDTH_DOWN, DDEX_TOGGLE, NEO6_TOGGLE, NEXT_MODE, TUNE_UP, TUNE_DOWN, PRESET_UP, PRESET_DOWN, FREQUENCY_UP, FREQUENCY_DOWN, MEMORY, BAND_TOGGLE, AM, FM, TUNE_PRESET_TOGGLE, TUNING_MODE_SELECT, PRESET_MODE_SELECT, FREQUENCY_DIRECT, PRESET_SCAN, TUNER_DISPLAY, RDS_PTY, RDS_TP, RDS_TA, FM_MONO_TOGGLE, ZONE2_TUNE_UP, ZONE2_TUNE_DOWN, ZONE2_PRESET_UP, ZONE2_PRESET_DOWN, ZONE2_FREQUENCY_UP, ZONE2_FREQUENCY_DOWN, ZONE2_BAND_TOGGLE, ZONE2_AM, ZONE2_FM, ZONE2_TUNE_PRESET_TOGGLE, ZONE2_TUNING_MODE_SELECT, ZONE2_PRESET_MODE_SELECT, ZONE2_PRESET_SCAN, ZONE2_FM_MONO_TOGGLE, ZONE3_TUNE_UP, ZONE3_TUNE_DOWN, ZONE3_PRESET_UP, ZONE3_PRESET_DOWN, ZONE3_FREQUENCY_UP, ZONE3_FREQUENCY_DOWN, ZONE3_BAND_TOGGLE, ZONE3_AM, ZONE3_FM, ZONE3_TUNE_PRESET_TOGGLE, ZONE3_TUNING_MODE_SELECT, ZONE3_PRESET_MODE_SELECT, ZONE3_PRESET_SCAN, ZONE3_FM_MONO_TOGGLE, ZONE4_TUNE_UP, ZONE4_TUNE_DOWN, ZONE4_PRESET_UP, ZONE4_PRESET_DOWN, ZONE4_FREQUENCY_UP, ZONE4_FREQUENCY_DOWN, ZONE4_BAND_TOGGLE, ZONE4_AM, ZONE4_FM, ZONE4_TUNE_PRESET_TOGGLE, ZONE4_TUNING_MODE_SELECT, ZONE4_PRESET_MODE_SELECT, ZONE4_PRESET_SCAN, ZONE4_FM_MONO_TOGGLE, KEY1, KEY2, KEY3, KEY4, KEY5, KEY6, KEY7, KEY8, KEY9, KEY0, ZONE2_KEY1, ZONE2_KEY2, ZONE2_KEY3, ZONE2_KEY4, ZONE2_KEY5, ZONE2_KEY6, ZONE2_KEY7, ZONE2_KEY8, ZONE2_KEY9, ZONE2_KEY0, ZONE3_KEY1, ZONE3_KEY2, ZONE3_KEY3, ZONE3_KEY4, ZONE3_KEY5, ZONE3_KEY6, ZONE3_KEY7, ZONE3_KEY8, ZONE3_KEY9, ZONE3_KEY0, ZONE4_KEY1, ZONE4_KEY2, ZONE4_KEY3, ZONE4_KEY4, ZONE4_KEY5, ZONE4_KEY6, ZONE4_KEY7, ZONE4_KEY8, ZONE4_KEY9, ZONE4_KEY0, MENU, EXIT, UP_PRESSED, UP_RELEASED, DOWN_PRESSED, DOWN_RELEASED, LEFT_PRESSED, LEFT_RELEASED, RIGHT_PRESSED, RIGHT_RELEASED, ENTER, RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT, DYNAMIC_RANGE, DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE, POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE, ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE, OUTPUT_RESOLUTION, HDMI_AMP_MODE, HDMI_TV_MODE, ROOM_EQ_TOGGLE, SPEAKER_SETTING_TOGGLE, RESET_FACTORY |
| rx1052 | TUNE_UP, TUNE_DOWN, PRESET_UP, PRESET_DOWN, FREQUENCY_UP, FREQUENCY_DOWN, MEMORY, BAND_TOGGLE, AM, FM, TUNE_PRESET_TOGGLE, TUNING_MODE_SELECT, PRESET_MODE_SELECT, FREQUENCY_DIRECT, PRESET_SCAN, FM_MONO_TOGGLE, ZONE2_TUNE_UP, ZONE2_TUNE_DOWN, ZONE2_PRESET_UP, ZONE2_PRESET_DOWN, ZONE2_FREQUENCY_UP, ZONE2_FREQUENCY_DOWN, ZONE2_BAND_TOGGLE, ZONE2_AM, ZONE2_FM, ZONE2_TUNE_PRESET_TOGGLE, ZONE2_TUNING_MODE_SELECT, ZONE2_PRESET_MODE_SELECT, ZONE2_PRESET_SCAN, ZONE2_FM_MONO_TOGGLE, ZONE3_TUNE_UP, ZONE3_TUNE_DOWN, ZONE3_PRESET_UP, ZONE3_PRESET_DOWN, ZONE3_FREQUENCY_UP, ZONE3_FREQUENCY_DOWN, ZONE3_BAND_TOGGLE, ZONE3_AM, ZONE3_FM, ZONE3_TUNE_PRESET_TOGGLE, ZONE3_TUNING_MODE_SELECT, ZONE3_PRESET_MODE_SELECT, ZONE3_PRESET_SCAN, ZONE3_FM_MONO_TOGGLE, ZONE4_TUNE_UP, ZONE4_TUNE_DOWN, ZONE4_PRESET_UP, ZONE4_PRESET_DOWN, ZONE4_FREQUENCY_UP, ZONE4_FREQUENCY_DOWN, ZONE4_BAND_TOGGLE, ZONE4_AM, ZONE4_FM, ZONE4_TUNE_PRESET_TOGGLE, ZONE4_TUNING_MODE_SELECT, ZONE4_PRESET_MODE_SELECT, ZONE4_PRESET_SCAN, ZONE4_FM_MONO_TOGGLE, KEY1, KEY2, KEY3, KEY4, KEY5, KEY6, KEY7, KEY8, KEY9, KEY0, ZONE2_KEY1, ZONE2_KEY2, ZONE2_KEY3, ZONE2_KEY4, ZONE2_KEY5, ZONE2_KEY6, ZONE2_KEY7, ZONE2_KEY8, ZONE2_KEY9, ZONE2_KEY0, ZONE3_KEY1, ZONE3_KEY2, ZONE3_KEY3, ZONE3_KEY4, ZONE3_KEY5, ZONE3_KEY6, ZONE3_KEY7, ZONE3_KEY8, ZONE3_KEY9, ZONE3_KEY0, ZONE4_KEY1, ZONE4_KEY2, ZONE4_KEY3, ZONE4_KEY4, ZONE4_KEY5, ZONE4_KEY6, ZONE4_KEY7, ZONE4_KEY8, ZONE4_KEY9, ZONE4_KEY0, POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE, ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE, RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT, ZONE_TOGGLE |
| x3 | PLAY, PAUSE, STOP, TRACK_FWD, TRACK_BACK | | x3 | PLAY, PAUSE, STOP, TRACK_FWD, TRACK_BACK |
| x5 | PLAY, PAUSE, STOP, TRACK_FWD, TRACK_BACK | | x5 | PLAY, PAUSE, STOP, TRACK_FWD, TRACK_BACK |

View File

@ -42,6 +42,7 @@ public class RotelBindingConstants {
public static final String THING_TYPE_ID_RSX1550 = "rsx1550"; public static final String THING_TYPE_ID_RSX1550 = "rsx1550";
public static final String THING_TYPE_ID_RSX1560 = "rsx1560"; public static final String THING_TYPE_ID_RSX1560 = "rsx1560";
public static final String THING_TYPE_ID_RSX1562 = "rsx1562"; public static final String THING_TYPE_ID_RSX1562 = "rsx1562";
public static final String THING_TYPE_ID_RX1052 = "rx1052";
public static final String THING_TYPE_ID_A11 = "a11"; public static final String THING_TYPE_ID_A11 = "a11";
public static final String THING_TYPE_ID_A12 = "a12"; public static final String THING_TYPE_ID_A12 = "a12";
public static final String THING_TYPE_ID_A14 = "a14"; public static final String THING_TYPE_ID_A14 = "a14";
@ -91,6 +92,7 @@ public class RotelBindingConstants {
public static final ThingTypeUID THING_TYPE_RSX1550 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_RSX1550); public static final ThingTypeUID THING_TYPE_RSX1550 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_RSX1550);
public static final ThingTypeUID THING_TYPE_RSX1560 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_RSX1560); public static final ThingTypeUID THING_TYPE_RSX1560 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_RSX1560);
public static final ThingTypeUID THING_TYPE_RSX1562 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_RSX1562); public static final ThingTypeUID THING_TYPE_RSX1562 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_RSX1562);
public static final ThingTypeUID THING_TYPE_RX1052 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_RX1052);
public static final ThingTypeUID THING_TYPE_A11 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_A11); public static final ThingTypeUID THING_TYPE_A11 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_A11);
public static final ThingTypeUID THING_TYPE_A12 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_A12); public static final ThingTypeUID THING_TYPE_A12 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_A12);
public static final ThingTypeUID THING_TYPE_A14 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_A14); public static final ThingTypeUID THING_TYPE_A14 = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_A14);
@ -163,6 +165,8 @@ public class RotelBindingConstants {
public static final String CHANNEL_MAIN_MUTE = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_MUTE; 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_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_MAIN_TREBLE = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_TREBLE;
public static final String CHANNEL_MAIN_SPEAKER_A = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_SPEAKER_A;
public static final String CHANNEL_MAIN_SPEAKER_B = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_SPEAKER_B;
public static final String CHANNEL_MAIN_OTHER_COMMAND = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_OTHER_COMMAND; public static final String CHANNEL_MAIN_OTHER_COMMAND = CHANNEL_GROUP_MAIN_ZONE + "#" + CHANNEL_OTHER_COMMAND;
public static final String CHANNEL_GROUP_ZONE1 = "zone1"; public static final String CHANNEL_GROUP_ZONE1 = "zone1";
@ -332,6 +336,7 @@ public class RotelBindingConstants {
public static final String KEY_POWER_ZONE2 = "power_zone2"; public static final String KEY_POWER_ZONE2 = "power_zone2";
public static final String KEY_POWER_ZONE3 = "power_zone3"; public static final String KEY_POWER_ZONE3 = "power_zone3";
public static final String KEY_POWER_ZONE4 = "power_zone4"; public static final String KEY_POWER_ZONE4 = "power_zone4";
public static final String KEY_POWER_ZONES = "power_zones";
public static final String KEY_SOURCE_ZONE2 = "source_zone2"; public static final String KEY_SOURCE_ZONE2 = "source_zone2";
public static final String KEY_SOURCE_ZONE3 = "source_zone3"; public static final String KEY_SOURCE_ZONE3 = "source_zone3";
public static final String KEY_SOURCE_ZONE4 = "source_zone4"; public static final String KEY_SOURCE_ZONE4 = "source_zone4";

View File

@ -14,10 +14,7 @@ package org.openhab.binding.rotel.internal;
import static org.openhab.binding.rotel.internal.RotelBindingConstants.*; import static org.openhab.binding.rotel.internal.RotelBindingConstants.*;
import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
@ -42,17 +39,16 @@ import org.osgi.service.component.annotations.Reference;
@Component(configurationPid = "binding.rotel", service = ThingHandlerFactory.class) @Component(configurationPid = "binding.rotel", service = ThingHandlerFactory.class)
public class RotelHandlerFactory extends BaseThingHandlerFactory { public class RotelHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(Stream private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_RSP1066, THING_TYPE_RSP1068,
.of(THING_TYPE_RSP1066, THING_TYPE_RSP1068, THING_TYPE_RSP1069, THING_TYPE_RSP1098, THING_TYPE_RSP1570, THING_TYPE_RSP1069, THING_TYPE_RSP1098, THING_TYPE_RSP1570, THING_TYPE_RSP1572, THING_TYPE_RSX1055,
THING_TYPE_RSP1572, THING_TYPE_RSX1055, THING_TYPE_RSX1056, THING_TYPE_RSX1057, THING_TYPE_RSX1058, THING_TYPE_RSX1056, THING_TYPE_RSX1057, THING_TYPE_RSX1058, THING_TYPE_RSX1065, THING_TYPE_RSX1067,
THING_TYPE_RSX1065, THING_TYPE_RSX1067, THING_TYPE_RSX1550, THING_TYPE_RSX1560, THING_TYPE_RSX1562, THING_TYPE_RSX1550, THING_TYPE_RSX1560, THING_TYPE_RSX1562, THING_TYPE_RX1052, THING_TYPE_A11,
THING_TYPE_A11, THING_TYPE_A12, THING_TYPE_A14, THING_TYPE_CD11, THING_TYPE_CD14, THING_TYPE_RA11, THING_TYPE_A12, THING_TYPE_A14, THING_TYPE_CD11, THING_TYPE_CD14, THING_TYPE_RA11, THING_TYPE_RA12,
THING_TYPE_RA12, THING_TYPE_RA1570, THING_TYPE_RA1572, THING_TYPE_RA1592, THING_TYPE_RAP1580, THING_TYPE_RA1570, THING_TYPE_RA1572, THING_TYPE_RA1592, THING_TYPE_RAP1580, THING_TYPE_RC1570,
THING_TYPE_RC1570, THING_TYPE_RC1572, THING_TYPE_RC1590, THING_TYPE_RCD1570, THING_TYPE_RCD1572, THING_TYPE_RC1572, THING_TYPE_RC1590, THING_TYPE_RCD1570, THING_TYPE_RCD1572, THING_TYPE_RCX1500,
THING_TYPE_RCX1500, THING_TYPE_RDD1580, THING_TYPE_RDG1520, THING_TYPE_RSP1576, THING_TYPE_RSP1582, THING_TYPE_RDD1580, THING_TYPE_RDG1520, THING_TYPE_RSP1576, THING_TYPE_RSP1582, THING_TYPE_RT09,
THING_TYPE_RT09, THING_TYPE_RT11, THING_TYPE_RT1570, THING_TYPE_T11, THING_TYPE_T14, THING_TYPE_C8, THING_TYPE_RT11, THING_TYPE_RT1570, THING_TYPE_T11, THING_TYPE_T14, THING_TYPE_C8, THING_TYPE_M8,
THING_TYPE_M8, THING_TYPE_P5, THING_TYPE_S5, THING_TYPE_X3, THING_TYPE_X5) THING_TYPE_P5, THING_TYPE_S5, THING_TYPE_X3, THING_TYPE_X5);
.collect(Collectors.toSet()));
private final SerialPortManager serialPortManager; private final SerialPortManager serialPortManager;
private final RotelStateDescriptionOptionProvider stateDescriptionProvider; private final RotelStateDescriptionOptionProvider stateDescriptionProvider;

View File

@ -23,6 +23,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.rotel.internal.communication.RotelCommand; import org.openhab.binding.rotel.internal.communication.RotelCommand;
import org.openhab.binding.rotel.internal.communication.RotelDsp; import org.openhab.binding.rotel.internal.communication.RotelDsp;
import org.openhab.binding.rotel.internal.communication.RotelFlagInfo;
import org.openhab.binding.rotel.internal.communication.RotelFlagInfoType;
import org.openhab.binding.rotel.internal.communication.RotelFlagsMapping; import org.openhab.binding.rotel.internal.communication.RotelFlagsMapping;
import org.openhab.binding.rotel.internal.communication.RotelSource; import org.openhab.binding.rotel.internal.communication.RotelSource;
import org.openhab.binding.rotel.internal.protocol.RotelProtocol; import org.openhab.binding.rotel.internal.protocol.RotelProtocol;
@ -44,19 +46,19 @@ public enum RotelModel {
concatenate(DSP_CMDS_SET1, MENU2_CTRL_CMDS, OTHER_CMDS_SET1), (byte) 0xA1, 42, 5, true, concatenate(DSP_CMDS_SET1, MENU2_CTRL_CMDS, OTHER_CMDS_SET1), (byte) 0xA1, 42, 5, true,
RotelFlagsMapping.MAPPING2), RotelFlagsMapping.MAPPING2),
RSP1069("RSP-1069", 38400, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2, RSP1069("RSP-1069", 38400, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2,
concatenate(DSP_CMDS_SET1, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2), (byte) 0xA2, 42, 5, true, concatenate(DSP_CMDS_SET1, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2, OTHER_CMDS_SET4), (byte) 0xA2,
RotelFlagsMapping.MAPPING5), 42, 5, true, RotelFlagsMapping.MAPPING3),
RSP1098("RSP-1098", 19200, 1, 1, true, 96, true, 6, false, ZONE_SELECT, 2, RSP1098("RSP-1098", 19200, 1, 1, true, 96, true, 6, false, ZONE_SELECT, 2,
concatenate(DSP_CMDS_SET1, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, List.of(REMOTE_VOLUME_UP, REMOTE_VOLUME_DOWN)), concatenate(DSP_CMDS_SET1, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, List.of(REMOTE_VOLUME_UP, REMOTE_VOLUME_DOWN)),
(byte) 0xA0, 13, 8, true, RotelFlagsMapping.MAPPING1), (byte) 0xA0, 13, 8, true, RotelFlagsMapping.MAPPING1),
RSP1570("RSP-1570", 115200, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 3, RSP1570("RSP-1570", 115200, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 3,
concatenate(DSP_CMDS_SET2, DSP_CMDS_SET1, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2, concatenate(DSP_CMDS_SET2, DSP_CMDS_SET1, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2,
List.of(RESET_FACTORY)), OTHER_CMDS_SET4, List.of(RESET_FACTORY)),
(byte) 0xA3, 42, 5, true, RotelFlagsMapping.MAPPING5), (byte) 0xA3, 42, 5, true, RotelFlagsMapping.MAPPING3),
RSP1572("RSP-1572", 115200, 2, 3, true, 96, true, null, false, RECORD_FONCTION_SELECT, 4, RSP1572("RSP-1572", 115200, 2, 3, true, 96, true, null, false, RECORD_FONCTION_SELECT, 4,
concatenate(DSP_CMDS_SET2, DSP_CMDS_SET1, NUMERIC_KEY_CMDS, MENU3_CTRL_CMDS, OTHER_CMDS_SET1, concatenate(DSP_CMDS_SET2, DSP_CMDS_SET1, NUMERIC_KEY_CMDS, MENU3_CTRL_CMDS, OTHER_CMDS_SET1,
OTHER_CMDS_SET4), OTHER_CMDS_SET2, OTHER_CMDS_SET4, OTHER_CMDS_SET8),
(byte) 0xA5, 42, 5, true, RotelFlagsMapping.MAPPING5), (byte) 0xA5, 42, 5, true, RotelFlagsMapping.MAPPING3),
RSX1055("RSX-1055", 19200, 3, 1, false, 90, false, 12, false, ZONE_SELECT, 1, RSX1055("RSX-1055", 19200, 3, 1, false, 90, false, 12, false, ZONE_SELECT, 1,
concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET1, NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET1), concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET1, NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET1),
(byte) 0xC3, 13, 8, true, RotelFlagsMapping.MAPPING1), (byte) 0xC3, 13, 8, true, RotelFlagsMapping.MAPPING1),
@ -65,13 +67,20 @@ public enum RotelModel {
MENU2_CTRL_CMDS, OTHER_CMDS_SET1), MENU2_CTRL_CMDS, OTHER_CMDS_SET1),
(byte) 0xC5, 13, 8, true, RotelFlagsMapping.MAPPING1), (byte) 0xC5, 13, 8, true, RotelFlagsMapping.MAPPING1),
RSX1057("RSX-1057", 19200, 1, 1, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2, RSX1057("RSX-1057", 19200, 1, 1, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2,
concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET2, ZONE2_TUNER_CMDS_SET2, NUMERIC_KEY_CMDS, ZONE2_NUMERIC_KEY_CMDS, concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET2, TUNER_CMDS_SET3, ZONE2_TUNER_CMDS_SET2, NUMERIC_KEY_CMDS,
MENU2_CTRL_CMDS, OTHER_CMDS_SET1), ZONE2_NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET1),
(byte) 0xC7, 13, 8, true, RotelFlagsMapping.MAPPING1), (byte) 0xC7, 13, 8, true, RotelFlagsMapping.MAPPING1),
RSX1058("RSX-1058", 38400, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2, RSX1058("RSX-1058", 38400, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 2,
concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET2, ZONE234_TUNER_CMDS_SET1, NUMERIC_KEY_CMDS, concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET2, TUNER_CMDS_SET3, ZONE234_TUNER_CMDS_SET1, NUMERIC_KEY_CMDS,
ZONE234_NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2), ZONE234_NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2, OTHER_CMDS_SET4),
(byte) 0xC8, 13, 8, true, RotelFlagsMapping.MAPPING4), (byte) 0xC8, 13, 8, true, new RotelFlagsMapping(List.of(//
new RotelFlagInfo(RotelFlagInfoType.MULTI_INPUT, 3, 1), //
new RotelFlagInfo(RotelFlagInfoType.ZONE2, 1, 7), //
new RotelFlagInfo(RotelFlagInfoType.ZONE3, 2, 7), //
new RotelFlagInfo(RotelFlagInfoType.ZONE4, 6, 2), //
new RotelFlagInfo(RotelFlagInfoType.CENTER, 8, 6), //
new RotelFlagInfo(RotelFlagInfoType.SURROUND_LEFT, 8, 4), //
new RotelFlagInfo(RotelFlagInfoType.SURROUND_RIGHT, 8, 3)))),
RSX1065("RSX-1065", 19200, 3, 1, false, 96, false, 12, false, ZONE_SELECT, 1, RSX1065("RSX-1065", 19200, 3, 1, false, 96, false, 12, false, ZONE_SELECT, 1,
concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET1, NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET3), concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET1, NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET3),
(byte) 0xC1, 42, 5, true, RotelFlagsMapping.MAPPING2), (byte) 0xC1, 42, 5, true, RotelFlagsMapping.MAPPING2),
@ -80,19 +89,34 @@ public enum RotelModel {
MENU2_CTRL_CMDS, OTHER_CMDS_SET1), MENU2_CTRL_CMDS, OTHER_CMDS_SET1),
(byte) 0xC4, 42, 5, true, RotelFlagsMapping.MAPPING2), (byte) 0xC4, 42, 5, true, RotelFlagsMapping.MAPPING2),
RSX1550("RSX-1550", 115200, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 3, RSX1550("RSX-1550", 115200, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 3,
concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET2, ZONE234_TUNER_CMDS_SET1, NUMERIC_KEY_CMDS, concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET2, TUNER_CMDS_SET3, ZONE234_TUNER_CMDS_SET1, NUMERIC_KEY_CMDS,
ZONE234_NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2, ZONE234_NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2, OTHER_CMDS_SET4,
List.of(RESET_FACTORY)), List.of(RESET_FACTORY)),
(byte) 0xC9, 13, 8, true, RotelFlagsMapping.MAPPING3), (byte) 0xC9, 13, 8, true, new RotelFlagsMapping(List.of(//
new RotelFlagInfo(RotelFlagInfoType.MULTI_INPUT, 4, 7), //
new RotelFlagInfo(RotelFlagInfoType.ZONE2, 1, 7), //
new RotelFlagInfo(RotelFlagInfoType.ZONE3, 2, 7), //
new RotelFlagInfo(RotelFlagInfoType.ZONE4, 6, 2), //
new RotelFlagInfo(RotelFlagInfoType.CENTER, 5, 6), //
new RotelFlagInfo(RotelFlagInfoType.SURROUND_LEFT, 5, 4), //
new RotelFlagInfo(RotelFlagInfoType.SURROUND_RIGHT, 5, 3)))),
RSX1560("RSX-1560", 115200, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 3, RSX1560("RSX-1560", 115200, 1, 3, true, 96, true, 6, false, RECORD_FONCTION_SELECT, 3,
concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET2, ZONE234_TUNER_CMDS_SET1, NUMERIC_KEY_CMDS, concatenate(DSP_CMDS_SET1, TUNER_CMDS_SET2, TUNER_CMDS_SET3, ZONE234_TUNER_CMDS_SET1, NUMERIC_KEY_CMDS,
ZONE234_NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2, ZONE234_NUMERIC_KEY_CMDS, MENU2_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2, OTHER_CMDS_SET4,
List.of(RESET_FACTORY)), List.of(RESET_FACTORY)),
(byte) 0xCA, 42, 5, true, RotelFlagsMapping.MAPPING5), (byte) 0xCA, 42, 5, true, RotelFlagsMapping.MAPPING3),
RSX1562("RSX-1562", 115200, 2, 3, true, 96, true, null, false, RECORD_FONCTION_SELECT, 4, RSX1562("RSX-1562", 115200, 2, 3, true, 96, true, null, false, RECORD_FONCTION_SELECT, 4,
concatenate(DSP_CMDS_SET2, DSP_CMDS_SET1, TUNER_CMDS_SET2, ZONE234_TUNER_CMDS_SET1, NUMERIC_KEY_CMDS, concatenate(DSP_CMDS_SET2, DSP_CMDS_SET1, TUNER_CMDS_SET2, TUNER_CMDS_SET3, ZONE234_TUNER_CMDS_SET1,
ZONE234_NUMERIC_KEY_CMDS, MENU3_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET4), NUMERIC_KEY_CMDS, ZONE234_NUMERIC_KEY_CMDS, MENU3_CTRL_CMDS, OTHER_CMDS_SET1, OTHER_CMDS_SET2,
(byte) 0xCC, 42, 5, true, RotelFlagsMapping.MAPPING5), OTHER_CMDS_SET4, OTHER_CMDS_SET8),
(byte) 0xCC, 42, 5, true, RotelFlagsMapping.MAPPING3),
RX1052("RX-1052", 38400, 22, 3, true, 90, true, 10, false, RECORD_FONCTION_SELECT, -1,
concatenate(TUNER_CMDS_SET2, ZONE234_TUNER_CMDS_SET1, NUMERIC_KEY_CMDS, ZONE234_NUMERIC_KEY_CMDS,
OTHER_CMDS_SET2, OTHER_CMDS_SET9),
(byte) 0x61, 11, 5, false, new RotelFlagsMapping(List.of(//
new RotelFlagInfo(RotelFlagInfoType.ZONE, 1, 1), //
new RotelFlagInfo(RotelFlagInfoType.SPEAKER_A, 1, 3), //
new RotelFlagInfo(RotelFlagInfoType.SPEAKER_B, 1, 2)))),
A11("A11", 115200, 4, 96, true, 10, 15, false, -1, false, true, true, 6, 0, SRC_CTRL_CMDS_SET1, A11("A11", 115200, 4, 96, true, 10, 15, false, -1, false, true, true, 6, 0, SRC_CTRL_CMDS_SET1,
NO_SPECIAL_CHARACTERS), NO_SPECIAL_CHARACTERS),
A12("A12", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, A12("A12", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0,
@ -154,7 +178,7 @@ public enum RotelModel {
T11("T11", 115200, 12, null, false, null, false, -1, false, true, 6, 0, List.of(), NO_SPECIAL_CHARACTERS), T11("T11", 115200, 12, null, false, null, false, -1, false, true, 6, 0, List.of(), NO_SPECIAL_CHARACTERS),
T14("T14", 115200, 13, null, false, null, false, -1, false, true, 6, 0, List.of(), NO_SPECIAL_CHARACTERS), T14("T14", 115200, 13, null, false, null, false, -1, false, true, 6, 0, List.of(), NO_SPECIAL_CHARACTERS),
C8("C8", 115200, POWER, 21, 3, true, false, 96, true, 10, false, 10, false, null, -1, true, false, true, 4, 0, C8("C8", 115200, POWER, 21, 3, true, false, 96, true, 10, false, 10, false, null, -1, true, false, true, 4, 0,
List.of(), (byte) 0, 0, 0, false, RotelFlagsMapping.NO_MAPPING, NO_SPECIAL_CHARACTERS), List.of(), (byte) 0, 0, 0, false, new RotelFlagsMapping(), NO_SPECIAL_CHARACTERS),
M8("M8", 115200, 0, null, false, null, false, -1, false, true, 4, 0, List.of(), NO_SPECIAL_CHARACTERS), M8("M8", 115200, 0, null, false, null, false, -1, false, true, 4, 0, List.of(), NO_SPECIAL_CHARACTERS),
P5("P5", 115200, 20, 96, true, 10, 10, false, -1, true, false, true, 4, 0, SRC_CTRL_CMDS_SET1, P5("P5", 115200, 20, 96, true, 10, 10, false, -1, true, false, true, 4, 0, SRC_CTRL_CMDS_SET1,
NO_SPECIAL_CHARACTERS), NO_SPECIAL_CHARACTERS),
@ -248,7 +272,7 @@ public enum RotelModel {
this(name, baudRate, POWER, sourceCategory, 0, false, false, volumeMax, directVolume, toneLevelMax, this(name, baudRate, POWER, sourceCategory, 0, false, false, volumeMax, directVolume, toneLevelMax,
toneLevelMax != null, null, playControl, null, dspCategory, getFrequencyAvailable, false, toneLevelMax != null, null, playControl, null, dspCategory, getFrequencyAvailable, false,
getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, otherCommands, (byte) 0, 0, 0, false, getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, otherCommands, (byte) 0, 0, 0, false,
RotelFlagsMapping.NO_MAPPING, specialCharacters); new RotelFlagsMapping(), specialCharacters);
} }
/** /**
@ -279,7 +303,7 @@ public enum RotelModel {
this(name, baudRate, POWER, sourceCategory, 0, false, false, volumeMax, directVolume, toneLevelMax, this(name, baudRate, POWER, sourceCategory, 0, false, false, volumeMax, directVolume, toneLevelMax,
toneLevelMax != null, balanceLevelMax, playControl, null, dspCategory, getFrequencyAvailable, toneLevelMax != null, balanceLevelMax, playControl, null, dspCategory, getFrequencyAvailable,
getSpeakerGroupsAvailable, getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, otherCommands, getSpeakerGroupsAvailable, getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, otherCommands,
(byte) 0, 0, 0, false, RotelFlagsMapping.NO_MAPPING, specialCharacters); (byte) 0, 0, 0, false, new RotelFlagsMapping(), specialCharacters);
} }
/** /**
@ -736,103 +760,41 @@ public enum RotelModel {
} }
/** /**
* Inform whether the multiple input source is set to ON in the flags * Inform whether the information is present in flags
* *
* @param flags the flag from the standard response message * @param infoType the type of information
* *
* @return true if the multiple input source is ON * @return true if the information is available
*
* @throws RotelException - If this information is not present in the flags for this model
*/ */
public boolean isMultiInputOn(byte[] flags) throws RotelException { public boolean isInfoPresentInFlags(RotelFlagInfoType infoType) {
return flagsMapping.isMultiInputOn(flags); return flagsMapping.isInfoPresent(infoType);
} }
/** /**
* Set the multiple input source to ON or OFF in the flags * Inform whether the information is set to ON in the flags
* *
* @param infoType the type of information
* @param flags the flag from the standard response message
*
* @return true if the information is ON
*
* @throws RotelException - If this information is not present in the flags for this model
*/
public boolean isInfoOnInFlags(RotelFlagInfoType infoType, byte[] flags) throws RotelException {
return flagsMapping.isInfoOn(infoType, flags);
}
/**
* Set the information to ON or OFF in the flags
*
* @param infoType the type of information
* @param flags the flag from the standard response message * @param flags the flag from the standard response message
* @param on true for ON and false for OFF * @param on true for ON and false for OFF
* *
* @throws RotelException - If this information is not present in the flags for this model * @return true if the information was updated in the flags, false if not
*/ */
public void setMultiInput(byte[] flags, boolean on) throws RotelException { public boolean setInfoInFlags(RotelFlagInfoType infoType, byte[] flags, boolean on) {
flagsMapping.setMultiInput(flags, on); return flagsMapping.setInfo(infoType, flags, on);
}
/**
* Inform whether the zone 2 is set to ON in the flags
*
* @param flags the flag from the standard response message
*
* @return true if the zone 2 is ON
*
* @throws RotelException - If this information is not present in the flags for this model
*/
public boolean isZone2On(byte[] flags) throws RotelException {
return flagsMapping.isZone2On(flags);
}
/**
* Set the zone 2 to ON or OFF in the flags
*
* @param flags the flag from the standard response message
* @param on true for ON and false for OFF
*
* @throws RotelException - If this information is not present in the flags for this model
*/
public void setZone2(byte[] flags, boolean on) throws RotelException {
flagsMapping.setZone2(flags, on);
}
/**
* Inform whether the zone 3 is set to ON in the flags
*
* @param flags the flag from the standard response message
*
* @return true if the zone 3 is ON
*
* @throws RotelException - If this information is not present in the flags for this model
*/
public boolean isZone3On(byte[] flags) throws RotelException {
return flagsMapping.isZone3On(flags);
}
/**
* Set the zone 3 to ON or OFF in the flags
*
* @param flags the flag from the standard response message
* @param on true for ON and false for OFF
*
* @throws RotelException - If this information is not present in the flags for this model
*/
public void setZone3(byte[] flags, boolean on) throws RotelException {
flagsMapping.setZone3(flags, on);
}
/**
* Inform whether the zone 4 is set to ON in the flags
*
* @param flags the flag from the standard response message
*
* @return true if the zone 4 is ON
*
* @throws RotelException - If this information is not present in the flags for this model
*/
public boolean isZone4On(byte[] flags) throws RotelException {
return flagsMapping.isZone4On(flags);
}
/**
* Set the zone 4 to ON or OFF in the flags
*
* @param flags the flag from the standard response message
* @param on true for ON and false for OFF
*
* @throws RotelException - If this information is not present in the flags for this model
*/
public void setZone4(byte[] flags, boolean on) throws RotelException {
flagsMapping.setZone4(flags, on);
} }
/** /**

View File

@ -150,6 +150,7 @@ public enum RotelCommand {
"main_zone_video5"), "main_zone_video5"),
MAIN_ZONE_SOURCE_VIDEO6("Main Zone Source Video 6", MAIN_ZONE_CMD, (byte) 0x94, "main_zone_video6", MAIN_ZONE_SOURCE_VIDEO6("Main Zone Source Video 6", MAIN_ZONE_CMD, (byte) 0x94, "main_zone_video6",
"main_zone_video6"), "main_zone_video6"),
MAIN_ZONE_SOURCE_PHONO("Main Zone Source Phono", MAIN_ZONE_CMD, (byte) 0x35, "main_zone_phono", "main_zone_phono"),
MAIN_ZONE_SOURCE_USB("Main Zone Source Front USB", MAIN_ZONE_CMD, (byte) 0x8E, "main_zone_usb", "main_zone_usb"), 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_SOURCE_MULTI_INPUT("Main Zone Source Multi Input", MAIN_ZONE_CMD, (byte) 0x15, "main_zone_multi_input",
"main_zone_multi_input"), "main_zone_multi_input"),
@ -166,6 +167,7 @@ public enum RotelCommand {
RECORD_SOURCE_VIDEO4("Record Source Video 4", RECORD_SRC_CMD, (byte) 0x08, "record_video4", "record_video4"), RECORD_SOURCE_VIDEO4("Record Source Video 4", RECORD_SRC_CMD, (byte) 0x08, "record_video4", "record_video4"),
RECORD_SOURCE_VIDEO5("Record Source Video 5", RECORD_SRC_CMD, (byte) 0x09, "record_video5", "record_video5"), RECORD_SOURCE_VIDEO5("Record Source Video 5", RECORD_SRC_CMD, (byte) 0x09, "record_video5", "record_video5"),
RECORD_SOURCE_VIDEO6("Record Source Video 6", RECORD_SRC_CMD, (byte) 0x94, "record_video6", "record_video6"), RECORD_SOURCE_VIDEO6("Record Source Video 6", RECORD_SRC_CMD, (byte) 0x94, "record_video6", "record_video6"),
RECORD_SOURCE_PHONO("Record Source Phono", RECORD_SRC_CMD, (byte) 0x35, "record_phono", "record_phono"),
RECORD_SOURCE_USB("Record Source Front USB", RECORD_SRC_CMD, (byte) 0x8E, "record_usb", "record_usb"), RECORD_SOURCE_USB("Record Source Front USB", RECORD_SRC_CMD, (byte) 0x8E, "record_usb", "record_usb"),
RECORD_SOURCE_MAIN("Record Follow Main Zone Source", RECORD_SRC_CMD, (byte) 0x6B, "record_follow_main", RECORD_SOURCE_MAIN("Record Follow Main Zone Source", RECORD_SRC_CMD, (byte) 0x6B, "record_follow_main",
"record_follow_main"), "record_follow_main"),
@ -178,6 +180,7 @@ public enum RotelCommand {
ZONE2_SOURCE_VIDEO4("Zone 2 Source Video 4", ZONE2_CMD, (byte) 0x08, "zone2_video4", "zone2_video4"), ZONE2_SOURCE_VIDEO4("Zone 2 Source Video 4", ZONE2_CMD, (byte) 0x08, "zone2_video4", "zone2_video4"),
ZONE2_SOURCE_VIDEO5("Zone 2 Source Video 5", ZONE2_CMD, (byte) 0x09, "zone2_video5", "zone2_video5"), ZONE2_SOURCE_VIDEO5("Zone 2 Source Video 5", ZONE2_CMD, (byte) 0x09, "zone2_video5", "zone2_video5"),
ZONE2_SOURCE_VIDEO6("Zone 2 Source Video 6", ZONE2_CMD, (byte) 0x94, "zone2_video6", "zone2_video6"), ZONE2_SOURCE_VIDEO6("Zone 2 Source Video 6", ZONE2_CMD, (byte) 0x94, "zone2_video6", "zone2_video6"),
ZONE2_SOURCE_PHONO("Zone 2 Source Phono", ZONE2_CMD, (byte) 0x35, "zone2_phono", "zone2_phono"),
ZONE2_SOURCE_USB("Zone 2 Source Front USB", ZONE2_CMD, (byte) 0x8E, "zone2_usb", "zone2_usb"), 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_SOURCE_MAIN("Zone 2 Follow Main Zone Source", ZONE2_CMD, (byte) 0x6B, "zone2_follow_main",
"zone2_follow_main"), "zone2_follow_main"),
@ -194,6 +197,7 @@ public enum RotelCommand {
ZONE3_SOURCE_VIDEO4("Zone 3 Source Video 4", ZONE3_CMD, (byte) 0x08, "zone3_video4", "zone3_video4"), ZONE3_SOURCE_VIDEO4("Zone 3 Source Video 4", ZONE3_CMD, (byte) 0x08, "zone3_video4", "zone3_video4"),
ZONE3_SOURCE_VIDEO5("Zone 3 Source Video 5", ZONE3_CMD, (byte) 0x09, "zone3_video5", "zone3_video5"), ZONE3_SOURCE_VIDEO5("Zone 3 Source Video 5", ZONE3_CMD, (byte) 0x09, "zone3_video5", "zone3_video5"),
ZONE3_SOURCE_VIDEO6("Zone 3 Source Video 6", ZONE3_CMD, (byte) 0x94, "zone3_video6", "zone3_video6"), ZONE3_SOURCE_VIDEO6("Zone 3 Source Video 6", ZONE3_CMD, (byte) 0x94, "zone3_video6", "zone3_video6"),
ZONE3_SOURCE_PHONO("Zone 3 Source Phono", ZONE3_CMD, (byte) 0x35, "zone3_phono", "zone3_phono"),
ZONE3_SOURCE_USB("Zone 3 Source Front USB", ZONE3_CMD, (byte) 0x8E, "zone3_usb", "zone3_usb"), 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_SOURCE_MAIN("Zone 3 Follow Main Zone Source", ZONE3_CMD, (byte) 0x6B, "zone3_follow_main",
"zone3_follow_main"), "zone3_follow_main"),
@ -210,6 +214,7 @@ public enum RotelCommand {
ZONE4_SOURCE_VIDEO4("Zone 4 Source Video 4", ZONE4_CMD, (byte) 0x08, "zone4_video4", "zone4_video4"), ZONE4_SOURCE_VIDEO4("Zone 4 Source Video 4", ZONE4_CMD, (byte) 0x08, "zone4_video4", "zone4_video4"),
ZONE4_SOURCE_VIDEO5("Zone 4 Source Video 5", ZONE4_CMD, (byte) 0x09, "zone4_video5", "zone4_video5"), ZONE4_SOURCE_VIDEO5("Zone 4 Source Video 5", ZONE4_CMD, (byte) 0x09, "zone4_video5", "zone4_video5"),
ZONE4_SOURCE_VIDEO6("Zone 4 Source Video 6", ZONE4_CMD, (byte) 0x94, "zone4_video6", "zone4_video6"), ZONE4_SOURCE_VIDEO6("Zone 4 Source Video 6", ZONE4_CMD, (byte) 0x94, "zone4_video6", "zone4_video6"),
ZONE4_SOURCE_PHONO("Zone 4 Source Phono", ZONE4_CMD, (byte) 0x35, "zone4_phono", "zone4_phono"),
ZONE4_SOURCE_USB("Zone 4 Source Front USB", ZONE4_CMD, (byte) 0x8E, "zone4_usb", "zone4_usb"), 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_SOURCE_MAIN("Zone 4 Follow Main Zone Source", ZONE4_CMD, (byte) 0x6B, "zone4_follow_main",
"zone4_follow_main"), "zone4_follow_main"),
@ -520,7 +525,8 @@ public enum RotelCommand {
RDS_PTY, RDS_TP, RDS_TA, FM_MONO_TOGGLE); RDS_PTY, RDS_TP, RDS_TA, FM_MONO_TOGGLE);
public static final List<RotelCommand> TUNER_CMDS_SET2 = List.of(TUNE_UP, TUNE_DOWN, PRESET_UP, PRESET_DOWN, public static final List<RotelCommand> TUNER_CMDS_SET2 = List.of(TUNE_UP, TUNE_DOWN, PRESET_UP, PRESET_DOWN,
FREQUENCY_UP, FREQUENCY_DOWN, MEMORY, BAND_TOGGLE, AM, FM, TUNE_PRESET_TOGGLE, TUNING_MODE_SELECT, FREQUENCY_UP, FREQUENCY_DOWN, MEMORY, BAND_TOGGLE, AM, FM, TUNE_PRESET_TOGGLE, TUNING_MODE_SELECT,
PRESET_MODE_SELECT, FREQUENCY_DIRECT, PRESET_SCAN, TUNER_DISPLAY, RDS_PTY, RDS_TP, RDS_TA, FM_MONO_TOGGLE); PRESET_MODE_SELECT, FREQUENCY_DIRECT, PRESET_SCAN, FM_MONO_TOGGLE);
public static final List<RotelCommand> TUNER_CMDS_SET3 = List.of(TUNER_DISPLAY, RDS_PTY, RDS_TP, RDS_TA);
public static final List<RotelCommand> ZONE2_TUNER_CMDS_SET1 = List.of(ZONE2_TUNE_UP, ZONE2_TUNE_DOWN, public static final List<RotelCommand> ZONE2_TUNER_CMDS_SET1 = List.of(ZONE2_TUNE_UP, ZONE2_TUNE_DOWN,
ZONE2_BAND_TOGGLE, ZONE2_AM, ZONE2_FM, ZONE2_TUNE_PRESET_TOGGLE, ZONE2_TUNING_MODE_SELECT, ZONE2_BAND_TOGGLE, ZONE2_AM, ZONE2_FM, ZONE2_TUNE_PRESET_TOGGLE, ZONE2_TUNING_MODE_SELECT,
ZONE2_PRESET_MODE_SELECT, ZONE2_PRESET_SCAN, ZONE2_FM_MONO_TOGGLE); ZONE2_PRESET_MODE_SELECT, ZONE2_PRESET_SCAN, ZONE2_FM_MONO_TOGGLE);
@ -563,17 +569,18 @@ public enum RotelCommand {
public static final List<RotelCommand> OTHER_CMDS_SET1 = List.of(RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT, public static final List<RotelCommand> OTHER_CMDS_SET1 = List.of(RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT,
DYNAMIC_RANGE, DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE); DYNAMIC_RANGE, DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE);
public static final List<RotelCommand> OTHER_CMDS_SET2 = List.of(POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE, public static final List<RotelCommand> OTHER_CMDS_SET2 = List.of(POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE,
ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE, OUTPUT_RESOLUTION, HDMI_AMP_MODE, ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE);
HDMI_TV_MODE);
public static final List<RotelCommand> OTHER_CMDS_SET3 = List.of(RECORD_FONCTION_SELECT, DYNAMIC_RANGE, public static final List<RotelCommand> OTHER_CMDS_SET3 = List.of(RECORD_FONCTION_SELECT, DYNAMIC_RANGE,
DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE); DIGITAL_INPUT_SELECT, ZONE_TOGGLE, CENTER_TRIM, SUB_TRIM, SURROUND_TRIM, CINEMA_EQ_TOGGLE);
public static final List<RotelCommand> OTHER_CMDS_SET4 = List.of(POWER_OFF_ALL_ZONES, PARTY_MODE_TOGGLE, public static final List<RotelCommand> OTHER_CMDS_SET4 = List.of(OUTPUT_RESOLUTION, HDMI_AMP_MODE, HDMI_TV_MODE);
ZONE2_PARTY_MODE_TOGGLE, ZONE3_PARTY_MODE_TOGGLE, ZONE4_PARTY_MODE_TOGGLE, OUTPUT_RESOLUTION, HDMI_AMP_MODE,
HDMI_TV_MODE, ROOM_EQ_TOGGLE, SPEAKER_SETTING_TOGGLE, RESET_FACTORY);
public static final List<RotelCommand> OTHER_CMDS_SET5 = List.of(POWER_MODE, POWER_MODE_QUICK, POWER_MODE_NORMAL, public static final List<RotelCommand> OTHER_CMDS_SET5 = List.of(POWER_MODE, POWER_MODE_QUICK, POWER_MODE_NORMAL,
RESET_FACTORY); RESET_FACTORY);
public static final List<RotelCommand> OTHER_CMDS_SET6 = List.of(POWER_MODE, RESET_FACTORY); public static final List<RotelCommand> OTHER_CMDS_SET6 = List.of(POWER_MODE, RESET_FACTORY);
public static final List<RotelCommand> OTHER_CMDS_SET7 = List.of(NEXT_MODE, RESET_FACTORY); public static final List<RotelCommand> OTHER_CMDS_SET7 = List.of(NEXT_MODE, RESET_FACTORY);
public static final List<RotelCommand> OTHER_CMDS_SET8 = List.of(ROOM_EQ_TOGGLE, SPEAKER_SETTING_TOGGLE,
RESET_FACTORY);
public static final List<RotelCommand> OTHER_CMDS_SET9 = List.of(RECORD_FONCTION_SELECT, TONE_CONTROL_SELECT,
ZONE_TOGGLE);
public static final byte PRIMARY_COMMAND = (byte) 0x10; public static final byte PRIMARY_COMMAND = (byte) 0x10;
@ -766,4 +773,27 @@ public enum RotelCommand {
return Stream.of(list1, list2, list3, list4, list5, list6, list7, list8, list9).flatMap(Collection::stream) return Stream.of(list1, list2, list3, list4, list5, list6, list7, list8, list9).flatMap(Collection::stream)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public static List<RotelCommand> concatenate(List<RotelCommand> list1, List<RotelCommand> list2,
List<RotelCommand> list3, List<RotelCommand> list4, List<RotelCommand> list5, List<RotelCommand> list6,
List<RotelCommand> list7, List<RotelCommand> list8, List<RotelCommand> list9, List<RotelCommand> list10) {
return Stream.of(list1, list2, list3, list4, list5, list6, list7, list8, list9, list10)
.flatMap(Collection::stream).collect(Collectors.toList());
}
public static List<RotelCommand> concatenate(List<RotelCommand> list1, List<RotelCommand> list2,
List<RotelCommand> list3, List<RotelCommand> list4, List<RotelCommand> list5, List<RotelCommand> list6,
List<RotelCommand> list7, List<RotelCommand> list8, List<RotelCommand> list9, List<RotelCommand> list10,
List<RotelCommand> list11) {
return Stream.of(list1, list2, list3, list4, list5, list6, list7, list8, list9, list10, list11)
.flatMap(Collection::stream).collect(Collectors.toList());
}
public static List<RotelCommand> concatenate(List<RotelCommand> list1, List<RotelCommand> list2,
List<RotelCommand> list3, List<RotelCommand> list4, List<RotelCommand> list5, List<RotelCommand> list6,
List<RotelCommand> list7, List<RotelCommand> list8, List<RotelCommand> list9, List<RotelCommand> list10,
List<RotelCommand> list11, List<RotelCommand> list12) {
return Stream.of(list1, list2, list3, list4, list5, list6, list7, list8, list9, list10, list11, list12)
.flatMap(Collection::stream).collect(Collectors.toList());
}
} }

View File

@ -0,0 +1,24 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.rotel.internal.communication;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Record describing one information in response flags (HEX protocol)
*
* @author Laurent Garnier - Initial contribution
*/
@NonNullByDefault
public record RotelFlagInfo(RotelFlagInfoType infoType, int flagNumber, int bitNumber) {
}

View File

@ -0,0 +1,34 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.rotel.internal.communication;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Represents the different types of information that can be included in response flags (HEX protocol)
*
* @author Laurent Garnier - Initial contribution
*/
@NonNullByDefault
public enum RotelFlagInfoType {
MULTI_INPUT,
ZONE2,
ZONE3,
ZONE4,
ZONE,
CENTER,
SURROUND_LEFT,
SURROUND_RIGHT,
SPEAKER_A,
SPEAKER_B
}

View File

@ -12,6 +12,10 @@
*/ */
package org.openhab.binding.rotel.internal.communication; package org.openhab.binding.rotel.internal.communication;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.rotel.internal.RotelException; import org.openhab.binding.rotel.internal.RotelException;
@ -23,174 +27,77 @@ import org.openhab.binding.rotel.internal.RotelException;
@NonNullByDefault @NonNullByDefault
public class RotelFlagsMapping { public class RotelFlagsMapping {
public static final RotelFlagsMapping MAPPING1 = new RotelFlagsMapping(3, 1, 5, 0, -1, -1, -1, -1, 8, 6, 8, 4, 8, public static final RotelFlagsMapping MAPPING1 = new RotelFlagsMapping(
3); List.of(new RotelFlagInfo(RotelFlagInfoType.MULTI_INPUT, 3, 1), //
public static final RotelFlagsMapping MAPPING2 = new RotelFlagsMapping(-1, -1, 4, 7, -1, -1, -1, -1, 5, 6, 5, 4, 5, new RotelFlagInfo(RotelFlagInfoType.ZONE2, 5, 0), //
3); new RotelFlagInfo(RotelFlagInfoType.CENTER, 8, 6), //
public static final RotelFlagsMapping MAPPING3 = new RotelFlagsMapping(4, 7, 1, 7, 2, 7, 6, 2, 5, 6, 5, 4, 5, 3); new RotelFlagInfo(RotelFlagInfoType.SURROUND_LEFT, 8, 4), //
public static final RotelFlagsMapping MAPPING4 = new RotelFlagsMapping(3, 1, 1, 7, 2, 7, 6, 2, 8, 6, 8, 4, 8, 3); new RotelFlagInfo(RotelFlagInfoType.SURROUND_RIGHT, 8, 3)));
public static final RotelFlagsMapping MAPPING5 = new RotelFlagsMapping(-1, -1, 3, 2, 4, 2, 4, 1, 5, 6, 5, 4, 5, 3); public static final RotelFlagsMapping MAPPING2 = new RotelFlagsMapping(
public static final RotelFlagsMapping NO_MAPPING = new RotelFlagsMapping(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, List.of(new RotelFlagInfo(RotelFlagInfoType.ZONE2, 4, 7), //
-1, -1, -1); new RotelFlagInfo(RotelFlagInfoType.CENTER, 5, 6), //
new RotelFlagInfo(RotelFlagInfoType.SURROUND_LEFT, 5, 4), //
new RotelFlagInfo(RotelFlagInfoType.SURROUND_RIGHT, 5, 3)));
public static final RotelFlagsMapping MAPPING3 = new RotelFlagsMapping(
List.of(new RotelFlagInfo(RotelFlagInfoType.ZONE2, 3, 2), //
new RotelFlagInfo(RotelFlagInfoType.ZONE3, 4, 2), //
new RotelFlagInfo(RotelFlagInfoType.ZONE4, 4, 1), //
new RotelFlagInfo(RotelFlagInfoType.CENTER, 5, 6), //
new RotelFlagInfo(RotelFlagInfoType.SURROUND_LEFT, 5, 4), //
new RotelFlagInfo(RotelFlagInfoType.SURROUND_RIGHT, 5, 3)));
private int multiInputFlagNumber; private Map<RotelFlagInfoType, RotelFlagInfo> infoMap;
private int multiInputBitNumber;
private int zone2FlagNumber;
private int zone2BitNumber;
private int zone3FlagNumber;
private int zone3BitNumber;
private int zone4FlagNumber;
private int zone4BitNumber;
private int centerFlagNumber;
private int centerBitNumber;
private int surroundLeftFlagNumber;
private int surroundLeftBitNumber;
private int surroundRightFlagNumber;
private int surroundRightBitNumber;
/** public RotelFlagsMapping() {
* Constructor this.infoMap = new HashMap<>();
* }
* For each flag number, value 1 means the first flag; a negative value is used for an undefined indicator.
* For each bit number, value is from 0 to 7; a negative value is used for an undefined indicator. public RotelFlagsMapping(List<RotelFlagInfo> infos) {
* this.infoMap = new HashMap<>();
* @param multiInputFlagNumber the flag number in the standard feedback message in which to find the multi input for (RotelFlagInfo info : infos) {
* indicator this.infoMap.put(info.infoType(), info);
* @param multiInputBitNumber the bit number in the flag in which to find the multi input indicator }
* @param zone2FlagNumber the flag number in the standard feedback message in which to find the zone 2 indicator
* @param zone2BitNumber the bit number in the flag in which to find the zone 2 indicator
* @param zone3FlagNumber the flag number in the standard feedback message in which to find the zone 3 indicator
* @param zone3BitNumber the bit number in the flag in which to find the zone 3 indicator
* @param zone4FlagNumber the flag number in the standard feedback message in which to find the zone 4 indicator
* @param zone4BitNumber the bit number in the flag in which to find the zone 4 indicator
* @param centerFlagNumber the flag number in the standard feedback message in which to find the center channel
* indicator
* @param centerBitNumber the bit number in the flag in which to find the center channel indicator
* @param surroundLeftFlagNumber the flag number in the standard feedback message in which to find the surround left
* channel indicator
* @param surroundLeftBitNumber the bit number in the flag in which to find the surround left channel indicator
* @param surroundRightFlagNumber the flag number in the standard feedback message in which to find the surround
* right channel indicator
* @param surroundRightBitNumber the bit number in the flag in which to find the surround right channel indicator
*/
private RotelFlagsMapping(int multiInputFlagNumber, int multiInputBitNumber, int zone2FlagNumber,
int zone2BitNumber, int zone3FlagNumber, int zone3BitNumber, int zone4FlagNumber, int zone4BitNumber,
int centerFlagNumber, int centerBitNumber, int surroundLeftFlagNumber, int surroundLeftBitNumber,
int surroundRightFlagNumber, int surroundRightBitNumber) {
this.multiInputFlagNumber = multiInputFlagNumber;
this.multiInputBitNumber = multiInputBitNumber;
this.zone2FlagNumber = zone2FlagNumber;
this.zone2BitNumber = zone2BitNumber;
this.zone3FlagNumber = zone3FlagNumber;
this.zone3BitNumber = zone3BitNumber;
this.zone4FlagNumber = zone4FlagNumber;
this.zone4BitNumber = zone4BitNumber;
this.centerFlagNumber = centerFlagNumber;
this.centerBitNumber = centerBitNumber;
this.surroundLeftFlagNumber = surroundLeftFlagNumber;
this.surroundLeftBitNumber = surroundLeftBitNumber;
this.surroundRightFlagNumber = surroundRightFlagNumber;
this.surroundRightBitNumber = surroundRightBitNumber;
} }
/** /**
* Get the multi input indicator * Get the availability of the information
* *
* @param flags the table of flags * @return true if the information is available
*
* @return true if the indicator is ON in the flags or false if OFF
*
* @throws RotelException in case the multi input indicator is undefined
*/ */
public boolean isMultiInputOn(byte[] flags) throws RotelException { public boolean isInfoPresent(RotelFlagInfoType infoType) {
return RotelFlagsMapping.isBitFlagOn(flags, multiInputFlagNumber, multiInputBitNumber); return infoMap.get(infoType) != null;
} }
/** /**
* Set the multi input indicator * Get the information
* *
* @param infoType the type of information
* @param flags the table of flags * @param flags the table of flags
* @param on true to set the indicator to ON or false to set it to OFF
* *
* @throws RotelException in case the multi input indicator is undefined * @return true if the information is ON in the flags or false if OFF
*
* @throws RotelException in case the information is undefined
*/ */
public void setMultiInput(byte[] flags, boolean on) throws RotelException { public boolean isInfoOn(RotelFlagInfoType infoType, byte[] flags) throws RotelException {
RotelFlagsMapping.setBitFlag(flags, multiInputFlagNumber, multiInputBitNumber, on); RotelFlagInfo info = infoMap.get(infoType);
if (info == null || info.flagNumber() > flags.length) {
throw new RotelException("Info " + infoType.name() + " not available in flags");
}
return RotelFlagsMapping.isBitFlagOn(flags, info.flagNumber(), info.bitNumber());
} }
/** /**
* Get the zone 2 indicator * Set the information
* *
* @param infoType the type of information
* @param flags the table of flags * @param flags the table of flags
* @param on true to set the information to ON or false to set it to OFF
* *
* @return true if the indicator is ON in the flags or false if OFF * @return true if the information was updated, false if not
*
* @throws RotelException in case the zone 2 indicator is undefined
*/ */
public boolean isZone2On(byte[] flags) throws RotelException { public boolean setInfo(RotelFlagInfoType infoType, byte[] flags, boolean on) {
return RotelFlagsMapping.isBitFlagOn(flags, zone2FlagNumber, zone2BitNumber); RotelFlagInfo info = infoMap.get(infoType);
} return info == null ? false : RotelFlagsMapping.setBitFlag(flags, info.flagNumber(), info.bitNumber(), on);
/**
* Set the zone 2 indicator
*
* @param flags the table of flags
* @param on true to set the indicator to ON or false to set it to OFF
*
* @throws RotelException in case the zone 2 indicator is undefined
*/
public void setZone2(byte[] flags, boolean on) throws RotelException {
RotelFlagsMapping.setBitFlag(flags, zone2FlagNumber, zone2BitNumber, on);
}
/**
* Get the zone 3 indicator
*
* @param flags the table of flags
*
* @return true if the indicator is ON in the flags or false if OFF
*
* @throws RotelException in case the zone 3 indicator is undefined
*/
public boolean isZone3On(byte[] flags) throws RotelException {
return RotelFlagsMapping.isBitFlagOn(flags, zone3FlagNumber, zone3BitNumber);
}
/**
* Set the zone 3 indicator
*
* @param flags the table of flags
* @param on true to set the indicator to ON or false to set it to OFF
*
* @throws RotelException in case the zone 3 indicator is undefined
*/
public void setZone3(byte[] flags, boolean on) throws RotelException {
RotelFlagsMapping.setBitFlag(flags, zone3FlagNumber, zone3BitNumber, on);
}
/**
* Get the zone 4 indicator
*
* @param flags the table of flags
*
* @return true if the indicator is ON in the flags or false if OFF
*
* @throws RotelException in case the zone 4 indicator is undefined
*/
public boolean isZone4On(byte[] flags) throws RotelException {
return RotelFlagsMapping.isBitFlagOn(flags, zone4FlagNumber, zone4BitNumber);
}
/**
* Set the zone 4 indicator
*
* @param flags the table of flags
* @param on true to set the indicator to ON or false to set it to OFF
*
* @throws RotelException in case the zone 4 indicator is undefined
*/
public void setZone4(byte[] flags, boolean on) throws RotelException {
RotelFlagsMapping.setBitFlag(flags, zone4FlagNumber, zone4BitNumber, on);
} }
/** /**
@ -203,12 +110,15 @@ public class RotelFlagsMapping {
* @throws RotelException in case the center or surround channel indicators are undefined * @throws RotelException in case the center or surround channel indicators are undefined
*/ */
public boolean isMoreThan2Channels(byte[] flags) throws RotelException { public boolean isMoreThan2Channels(byte[] flags) throws RotelException {
return (centerFlagNumber >= 1 && centerFlagNumber <= flags.length RotelFlagInfo center = infoMap.get(RotelFlagInfoType.CENTER);
&& RotelFlagsMapping.isBitFlagOn(flags, centerFlagNumber, centerBitNumber)) RotelFlagInfo surroundLeft = infoMap.get(RotelFlagInfoType.SURROUND_LEFT);
|| (surroundLeftFlagNumber >= 1 && surroundLeftFlagNumber <= flags.length RotelFlagInfo surroundRight = infoMap.get(RotelFlagInfoType.SURROUND_RIGHT);
&& RotelFlagsMapping.isBitFlagOn(flags, surroundLeftFlagNumber, surroundLeftBitNumber)) return (center != null && center.flagNumber() <= flags.length
|| (surroundRightFlagNumber >= 1 && surroundRightFlagNumber <= flags.length && RotelFlagsMapping.isBitFlagOn(flags, center.flagNumber(), center.bitNumber()))
&& RotelFlagsMapping.isBitFlagOn(flags, surroundRightFlagNumber, surroundRightBitNumber)); || (surroundLeft != null && surroundLeft.flagNumber() <= flags.length
&& RotelFlagsMapping.isBitFlagOn(flags, surroundLeft.flagNumber(), surroundLeft.bitNumber()))
|| (surroundRight != null && surroundRight.flagNumber() <= flags.length
&& RotelFlagsMapping.isBitFlagOn(flags, surroundRight.flagNumber(), surroundRight.bitNumber()));
} }
/** /**
@ -241,19 +151,17 @@ public class RotelFlagsMapping {
* @param bitNumber the bit number in the flag to consider * @param bitNumber the bit number in the flag to consider
* @param on true to set the bit value to 1 or false to set it to 0 * @param on true to set the bit value to 1 or false to set it to 0
* *
* @throws RotelException in case of out of bounds value for the flag number or the bit number * @return true if the flag was updated, false if not
*/ */
private static void setBitFlag(byte[] flags, int flagNumber, int bitNumber, boolean on) throws RotelException { private static boolean setBitFlag(byte[] flags, int flagNumber, int bitNumber, boolean on) {
if (flagNumber < 1 || flagNumber > flags.length) { if (flagNumber < 1 || flagNumber > flags.length || bitNumber < 0 || bitNumber > 7) {
throw new RotelException("Flag number out of bounds"); return false;
}
if (bitNumber < 0 || bitNumber > 7) {
throw new RotelException("Bit number out of bounds");
} }
if (on) { if (on) {
flags[flagNumber - 1] |= (1 << bitNumber); flags[flagNumber - 1] |= (1 << bitNumber);
} else { } else {
flags[flagNumber - 1] &= ~(1 << bitNumber); flags[flagNumber - 1] &= ~(1 << bitNumber);
} }
return true;
} }
} }

View File

@ -312,11 +312,11 @@ public class RotelSimuConnector extends RotelConnector {
case RECORD_FONCTION_SELECT: case RECORD_FONCTION_SELECT:
if (model.getNumberOfZones() > 1 && model.getZoneSelectCmd() == cmd) { if (model.getNumberOfZones() > 1 && model.getZoneSelectCmd() == cmd) {
showZone++; showZone++;
if (showZone >= model.getNumberOfZones()) { if (showZone > model.getNumberOfZones()) {
showZone = 1; showZone = 1;
if (!powers[0]) { }
showZone++; if (showZone == 1 && !powers[0]) {
} showZone++;
} }
} else { } else {
showZone = 1; showZone = 1;
@ -325,6 +325,9 @@ public class RotelSimuConnector extends RotelConnector {
selectingRecord = powers[0]; selectingRecord = powers[0];
showTreble = false; showTreble = false;
textLine2 = buildRecordResponse(); textLine2 = buildRecordResponse();
if (model.getRespNbChars() == 11) {
text = textLine2;
}
} else if (showZone >= 2 && showZone <= 4) { } else if (showZone >= 2 && showZone <= 4) {
selectingRecord = false; selectingRecord = false;
text = textLine2 = buildZonePowerResponse(showZone); text = textLine2 = buildZonePowerResponse(showZone);
@ -1182,8 +1185,8 @@ public class RotelSimuConnector extends RotelConnector {
// Check if command is a change of record source // Check if command is a change of record source
try { try {
recordSource = model.getRecordSourceFromCommand(cmd); recordSource = model.getRecordSourceFromCommand(cmd);
text = buildSourceLine1Response();
textLine2 = buildRecordResponse(); textLine2 = buildRecordResponse();
text = model.getRespNbChars() == 11 ? textLine2 : buildSourceLine1Response();
accepted = true; accepted = true;
} catch (RotelException e) { } catch (RotelException e) {
} }
@ -1217,21 +1220,26 @@ public class RotelSimuConnector extends RotelConnector {
if (protocol == RotelProtocol.HEX) { if (protocol == RotelProtocol.HEX) {
byte[] chars = Arrays.copyOf(text.getBytes(StandardCharsets.US_ASCII), model.getRespNbChars()); byte[] chars = Arrays.copyOf(text.getBytes(StandardCharsets.US_ASCII), model.getRespNbChars());
byte[] flags = new byte[model.getRespNbFlags()]; byte[] flags = new byte[model.getRespNbFlags()];
try { if (model.isInfoPresentInFlags(RotelFlagInfoType.MULTI_INPUT)) {
model.setMultiInput(flags, multiinput); model.setInfoInFlags(RotelFlagInfoType.MULTI_INPUT, flags, multiinput);
} catch (RotelException e) {
} }
try { if (model.isInfoPresentInFlags(RotelFlagInfoType.ZONE2)) {
model.setZone2(flags, powers[2]); model.setInfoInFlags(RotelFlagInfoType.ZONE2, flags, powers[2]);
} catch (RotelException e) {
} }
try { if (model.isInfoPresentInFlags(RotelFlagInfoType.ZONE3)) {
model.setZone3(flags, powers[3]); model.setInfoInFlags(RotelFlagInfoType.ZONE3, flags, powers[3]);
} catch (RotelException e) {
} }
try { if (model.isInfoPresentInFlags(RotelFlagInfoType.ZONE4)) {
model.setZone4(flags, powers[4]); model.setInfoInFlags(RotelFlagInfoType.ZONE4, flags, powers[4]);
} catch (RotelException e) { }
if (model.isInfoPresentInFlags(RotelFlagInfoType.ZONE)) {
model.setInfoInFlags(RotelFlagInfoType.ZONE, flags, powers[2] || powers[3] || powers[4]);
}
if (model.isInfoPresentInFlags(RotelFlagInfoType.SPEAKER_A)) {
model.setInfoInFlags(RotelFlagInfoType.SPEAKER_A, flags, speakerA);
}
if (model.isInfoPresentInFlags(RotelFlagInfoType.SPEAKER_B)) {
model.setInfoInFlags(RotelFlagInfoType.SPEAKER_B, flags, speakerB);
} }
int size = 6 + model.getRespNbChars() + model.getRespNbFlags(); int size = 6 + model.getRespNbChars() + model.getRespNbFlags();
byte[] dataBuffer = new byte[size]; byte[] dataBuffer = new byte[size];
@ -1479,9 +1487,18 @@ public class RotelSimuConnector extends RotelConnector {
if (!powers[0]) { if (!powers[0]) {
text = ""; text = "";
} else if (mutes[0]) { } else if (mutes[0]) {
text = "MUTE ON"; text = model.getRespNbChars() == 11 ? " MUTE ON " : "MUTE ON";
} else { } else {
text = getSourceLabel(sources[0], false) + " " + getSourceLabel(recordSource, true); text = getSourceLabel(sources[0], false);
if (model.getRespNbChars() == 11) {
if ("TUNER".equals(text)) {
text = "104.30M 10 ";
} else {
text += " " + buildVolumeValue(0);
}
} else {
text += " " + getSourceLabel(recordSource, true);
}
} }
return text; return text;
} }
@ -1507,26 +1524,16 @@ public class RotelSimuConnector extends RotelConnector {
} }
private String buildZonePowerResponse(int numZone) { private String buildZonePowerResponse(int numZone) {
String zone; String zone = model.getRespNbChars() == 11 ? " Z" : "ZONE";
if (numZone == 2) { if (numZone != 2 || model.getNumberOfZones() > 2) {
zone = model.getNumberOfZones() > 2 ? "ZONE2" : "ZONE"; zone += String.format("%d", numZone);
} else {
zone = String.format("ZONE%d", numZone);
} }
String state = powers[numZone] ? getSourceLabel(sources[numZone], true) : "OFF"; String state = powers[numZone] ? getSourceLabel(sources[numZone], true) : "OFF";
return zone + " " + state; return zone + " " + state;
} }
private String buildVolumeLine1Response() { private String buildVolumeLine1Response() {
String text; return String.format(model.getRespNbChars() == 11 ? "VOLUME %s" : " VOLUME %s ", buildVolumeValue(0));
if (volumes[0] == minVolume) {
text = " VOLUME MIN ";
} else if (volumes[0] == maxVolume) {
text = " VOLUME MAX ";
} else {
text = String.format(" VOLUME %02d ", volumes[0]);
}
return text;
} }
private String buildVolumeLine1RightResponse() { private String buildVolumeLine1RightResponse() {
@ -1535,32 +1542,36 @@ public class RotelSimuConnector extends RotelConnector {
text = ""; text = "";
} else if (mutes[0]) { } else if (mutes[0]) {
text = "MUTE ON"; text = "MUTE ON";
} else if (volumes[0] == minVolume) {
text = "VOL MIN";
} else if (volumes[0] == maxVolume) {
text = "VOL MAX";
} else { } else {
text = String.format("VOL %02d", volumes[0]); text = String.format("VOL %s", buildVolumeValue(0));
} }
return text; return text;
} }
private String buildZoneVolumeResponse(int numZone) { private String buildZoneVolumeResponse(int numZone) {
String zone; String zone = model.getRespNbChars() == 11 ? " Z" : "ZONE";
if (numZone == 2) { if (numZone != 2 || model.getNumberOfZones() > 2) {
zone = model.getNumberOfZones() > 2 ? "ZONE2" : "ZONE"; zone += String.format("%d", numZone);
} else {
zone = String.format("ZONE%d", numZone);
} }
String text; String text;
if (mutes[numZone]) { if (mutes[numZone]) {
text = zone + " MUTE ON"; text = zone + " MUTE ON";
} else if (volumes[numZone] == minVolume) {
text = zone + " VOL MIN";
} else if (volumes[numZone] == maxVolume) {
text = zone + " VOL MAX";
} else { } else {
text = String.format("%s VOL %02d", zone, volumes[numZone]); text = String.format("%s VOL %s", zone, buildVolumeValue(numZone));
}
return text;
}
private String buildVolumeValue(int numZone) {
String text;
if (volumes[numZone] == minVolume) {
text = "MIN";
} else if (volumes[numZone] == maxVolume) {
text = "MAX";
} else if (model.getRespNbChars() == 11) {
text = String.format(volumes[numZone] < 10 ? " %d" : " %d", volumes[numZone]);
} else {
text = String.format(" %02d", volumes[numZone]);
} }
return text; return text;
} }
@ -1568,15 +1579,15 @@ public class RotelSimuConnector extends RotelConnector {
private String buildBassLine1Response() { private String buildBassLine1Response() {
String text; String text;
if (basses[0] == minToneLevel) { if (basses[0] == minToneLevel) {
text = " BASS MIN "; text = model.getRespNbChars() == 11 ? " BASS MIN " : " BASS MIN ";
} else if (basses[0] == maxToneLevel) { } else if (basses[0] == maxToneLevel) {
text = " BASS MAX "; text = model.getRespNbChars() == 11 ? " BASS MAX " : " BASS MAX ";
} else if (basses[0] == 0) { } else if (basses[0] == 0) {
text = " BASS 0 "; text = model.getRespNbChars() == 11 ? " BASS 0 " : " BASS 0 ";
} else if (basses[0] > 0) { } else if (basses[0] > 0) {
text = String.format(" BASS +%02d ", basses[0]); text = String.format(model.getRespNbChars() == 11 ? " BASS + %d " : " BASS +%02d ", basses[0]);
} else { } else {
text = String.format(" BASS -%02d ", -basses[0]); text = String.format(model.getRespNbChars() == 11 ? " BASS - %d " : " BASS -%02d ", -basses[0]);
} }
return text; return text;
} }
@ -1600,15 +1611,15 @@ public class RotelSimuConnector extends RotelConnector {
private String buildTrebleLine1Response() { private String buildTrebleLine1Response() {
String text; String text;
if (trebles[0] == minToneLevel) { if (trebles[0] == minToneLevel) {
text = " TREBLE MIN "; text = model.getRespNbChars() == 11 ? "TREBLE MIN " : " TREBLE MIN ";
} else if (trebles[0] == maxToneLevel) { } else if (trebles[0] == maxToneLevel) {
text = " TREBLE MAX "; text = model.getRespNbChars() == 11 ? "TREBLE MAX " : " TREBLE MAX ";
} else if (trebles[0] == 0) { } else if (trebles[0] == 0) {
text = " TREBLE 0 "; text = model.getRespNbChars() == 11 ? "TREBLE 0 " : " TREBLE 0 ";
} else if (trebles[0] > 0) { } else if (trebles[0] > 0) {
text = String.format(" TREBLE +%02d ", trebles[0]); text = String.format(model.getRespNbChars() == 11 ? "TREBLE + %d " : " TREBLE +%02d ", trebles[0]);
} else { } else {
text = String.format(" TREBLE -%02d ", -trebles[0]); text = String.format(model.getRespNbChars() == 11 ? "TREBLE - %d " : " TREBLE -%02d ", trebles[0]);
} }
return text; return text;
} }

View File

@ -310,7 +310,33 @@ public enum RotelSource {
CAT21_INPUTC(21, "INPUTC", "Input C", RotelCommand.SOURCE_INPUT_C, null, RotelCommand.ZONE1_SOURCE_INPUT_C, 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), 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, 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); RotelCommand.ZONE2_SOURCE_INPUT_D, RotelCommand.ZONE3_SOURCE_INPUT_D, RotelCommand.ZONE4_SOURCE_INPUT_D),
CAT22_CD(22, "CD", "CD", RotelCommand.SOURCE_CD, RotelCommand.RECORD_SOURCE_CD, RotelCommand.MAIN_ZONE_SOURCE_CD,
RotelCommand.ZONE2_SOURCE_CD, RotelCommand.ZONE3_SOURCE_CD, RotelCommand.ZONE4_SOURCE_CD),
CAT22_TUNER(22, "TUNER", "TUNER", RotelCommand.SOURCE_TUNER, RotelCommand.RECORD_SOURCE_TUNER,
RotelCommand.MAIN_ZONE_SOURCE_TUNER, RotelCommand.ZONE2_SOURCE_TUNER, RotelCommand.ZONE3_SOURCE_TUNER,
RotelCommand.ZONE4_SOURCE_TUNER),
CAT22_TAPE(22, "TAPE", "TAPE", RotelCommand.SOURCE_TAPE, RotelCommand.RECORD_SOURCE_TAPE,
RotelCommand.MAIN_ZONE_SOURCE_TAPE, RotelCommand.ZONE2_SOURCE_TAPE, RotelCommand.ZONE3_SOURCE_TAPE,
RotelCommand.ZONE4_SOURCE_TAPE),
CAT22_PHONO(22, "PHONO", "PHONO", RotelCommand.SOURCE_PHONO, RotelCommand.RECORD_SOURCE_PHONO,
RotelCommand.MAIN_ZONE_SOURCE_PHONO, RotelCommand.ZONE2_SOURCE_PHONO, RotelCommand.ZONE3_SOURCE_PHONO,
RotelCommand.ZONE4_SOURCE_PHONO),
CAT22_VIDEO1(22, "VIDEO1", "VIDEO 1", RotelCommand.SOURCE_VIDEO1, RotelCommand.RECORD_SOURCE_VIDEO1,
RotelCommand.MAIN_ZONE_SOURCE_VIDEO1, RotelCommand.ZONE2_SOURCE_VIDEO1, RotelCommand.ZONE3_SOURCE_VIDEO1,
RotelCommand.ZONE4_SOURCE_VIDEO1),
CAT22_VIDEO2(22, "VIDEO2", "VIDEO 2", RotelCommand.SOURCE_VIDEO2, RotelCommand.RECORD_SOURCE_VIDEO2,
RotelCommand.MAIN_ZONE_SOURCE_VIDEO2, RotelCommand.ZONE2_SOURCE_VIDEO2, RotelCommand.ZONE3_SOURCE_VIDEO2,
RotelCommand.ZONE4_SOURCE_VIDEO2),
CAT22_VIDEO3(22, "VIDEO3", "VIDEO 3", RotelCommand.SOURCE_VIDEO3, RotelCommand.RECORD_SOURCE_VIDEO3,
RotelCommand.MAIN_ZONE_SOURCE_VIDEO3, RotelCommand.ZONE2_SOURCE_VIDEO3, RotelCommand.ZONE3_SOURCE_VIDEO3,
RotelCommand.ZONE4_SOURCE_VIDEO3),
CAT22_VIDEO4(22, "VIDEO4", "VIDEO 4", RotelCommand.SOURCE_VIDEO4, RotelCommand.RECORD_SOURCE_VIDEO4,
RotelCommand.MAIN_ZONE_SOURCE_VIDEO4, RotelCommand.ZONE2_SOURCE_VIDEO4, RotelCommand.ZONE3_SOURCE_VIDEO4,
RotelCommand.ZONE4_SOURCE_VIDEO4),
CAT22_FOLLOW_MAIN(22, "MAIN", "Follow Main Zone Source", null, RotelCommand.RECORD_SOURCE_MAIN, null,
RotelCommand.ZONE2_SOURCE_MAIN, RotelCommand.ZONE3_SOURCE_MAIN, RotelCommand.ZONE4_SOURCE_MAIN);
private int category; private int category;
private String name; private String name;

View File

@ -13,6 +13,7 @@
package org.openhab.binding.rotel.internal.configuration; package org.openhab.binding.rotel.internal.configuration;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/** /**
* The {@link RotelThingConfiguration} class contains fields mapping thing configuration parameters. * The {@link RotelThingConfiguration} class contains fields mapping thing configuration parameters.
@ -23,6 +24,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
public class RotelThingConfiguration { public class RotelThingConfiguration {
public @NonNullByDefault({}) String serialPort; public @NonNullByDefault({}) String serialPort;
public @Nullable Integer baudRate;
public @NonNullByDefault({}) String host; public @NonNullByDefault({}) String host;
public @NonNullByDefault({}) Integer port; public @NonNullByDefault({}) Integer port;
public @NonNullByDefault({}) String inputLabelCd; public @NonNullByDefault({}) String inputLabelCd;

View File

@ -90,6 +90,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
private @Nullable ScheduledFuture<?> reconnectJob; private @Nullable ScheduledFuture<?> reconnectJob;
private @Nullable ScheduledFuture<?> powerOffJob; private @Nullable ScheduledFuture<?> powerOffJob;
private @Nullable ScheduledFuture<?> powerZonesJob;
private @Nullable ScheduledFuture<?>[] powerOnZoneJobs = { null, null, null, null, null }; private @Nullable ScheduledFuture<?>[] powerOnZoneJobs = { null, null, null, null, null };
private RotelModel model; private RotelModel model;
@ -104,6 +105,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
private int currentZone = 1; private int currentZone = 1;
private boolean selectingRecord; private boolean selectingRecord;
private @Nullable Boolean powerZones;
private @Nullable Boolean[] powers = { null, false, false, false, false }; private @Nullable Boolean[] powers = { null, false, false, false, false };
private boolean powerControlPerZone; private boolean powerControlPerZone;
private @Nullable RotelSource recordSource; private @Nullable RotelSource recordSource;
@ -219,6 +221,9 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
case THING_TYPE_ID_RSX1562: case THING_TYPE_ID_RSX1562:
model = RotelModel.RSX1562; model = RotelModel.RSX1562;
break; break;
case THING_TYPE_ID_RX1052:
model = RotelModel.RX1052;
break;
case THING_TYPE_ID_A11: case THING_TYPE_ID_A11:
model = RotelModel.A11; model = RotelModel.A11;
break; break;
@ -435,8 +440,9 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
if (USE_SIMULATED_DEVICE) { if (USE_SIMULATED_DEVICE) {
connector = new RotelSimuConnector(model, protocolHandler, sourcesLabels, readerThreadName); connector = new RotelSimuConnector(model, protocolHandler, sourcesLabels, readerThreadName);
} else if (config.serialPort != null) { } else if (config.serialPort != null) {
connector = new RotelSerialConnector(serialPortManager, config.serialPort, model.getBaudRate(), connector = new RotelSerialConnector(serialPortManager, config.serialPort,
protocolHandler, readerThreadName); config.baudRate != null ? config.baudRate : model.getBaudRate(), protocolHandler,
readerThreadName);
} else { } else {
connector = new RotelIpConnector(config.host, config.port, protocolHandler, readerThreadName); connector = new RotelIpConnector(config.host, config.port, protocolHandler, readerThreadName);
} }
@ -493,6 +499,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
public void dispose() { public void dispose() {
logger.debug("Disposing handler for thing {}", getThing().getUID()); logger.debug("Disposing handler for thing {}", getThing().getUID());
cancelPowerOffJob(); cancelPowerOffJob();
cancelCheckPowerZonesJob();
for (int zone = 0; zone <= model.getNumberOfZones(); zone++) { for (int zone = 0; zone <= model.getNumberOfZones(); zone++) {
cancelPowerOnZoneJob(zone); cancelPowerOnZoneJob(zone);
} }
@ -946,6 +953,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
} }
break; break;
case CHANNEL_SPEAKER_A: case CHANNEL_SPEAKER_A:
case CHANNEL_MAIN_SPEAKER_A:
if (!isPowerOn()) { if (!isPowerOn()) {
success = false; success = false;
logger.debug("Command {} from channel {} ignored: device in standby", command, channel); logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
@ -955,6 +963,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
} }
break; break;
case CHANNEL_SPEAKER_B: case CHANNEL_SPEAKER_B:
case CHANNEL_MAIN_SPEAKER_B:
if (!isPowerOn()) { if (!isPowerOn()) {
success = false; success = false;
logger.debug("Command {} from channel {} ignored: device in standby", command, channel); logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
@ -1431,6 +1440,13 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
throw new RotelException("Invalid value"); throw new RotelException("Invalid value");
} }
break; break;
case KEY_POWER_ZONES:
if (POWER_ON.equalsIgnoreCase(value) || STANDBY.equalsIgnoreCase(value)) {
handlePowerZones(POWER_ON.equalsIgnoreCase(value));
} else {
throw new RotelException("Invalid value");
}
break;
case KEY_POWER_ZONE2: case KEY_POWER_ZONE2:
case KEY_POWER_ZONE3: case KEY_POWER_ZONE3:
case KEY_POWER_ZONE4: case KEY_POWER_ZONE4:
@ -1747,21 +1763,29 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
speakerb = false; speakerb = false;
updateChannelState(CHANNEL_SPEAKER_A); updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B); updateChannelState(CHANNEL_SPEAKER_B);
updateChannelState(CHANNEL_MAIN_SPEAKER_A);
updateChannelState(CHANNEL_MAIN_SPEAKER_B);
} else if (MSG_VALUE_SPEAKER_B.equalsIgnoreCase(value)) { } else if (MSG_VALUE_SPEAKER_B.equalsIgnoreCase(value)) {
speakera = false; speakera = false;
speakerb = true; speakerb = true;
updateChannelState(CHANNEL_SPEAKER_A); updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B); updateChannelState(CHANNEL_SPEAKER_B);
updateChannelState(CHANNEL_MAIN_SPEAKER_A);
updateChannelState(CHANNEL_MAIN_SPEAKER_B);
} else if (MSG_VALUE_SPEAKER_AB.equalsIgnoreCase(value)) { } else if (MSG_VALUE_SPEAKER_AB.equalsIgnoreCase(value)) {
speakera = true; speakera = true;
speakerb = true; speakerb = true;
updateChannelState(CHANNEL_SPEAKER_A); updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B); updateChannelState(CHANNEL_SPEAKER_B);
updateChannelState(CHANNEL_MAIN_SPEAKER_A);
updateChannelState(CHANNEL_MAIN_SPEAKER_B);
} else if (MSG_VALUE_OFF.equalsIgnoreCase(value)) { } else if (MSG_VALUE_OFF.equalsIgnoreCase(value)) {
speakera = false; speakera = false;
speakerb = false; speakerb = false;
updateChannelState(CHANNEL_SPEAKER_A); updateChannelState(CHANNEL_SPEAKER_A);
updateChannelState(CHANNEL_SPEAKER_B); updateChannelState(CHANNEL_SPEAKER_B);
updateChannelState(CHANNEL_MAIN_SPEAKER_A);
updateChannelState(CHANNEL_MAIN_SPEAKER_B);
} else { } else {
throw new RotelException("Invalid value"); throw new RotelException("Invalid value");
} }
@ -1864,11 +1888,30 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
updateChannelState(CHANNEL_MAIN_MUTE); updateChannelState(CHANNEL_MAIN_MUTE);
updateChannelState(CHANNEL_MAIN_BASS); updateChannelState(CHANNEL_MAIN_BASS);
updateChannelState(CHANNEL_MAIN_TREBLE); updateChannelState(CHANNEL_MAIN_TREBLE);
updateChannelState(CHANNEL_MAIN_SPEAKER_A);
updateChannelState(CHANNEL_MAIN_SPEAKER_B);
updateChannelState(CHANNEL_ALL_POWER); updateChannelState(CHANNEL_ALL_POWER);
updateChannelState(CHANNEL_ALL_BRIGHTNESS); updateChannelState(CHANNEL_ALL_BRIGHTNESS);
} }
/**
* Handle the received information that at least one zone power is ON or all zones power is OFF
*/
private void handlePowerZones(boolean power) {
Boolean prev = powerZones;
powerZones = power;
if (prev == null && power) {
// We know that at least one zone is ON but we don't know which ones
scheduleCheckPowerZonesJob();
} else if ((prev == null || prev.booleanValue() != power) && !power) {
cancelCheckPowerZonesJob();
for (int zone = 1; zone <= model.getNumberOfZones(); zone++) {
handlePowerOffZone(zone);
}
}
}
/** /**
* Handle the received information that a zone power is ON * Handle the received information that a zone power is ON
*/ */
@ -2178,6 +2221,41 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
} }
} }
/**
* Schedule the job to run with a few seconds delay
*/
private void scheduleCheckPowerZonesJob() {
logger.debug("Schedule check power zones job");
cancelCheckPowerZonesJob();
powerZonesJob = scheduler.schedule(() -> {
synchronized (sequenceLock) {
logger.debug("Check power zones job");
try {
selectZone(model.getNumberOfZones(), model.getZoneSelectCmd());
} catch (RotelException e) {
logger.debug("Check power zones sequence failed: {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/offline.comm-error-check-power-zones-sequence");
closeConnection();
} catch (InterruptedException e) {
logger.debug("Check power zones sequence interrupted: {}", e.getMessage());
Thread.currentThread().interrupt();
}
}
}, 2500, TimeUnit.MILLISECONDS);
}
/**
* Cancel the job scheduled when the device power (main zone) or a zone power switched ON
*/
private void cancelCheckPowerZonesJob() {
ScheduledFuture<?> job = powerZonesJob;
if (job != null && !job.isCancelled()) {
job.cancel(true);
powerZonesJob = null;
}
}
/** /**
* Schedule the reconnection job * Schedule the reconnection job
*/ */
@ -2443,11 +2521,13 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
} }
break; break;
case CHANNEL_SPEAKER_A: case CHANNEL_SPEAKER_A:
case CHANNEL_MAIN_SPEAKER_A:
if (isPowerOn()) { if (isPowerOn()) {
state = OnOffType.from(speakera); state = OnOffType.from(speakera);
} }
break; break;
case CHANNEL_SPEAKER_B: case CHANNEL_SPEAKER_B:
case CHANNEL_MAIN_SPEAKER_B:
if (isPowerOn()) { if (isPowerOn()) {
state = OnOffType.from(speakerb); state = OnOffType.from(speakerb);
} }
@ -2536,7 +2616,11 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
private RotelCommand getVolumeUpCommand(int numZone) { private RotelCommand getVolumeUpCommand(int numZone) {
switch (numZone) { switch (numZone) {
case 0: case 0:
return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_VOLUME_UP : RotelCommand.VOLUME_UP; // Spec for RX-1052 defines an unusual code for main zone volume up.
// An error in the spec is suspected. The general volume up code is preferred.
return (model.hasOtherThanPrimaryCommands() && model != RotelModel.RX1052)
? RotelCommand.MAIN_ZONE_VOLUME_UP
: RotelCommand.VOLUME_UP;
case 1: case 1:
return RotelCommand.ZONE1_VOLUME_UP; return RotelCommand.ZONE1_VOLUME_UP;
case 2: case 2:
@ -2560,7 +2644,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
private RotelCommand getVolumeDownCommand(int numZone) { private RotelCommand getVolumeDownCommand(int numZone) {
switch (numZone) { switch (numZone) {
case 0: case 0:
return model.hasOtherThanPrimaryCommands() ? RotelCommand.MAIN_ZONE_VOLUME_DOWN // Spec for RX-1052 defines an unusual code for main zone volume down.
// An error in the spec is suspected. The general volume down code is preferred.
return (model.hasOtherThanPrimaryCommands() && model != RotelModel.RX1052)
? RotelCommand.MAIN_ZONE_VOLUME_DOWN
: RotelCommand.VOLUME_DOWN; : RotelCommand.VOLUME_DOWN;
case 1: case 1:
return RotelCommand.ZONE1_VOLUME_DOWN; return RotelCommand.ZONE1_VOLUME_DOWN;

View File

@ -17,6 +17,7 @@ import static org.openhab.binding.rotel.internal.RotelBindingConstants.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
@ -24,6 +25,7 @@ import org.openhab.binding.rotel.internal.RotelException;
import org.openhab.binding.rotel.internal.RotelModel; import org.openhab.binding.rotel.internal.RotelModel;
import org.openhab.binding.rotel.internal.communication.RotelCommand; import org.openhab.binding.rotel.internal.communication.RotelCommand;
import org.openhab.binding.rotel.internal.communication.RotelDsp; import org.openhab.binding.rotel.internal.communication.RotelDsp;
import org.openhab.binding.rotel.internal.communication.RotelFlagInfoType;
import org.openhab.binding.rotel.internal.communication.RotelFlagsMapping; import org.openhab.binding.rotel.internal.communication.RotelFlagsMapping;
import org.openhab.binding.rotel.internal.communication.RotelSource; import org.openhab.binding.rotel.internal.communication.RotelSource;
import org.openhab.binding.rotel.internal.protocol.RotelAbstractProtocolHandler; import org.openhab.binding.rotel.internal.protocol.RotelAbstractProtocolHandler;
@ -93,11 +95,17 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
private static final String KEY_HEX_BYPASS = "bypass"; private static final String KEY_HEX_BYPASS = "bypass";
private static final String KEY1_HEX_ZONE2 = "zone "; private static final String KEY1_HEX_ZONE2 = "zone ";
private static final String KEY2_HEX_ZONE2 = "zone2 "; private static final String KEY2_HEX_ZONE2 = "zone2 ";
private static final String KEY3_HEX_ZONE2 = "z2 ";
private static final String KEY_HEX_ZONE3 = "zone3 "; private static final String KEY_HEX_ZONE3 = "zone3 ";
private static final String KEY2_HEX_ZONE3 = "z3 ";
private static final String KEY_HEX_ZONE4 = "zone4 "; private static final String KEY_HEX_ZONE4 = "zone4 ";
private static final String KEY2_HEX_ZONE4 = "z4 ";
private static final String KEY_HEX_RECORD = "rec "; private static final String KEY_HEX_RECORD = "rec ";
private static final String SOURCE = "source"; private static final String SOURCE = "source";
private static final Pattern PATTERN_TUNER_FREQ_FM = Pattern.compile("\\d{2,3}[\\.,]\\d{1,2}M.*");
private static final Pattern PATTERN_TUNER_FREQ_AM = Pattern.compile("\\d{3,4}K.*");
private final Logger logger = LoggerFactory.getLogger(RotelHexProtocolHandler.class); private final Logger logger = LoggerFactory.getLogger(RotelHexProtocolHandler.class);
private final Map<RotelSource, String> sourcesLabels; private final Map<RotelSource, String> sourcesLabels;
@ -325,25 +333,59 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
} }
} }
} }
try { if (model.isInfoPresentInFlags(RotelFlagInfoType.ZONE2)) {
dispatchKeyValue(KEY_POWER_ZONE2, model.isZone2On(flags) ? POWER_ON : STANDBY); try {
} catch (RotelException e1) { dispatchKeyValue(KEY_POWER_ZONE2,
// Can't get zone power information from flags data, so we just do not notify of this information that way model.isInfoOnInFlags(RotelFlagInfoType.ZONE2, flags) ? POWER_ON : STANDBY);
} catch (RotelException e1) {
// Ignore it
}
} }
try { if (model.isInfoPresentInFlags(RotelFlagInfoType.ZONE3)) {
dispatchKeyValue(KEY_POWER_ZONE3, model.isZone3On(flags) ? POWER_ON : STANDBY); try {
} catch (RotelException e1) { dispatchKeyValue(KEY_POWER_ZONE3,
// Can't get zone power information from flags data, so we just do not notify of this information that way model.isInfoOnInFlags(RotelFlagInfoType.ZONE3, flags) ? POWER_ON : STANDBY);
} catch (RotelException e1) {
// Ignore it
}
} }
try { if (model.isInfoPresentInFlags(RotelFlagInfoType.ZONE4)) {
dispatchKeyValue(KEY_POWER_ZONE4, model.isZone4On(flags) ? POWER_ON : STANDBY); try {
} catch (RotelException e1) { dispatchKeyValue(KEY_POWER_ZONE4,
// Can't get zone power information from flags data, so we just do not notify of this information that way model.isInfoOnInFlags(RotelFlagInfoType.ZONE4, flags) ? POWER_ON : STANDBY);
} catch (RotelException e1) {
// Ignore it
}
}
if (model.isInfoPresentInFlags(RotelFlagInfoType.ZONE)) {
try {
dispatchKeyValue(KEY_POWER_ZONES,
model.isInfoOnInFlags(RotelFlagInfoType.ZONE, flags) ? POWER_ON : STANDBY);
} catch (RotelException e1) {
// Ignore it
}
}
if (model.isInfoPresentInFlags(RotelFlagInfoType.SPEAKER_A)
&& model.isInfoPresentInFlags(RotelFlagInfoType.SPEAKER_B)) {
try {
String speakerValue = MSG_VALUE_OFF;
if (model.isInfoOnInFlags(RotelFlagInfoType.SPEAKER_A, flags)
&& model.isInfoOnInFlags(RotelFlagInfoType.SPEAKER_B, flags)) {
speakerValue = MSG_VALUE_SPEAKER_AB;
} else if (model.isInfoOnInFlags(RotelFlagInfoType.SPEAKER_A, flags)) {
speakerValue = MSG_VALUE_SPEAKER_A;
} else if (model.isInfoOnInFlags(RotelFlagInfoType.SPEAKER_B, flags)) {
speakerValue = MSG_VALUE_SPEAKER_B;
}
dispatchKeyValue(KEY_SPEAKER, speakerValue);
} catch (RotelException e1) {
// Ignore it
}
} }
boolean checkMultiIn = false; boolean checkMultiIn = false;
boolean checkSource = true; boolean checkSource = true;
try { try {
if (model.isMultiInputOn(flags)) { if (model.isInfoOnInFlags(RotelFlagInfoType.MULTI_INPUT, flags)) {
checkSource = false; checkSource = false;
try { try {
RotelSource source = model.getSourceFromName(RotelSource.CAT1_MULTI.getName()); RotelSource source = model.getSourceFromName(RotelSource.CAT1_MULTI.getName());
@ -373,8 +415,9 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
String valueLowerCase = value.trim().toLowerCase(); String valueLowerCase = value.trim().toLowerCase();
if (!valueLowerCase.isEmpty() && !valueLowerCase.startsWith(KEY1_HEX_ZONE2) if (!valueLowerCase.isEmpty() && !valueLowerCase.startsWith(KEY1_HEX_ZONE2)
&& !valueLowerCase.startsWith(KEY2_HEX_ZONE2) && !valueLowerCase.startsWith(KEY_HEX_ZONE3) && !valueLowerCase.startsWith(KEY2_HEX_ZONE2) && !valueLowerCase.startsWith(KEY3_HEX_ZONE2)
&& !valueLowerCase.startsWith(KEY_HEX_ZONE4)) { && !valueLowerCase.startsWith(KEY_HEX_ZONE3) && !valueLowerCase.startsWith(KEY2_HEX_ZONE3)
&& !valueLowerCase.startsWith(KEY_HEX_ZONE4) && !valueLowerCase.startsWith(KEY2_HEX_ZONE4)) {
dispatchKeyValue(KEY_POWER, POWER_ON); dispatchKeyValue(KEY_POWER, POWER_ON);
} }
@ -384,12 +427,12 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
// Line 1 left // Line 1 left
value = new String(incomingMessage, idxChars, 14, StandardCharsets.US_ASCII); value = new String(incomingMessage, idxChars, 14, StandardCharsets.US_ASCII);
logger.debug("handleValidHexMessage: line 1 left *{}*", value); logger.debug("handleValidHexMessage: line 1 left *{}*", value);
parseText(value, checkSource, checkMultiIn, false, false, false, false, false, true); parseText(value, checkSource, checkMultiIn, false, false, false, false, false, false, true, false);
// Line 1 right // Line 1 right
value = new String(incomingMessage, idxChars + 14, 7, StandardCharsets.US_ASCII); value = new String(incomingMessage, idxChars + 14, 7, StandardCharsets.US_ASCII);
logger.debug("handleValidHexMessage: line 1 right *{}*", value); logger.debug("handleValidHexMessage: line 1 right *{}*", value);
parseText(value, false, false, false, false, false, false, false, true); parseText(value, false, false, false, false, false, false, false, false, true, false);
// Full line 1 // Full line 1
value = new String(incomingMessage, idxChars, 21, StandardCharsets.US_ASCII); value = new String(incomingMessage, idxChars, 21, StandardCharsets.US_ASCII);
@ -398,16 +441,18 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
// Line 2 right // Line 2 right
value = new String(incomingMessage, idxChars + 35, 7, StandardCharsets.US_ASCII); value = new String(incomingMessage, idxChars + 35, 7, StandardCharsets.US_ASCII);
logger.debug("handleValidHexMessage: line 2 right *{}*", value); logger.debug("handleValidHexMessage: line 2 right *{}*", value);
parseText(value, false, false, false, false, false, false, false, true); parseText(value, false, false, false, false, false, false, false, false, true, false);
// Full line 2 // Full line 2
value = new String(incomingMessage, idxChars + 21, 21, StandardCharsets.US_ASCII); value = new String(incomingMessage, idxChars + 21, 21, StandardCharsets.US_ASCII);
logger.debug("handleValidHexMessage: line 2 *{}*", value); logger.debug("handleValidHexMessage: line 2 *{}*", value);
parseText(value, false, false, true, true, false, true, true, true); parseText(value, false, false, true, true, false, false, true, true, true, false);
dispatchKeyValue(KEY_LINE2, value); dispatchKeyValue(KEY_LINE2, value);
} else { } else {
value = new String(incomingMessage, idxChars, model.getRespNbChars(), StandardCharsets.US_ASCII); value = new String(incomingMessage, idxChars, model.getRespNbChars(), StandardCharsets.US_ASCII);
parseText(value, checkSource, checkMultiIn, true, false, true, true, checkStereo, false); parseText(value, checkSource, checkMultiIn, true, model.getRespNbChars() == 11,
model.getRespNbChars() != 11, model.getRespNbChars() == 11, model.hasDspControl(), checkStereo,
false, model.getRespNbChars() == 11);
dispatchKeyValue(KEY_LINE1, value); dispatchKeyValue(KEY_LINE1, value);
} }
@ -424,25 +469,28 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
* @param searchMultiIn true if MULTI IN indication has to be searched in the text * @param searchMultiIn true if MULTI IN indication has to be searched in the text
* @param searchZone true if a zone information has to be searched in the text * @param searchZone true if a zone information has to be searched in the text
* @param searchRecord true if a record source has to be searched in the text * @param searchRecord true if a record source has to be searched in the text
* @param searchRecordAfterSource true if a record source has to be searched in the text after the a found source * @param searchRecordAfterSource true if a record source has to be searched in the text after the found source
* @param searchVolumeAfterSource true if a volume value has to be searched in the text after the found source
* @param searchDsp true if a DSP mode has to be searched in the text * @param searchDsp true if a DSP mode has to be searched in the text
* @param searchStereo true if a STEREO has to be considered in the search * @param searchStereo true if a STEREO has to be considered in the search
* @param multipleInfo true if source and volume/mute are provided separately * @param multipleInfo true if source and volume/mute are provided separately
* @param searchTunerFreq true if a tuner frequency has to be searched in the text
*/ */
private void parseText(String text, boolean searchSource, boolean searchMultiIn, boolean searchZone, private void parseText(String text, boolean searchSource, boolean searchMultiIn, boolean searchZone,
boolean searchRecord, boolean searchRecordAfterSource, boolean searchDsp, boolean searchStereo, boolean searchRecord, boolean searchRecordAfterSource, boolean searchVolumeAfterSource, boolean searchDsp,
boolean multipleInfo) { boolean searchStereo, boolean multipleInfo, boolean searchTunerFreq) {
String value = text.trim(); String value = text.trim();
String valueLowerCase = value.toLowerCase(); String valueLowerCase = value.toLowerCase();
if (searchRecord) { if (searchRecord) {
dispatchKeyValue(KEY_RECORD_SEL, valueLowerCase.startsWith(KEY_HEX_RECORD) ? MSG_VALUE_ON : MSG_VALUE_OFF); dispatchKeyValue(KEY_RECORD_SEL, valueLowerCase.startsWith(KEY_HEX_RECORD) ? MSG_VALUE_ON : MSG_VALUE_OFF);
} }
if (searchZone) { if (searchZone) {
if (valueLowerCase.startsWith(KEY1_HEX_ZONE2) || valueLowerCase.startsWith(KEY2_HEX_ZONE2)) { if (valueLowerCase.startsWith(KEY1_HEX_ZONE2) || valueLowerCase.startsWith(KEY2_HEX_ZONE2)
|| valueLowerCase.startsWith(KEY3_HEX_ZONE2)) {
dispatchKeyValue(KEY_ZONE, "2"); dispatchKeyValue(KEY_ZONE, "2");
} else if (valueLowerCase.startsWith(KEY_HEX_ZONE3)) { } else if (valueLowerCase.startsWith(KEY_HEX_ZONE3) || valueLowerCase.startsWith(KEY2_HEX_ZONE3)) {
dispatchKeyValue(KEY_ZONE, "3"); dispatchKeyValue(KEY_ZONE, "3");
} else if (valueLowerCase.startsWith(KEY_HEX_ZONE4)) { } else if (valueLowerCase.startsWith(KEY_HEX_ZONE4) || valueLowerCase.startsWith(KEY2_HEX_ZONE4)) {
dispatchKeyValue(KEY_ZONE, "4"); dispatchKeyValue(KEY_ZONE, "4");
} else { } else {
dispatchKeyValue(KEY_ZONE, "1"); dispatchKeyValue(KEY_ZONE, "1");
@ -555,19 +603,41 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
} else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_MPEG)) { } else if (searchDsp && valueLowerCase.startsWith(KEY_HEX_MPEG)) {
logger.debug("MPEG"); logger.debug("MPEG");
dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback()); dispatchKeyValue(KEY_DSP_MODE, RotelDsp.CAT4_NONE.getFeedback());
} else if (searchZone } else if (searchZone && valueLowerCase.startsWith(KEY1_HEX_ZONE2)) {
&& (valueLowerCase.startsWith(KEY1_HEX_ZONE2) || valueLowerCase.startsWith(KEY2_HEX_ZONE2))) { parseZone2(value.substring(KEY1_HEX_ZONE2.length()), multipleInfo);
value = value.substring( } else if (searchZone && valueLowerCase.startsWith(KEY2_HEX_ZONE2)) {
valueLowerCase.startsWith(KEY1_HEX_ZONE2) ? KEY1_HEX_ZONE2.length() : KEY2_HEX_ZONE2.length()); parseZone2(value.substring(KEY2_HEX_ZONE2.length()), multipleInfo);
parseZone2(value, multipleInfo); } else if (searchZone && valueLowerCase.startsWith(KEY3_HEX_ZONE2)) {
parseZone2(value.substring(KEY3_HEX_ZONE2.length()), multipleInfo);
} else if (searchZone && valueLowerCase.startsWith(KEY_HEX_ZONE3)) { } else if (searchZone && valueLowerCase.startsWith(KEY_HEX_ZONE3)) {
parseZone3(value.substring(KEY_HEX_ZONE3.length()), multipleInfo); parseZone3(value.substring(KEY_HEX_ZONE3.length()), multipleInfo);
} else if (searchZone && valueLowerCase.startsWith(KEY2_HEX_ZONE3)) {
parseZone3(value.substring(KEY2_HEX_ZONE3.length()), multipleInfo);
} else if (searchZone && valueLowerCase.startsWith(KEY_HEX_ZONE4)) { } else if (searchZone && valueLowerCase.startsWith(KEY_HEX_ZONE4)) {
parseZone4(value.substring(KEY_HEX_ZONE4.length()), multipleInfo); parseZone4(value.substring(KEY_HEX_ZONE4.length()), multipleInfo);
} else if (searchZone && valueLowerCase.startsWith(KEY2_HEX_ZONE4)) {
parseZone4(value.substring(KEY2_HEX_ZONE4.length()), multipleInfo);
} else if (searchRecord && valueLowerCase.startsWith(KEY_HEX_RECORD)) { } else if (searchRecord && valueLowerCase.startsWith(KEY_HEX_RECORD)) {
parseRecord(value.substring(KEY_HEX_RECORD.length())); parseRecord(value.substring(KEY_HEX_RECORD.length()));
} else if (searchSource || searchRecordAfterSource) { } else if (searchSource && searchTunerFreq
parseSourceAndRecord(value, searchSource, searchRecordAfterSource, multipleInfo); && (PATTERN_TUNER_FREQ_FM.matcher(value).matches() || PATTERN_TUNER_FREQ_AM.matcher(value).matches())) {
try {
RotelSource source = model.getSourceFromName("TUNER");
RotelCommand cmd = source.getCommand();
if (cmd != null) {
String value2 = cmd.getAsciiCommandV2();
if (value2 != null) {
dispatchKeyValue(KEY_SOURCE, value2);
if (!multipleInfo) {
dispatchKeyValue(KEY_MUTE, MSG_VALUE_OFF);
}
}
}
} catch (RotelException e) {
// Ignore it, no tuner source found for this model
}
} else if (searchSource || searchRecordAfterSource || searchVolumeAfterSource) {
parseSourceAndOther(value, searchSource, searchRecordAfterSource, searchVolumeAfterSource, multipleInfo);
} }
} }
@ -603,8 +673,8 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
return source; return source;
} }
private void parseSourceAndRecord(String text, boolean searchSource, boolean searchRecordAfterSource, private void parseSourceAndOther(String text, boolean searchSource, boolean searchRecordAfterSource,
boolean multipleInfo) { boolean searchVolumeAfterSource, boolean multipleInfo) {
RotelSource source = parseSource(text, false); RotelSource source = parseSource(text, false);
if (source != null) { if (source != null) {
if (searchSource) { if (searchSource) {
@ -620,6 +690,16 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
} }
} }
if (searchVolumeAfterSource) {
String value = extractNumber(text, getSourceLabel(source).length());
if (!value.isEmpty()) {
dispatchKeyValue(KEY_VOLUME, value);
if (!searchSource && !multipleInfo) {
dispatchKeyValue(KEY_MUTE, MSG_VALUE_OFF);
}
}
}
if (searchRecordAfterSource) { if (searchRecordAfterSource) {
String value = text.substring(getSourceLabel(source).length()).trim(); String value = text.substring(getSourceLabel(source).length()).trim();
source = parseSource(value, true); source = parseSource(value, true);
@ -659,6 +739,9 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
private void parseZone2(String text, boolean multipleInfo) { private void parseZone2(String text, boolean multipleInfo) {
String value = text.trim(); String value = text.trim();
if (!model.isInfoPresentInFlags(RotelFlagInfoType.ZONE2)) {
dispatchKeyValue(KEY_POWER_ZONE2, MSG_VALUE_OFF.equalsIgnoreCase(value) ? STANDBY : MSG_VALUE_ON);
}
String valueLowerCase = value.toLowerCase(); String valueLowerCase = value.toLowerCase();
if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) { if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) {
value = extractNumber(value, value = extractNumber(value,
@ -693,6 +776,9 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
private void parseZone3(String text, boolean multipleInfo) { private void parseZone3(String text, boolean multipleInfo) {
String value = text.trim(); String value = text.trim();
if (!model.isInfoPresentInFlags(RotelFlagInfoType.ZONE3)) {
dispatchKeyValue(KEY_POWER_ZONE3, MSG_VALUE_OFF.equalsIgnoreCase(value) ? STANDBY : MSG_VALUE_ON);
}
String valueLowerCase = value.toLowerCase(); String valueLowerCase = value.toLowerCase();
if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) { if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) {
value = extractNumber(value, value = extractNumber(value,
@ -727,6 +813,9 @@ public class RotelHexProtocolHandler extends RotelAbstractProtocolHandler {
private void parseZone4(String text, boolean multipleInfo) { private void parseZone4(String text, boolean multipleInfo) {
String value = text.trim(); String value = text.trim();
if (!model.isInfoPresentInFlags(RotelFlagInfoType.ZONE4)) {
dispatchKeyValue(KEY_POWER_ZONE4, MSG_VALUE_OFF.equalsIgnoreCase(value) ? STANDBY : MSG_VALUE_ON);
}
String valueLowerCase = value.toLowerCase(); String valueLowerCase = value.toLowerCase();
if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) { if (valueLowerCase.startsWith(KEY1_HEX_VOLUME) || valueLowerCase.startsWith(KEY2_HEX_VOLUME)) {
value = extractNumber(value, value = extractNumber(value,

View File

@ -320,4 +320,48 @@
</parameter> </parameter>
</config-description> </config-description>
<config-description uri="thing-type:rotel:serial6">
<parameter name="serialPort" type="text" required="false">
<context>serial-port</context>
<limitToOptions>false</limitToOptions>
<label>@text/config.serialPort.label</label>
<description>@text/config.serialPort.description</description>
</parameter>
<parameter name="baudRate" type="integer" required="false">
<label>@text/config.baudRate.label</label>
<description>@text/config.baudRate.description</description>
<limitToOptions>true</limitToOptions>
<options>
<option value="19200">19200</option>
<option value="38400">38400</option>
</options>
<default>38400</default>
</parameter>
<parameter name="host" type="text" required="false">
<context>network-address</context>
<label>@text/config.hostOverIp.label</label>
<description>@text/config.hostOverIp.description</description>
</parameter>
<parameter name="port" type="integer" required="false">
<label>@text/config.portOverIp.label</label>
<description>@text/config.portOverIp.description</description>
</parameter>
<parameter name="inputLabelVideo1" type="text" required="false">
<label>@text/config.inputLabelVideo1.label</label>
<description>@text/config.inputLabelVideo1.description</description>
</parameter>
<parameter name="inputLabelVideo2" type="text" required="false">
<label>@text/config.inputLabelVideo2.label</label>
<description>@text/config.inputLabelVideo2.description</description>
</parameter>
<parameter name="inputLabelVideo3" type="text" required="false">
<label>@text/config.inputLabelVideo3.label</label>
<description>@text/config.inputLabelVideo3.description</description>
</parameter>
<parameter name="inputLabelVideo4" type="text" required="false">
<label>@text/config.inputLabelVideo4.label</label>
<description>@text/config.inputLabelVideo4.description</description>
</parameter>
</config-description>
</config-description:config-descriptions> </config-description:config-descriptions>

View File

@ -89,6 +89,8 @@ thing-type.rotel.rt11.label = RT-11 Tuner
thing-type.rotel.rt11.description = Connection to the Rotel RT-11 tuner thing-type.rotel.rt11.description = Connection to the Rotel RT-11 tuner
thing-type.rotel.rt1570.label = RT-1570 Tuner thing-type.rotel.rt1570.label = RT-1570 Tuner
thing-type.rotel.rt1570.description = Connection to the Rotel RT-1570 tuner thing-type.rotel.rt1570.description = Connection to the Rotel RT-1570 tuner
thing-type.rotel.rx1052.label = RX-1052 Stereo Receiver
thing-type.rotel.rx1052.description = Connection to the Rotel RX-1052 stereo receiver
thing-type.rotel.s5.label = S5 Stereo Amplifier thing-type.rotel.s5.label = S5 Stereo Amplifier
thing-type.rotel.s5.description = Connection to the Rotel Michi S5 stereo amplifier thing-type.rotel.s5.description = Connection to the Rotel Michi S5 stereo amplifier
thing-type.rotel.t11.label = T11 Tuner thing-type.rotel.t11.label = T11 Tuner
@ -144,6 +146,8 @@ channel-type.rotel.volumeUpDown.description = Increase or decrease the volume
# thing type configuration # thing type configuration
config.baudRate.label = Baud Rate
config.baudRate.description = Baud rate to use for connecting to the Rotel device. Select the highest baud rate if your black unit has at least serial number 090-6441001 or your silver unit has at least serial number 990-6441001.
config.host.label = Address config.host.label = Address
config.host.description = Host name or IP address of the Rotel device (IP connection) or the machine connected to the Rotel device (serial over IP) config.host.description = Host name or IP address of the Rotel device (IP connection) or the machine connected to the Rotel device (serial over IP)
config.hostOverIp.label = Address config.hostOverIp.label = Address
@ -428,6 +432,7 @@ offline.config-error-invalid-port = Invalid port configuration setting
offline.config-error-invalid-serial-over-ip = Use host and port configuration settings for a serial over IP connection offline.config-error-invalid-serial-over-ip = Use host and port configuration settings for a serial over IP connection
offline.comm-error-init-sequence = Init sequence failed offline.comm-error-init-sequence = Init sequence failed
offline.comm-error-init-sequence-zone = Init sequence zone {0} failed offline.comm-error-init-sequence-zone = Init sequence zone {0} failed
offline.comm-error-check-power-zones-sequence = Check power zones sequence failed
offline.comm-error-reading-thread = Reading thread ended offline.comm-error-reading-thread = Reading thread ended
offline.comm-error-sending-command = Sending command failed offline.comm-error-sending-command = Sending command failed
offline.comm-error-reconnection = Reconnection failed offline.comm-error-reconnection = Reconnection failed

View File

@ -90,6 +90,24 @@
</channels> </channels>
</channel-group-type> </channel-group-type>
<channel-group-type id="mainZoneType6">
<label>@text/channel-group.mainZone.label</label>
<description>@text/channel-group.mainZone.description</description>
<channels>
<channel id="power" typeId="system.power"/>
<channel id="source" typeId="source"/>
<channel id="recordSource" typeId="recordSource"/>
<channel id="volume" typeId="system.volume"/>
<channel id="mute" typeId="system.mute"/>
<channel id="bass" typeId="bass"/>
<channel id="treble" typeId="treble"/>
<channel id="speakera" typeId="speakera"/>
<channel id="speakerb" typeId="speakerb"/>
<channel id="line1" typeId="frontPanelLine"/>
<channel id="otherCommand" typeId="otherCommand"/>
</channels>
</channel-group-type>
<channel-group-type id="zone2type1"> <channel-group-type id="zone2type1">
<label>@text/channel-group.zone2.label</label> <label>@text/channel-group.zone2.label</label>
<description>@text/channel-group.zone2.description</description> <description>@text/channel-group.zone2.description</description>

View File

@ -0,0 +1,26 @@
<?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 RX-1052 Connection Thing Type -->
<thing-type id="rx1052">
<label>RX-1052 Stereo Receiver</label>
<description>Connection to the Rotel RX-1052 stereo receiver</description>
<channel-groups>
<channel-group id="mainZone" typeId="mainZoneType6"/>
<channel-group id="zone2" typeId="zone2type1"/>
<channel-group id="zone3" typeId="zone3"/>
<channel-group id="zone4" typeId="zone4"/>
</channel-groups>
<properties>
<property name="protocol">HEX</property>
</properties>
<config-description-ref uri="thing-type:rotel:serial6"/>
</thing-type>
</thing:thing-descriptions>