mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[kaleidescape] Support discovery of Strato V (#17371)
* Support discovery of Strato V Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com> Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
parent
8b3299aa85
commit
d8d5b3da62
@ -16,13 +16,14 @@ The supported thing types are:
|
||||
`player` Any KPlayer, M Class [M300, M500, M700] or Cinema One 1st Gen player
|
||||
`cinemaone` Cinema One (2nd Gen)
|
||||
`alto`
|
||||
`strato` Includes Strato, Strato S, or Strato C
|
||||
`strato` Includes Strato, Strato S, Strato C or Strato V
|
||||
|
||||
The binding supports either a TCP/IP connection or direct serial port connection (19200-8-N-1) to the Kaleidescape component.
|
||||
|
||||
## Discovery
|
||||
|
||||
Manually initiated Auto-discovery will locate all supported Kaleidescape components if they are on the same IP subnet of the openHAB server.
|
||||
Auto-discovery is supported for Alto and Strato components if the device can be located on the local network using UPnP.
|
||||
Manually initiated discovery will locate all legacy Premiere line components if they are on the same IP subnet of the openHAB server.
|
||||
In the Inbox, select Search For Things and then choose the Kaleidescape Binding to initiate a discovery scan.
|
||||
|
||||
## Thing Configuration
|
||||
@ -42,7 +43,6 @@ The thing has the following configuration parameters:
|
||||
|
||||
Some notes:
|
||||
|
||||
- Due to a bug in the control protocol, a Strato C player will be identified as a Premiere 'Player' by the auto discovery process.
|
||||
- The only caveat of note about this binding is the updatePeriod configuration parameter.
|
||||
- When set to the default of 0, the component only sends running time update messages sporadically (as an example: when the movie chapter changes) while content is playing.
|
||||
- In this case, the running time channels will also only sporadically update.
|
||||
|
@ -5,6 +5,7 @@
|
||||
<feature name="openhab-binding-kaleidescape" description="Kaleidescape Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-serial</feature>
|
||||
<feature>openhab-transport-upnp</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.kaleidescape/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
|
@ -35,6 +35,10 @@ public class KaleidescapeBindingConstants {
|
||||
public static final ThingTypeUID THING_TYPE_ALTO = new ThingTypeUID(BINDING_ID, "alto");
|
||||
public static final ThingTypeUID THING_TYPE_STRATO = new ThingTypeUID(BINDING_ID, "strato");
|
||||
|
||||
// Constants related to discovery
|
||||
public static final String PROPERTY_UUID = "uuid";
|
||||
public static final String PROPERTY_HOST_NAME = "host";
|
||||
public static final String PROPERTY_PORT_NUM = "port";
|
||||
public static final int DEFAULT_API_PORT = 10000;
|
||||
public static final int DISCOVERY_THREAD_POOL_SIZE = 15;
|
||||
public static final boolean DISCOVERY_DEFAULT_AUTO_DISCOVER = false;
|
||||
|
@ -76,44 +76,63 @@ public class KaleidescapeStatusCodes {
|
||||
|
||||
static {
|
||||
VIDEO_MODE.put("00", "No output");
|
||||
VIDEO_MODE.put("01", "480i60 4:3");
|
||||
VIDEO_MODE.put("02", "480i60 16:9");
|
||||
VIDEO_MODE.put("03", "480p60 4:3");
|
||||
VIDEO_MODE.put("04", "480p60 16:9");
|
||||
VIDEO_MODE.put("05", "576i50 4:3");
|
||||
VIDEO_MODE.put("06", "576i50 16:9");
|
||||
VIDEO_MODE.put("07", "576p50 4:3");
|
||||
VIDEO_MODE.put("08", "576p50 16:9");
|
||||
VIDEO_MODE.put("09", "720p60 NTSC HD");
|
||||
VIDEO_MODE.put("10", "720p50 PAL HD");
|
||||
VIDEO_MODE.put("11", "1080i60 16:9");
|
||||
VIDEO_MODE.put("12", "1080i50 16:9");
|
||||
VIDEO_MODE.put("13", "1080p60 16:9");
|
||||
VIDEO_MODE.put("14", "1080p50 16:9");
|
||||
VIDEO_MODE.put("15", RESERVED);
|
||||
VIDEO_MODE.put("16", RESERVED);
|
||||
VIDEO_MODE.put("17", "1080p24 16:9");
|
||||
VIDEO_MODE.put("18", RESERVED);
|
||||
VIDEO_MODE.put("19", "480i60 64:27");
|
||||
VIDEO_MODE.put("20", "576i50 64:27");
|
||||
VIDEO_MODE.put("21", "1080i60 64:27");
|
||||
VIDEO_MODE.put("22", "1080i50 64:27");
|
||||
VIDEO_MODE.put("23", "1080p60 64:27");
|
||||
VIDEO_MODE.put("24", "1080p50 64:27");
|
||||
VIDEO_MODE.put("25", "1080p24 64:27");
|
||||
VIDEO_MODE.put("26", "1080p24 64:27");
|
||||
VIDEO_MODE.put("27", "3840x 2160p24 16:9");
|
||||
VIDEO_MODE.put("28", "3840x 2160p24 64:27");
|
||||
VIDEO_MODE.put("29", "3840x 2160p30 16:9");
|
||||
VIDEO_MODE.put("30", "3840x 2160p30 64:27");
|
||||
VIDEO_MODE.put("31", "3840x 2160p60 16:9");
|
||||
VIDEO_MODE.put("32", "3840x 2160p60 64:27");
|
||||
VIDEO_MODE.put("33", "3840x 2160p25 16:9");
|
||||
VIDEO_MODE.put("34", "3840x 2160p25 64:27");
|
||||
VIDEO_MODE.put("35", "3840x 2160p50 16:9");
|
||||
VIDEO_MODE.put("36", "3840x 2160p50 64:27");
|
||||
VIDEO_MODE.put("37", "3840x 2160p24 16:9");
|
||||
VIDEO_MODE.put("38", "3840x 2160p24 64:27");
|
||||
VIDEO_MODE.put("01", "720x480i59.94 4:3");
|
||||
VIDEO_MODE.put("02", "720x480i59.94 16:9");
|
||||
VIDEO_MODE.put("03", "720x480p59.94 4:3");
|
||||
VIDEO_MODE.put("04", "720x480p59.94 16:9");
|
||||
VIDEO_MODE.put("05", "720x576i50 4:3");
|
||||
VIDEO_MODE.put("06", "720x576i50 16:9");
|
||||
VIDEO_MODE.put("07", "720x576p50 4:3");
|
||||
VIDEO_MODE.put("08", "720x576p50 16:9");
|
||||
VIDEO_MODE.put("09", "1280x720p59.94 NTSC HD");
|
||||
VIDEO_MODE.put("10", "1280x720p50 PAL HD");
|
||||
VIDEO_MODE.put("11", "1920x1080i59.94 16:9");
|
||||
VIDEO_MODE.put("12", "1920x1080i50 16:9");
|
||||
VIDEO_MODE.put("13", "1920x1080p59.94 16:9");
|
||||
VIDEO_MODE.put("14", "1920x1080p50 16:9");
|
||||
VIDEO_MODE.put("15", "1280x720p23.976 16:9");
|
||||
VIDEO_MODE.put("16", "1280x720p24 16:9");
|
||||
VIDEO_MODE.put("17", "1920x1080p23.976 16:9");
|
||||
VIDEO_MODE.put("18", "1920x1080p24 16:9");
|
||||
VIDEO_MODE.put("19", "720x480i59.94 64:27");
|
||||
VIDEO_MODE.put("20", "720x576i50 64:27");
|
||||
VIDEO_MODE.put("21", "1920x1080i59.94 64:27");
|
||||
VIDEO_MODE.put("22", "1920x1080i50 64:27");
|
||||
VIDEO_MODE.put("23", "1920x1080p59.94 64:27");
|
||||
VIDEO_MODE.put("24", "1920x1080p50 64:27");
|
||||
VIDEO_MODE.put("25", "1920x1080p23.976 64:27");
|
||||
VIDEO_MODE.put("26", "1920x1080p24 64:27");
|
||||
VIDEO_MODE.put("27", "3840x2160p23.976 16:9");
|
||||
VIDEO_MODE.put("28", "3840x2160p23.976 64:27");
|
||||
VIDEO_MODE.put("29", "3840x2160p29.97 16:9");
|
||||
VIDEO_MODE.put("30", "3840x2160p29.97 64:27");
|
||||
VIDEO_MODE.put("31", "3840x2160p59.94 16:9");
|
||||
VIDEO_MODE.put("32", "3840x2160p59.94 64:27");
|
||||
VIDEO_MODE.put("33", "3840x2160p25 16:9");
|
||||
VIDEO_MODE.put("34", "3840x2160p25 64:27");
|
||||
VIDEO_MODE.put("35", "3840x2160p50 16:9");
|
||||
VIDEO_MODE.put("36", "3840x2160p50 64:27");
|
||||
VIDEO_MODE.put("37", "3840x2160p24 16:9");
|
||||
VIDEO_MODE.put("38", "3840x2160p24 64:27");
|
||||
VIDEO_MODE.put("39", "1280x720p60 16:9");
|
||||
VIDEO_MODE.put("40", "1920x1080i60 16:9");
|
||||
VIDEO_MODE.put("41", "1920x1080i60 64:27");
|
||||
VIDEO_MODE.put("42", "1920x1080p60 16:9");
|
||||
VIDEO_MODE.put("43", "1920x1080p60 64:27");
|
||||
VIDEO_MODE.put("44", "3840x2160p 16:9");
|
||||
VIDEO_MODE.put("45", "3840x2160p 64:27");
|
||||
VIDEO_MODE.put("46", "1280x720p25 16:9");
|
||||
VIDEO_MODE.put("47", "1920x1080p25 16:9");
|
||||
VIDEO_MODE.put("48", "1920x1080p25 64:27");
|
||||
VIDEO_MODE.put("49", RESERVED);
|
||||
VIDEO_MODE.put("50", "1280x720p29.97 16:9");
|
||||
VIDEO_MODE.put("51", "1920x1080p29.97 16:9");
|
||||
VIDEO_MODE.put("52", "1920x1080p29.97 64:27");
|
||||
VIDEO_MODE.put("53", "1280x720p30 16:9");
|
||||
VIDEO_MODE.put("54", "1920x1080p30 16:9");
|
||||
VIDEO_MODE.put("55", "1920x1080p30 64:27");
|
||||
VIDEO_MODE.put("56", "3840x2160p30 16:9");
|
||||
VIDEO_MODE.put("57", "3840x2160p30 64:27");
|
||||
}
|
||||
|
||||
// map to lookup eotf
|
||||
@ -121,8 +140,11 @@ public class KaleidescapeStatusCodes {
|
||||
static {
|
||||
EOTF.put("00", UNKNOWN);
|
||||
EOTF.put("01", "SDR");
|
||||
EOTF.put("02", "HDR");
|
||||
EOTF.put("03", "SMTPE ST 2048");
|
||||
EOTF.put("02", RESERVED);
|
||||
EOTF.put("03", "HDR10");
|
||||
EOTF.put("04", RESERVED);
|
||||
EOTF.put("05", "Dolby Vision - standard");
|
||||
EOTF.put("03", "Dolby Vision - low-latency");
|
||||
}
|
||||
|
||||
// map to lookup readiness state
|
||||
|
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 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.kaleidescape.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.kaleidescape.internal.KaleidescapeBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.jupnp.model.meta.RemoteDevice;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link KaleidescapeDiscoveryParticipant} class discovers Strato/Encore line components automatically via UPnP.
|
||||
*
|
||||
* @author Michael Lobstein - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(immediate = true)
|
||||
public class KaleidescapeDiscoveryParticipant implements UpnpDiscoveryParticipant {
|
||||
private final Logger logger = LoggerFactory.getLogger(KaleidescapeDiscoveryParticipant.class);
|
||||
|
||||
private static final String MANUFACTURER = "Kaleidescape";
|
||||
|
||||
// Component Types
|
||||
private static final String ALTO = "Alto";
|
||||
private static final String STRATO = "Strato";
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
return Set.of(THING_TYPE_ALTO, THING_TYPE_STRATO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DiscoveryResult createResult(RemoteDevice device) {
|
||||
final ThingUID uid = getThingUID(device);
|
||||
if (uid != null) {
|
||||
final Map<String, Object> properties = new HashMap<>(3);
|
||||
final String label;
|
||||
|
||||
if (device.getDetails().getFriendlyName() != null && !device.getDetails().getFriendlyName().isBlank()) {
|
||||
label = device.getDetails().getFriendlyName();
|
||||
} else {
|
||||
label = device.getDetails().getModelDetails().getModelName();
|
||||
}
|
||||
|
||||
properties.put(PROPERTY_UUID, uid.getId());
|
||||
properties.put(PROPERTY_HOST_NAME, device.getIdentity().getDescriptorURL().getHost());
|
||||
properties.put(PROPERTY_PORT_NUM, DEFAULT_API_PORT);
|
||||
|
||||
final DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties)
|
||||
.withRepresentationProperty(PROPERTY_UUID).withLabel(label).build();
|
||||
|
||||
logger.debug("Created a DiscoveryResult for device '{}' with UID '{}'", label, uid.getId());
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingUID getThingUID(RemoteDevice device) {
|
||||
if (device.getDetails().getManufacturerDetails().getManufacturer() != null
|
||||
&& device.getDetails().getModelDetails().getModelName() != null
|
||||
&& device.getDetails().getManufacturerDetails().getManufacturer().startsWith(MANUFACTURER)) {
|
||||
final String modelName = device.getDetails().getModelDetails().getModelName();
|
||||
final String id = device.getIdentity().getUdn().getIdentifierString().replace(":", EMPTY);
|
||||
|
||||
logger.debug("Kaleidescape {} with id {} found at {}", modelName, id,
|
||||
device.getIdentity().getDescriptorURL().getHost());
|
||||
|
||||
if (id.isBlank()) {
|
||||
logger.debug("Invalid UDN for Kaleidescape device: {}", device.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
if (modelName.contains(ALTO)) {
|
||||
return new ThingUID(THING_TYPE_ALTO, id);
|
||||
} else if (modelName.contains(STRATO)) {
|
||||
return new ThingUID(THING_TYPE_STRATO, id);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -25,16 +25,12 @@ import java.net.DatagramSocket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@ -50,7 +46,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link KaleidescapeDiscoveryService} class allow manual discovery of Kaleidescape components.
|
||||
* The {@link KaleidescapeDiscoveryService} class allows manual discovery of legacy Premiere line components.
|
||||
*
|
||||
* @author Chris Graham - Initial contribution
|
||||
* @author Michael Lobstein - Adapted for the Kaleidescape binding
|
||||
@ -60,22 +56,17 @@ import org.slf4j.LoggerFactory;
|
||||
@Component(service = DiscoveryService.class, configurationPid = "discovery.kaleidescape")
|
||||
public class KaleidescapeDiscoveryService extends AbstractDiscoveryService {
|
||||
private final Logger logger = LoggerFactory.getLogger(KaleidescapeDiscoveryService.class);
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
|
||||
.unmodifiableSet(Stream.of(THING_TYPE_PLAYER, THING_TYPE_CINEMA_ONE, THING_TYPE_ALTO, THING_TYPE_STRATO)
|
||||
.collect(Collectors.toSet()));
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_PLAYER,
|
||||
THING_TYPE_CINEMA_ONE);
|
||||
|
||||
private static final int K_HEARTBEAT_PORT = 1443;
|
||||
|
||||
// Component Types
|
||||
private static final String PLAYER = "Player";
|
||||
private static final String CINEMA_ONE = "Cinema One";
|
||||
private static final String ALTO = "Alto";
|
||||
private static final String STRATO = "Strato";
|
||||
private static final String STRATO_S = "Strato S";
|
||||
private static final String DISC_VAULT = "Disc Vault";
|
||||
|
||||
private static final Set<String> ALLOWED_DEVICES = new HashSet<>(
|
||||
Arrays.asList(PLAYER, CINEMA_ONE, ALTO, STRATO, STRATO_S, DISC_VAULT));
|
||||
private static final Set<String> ALLOWED_DEVICES = Set.of(PLAYER, CINEMA_ONE, DISC_VAULT);
|
||||
|
||||
@Nullable
|
||||
private ExecutorService executorService = null;
|
||||
@ -201,13 +192,11 @@ public class KaleidescapeDiscoveryService extends AbstractDiscoveryService {
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
|
||||
|
||||
ThingTypeUID thingTypeUid = THING_TYPE_PLAYER;
|
||||
String friendlyName = EMPTY;
|
||||
String serialNumber = EMPTY;
|
||||
String componentType = EMPTY;
|
||||
String line;
|
||||
String videoZone = null;
|
||||
String audioZone = null;
|
||||
int lineCount = 0;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
@ -217,7 +206,6 @@ public class KaleidescapeDiscoveryService extends AbstractDiscoveryService {
|
||||
switch (strArr[1]) {
|
||||
case "NUM_ZONES":
|
||||
videoZone = strArr[2];
|
||||
audioZone = strArr[3];
|
||||
break;
|
||||
case "DEVICE_TYPE_NAME":
|
||||
componentType = strArr[2];
|
||||
@ -241,39 +229,13 @@ public class KaleidescapeDiscoveryService extends AbstractDiscoveryService {
|
||||
}
|
||||
}
|
||||
|
||||
// see if we have a video zone
|
||||
if ("01".equals(videoZone)) {
|
||||
// now check if we are one of the allowed types
|
||||
if (ALLOWED_DEVICES.contains(componentType)) {
|
||||
if (STRATO_S.equals(componentType) || STRATO.equals(componentType)) {
|
||||
thingTypeUid = THING_TYPE_STRATO;
|
||||
}
|
||||
// see if we have a video zone and are one of the allowed types
|
||||
if ("01".equals(videoZone) && ALLOWED_DEVICES.contains(componentType)) {
|
||||
// default THING_TYPE_PLAYER for Any KPlayer, M Class [M300, M500, M700] or Cinema One 1st Gen
|
||||
// Cinema One 2nd Gen uses THING_TYPE_CINEMA_ONE
|
||||
|
||||
// A 'Player' without an audio zone is really a Strato C
|
||||
// does not work yet, Strato C erroneously reports "01" for audio zones
|
||||
// so we are unable to differentiate a Strato C from a Premiere player
|
||||
if ("00".equals(audioZone) && PLAYER.equals(componentType)) {
|
||||
thingTypeUid = THING_TYPE_STRATO;
|
||||
}
|
||||
|
||||
// Alto
|
||||
if (ALTO.equals(componentType)) {
|
||||
thingTypeUid = THING_TYPE_ALTO;
|
||||
}
|
||||
|
||||
// Cinema One
|
||||
if (CINEMA_ONE.equals(componentType)) {
|
||||
thingTypeUid = THING_TYPE_CINEMA_ONE;
|
||||
}
|
||||
|
||||
// A Disc Vault with a video zone (the M700 vault), just call it a THING_TYPE_PLAYER
|
||||
if (DISC_VAULT.equals(componentType)) {
|
||||
thingTypeUid = THING_TYPE_PLAYER;
|
||||
}
|
||||
|
||||
// default THING_TYPE_PLAYER
|
||||
submitDiscoveryResults(thingTypeUid, ipAddress, friendlyName, serialNumber);
|
||||
}
|
||||
submitDiscoveryResults(CINEMA_ONE.equals(componentType) ? THING_TYPE_CINEMA_ONE : THING_TYPE_PLAYER,
|
||||
ipAddress, friendlyName, serialNumber);
|
||||
} else {
|
||||
logger.debug("No Suitable Kaleidescape component found at IP address ({})", ipAddress);
|
||||
}
|
||||
@ -300,10 +262,10 @@ public class KaleidescapeDiscoveryService extends AbstractDiscoveryService {
|
||||
|
||||
HashMap<String, Object> properties = new HashMap<>();
|
||||
|
||||
properties.put("host", ip);
|
||||
properties.put("port", DEFAULT_API_PORT);
|
||||
properties.put(PROPERTY_HOST_NAME, ip);
|
||||
properties.put(PROPERTY_PORT_NUM, DEFAULT_API_PORT);
|
||||
|
||||
thingDiscovered(DiscoveryResultBuilder.create(uid).withProperties(properties).withRepresentationProperty("host")
|
||||
.withLabel(friendlyName).build());
|
||||
thingDiscovered(DiscoveryResultBuilder.create(uid).withProperties(properties)
|
||||
.withRepresentationProperty(PROPERTY_HOST_NAME).withLabel(friendlyName).build());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user