mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[sonos] Discovery of unsupported models without exception (#12609)
* [sonos] Discovery of unsupported models without exception * Unit tests added for method extractModelName * Replace extractModelName by buildThingTypeIdFromModelName Transform the found model name into a valid thing type ID when trying to match a thing type This could avoid an IllegalArgumentException thrown by the discovery service when new models will be introduced on the market. Should be compatible with Bubble UPnP Server which modifies the model name A message is now logged for unsupported Sonos models. Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
parent
77ed54d338
commit
2a4482a26a
@ -1014,21 +1014,41 @@ public class SonosXMLParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* The model name provided by upnp is formated like in the example form "Sonos PLAY:1" or "Sonos PLAYBAR"
|
||||
* Build a valid thing type ID from the model name provided by UPnP
|
||||
*
|
||||
* @param sonosModelName Sonos model name provided via upnp device
|
||||
* @return the extracted players model name without column (:) character used for ThingType creation
|
||||
* @param sonosModelName Sonos model name provided via UPnP device
|
||||
* @return a valid thing type ID that can then be used for ThingType creation
|
||||
*/
|
||||
public static String extractModelName(String sonosModelName) {
|
||||
String ret = sonosModelName;
|
||||
Matcher matcher = Pattern.compile("\\s(.*)").matcher(ret);
|
||||
public static String buildThingTypeIdFromModelName(String sonosModelName) {
|
||||
// For Ikea SYMFONISK models, the model name now starts with "SYMFONISK" with recent firmwares
|
||||
if (sonosModelName.toUpperCase().contains("SYMFONISK")) {
|
||||
return "SYMFONISK";
|
||||
}
|
||||
String id = sonosModelName;
|
||||
// Remove until the first space (in practice, it removes the leading "Sonos " from the model name)
|
||||
Matcher matcher = Pattern.compile("\\s(.*)").matcher(id);
|
||||
if (matcher.find()) {
|
||||
ret = matcher.group(1);
|
||||
id = matcher.group(1);
|
||||
// Remove a potential ending text surrounded with parenthesis
|
||||
matcher = Pattern.compile("(.*)\\s\\(.*\\)").matcher(id);
|
||||
if (matcher.find()) {
|
||||
id = matcher.group(1);
|
||||
}
|
||||
}
|
||||
if (ret.contains(":")) {
|
||||
ret = ret.replace(":", "");
|
||||
// Finally remove unexpected characters in a thing type ID
|
||||
id = id.replaceAll("[^a-zA-Z0-9_]", "");
|
||||
// ZP80 is translated to CONNECT and ZP100 to CONNECTAMP
|
||||
switch (id) {
|
||||
case "ZP80":
|
||||
id = "CONNECT";
|
||||
break;
|
||||
case "ZP100":
|
||||
id = "CONNECTAMP";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return id;
|
||||
}
|
||||
|
||||
public static String compileMetadataString(SonosEntry entry) {
|
||||
|
@ -80,45 +80,25 @@ public class ZonePlayerDiscoveryParticipant implements UpnpDiscoveryParticipant
|
||||
public @Nullable ThingUID getThingUID(RemoteDevice device) {
|
||||
if (device.getDetails().getManufacturerDetails().getManufacturer() != null) {
|
||||
if (device.getDetails().getManufacturerDetails().getManufacturer().toUpperCase().contains("SONOS")) {
|
||||
boolean ignored = false;
|
||||
String modelName = getModelName(device);
|
||||
switch (modelName) {
|
||||
case "ZP80":
|
||||
modelName = "CONNECT";
|
||||
break;
|
||||
case "ZP100":
|
||||
modelName = "CONNECTAMP";
|
||||
break;
|
||||
case "One SL":
|
||||
modelName = "OneSL";
|
||||
break;
|
||||
case "Arc SL":
|
||||
modelName = "ArcSL";
|
||||
break;
|
||||
case "Roam SL":
|
||||
modelName = "RoamSL";
|
||||
break;
|
||||
case "Sub":
|
||||
// The Sonos Sub is ignored
|
||||
ignored = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!ignored) {
|
||||
ThingTypeUID thingUID = new ThingTypeUID(SonosBindingConstants.BINDING_ID, modelName);
|
||||
if (!SonosBindingConstants.SUPPORTED_KNOWN_THING_TYPES_UIDS.contains(thingUID)) {
|
||||
String id = SonosXMLParser
|
||||
.buildThingTypeIdFromModelName(device.getDetails().getModelDetails().getModelName());
|
||||
if (!"Sub".equalsIgnoreCase(id)) {
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(SonosBindingConstants.BINDING_ID, id);
|
||||
if (!SonosBindingConstants.SUPPORTED_KNOWN_THING_TYPES_UIDS.contains(thingTypeUID)) {
|
||||
// Try with the model name all in uppercase
|
||||
thingUID = new ThingTypeUID(SonosBindingConstants.BINDING_ID, modelName.toUpperCase());
|
||||
thingTypeUID = new ThingTypeUID(SonosBindingConstants.BINDING_ID, id.toUpperCase());
|
||||
// In case a new "unknown" Sonos player is discovered a generic ThingTypeUID will be used
|
||||
if (!SonosBindingConstants.SUPPORTED_KNOWN_THING_TYPES_UIDS.contains(thingUID)) {
|
||||
thingUID = SonosBindingConstants.ZONEPLAYER_THING_TYPE_UID;
|
||||
if (!SonosBindingConstants.SUPPORTED_KNOWN_THING_TYPES_UIDS.contains(thingTypeUID)) {
|
||||
thingTypeUID = SonosBindingConstants.ZONEPLAYER_THING_TYPE_UID;
|
||||
logger.warn(
|
||||
"'{}' is not yet a supported model, thing type '{}' is considered as default; please open an issue",
|
||||
device.getDetails().getModelDetails().getModelName(), thingTypeUID);
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("Discovered a Sonos '{}' thing with UDN '{}'", thingUID,
|
||||
logger.debug("Discovered a Sonos '{}' thing with UDN '{}'", thingTypeUID,
|
||||
device.getIdentity().getUdn().getIdentifierString());
|
||||
return new ThingUID(thingUID, device.getIdentity().getUdn().getIdentifierString());
|
||||
return new ThingUID(thingTypeUID, device.getIdentity().getUdn().getIdentifierString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,13 +106,6 @@ public class ZonePlayerDiscoveryParticipant implements UpnpDiscoveryParticipant
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getModelName(RemoteDevice device) {
|
||||
// For Ikea SYMFONISK models, the model name now starts with "SYMFONISK" with recent firmwares
|
||||
// We can no more use extractModelName as it deletes the first word ("Sonos" for all other devices)
|
||||
return device.getDetails().getModelDetails().getModelName().toUpperCase().contains("SYMFONISK") ? "SYMFONISK"
|
||||
: SonosXMLParser.extractModelName(device.getDetails().getModelDetails().getModelName());
|
||||
}
|
||||
|
||||
private @Nullable String getSonosRoomName(RemoteDevice device) {
|
||||
return SonosXMLParser.getRoomName(device.getIdentity().getDescriptorURL().toString());
|
||||
}
|
||||
|
@ -3292,7 +3292,8 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
|
||||
URL descriptor = service.getDescriptorURL(this);
|
||||
if (descriptor != null) {
|
||||
String sonosModelDescription = SonosXMLParser.parseModelDescription(descriptor);
|
||||
return sonosModelDescription == null ? null : SonosXMLParser.extractModelName(sonosModelDescription);
|
||||
return sonosModelDescription == null ? null
|
||||
: SonosXMLParser.buildThingTypeIdFromModelName(sonosModelDescription);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.sonos.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SonosXMLParserTest {
|
||||
|
||||
@Test
|
||||
public void buildThingTypeIdFromModelWithoutSpace() {
|
||||
assertEquals("Move", SonosXMLParser.buildThingTypeIdFromModelName("Sonos Move"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildThingTypeIdFromModelWithSpace() {
|
||||
assertEquals("RoamSL", SonosXMLParser.buildThingTypeIdFromModelName("Sonos Roam SL"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildThingTypeIdFromModelWithColon() {
|
||||
assertEquals("PLAY5", SonosXMLParser.buildThingTypeIdFromModelName("Sonos PLAY:5"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildThingTypeIdFromSymfoniskModel() {
|
||||
assertEquals("SYMFONISK", SonosXMLParser.buildThingTypeIdFromModelName("SYMFONISK Table lamp"));
|
||||
assertEquals("SYMFONISK", SonosXMLParser.buildThingTypeIdFromModelName("Symfonisk Table lamp"));
|
||||
assertEquals("SYMFONISK", SonosXMLParser.buildThingTypeIdFromModelName("Sonos Symfonisk"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildThingTypeIdFromZP80Model() {
|
||||
assertEquals("CONNECT", SonosXMLParser.buildThingTypeIdFromModelName("Sonos ZP80"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildThingTypeIdFromZP100Model() {
|
||||
assertEquals("CONNECTAMP", SonosXMLParser.buildThingTypeIdFromModelName("Sonos ZP100"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildThingTypeIdFromModelWithAdditionalTextInParenthesis() {
|
||||
assertEquals("OneSL", SonosXMLParser.buildThingTypeIdFromModelName("Sonos One SL (OpenHome)"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user