* [sonos] Add support for Sonos Arc/Arc SL + new controls for sub/surround speakers
Related to #9874
Signed-off-by: Laurent Garnier <lg.hc@free.fr>
* Use OnOffType.from
Signed-off-by: Laurent Garnier <lg.hc@free.fr>
| standalone | Switch | W | Make the Zone Player leave its Group and become a standalone Zone Player | all |
| state | String | R | The State channel contains state of the Zone Player, e.g. PLAYING, STOPPED, ... | all |
| stop | Switch | W | Write `ON` to this channel: Stops the Zone Player player. | all |
+| subwoofer | Switch | RW | Enable or disable the subwoofer | Arc, Arc SL |
+| subwoofergain | Number | RW | Set or get the subwoofer gain adjustment (value in range -15 / 15) | Arc, Arc SL |
+| surround | Switch | RW | Enable or disable the surround audio | Arc, Arc SL |
+| surroundmusicmode | String | RW | Set or get the surround playback mode for music, either 0 for Ambient or 1 for full | Arc, Arc SL |
+| surroundmusiclevel | Number | RW | Set or get the surround level adjustment for music (value in range -15 / 15) | Arc, Arc SL |
+| surroundtvlevel | Number | RW | Set or get the surround level adjustment for TV (value in range -15 / 15) | Arc, Arc SL |
| tuneinstationid | String | RW | Provide the current TuneIn station id or play the TuneIn radio given by its station id | all |
| volume | Dimmer | RW | Set or get the master volume of the Zone Player | all |
| zonegroupid | String | R | Id of the Zone Group the Zone Player belongs to | all |
public static final ThingTypeUID CONNECTAMP_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "CONNECTAMP");
public static final ThingTypeUID AMP_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "Amp");
public static final ThingTypeUID SYMFONISK_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "SYMFONISK");
+ public static final ThingTypeUID ARC_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "Arc");
+ public static final ThingTypeUID ARC_SL_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "ArcSL");
public static final ThingTypeUID ZONEPLAYER_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "zoneplayer");
- public static final Set<ThingTypeUID> WITH_LINEIN_THING_TYPES_UIDS = Stream
- .of(PLAY5_THING_TYPE_UID, PLAYBAR_THING_TYPE_UID, PLAYBASE_THING_TYPE_UID, BEAM_THING_TYPE_UID,
- CONNECT_THING_TYPE_UID, CONNECTAMP_THING_TYPE_UID, PORT_THING_TYPE_UID)
+ public static final Set<ThingTypeUID> WITH_LINEIN_THING_TYPES_UIDS = Stream.of(PLAY5_THING_TYPE_UID,
+ PLAYBAR_THING_TYPE_UID, PLAYBASE_THING_TYPE_UID, BEAM_THING_TYPE_UID, CONNECT_THING_TYPE_UID,
+ CONNECTAMP_THING_TYPE_UID, PORT_THING_TYPE_UID, ARC_THING_TYPE_UID, ARC_SL_THING_TYPE_UID)
.collect(Collectors.toSet());
public static final Set<ThingTypeUID> WITH_ANALOG_LINEIN_THING_TYPES_UIDS = Stream.of(AMP_THING_TYPE_UID)
public static final Set<ThingTypeUID> WITH_DIGITAL_LINEIN_THING_TYPES_UIDS = Stream.of(AMP_THING_TYPE_UID)
.collect(Collectors.toSet());
- public static final Set<ThingTypeUID> SUPPORTED_KNOWN_THING_TYPES_UIDS = Stream.of(ONE_THING_TYPE_UID,
- ONE_SL_THING_TYPE_UID, PLAY1_THING_TYPE_UID, PLAY3_THING_TYPE_UID, PLAY5_THING_TYPE_UID,
- PLAYBAR_THING_TYPE_UID, PLAYBASE_THING_TYPE_UID, BEAM_THING_TYPE_UID, CONNECT_THING_TYPE_UID,
- CONNECTAMP_THING_TYPE_UID, PORT_THING_TYPE_UID, AMP_THING_TYPE_UID, SYMFONISK_THING_TYPE_UID)
+ public static final Set<ThingTypeUID> SUPPORTED_KNOWN_THING_TYPES_UIDS = Stream
+ .of(ONE_THING_TYPE_UID, ONE_SL_THING_TYPE_UID, PLAY1_THING_TYPE_UID, PLAY3_THING_TYPE_UID,
+ PLAY5_THING_TYPE_UID, PLAYBAR_THING_TYPE_UID, PLAYBASE_THING_TYPE_UID, BEAM_THING_TYPE_UID,
+ CONNECT_THING_TYPE_UID, CONNECTAMP_THING_TYPE_UID, PORT_THING_TYPE_UID, AMP_THING_TYPE_UID,
+ SYMFONISK_THING_TYPE_UID, ARC_THING_TYPE_UID, ARC_SL_THING_TYPE_UID)
.collect(Collectors.toSet());
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<>(SUPPORTED_KNOWN_THING_TYPES_UIDS);
public static final String STANDALONE = "standalone";
public static final String STATE = "state";
public static final String STOP = "stop";
+ public static final String SUBWOOFER = "subwoofer";
+ public static final String SUBWOOFERGAIN = "subwoofergain";
+ public static final String SURROUND = "surround";
+ public static final String SURROUNDMUSICMODE = "surroundmusicmode";
+ public static final String SURROUNDMUSICLEVEL = "surroundmusiclevel";
+ public static final String SURROUNDTVLEVEL = "surroundtvlevel";
public static final String TUNEINSTATIONID = "tuneinstationid";
public static final String VOLUME = "volume";
public static final String ZONEGROUPID = "zonegroupid";
case "One SL":
modelName = "OneSL";
break;
+ case "Arc SL":
+ modelName = "ArcSL";
+ break;
default:
break;
}
private static final int TUNEIN_DEFAULT_SERVICE_TYPE = 65031;
+ private static final int MIN_SUBWOOFER_GAIN = -15;
+ private static final int MAX_SUBWOOFER_GAIN = 15;
+ private static final int MIN_SURROUND_LEVEL = -15;
+ private static final int MAX_SURROUND_LEVEL = 15;
+
private final Logger logger = LoggerFactory.getLogger(ZonePlayerHandler.class);
private final ThingRegistry localThingRegistry;
case VOLUME:
setVolumeForGroup(command);
break;
+ case SUBWOOFER:
+ setSubwoofer(command);
+ break;
+ case SUBWOOFERGAIN:
+ setSubwooferGain(command);
+ break;
+ case SURROUND:
+ setSurround(command);
+ break;
+ case SURROUNDMUSICMODE:
+ setSurroundMusicMode(command);
+ break;
+ case SURROUNDMUSICLEVEL:
+ setSurroundMusicLevel(command);
+ break;
+ case SURROUNDTVLEVEL:
+ setSurroundTvLevel(command);
+ break;
case ADD:
addMember(command);
break;
case "MuteMaster":
updateChannel(MUTE);
break;
+ case "SubEnabled":
+ updateChannel(SUBWOOFER);
+ break;
+ case "SubGain":
+ updateChannel(SUBWOOFERGAIN);
+ break;
+ case "SurroundEnabled":
+ updateChannel(SURROUND);
+ break;
+ case "SurroundMode":
+ updateChannel(SURROUNDMUSICMODE);
+ break;
+ case "SurroundLevel":
+ updateChannel(SURROUNDTVLEVEL);
+ break;
+ case "MusicSurroundLevel":
+ updateChannel(SURROUNDMUSICLEVEL);
+ break;
case "NightMode":
updateChannel(NIGHTMODE);
break;
newState = isMuted() ? OnOffType.ON : OnOffType.OFF;
}
break;
+ case SUBWOOFER:
+ value = getSubwooferEnabled();
+ if (value != null) {
+ newState = OnOffType.from(value);
+ }
+ break;
+ case SUBWOOFERGAIN:
+ value = getSubwooferGain();
+ if (value != null) {
+ newState = new DecimalType(value);
+ }
+ break;
+ case SURROUND:
+ value = getSurroundEnabled();
+ if (value != null) {
+ newState = OnOffType.from(value);
+ }
+ break;
+ case SURROUNDMUSICMODE:
+ value = getSurroundMusicMode();
+ if (value != null) {
+ newState = new StringType(value);
+ }
+ break;
+ case SURROUNDMUSICLEVEL:
+ value = getSurroundMusicLevel();
+ if (value != null) {
+ newState = new DecimalType(value);
+ }
+ break;
+ case SURROUNDTVLEVEL:
+ value = getSurroundTvLevel();
+ if (value != null) {
+ newState = new DecimalType(value);
+ }
+ break;
case NIGHTMODE:
value = getNightMode();
if (value != null) {
return stateMap.get("VolumeMaster");
}
+ public @Nullable String getSurroundEnabled() {
+ return stateMap.get("SurroundEnabled");
+ }
+
+ public @Nullable String getSurroundMusicMode() {
+ return stateMap.get("SurroundMode");
+ }
+
+ public @Nullable String getSurroundTvLevel() {
+ return stateMap.get("SurroundLevel");
+ }
+
+ public @Nullable String getSurroundMusicLevel() {
+ return stateMap.get("MusicSurroundLevel");
+ }
+
+ public @Nullable String getSubwooferEnabled() {
+ return stateMap.get("SubEnabled");
+ }
+
+ public @Nullable String getSubwooferGain() {
+ return stateMap.get("SubGain");
+ }
+
public @Nullable String getTransportState() {
return stateMap.get("TransportState");
}
}
}
- public void setNightMode(Command command) {
- if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
- setEQ("NightMode", (command.equals(OnOffType.ON) || command.equals(UpDownType.UP)
- || command.equals(OpenClosedType.OPEN)) ? "1" : "0");
+ public void setSubwoofer(Command command) {
+ setEqualizerBooleanSetting(command, "SubEnabled");
+ }
+
+ public void setSubwooferGain(Command command) {
+ setEqualizerNumericSetting(command, "SubGain", getSubwooferGain(), MIN_SUBWOOFER_GAIN, MAX_SUBWOOFER_GAIN);
+ }
+
+ public void setSurround(Command command) {
+ setEqualizerBooleanSetting(command, "SurroundEnabled");
+ }
+
+ public void setSurroundMusicMode(Command command) {
+ if (command instanceof StringType) {
+ setEQ("SurroundMode", command.toString());
}
}
+ public void setSurroundMusicLevel(Command command) {
+ setEqualizerNumericSetting(command, "MusicSurroundLevel", getSurroundMusicLevel(), MIN_SURROUND_LEVEL,
+ MAX_SURROUND_LEVEL);
+ }
+
+ public void setSurroundTvLevel(Command command) {
+ setEqualizerNumericSetting(command, "SurroundLevel", getSurroundTvLevel(), MIN_SURROUND_LEVEL,
+ MAX_SURROUND_LEVEL);
+ }
+
+ public void setNightMode(Command command) {
+ setEqualizerBooleanSetting(command, "NightMode");
+ }
+
public void setSpeechEnhancement(Command command) {
+ setEqualizerBooleanSetting(command, "DialogLevel");
+ }
+
+ private void setEqualizerBooleanSetting(Command command, String eqType) {
if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
- setEQ("DialogLevel", (command.equals(OnOffType.ON) || command.equals(UpDownType.UP)
+ setEQ(eqType, (command.equals(OnOffType.ON) || command.equals(UpDownType.UP)
|| command.equals(OpenClosedType.OPEN)) ? "1" : "0");
}
}
+ private void setEqualizerNumericSetting(Command command, String eqType, @Nullable String currentValue, int minValue,
+ int maxValue) {
+ if (command instanceof IncreaseDecreaseType || command instanceof DecimalType) {
+ String newValue = null;
+ if (command == IncreaseDecreaseType.INCREASE && currentValue != null) {
+ int i = Integer.valueOf(currentValue);
+ newValue = String.valueOf(Math.min(maxValue, i + 1));
+ } else if (command == IncreaseDecreaseType.DECREASE && currentValue != null) {
+ int i = Integer.valueOf(currentValue);
+ newValue = String.valueOf(Math.max(minValue, i - 1));
+ } else if (command instanceof DecimalType) {
+ newValue = String.valueOf(((DecimalType) command).intValue());
+ } else {
+ return;
+ }
+ setEQ(eqType, newValue);
+ }
+ }
+
private void setEQ(String eqType, String value) {
try {
Map<String, String> inputs = new HashMap<>();
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="sonos"
+ 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">
+
+ <!-- Soundbar Arc Thing Type -->
+ <thing-type id="Arc" listed="false">
+ <label>Arc</label>
+ <description>Represents SONOS Arc soundbar</description>
+
+ <channels>
+ <channel id="add" typeId="add"/>
+ <channel id="alarm" typeId="alarm"/>
+ <channel id="alarmproperties" typeId="alarmproperties"/>
+ <channel id="alarmrunning" typeId="alarmrunning"/>
+ <channel id="control" typeId="system.media-control"/>
+ <channel id="currentalbum" typeId="currentalbum"/>
+ <channel id="currentalbumart" typeId="currentalbumart"/>
+ <channel id="currentalbumarturl" typeId="currentalbumarturl"/>
+ <channel id="currentartist" typeId="system.media-artist"/>
+ <channel id="currenttitle" typeId="system.media-title"/>
+ <channel id="currenttrack" typeId="currenttrack"/>
+ <channel id="shuffle" typeId="shuffle"/>
+ <channel id="repeat" typeId="repeat"/>
+ <channel id="favorite" typeId="favorite"/>
+ <channel id="led" typeId="led"/>
+ <channel id="localcoordinator" typeId="localcoordinator"/>
+ <channel id="mute" typeId="system.mute"/>
+ <channel id="notificationsound" typeId="notificationsound"/>
+ <channel id="playlist" typeId="playlist"/>
+ <channel id="clearqueue" typeId="clearqueue"/>
+ <channel id="playlinein" typeId="playlinein"/>
+ <channel id="playqueue" typeId="playqueue"/>
+ <channel id="playtrack" typeId="playtrack"/>
+ <channel id="playuri" typeId="playuri"/>
+ <channel id="publicaddress" typeId="publicaddress"/>
+ <channel id="radio" typeId="radio"/>
+ <channel id="remove" typeId="remove"/>
+ <channel id="restore" typeId="restore"/>
+ <channel id="restoreall" typeId="restoreall"/>
+ <channel id="save" typeId="save"/>
+ <channel id="saveall" typeId="saveall"/>
+ <channel id="snooze" typeId="snooze"/>
+ <channel id="standalone" typeId="standalone"/>
+ <channel id="state" typeId="state"/>
+ <channel id="stop" typeId="stop"/>
+ <channel id="tuneinstationid" typeId="tuneinstationid"/>
+ <channel id="volume" typeId="system.volume"/>
+ <channel id="zonegroupid" typeId="zonegroupid"/>
+ <channel id="zonename" typeId="zonename"/>
+ <channel id="coordinator" typeId="coordinator"/>
+ <channel id="sleeptimer" typeId="sleeptimer"/>
+ <channel id="currenttransporturi" typeId="currenttransporturi"/>
+ <channel id="currenttrackuri" typeId="currenttrackuri"/>
+ <!-- Extended SONOS channels -->
+ <channel id="linein" typeId="linein"/>
+ <channel id="nightmode" typeId="nightmode"/>
+ <channel id="speechenhancement" typeId="speechenhancement"/>
+ <channel id="subwoofer" typeId="subwoofer"/>
+ <channel id="subwoofergain" typeId="subwoofergain"/>
+ <channel id="surround" typeId="surround"/>
+ <channel id="surroundmusicmode" typeId="surroundmusicmode"/>
+ <channel id="surroundmusiclevel" typeId="surroundmusiclevel"/>
+ <channel id="surroundtvlevel" typeId="surroundtvlevel"/>
+ </channels>
+
+ <properties>
+ <property name="vendor">SONOS</property>
+ <property name="modelId">Arc</property>
+ </properties>
+
+ <representation-property>udn</representation-property>
+
+ <config-description-ref uri="thing-type:sonos:zoneplayer"/>
+ </thing-type>
+</thing:thing-descriptions>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="sonos"
+ 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">
+
+ <!-- Soundbar Arc SL Thing Type -->
+ <thing-type id="ArcSL" listed="false">
+ <label>Arc</label>
+ <description>Represents SONOS Arc SL soundbar</description>
+
+ <channels>
+ <channel id="add" typeId="add"/>
+ <channel id="alarm" typeId="alarm"/>
+ <channel id="alarmproperties" typeId="alarmproperties"/>
+ <channel id="alarmrunning" typeId="alarmrunning"/>
+ <channel id="control" typeId="system.media-control"/>
+ <channel id="currentalbum" typeId="currentalbum"/>
+ <channel id="currentalbumart" typeId="currentalbumart"/>
+ <channel id="currentalbumarturl" typeId="currentalbumarturl"/>
+ <channel id="currentartist" typeId="system.media-artist"/>
+ <channel id="currenttitle" typeId="system.media-title"/>
+ <channel id="currenttrack" typeId="currenttrack"/>
+ <channel id="shuffle" typeId="shuffle"/>
+ <channel id="repeat" typeId="repeat"/>
+ <channel id="favorite" typeId="favorite"/>
+ <channel id="led" typeId="led"/>
+ <channel id="localcoordinator" typeId="localcoordinator"/>
+ <channel id="mute" typeId="system.mute"/>
+ <channel id="notificationsound" typeId="notificationsound"/>
+ <channel id="playlist" typeId="playlist"/>
+ <channel id="clearqueue" typeId="clearqueue"/>
+ <channel id="playlinein" typeId="playlinein"/>
+ <channel id="playqueue" typeId="playqueue"/>
+ <channel id="playtrack" typeId="playtrack"/>
+ <channel id="playuri" typeId="playuri"/>
+ <channel id="publicaddress" typeId="publicaddress"/>
+ <channel id="radio" typeId="radio"/>
+ <channel id="remove" typeId="remove"/>
+ <channel id="restore" typeId="restore"/>
+ <channel id="restoreall" typeId="restoreall"/>
+ <channel id="save" typeId="save"/>
+ <channel id="saveall" typeId="saveall"/>
+ <channel id="snooze" typeId="snooze"/>
+ <channel id="standalone" typeId="standalone"/>
+ <channel id="state" typeId="state"/>
+ <channel id="stop" typeId="stop"/>
+ <channel id="tuneinstationid" typeId="tuneinstationid"/>
+ <channel id="volume" typeId="system.volume"/>
+ <channel id="zonegroupid" typeId="zonegroupid"/>
+ <channel id="zonename" typeId="zonename"/>
+ <channel id="coordinator" typeId="coordinator"/>
+ <channel id="sleeptimer" typeId="sleeptimer"/>
+ <channel id="currenttransporturi" typeId="currenttransporturi"/>
+ <channel id="currenttrackuri" typeId="currenttrackuri"/>
+ <!-- Extended SONOS channels -->
+ <channel id="linein" typeId="linein"/>
+ <channel id="nightmode" typeId="nightmode"/>
+ <channel id="speechenhancement" typeId="speechenhancement"/>
+ <channel id="subwoofer" typeId="subwoofer"/>
+ <channel id="subwoofergain" typeId="subwoofergain"/>
+ <channel id="surround" typeId="surround"/>
+ <channel id="surroundmusicmode" typeId="surroundmusicmode"/>
+ <channel id="surroundmusiclevel" typeId="surroundmusiclevel"/>
+ <channel id="surroundtvlevel" typeId="surroundtvlevel"/>
+ </channels>
+
+ <properties>
+ <property name="vendor">SONOS</property>
+ <property name="modelId">Arc SL</property>
+ </properties>
+
+ <representation-property>udn</representation-property>
+
+ <config-description-ref uri="thing-type:sonos:zoneplayer"/>
+ </thing-type>
+</thing:thing-descriptions>
<description>Stop the Zone Player. ON if the player is stopped.</description>
</channel-type>
+ <channel-type id="subwoofer" advanced="true">
+ <item-type>Switch</item-type>
+ <label>Subwoofer</label>
+ <description>Enable or disable the subwoofer</description>
+ </channel-type>
+
+ <channel-type id="subwoofergain" advanced="true">
+ <item-type>Number</item-type>
+ <label>Subwoofer Gain</label>
+ <description>Set or get the subwoofer gain adjustment</description>
+ <state min="-15" max="15" step="1" readOnly="false" pattern="%d"/>
+ </channel-type>
+
+ <channel-type id="surround" advanced="true">
+ <item-type>Switch</item-type>
+ <label>Surround Audio</label>
+ <description>Enable or disable the surround audio</description>
+ </channel-type>
+
+ <channel-type id="surroundmusicmode" advanced="true">
+ <item-type>String</item-type>
+ <label>Surround Music Mode</label>
+ <description>Set or get the surround playback mode for music</description>
+ <state readOnly="false">
+ <options>
+ <option value="0">Ambient</option>
+ <option value="1">Full</option>
+ </options>
+ </state>
+ </channel-type>
+
+ <channel-type id="surroundmusiclevel" advanced="true">
+ <item-type>Number</item-type>
+ <label>Surround Music Level</label>
+ <description>Set or get the surround level adjustment for music</description>
+ <state min="-15" max="15" step="1" readOnly="false" pattern="%d"/>
+ </channel-type>
+
+ <channel-type id="surroundtvlevel" advanced="true">
+ <item-type>Number</item-type>
+ <label>Surround TV Level</label>
+ <description>Set or get the surround level adjustment for TV</description>
+ <state min="-15" max="15" step="1" readOnly="false" pattern="%d"/>
+ </channel-type>
+
<channel-type id="tuneinstationid" advanced="true">
<item-type>String</item-type>
<label>TuneIn Station Id</label>