diff --git a/bundles/org.openhab.binding.sonyprojector/README.md b/bundles/org.openhab.binding.sonyprojector/README.md index ab473a0e9b9..3501a50c852 100644 --- a/bundles/org.openhab.binding.sonyprojector/README.md +++ b/bundles/org.openhab.binding.sonyprojector/README.md @@ -94,8 +94,8 @@ This binding supports the following thing types: ## Discovery -Discovery is not supported at the moment. -You have to add all things manually. +If the projector is connected via Ethernet and the 'Start SDDP Service' option is present and enabled in the projector Advanced Settings->Service page, the Thing using Ethernet connection and PJ Talk will be discovered automatically. +Serial or Serial over IP connections must be configured manually. ## Binding Configuration diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/feature/feature.xml b/bundles/org.openhab.binding.sonyprojector/src/main/feature/feature.xml index e4b84c94f63..36b97ec5519 100644 --- a/bundles/org.openhab.binding.sonyprojector/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.sonyprojector/src/main/feature/feature.xml @@ -5,6 +5,7 @@ openhab-runtime-base openhab-transport-serial + openhab-core-config-discovery-sddp mvn:org.openhab.addons.bundles/org.openhab.binding.sonyprojector/${project.version} diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/SonyProjectorItem.java b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/SonyProjectorItem.java index 76743a41cd1..d57aff1b254 100644 --- a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/SonyProjectorItem.java +++ b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/SonyProjectorItem.java @@ -143,6 +143,9 @@ public enum SonyProjectorItem { SERIAL_NUMBER("Serial Number", new byte[] { (byte) 0x80, 0x02 }), INSTALLATION_LOCATION("Installation Location", new byte[] { (byte) 0x80, 0x03 }), + MAC_ADDRESS("MAC Address", new byte[] { (byte) 0x90, 0x00 }), + IP_ADDRESS("IP Address", new byte[] { (byte) 0x90, 0x01 }), + MENU("Menu", null, new byte[] { 0x17, 0x29 }), UP("Cursor UP", null, new byte[] { 0x17, 0x35 }), DOWN("Cursor DOWN", null, new byte[] { 0x17, 0x36 }), diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/sdcp/SonyProjectorSdcpConnector.java b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/sdcp/SonyProjectorSdcpConnector.java index 5f32f583c08..c97b7ddf8a7 100644 --- a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/sdcp/SonyProjectorSdcpConnector.java +++ b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/sdcp/SonyProjectorSdcpConnector.java @@ -311,4 +311,15 @@ public class SonyProjectorSdcpConnector extends SonyProjectorConnector { public String getModelName() throws SonyProjectorException { return new String(getSetting(SonyProjectorItem.MODEL_NAME), StandardCharsets.UTF_8); } + + /** + * Request the MAC address + * + * @return the MAC address + * + * @throws SonyProjectorException in case of any problem + */ + public String getMacAddress() throws SonyProjectorException { + return new String(getSetting(SonyProjectorItem.MAC_ADDRESS), StandardCharsets.UTF_8); + } } diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorEthernetConfiguration.java b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorEthernetConfiguration.java index dfec1e7bff5..15f965fd466 100644 --- a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorEthernetConfiguration.java +++ b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorEthernetConfiguration.java @@ -13,7 +13,6 @@ package org.openhab.binding.sonyprojector.internal.configuration; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; /** * The {@link SonyProjectorEthernetConfiguration} class contains fields mapping thing configuration parameters. @@ -23,9 +22,12 @@ import org.eclipse.jdt.annotation.Nullable; */ @NonNullByDefault public class SonyProjectorEthernetConfiguration { + public static final int DEFAULT_PORT = 53484; + private static final String DEFAULT_COMMUNITY = "SONY"; + public static final String MODEL_AUTO = "AUTO"; - public @NonNullByDefault({}) String host; - public @Nullable Integer port; - public @Nullable String community; - public @Nullable String model; + public String host = ""; + public int port = DEFAULT_PORT; + public String community = DEFAULT_COMMUNITY; + public String model = MODEL_AUTO; } diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialConfiguration.java b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialConfiguration.java index 27e5f62d2fa..b9f470f78c2 100644 --- a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialConfiguration.java +++ b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialConfiguration.java @@ -13,6 +13,7 @@ package org.openhab.binding.sonyprojector.internal.configuration; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.sonyprojector.internal.handler.SonyProjectorHandler; /** * The {@link SonyProjectorSerialConfiguration} class contains fields mapping thing configuration parameters. @@ -21,7 +22,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault; */ @NonNullByDefault public class SonyProjectorSerialConfiguration { - - public @NonNullByDefault({}) String port; - public @NonNullByDefault({}) String model; + public String port = ""; + public String model = SonyProjectorHandler.DEFAULT_MODEL.getName(); } diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialOverIpConfiguration.java b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialOverIpConfiguration.java index e39669e1792..3bd6ac37758 100644 --- a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialOverIpConfiguration.java +++ b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialOverIpConfiguration.java @@ -13,6 +13,7 @@ package org.openhab.binding.sonyprojector.internal.configuration; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.sonyprojector.internal.handler.SonyProjectorHandler; /** * The {@link SonyProjectorSerialOverIpConfiguration} class contains fields mapping thing configuration parameters. @@ -21,8 +22,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; */ @NonNullByDefault public class SonyProjectorSerialOverIpConfiguration { - - public @NonNullByDefault({}) String host; - public @NonNullByDefault({}) Integer port; - public @NonNullByDefault({}) String model; + public String host = ""; + public int port; + public String model = SonyProjectorHandler.DEFAULT_MODEL.getName(); } diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/discovery/SonyProjectorDiscoveryParticipant.java b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/discovery/SonyProjectorDiscoveryParticipant.java new file mode 100644 index 00000000000..36e30a756a3 --- /dev/null +++ b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/discovery/SonyProjectorDiscoveryParticipant.java @@ -0,0 +1,82 @@ +/** + * 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.sonyprojector.internal.discovery; + +import static org.openhab.binding.sonyprojector.internal.SonyProjectorBindingConstants.THING_TYPE_ETHERNET; + +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.sonyprojector.internal.configuration.SonyProjectorEthernetConfiguration; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.config.discovery.sddp.SddpDevice; +import org.openhab.core.config.discovery.sddp.SddpDiscoveryParticipant; +import org.openhab.core.thing.Thing; +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; + +/** + * Discovery Service for Sony Projectors that support SDDP. + * + * @author Laurent Garnier - Initial contribution + * + */ +@NonNullByDefault +@Component(immediate = true) +public class SonyProjectorDiscoveryParticipant implements SddpDiscoveryParticipant { + private final Logger logger = LoggerFactory.getLogger(SonyProjectorDiscoveryParticipant.class); + + private static final String SONY = "SONY"; + private static final String TYPE_PROJECTOR = "PROJECTOR"; + + @Override + public Set getSupportedThingTypeUIDs() { + return Set.of(THING_TYPE_ETHERNET); + } + + @Override + public @Nullable DiscoveryResult createResult(SddpDevice device) { + final ThingUID uid = getThingUID(device); + if (uid != null) { + final String label = device.manufacturer + " " + device.model; + final Map properties = Map.of("host", device.ipAddress, // + "port", SonyProjectorEthernetConfiguration.DEFAULT_PORT, // + "model", SonyProjectorEthernetConfiguration.MODEL_AUTO, // + Thing.PROPERTY_MAC_ADDRESS, device.macAddress); + logger.debug("Created a DiscoveryResult for device '{}' with UID '{}'", label, uid.getId()); + return DiscoveryResultBuilder.create(uid).withProperties(properties) + .withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS).withLabel(label).build(); + } else { + return null; + } + } + + @Override + public @Nullable ThingUID getThingUID(SddpDevice device) { + if (device.manufacturer.toUpperCase(Locale.ENGLISH).contains(SONY) + && device.type.toUpperCase(Locale.ENGLISH).contains(TYPE_PROJECTOR) && !device.macAddress.isBlank() + && !device.ipAddress.isBlank()) { + + logger.debug("Sony projector with mac {} found at {}", device.macAddress, device.ipAddress); + return new ThingUID(THING_TYPE_ETHERNET, device.macAddress); + } + return null; + } +} diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/handler/SonyProjectorHandler.java b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/handler/SonyProjectorHandler.java index 620e6c40d95..bfd2485b9dd 100644 --- a/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/handler/SonyProjectorHandler.java +++ b/bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/handler/SonyProjectorHandler.java @@ -13,6 +13,7 @@ package org.openhab.binding.sonyprojector.internal.handler; import static org.openhab.binding.sonyprojector.internal.SonyProjectorBindingConstants.*; +import static org.openhab.binding.sonyprojector.internal.configuration.SonyProjectorEthernetConfiguration.MODEL_AUTO; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -67,7 +68,7 @@ import org.slf4j.LoggerFactory; @NonNullByDefault public class SonyProjectorHandler extends BaseThingHandler { - private static final SonyProjectorModel DEFAULT_MODEL = SonyProjectorModel.VW520; + public static final SonyProjectorModel DEFAULT_MODEL = SonyProjectorModel.VW528; private static final long POLLING_INTERVAL = TimeUnit.SECONDS.toSeconds(15); private final Logger logger = LoggerFactory.getLogger(SonyProjectorHandler.class); @@ -83,6 +84,7 @@ public class SonyProjectorHandler extends BaseThingHandler { private @Nullable ScheduledFuture refreshJob; + private boolean identifyMac; private boolean identifyProjector; private SonyProjectorModel projectorModel = DEFAULT_MODEL; private SonyProjectorConnector connector = new SonyProjectorSdcpSimuConnector(DEFAULT_MODEL); @@ -321,10 +323,13 @@ public class SonyProjectorHandler extends BaseThingHandler { logger.debug("Ethernet config port {}", config.port); logger.debug("Ethernet config model {}", configModel); logger.debug("Ethernet config community {}", config.community); - if (config.host == null || config.host.isEmpty()) { + if (config.host.isBlank()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.config-error-unknown-host"); - } else if (configModel == null || configModel.isEmpty()) { + } else if (config.port <= 0) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "@text/offline.config-error-invalid-port"); + } else if (configModel.isBlank()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.config-error-unknown-model"); } else { @@ -332,8 +337,9 @@ public class SonyProjectorHandler extends BaseThingHandler { connector = simu ? new SonyProjectorSdcpSimuConnector(DEFAULT_MODEL) : new SonyProjectorSdcpConnector(config.host, config.port, config.community, DEFAULT_MODEL); - identifyProjector = "AUTO".equals(configModel); - projectorModel = switchToModel("AUTO".equals(configModel) ? null : configModel, true); + identifyMac = getThing().getProperties().get(Thing.PROPERTY_MAC_ADDRESS) == null; + identifyProjector = MODEL_AUTO.equals(configModel); + projectorModel = switchToModel(identifyProjector ? null : configModel, true); updateStatus(ThingStatus.UNKNOWN); } @@ -342,13 +348,13 @@ public class SonyProjectorHandler extends BaseThingHandler { String configModel = config.model; logger.debug("Serial config port {}", config.port); logger.debug("Serial config model {}", configModel); - if (config.port == null || config.port.isEmpty()) { + if (config.port.isBlank()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.config-error-unknown-port"); } else if (config.port.toLowerCase().startsWith("rfc2217")) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.config-error-invalid-thing-type"); - } else if (configModel == null || configModel.isEmpty()) { + } else if (configModel.isBlank()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.config-error-unknown-model"); } else { @@ -356,6 +362,7 @@ public class SonyProjectorHandler extends BaseThingHandler { connector = simu ? new SonyProjectorSerialSimuConnector(serialPortManager, DEFAULT_MODEL) : new SonyProjectorSerialConnector(serialPortManager, config.port, DEFAULT_MODEL); + identifyMac = false; identifyProjector = false; projectorModel = switchToModel(configModel, true); @@ -367,16 +374,13 @@ public class SonyProjectorHandler extends BaseThingHandler { logger.debug("Serial over IP config host {}", config.host); logger.debug("Serial over IP config port {}", config.port); logger.debug("Serial over IP config model {}", configModel); - if (config.host == null || config.host.isEmpty()) { + if (config.host.isBlank()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.config-error-unknown-host"); - } else if (config.port == null) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "@text/offline.config-error-unknown-port"); } else if (config.port <= 0) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.config-error-invalid-port"); - } else if (configModel == null || configModel.isEmpty()) { + } else if (configModel.isBlank()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.config-error-unknown-model"); } else { @@ -385,6 +389,7 @@ public class SonyProjectorHandler extends BaseThingHandler { connector = simu ? new SonyProjectorSerialSimuConnector(serialPortManager, DEFAULT_MODEL) : new SonyProjectorSerialOverIpConnector(serialPortManager, config.host, config.port, DEFAULT_MODEL); + identifyMac = false; identifyProjector = false; projectorModel = switchToModel(configModel, true); @@ -432,6 +437,7 @@ public class SonyProjectorHandler extends BaseThingHandler { boolean isOn = refreshPowerState(); refreshModel(); + refreshMacAddress(); refreshChannel(CHANNEL_INPUT, isOn); refreshChannel(CHANNEL_CALIBRATION_PRESET, isOn); refreshChannel(CHANNEL_CONTRAST, isOn); @@ -537,6 +543,19 @@ public class SonyProjectorHandler extends BaseThingHandler { return model; } + private void refreshMacAddress() { + if (identifyMac && getThing().getThingTypeUID().equals(THING_TYPE_ETHERNET)) { + try { + String mac = ((SonyProjectorSdcpConnector) connector).getMacAddress(); + logger.debug("getMacAddress returned {}", mac); + getThing().setProperty(Thing.PROPERTY_MAC_ADDRESS, mac); + identifyMac = false; + } catch (SonyProjectorException e) { + logger.debug("getMacAddress failed: {}", e.getMessage()); + } + } + } + private boolean refreshPowerState() { boolean on = false; State state = UnDefType.UNDEF; diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.openhab.binding.sonyprojector/src/main/resources/OH-INF/addon/addon.xml index f6205e8fb5d..aab8eae215b 100644 --- a/bundles/org.openhab.binding.sonyprojector/src/main/resources/OH-INF/addon/addon.xml +++ b/bundles/org.openhab.binding.sonyprojector/src/main/resources/OH-INF/addon/addon.xml @@ -12,9 +12,13 @@ sddp + + manufacturer + (?i).*sony.* + type - (?i)sony:projector.* + (?i).*projector.*