]> git.basschouten.com Git - openhab-addons.git/commitdiff
[sonyprojector] Add discovery through SDDP (#16849)
authorlolodomo <lg.hc@free.fr>
Fri, 14 Jun 2024 15:48:02 +0000 (17:48 +0200)
committerGitHub <noreply@github.com>
Fri, 14 Jun 2024 15:48:02 +0000 (17:48 +0200)
Only applicable to projector models having a network connector

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
bundles/org.openhab.binding.sonyprojector/README.md
bundles/org.openhab.binding.sonyprojector/src/main/feature/feature.xml
bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/SonyProjectorItem.java
bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/communication/sdcp/SonyProjectorSdcpConnector.java
bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorEthernetConfiguration.java
bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialConfiguration.java
bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/configuration/SonyProjectorSerialOverIpConfiguration.java
bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/discovery/SonyProjectorDiscoveryParticipant.java [new file with mode: 0644]
bundles/org.openhab.binding.sonyprojector/src/main/java/org/openhab/binding/sonyprojector/internal/handler/SonyProjectorHandler.java
bundles/org.openhab.binding.sonyprojector/src/main/resources/OH-INF/addon/addon.xml

index ab473a0e9b9e87424d16c9419966ff9c64b67506..3501a50c852ba8ef1869a7babfa1688c82e208ad 100644 (file)
@@ -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
 
index e4b84c94f63dee01bff7a49306134e3c7edd1847..36b97ec551930f62bc41cc8b9364eec7b4911329 100644 (file)
@@ -5,6 +5,7 @@
        <feature name="openhab-binding-sonyprojector" description="Sony Projector Binding" version="${project.version}">
                <feature>openhab-runtime-base</feature>
                <feature>openhab-transport-serial</feature>
+               <feature>openhab-core-config-discovery-sddp</feature>
                <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.sonyprojector/${project.version}</bundle>
        </feature>
 </features>
index 76743a41cd1c44bbf1179dec230714f88e02a0de..d57aff1b25481e9cecf3187483d41b6af754c846 100644 (file)
@@ -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 }),
index 5f32f583c08ec95ec013480175b46ba2db1f13e7..c97b7ddf8a751c497fb3f7626485580b1a348365 100644 (file)
@@ -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);
+    }
 }
index dfec1e7bff5fbec5eb9a8fb11221c2f1070e4e3b..15f965fd466610b40cc86b6e8bc73578973b9544 100644 (file)
@@ -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;
 }
index 27e5f62d2fa2878b637a48009adfd5174a18d75b..b9f470f78c2da019cf3fd9d521b5795ea45ce69f 100644 (file)
@@ -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();
 }
index e39669e179248769ab5fedc60c523be358062b69..3bd6ac3775891f1ed2e9ee3d416943172d7885d6 100644 (file)
@@ -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 (file)
index 0000000..36e30a7
--- /dev/null
@@ -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<ThingTypeUID> 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<String, Object> 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;
+    }
+}
index 620e6c40d955fcfc9b33d7a815f7e555f06c861d..bfd2485b9ddee81ca4d44a33b5b4c946df31a7c1 100644 (file)
@@ -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;
index f6205e8fb5ded210dcb8c48ff8ebfc2c1fdc3268..aab8eae215b25052ef0ba0791e2646451b4f6133 100644 (file)
                <discovery-method>
                        <service-type>sddp</service-type>
                        <match-properties>
+                               <match-property>
+                                       <name>manufacturer</name>
+                                       <regex>(?i).*sony.*</regex>
+                               </match-property>
                                <match-property>
                                        <name>type</name>
-                                       <regex>(?i)sony:projector.*</regex>
+                                       <regex>(?i).*projector.*</regex>
                                </match-property>
                        </match-properties>
                </discovery-method>