]> git.basschouten.com Git - openhab-addons.git/commitdiff
[homekit] delay starting until a particular StartLevel (#13877)
authorCody Cutrer <cody@cutrer.us>
Sun, 11 Dec 2022 14:54:10 +0000 (07:54 -0700)
committerGitHub <noreply@github.com>
Sun, 11 Dec 2022 14:54:10 +0000 (15:54 +0100)
* [homekit] delay starting until a particular StartLevel

instead of a blind "delay by seconds", the new default won't even
attempt to start until items are loaded (both file-based and UI-based),
with an additional config to let the user delay it any further (in
case they have items coming from JSR223 scripts that can't run until
at least SL20 anyway).

Signed-off-by: Cody Cutrer <cody@cutrer.us>
bundles/org.openhab.io.homekit/README.md
bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java
bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitSettings.java
bundles/org.openhab.io.homekit/src/main/resources/OH-INF/config/config.xml
bundles/org.openhab.io.homekit/src/main/resources/OH-INF/i18n/homekit.properties

index 23bd586a8bf8def933da8ef8a08ddbd6350f1c63..abcd298d4f137faeea9b0a3ee2d2c7aeb679b6f0 100644 (file)
@@ -105,22 +105,21 @@ Some settings are only visible in UI if the checkbox "Show advanced" is activate
 
 ### Overview of all settings
 
-| Setting                  | Description                                                                                                                                                                                                                                                                                       | Default value |
-|:-------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------|
-| networkInterface         | IP address or domain name under which the HomeKit bridge can be reached. If no value is configured, the add-on uses the primary IP address configured for openHAB. If unsure, keep it empty                                                                                                       | (none)        |
-| port                     | Port under which the HomeKit bridge can be reached.                                                                                                                                                                                                                                               | 9123          |
-| useOHmDNS                | mDNS service is used to advertise openHAB as HomeKit bridge in the network so that HomeKit clients can find it. openHAB has already mDNS service running. This option defines whether the mDNS service of openHAB or a separate service should be used.                                           | false         |
-| blockUserDeletion        | Blocks HomeKit user deletion in openHAB and as result unpairing of devices. If you experience an issue with accessories becoming non-responsive after some time, try to enable this setting. You can also enable this setting if your HomeKit setup is done and you will not re-pair ios devices. | false         |
-| pin                      | Pin code used for pairing with iOS devices. Apparently, pin codes are provided by Apple and represent specific device types, so they cannot be chosen freely. The pin code 031-45-154 is used in sample applications and known to work.                                                           | 031-45-154    |
-| startDelay               | HomeKit start delay in seconds in case the number of accessories is lower than last time. This helps to avoid resetting home app in case not all items have been initialised properly before HomeKit integration start. Ignored if `useDummyAccessories` is on.                                   | 30            |
-| useFahrenheitTemperature | Set to true to use Fahrenheit degrees, or false to use Celsius degrees. Note if an item has a QuantityType as its state, this configuration is ignored and it's always converted properly.                                                                                                        | false         |
-| thermostatTargetModeCool | Word used for activating the cooling mode of the device (if applicable). It can be overwritten at item level.                                                                                                                                                                                     | CoolOn        |
-| thermostatTargetModeHeat | Word used for activating the heating mode of the device (if applicable). It can be overwritten at item level.                                                                                                                                                                                     | HeatOn        |
-| thermostatTargetModeAuto | Word used for activating the automatic mode of the device (if applicable). It can be overwritten at item level.                                                                                                                                                                                   | Auto          |
-| thermostatTargetModeOff  | Word used to set the thermostat mode of the device to off (if applicable).  It can be overwritten at item level.                                                                                                                                                                                  | Off           |
-| name                     | Name under which this HomeKit bridge is announced on the network. This is also the name displayed on the iOS device when searching for available bridges.                                                                                                                                         | openHAB       |
-| instances                | Defines how many bridges to expose. Necessary if you have more than 149 accessories. Accessories must be assigned to additional instances via metadata. Additional bridges will use incrementing port numbers.                                                                                    | 1             |
-| useDummyAccessories      | When an accessory is missing, substitute a dummy in its place instead of removing it. See [Dummy Accessories](#dummy-accessories). | false     |
+| Setting                  | Description                                                                                                                                                                                                                                                                                                                                                                          | Default value        |
+|:-------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------|
+| networkInterface         | IP address or domain name under which the HomeKit bridge can be reached. If no value is configured, the add-on uses the primary IP address configured for openHAB. If unsure, keep it empty                                                                                                                                                                                          | (none)               |
+| port                     | Port under which the HomeKit bridge can be reached.                                                                                                                                                                                                                                                                                                                                  | 9123                 |
+| useOHmDNS                | mDNS service is used to advertise openHAB as HomeKit bridge in the network so that HomeKit clients can find it. openHAB has already mDNS service running. This option defines whether the mDNS service of openHAB or a separate service should be used.                                                                                                                              | false                |
+| blockUserDeletion        | Blocks HomeKit user deletion in openHAB and as result unpairing of devices. If you experience an issue with accessories becoming non-responsive after some time, try to enable this setting. You can also enable this setting if your HomeKit setup is done and you will not re-pair ios devices.                                                                                    | false                |
+| pin                      | Pin code used for pairing with iOS devices. Apparently, pin codes are provided by Apple and represent specific device types, so they cannot be chosen freely. The pin code 031-45-154 is used in sample applications and known to work.                                                                                                                                              | 031-45-154           |
+| useFahrenheitTemperature | Set to true to use Fahrenheit degrees, or false to use Celsius degrees. Note if an item has a QuantityType as its state, this configuration is ignored and it's always converted properly.                                                                                                                                                                                           | false                |
+| thermostatTargetModeCool | Word used for activating the cooling mode of the device (if applicable). It can be overwritten at item level.                                                                                                                                                                                                                                                                        | CoolOn               |
+| thermostatTargetModeHeat | Word used for activating the heating mode of the device (if applicable). It can be overwritten at item level.                                                                                                                                                                                                                                                                        | HeatOn               |
+| thermostatTargetModeAuto | Word used for activating the automatic mode of the device (if applicable). It can be overwritten at item level.                                                                                                                                                                                                                                                                      | Auto                 |
+| thermostatTargetModeOff  | Word used to set the thermostat mode of the device to off (if applicable).  It can be overwritten at item level.                                                                                                                                                                                                                                                                     | Off                  |
+| name                     | Name under which this HomeKit bridge is announced on the network. This is also the name displayed on the iOS device when searching for available bridges.                                                                                                                                                                                                                            | openHAB              |
+| instances                | Defines how many bridges to expose. Necessary if you have more than 149 accessories. Accessories must be assigned to additional instances via metadata. Additional bridges will use incrementing port numbers.                                                                                                                                                                       | 1                    |
+| useDummyAccessories      | When an accessory is missing, substitute a dummy in its place instead of removing it. See [Dummy Accessories](#dummy-accessories).                                                                                                                                                                                                                                                   | false                |
 
 ## Item Configuration
 
index 294ba08d1cdeb7fbc2fab83226361800119a8981..468c1c9b9434aaf6006da0d6a1a9916c2aa16f91 100644 (file)
@@ -22,7 +22,6 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
 
 import javax.jmdns.JmDNS;
 
@@ -37,6 +36,10 @@ import org.openhab.core.items.MetadataRegistry;
 import org.openhab.core.net.CidrAddress;
 import org.openhab.core.net.NetworkAddressChangeListener;
 import org.openhab.core.net.NetworkAddressService;
+import org.openhab.core.service.ReadyMarker;
+import org.openhab.core.service.ReadyMarkerFilter;
+import org.openhab.core.service.ReadyService;
+import org.openhab.core.service.StartLevelService;
 import org.openhab.core.storage.Storage;
 import org.openhab.core.storage.StorageService;
 import org.openhab.io.homekit.Homekit;
@@ -66,7 +69,7 @@ import io.github.hapjava.server.impl.crypto.HAPSetupCodeUtils;
         Constants.SERVICE_PID + "=org.openhab.homekit", "port:Integer=9123" })
 @ConfigurableService(category = "io", label = "HomeKit Integration", description_uri = "io:homekit")
 @NonNullByDefault
-public class HomekitImpl implements Homekit, NetworkAddressChangeListener {
+public class HomekitImpl implements Homekit, NetworkAddressChangeListener, ReadyService.ReadyTracker {
     private final Logger logger = LoggerFactory.getLogger(HomekitImpl.class);
 
     private final StorageService storageService;
@@ -74,6 +77,7 @@ public class HomekitImpl implements Homekit, NetworkAddressChangeListener {
     private final ConfigurationAdmin configAdmin;
     private final ItemRegistry itemRegistry;
     private final MetadataRegistry metadataRegistry;
+    private final ReadyService readyService;
 
     private final List<HomekitAuthInfoImpl> authInfos = new ArrayList<>();
     private HomekitSettings settings;
@@ -81,6 +85,7 @@ public class HomekitImpl implements Homekit, NetworkAddressChangeListener {
     private final List<HomekitServer> homekitServers = new ArrayList<>();
     private final List<HomekitRoot> bridges = new ArrayList<>();
     private MDNSClient mdnsClient;
+    private int currentStartLevel = 0;
 
     private final List<HomekitChangeListener> changeListeners = new ArrayList<>();
 
@@ -90,7 +95,8 @@ public class HomekitImpl implements Homekit, NetworkAddressChangeListener {
     @Activate
     public HomekitImpl(@Reference StorageService storageService, @Reference ItemRegistry itemRegistry,
             @Reference NetworkAddressService networkAddressService, @Reference MetadataRegistry metadataRegistry,
-            @Reference ConfigurationAdmin configAdmin, @Reference MDNSClient mdnsClient, Map<String, Object> properties)
+            @Reference ConfigurationAdmin configAdmin, @Reference MDNSClient mdnsClient,
+            @Reference ReadyService readyService, Map<String, Object> properties)
             throws IOException, InvalidAlgorithmParameterException {
         this.storageService = storageService;
         this.networkAddressService = networkAddressService;
@@ -99,13 +105,9 @@ public class HomekitImpl implements Homekit, NetworkAddressChangeListener {
         this.mdnsClient = mdnsClient;
         this.itemRegistry = itemRegistry;
         this.metadataRegistry = metadataRegistry;
+        this.readyService = readyService;
         networkAddressService.addNetworkAddressChangeListener(this);
-        try {
-            startHomekitServer();
-        } catch (IOException | InvalidAlgorithmParameterException e) {
-            logger.warn("cannot activate HomeKit binding. {}", e.getMessage());
-            throw e;
-        }
+        readyService.registerTracker(this, new ReadyMarkerFilter().withType(StartLevelService.STARTLEVEL_MARKER_TYPE));
     }
 
     private HomekitSettings processConfig(Map<String, Object> properties) {
@@ -160,7 +162,9 @@ public class HomekitImpl implements Homekit, NetworkAddressChangeListener {
                     || oldSettings.instances != settings.instances) {
                 // the HomeKit server settings changed. we do a complete re-init
                 stopHomekitServer();
-                startHomekitServer();
+                if (currentStartLevel >= StartLevelService.STARTLEVEL_STATES) {
+                    startHomekitServer();
+                }
             } else {
                 for (HomekitChangeListener changeListener : changeListeners) {
                     changeListener.updateSettings(settings);
@@ -171,6 +175,36 @@ public class HomekitImpl implements Homekit, NetworkAddressChangeListener {
         }
     }
 
+    @Override
+    public synchronized void onReadyMarkerAdded(ReadyMarker readyMarker) {
+        int newLevel = Integer.parseInt(readyMarker.getIdentifier());
+        currentStartLevel = newLevel;
+
+        if (newLevel >= StartLevelService.STARTLEVEL_STATES) {
+            try {
+                startHomekitServer();
+            } catch (IOException | InvalidAlgorithmParameterException e) {
+                logger.warn("could not initialize HomeKit bridge: {}", e.getMessage());
+            }
+        }
+    }
+
+    @Override
+    @SuppressWarnings("PMD.EmptyWhileStmt")
+    public synchronized void onReadyMarkerRemoved(ReadyMarker readyMarker) {
+        int newLevel = Integer.parseInt(readyMarker.getIdentifier());
+
+        if (currentStartLevel > newLevel) {
+            while (newLevel-- > 0 && !readyService
+                    .isReady(new ReadyMarker(StartLevelService.STARTLEVEL_MARKER_TYPE, Integer.toString(newLevel)))) {
+            }
+            currentStartLevel = newLevel;
+            if (currentStartLevel < StartLevelService.STARTLEVEL_STATES) {
+                stopHomekitServer();
+            }
+        }
+    }
+
     private HomekitRoot startBridge(HomekitServer homekitServer, HomekitAuthInfoImpl authInfo,
             HomekitChangeListener changeListener, int instance) throws IOException {
         String name = settings.name;
@@ -187,21 +221,7 @@ public class HomekitImpl implements Homekit, NetworkAddressChangeListener {
 
         final int lastAccessoryCount = changeListener.getLastAccessoryCount();
         int currentAccessoryCount = changeListener.getAccessories().size();
-        if (!settings.useDummyAccessories && currentAccessoryCount < lastAccessoryCount) {
-            logger.debug(
-                    "it looks like not all items were initialized yet. Old configuration had {} accessories, the current one has only {} accessories. Delay HomeKit bridge start for {} seconds.",
-                    lastAccessoryCount, currentAccessoryCount, settings.startDelay);
-            scheduler.schedule(() -> {
-                if (currentAccessoryCount < lastAccessoryCount) {
-                    // the number of items is still different, maybe it is desired.
-                    // make new configuration revision.
-                    changeListener.makeNewConfigurationRevision();
-                }
-                bridge.start();
-            }, settings.startDelay, TimeUnit.SECONDS);
-        } else { // start bridge immediately.
-            bridge.start();
-        }
+        bridge.start();
         return bridge;
     }
 
@@ -319,6 +339,9 @@ public class HomekitImpl implements Homekit, NetworkAddressChangeListener {
     @Override
     public synchronized void onChanged(final List<CidrAddress> added, final List<CidrAddress> removed) {
         logger.trace("HomeKit bridge reacting on network interface changes.");
+        if (currentStartLevel < StartLevelService.STARTLEVEL_STATES) {
+            return;
+        }
         removed.forEach(i -> {
             logger.trace("removed interface {}", i.getAddress().toString());
             if (i.getAddress().equals(networkInterface)) {
index 0f0a7dc5d6698af234da15b5226c9c544a56fb0d..e9111d5e4f4842d25aa8229f8a8de2280d8ebdf9 100644 (file)
@@ -30,7 +30,6 @@ public class HomekitSettings {
     public String pin = "031-45-154";
     public String setupId;
     public String qrCode;
-    public int startDelay = 30;
     public boolean useDummyAccessories = false;
     public boolean useFahrenheitTemperature = false;
     public boolean useOHmDNS = false;
index ed04873c784377d62a2765d3dd30d7a8db929a37..ca5bbf3bcfc0d1f73c4a84525f1030576870943c 100644 (file)
                        <description>Defines the IP address of the network interface to expose the HomeKit integration on.</description>
                        <advanced>true</advanced>
                </parameter>
-               <parameter name="startDelay" type="integer" required="true" groupName="core" unit="s">
-                       <label>Start Delay</label>
-                       <description>HomeKit start delay in case of item configuration differences.</description>
-                       <default>30</default>
-                       <advanced>true</advanced>
-               </parameter>
                <parameter name="useDummyAccessories" type="boolean" required="true" groupName="core">
                        <label>Use Dummy Accessories</label>
                        <description><![CDATA[Create dummy accessories when an item is missing. See <a href="https://www.openhab.org/addons/integrations/homekit/#dummy-accessories">the documentation</a> for more information.
index fc586100248a0862d16d265328bdd02826c7ea98..0aef5ac4f5f2eb245894604eda107c181106fb62 100644 (file)
@@ -23,8 +23,6 @@ io.config.homekit.qrCode.label = HomeKit QR Code
 io.config.homekit.qrCode.description = Scan QR code with home app to add openHAB as HomeKit bridge.
 io.config.homekit.setupId.label = Setup ID
 io.config.homekit.setupId.description = Setup ID used for pairing using QR Code. Alphanumeric code of length 4.
-io.config.homekit.startDelay.label = Start Delay
-io.config.homekit.startDelay.description = HomeKit start delay in case of item configuration differences.
 io.config.homekit.thermostatCurrentModeCooling.label = Cooling Value
 io.config.homekit.thermostatCurrentModeCooling.description = Value for setting target heatingCoolingCurrentMode to COOL (IE: indicating that the air condition is currently cooling the home).
 io.config.homekit.thermostatCurrentModeHeating.label = Heating Value