diff --git a/bundles/org.openhab.io.homekit/README.md b/bundles/org.openhab.io.homekit/README.md index c70eaaec1efea..a8273c7eb0d85 100644 --- a/bundles/org.openhab.io.homekit/README.md +++ b/bundles/org.openhab.io.homekit/README.md @@ -47,6 +47,7 @@ org.openhab.homekit:maximumTemperature=100 | networkInterface | IP address or domain name under which the HomeKit bridge can be reached. If no value is configured, the add-on uses the first network adapter address. | (none) | | port | Port under which the HomeKit bridge can be reached. | 9123 | | 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. | 30 | | useFahrenheitTemperature | Set to true to use Fahrenheit degrees, or false to use Celsius degrees. | false | | thermostatTargetModeCool | Word used for activating the cooling mode of the device (if applicable). | CoolOn | | thermostatTargetModeHeat | Word used for activating the heating mode of the device (if applicable). | HeatOn | diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitChangeListener.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitChangeListener.java index 0af70e0dcf8ec..65c43d1f53681 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitChangeListener.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitChangeListener.java @@ -51,12 +51,14 @@ public class HomekitChangeListener implements ItemRegistryChangeListener { private final Logger logger = LoggerFactory.getLogger(HomekitChangeListener.class); private final static String REVISION_CONFIG = "revision"; + private final static String ACCESSORY_COUNT = "accessory_count"; private final ItemRegistry itemRegistry; private final HomekitAccessoryRegistry accessoryRegistry = new HomekitAccessoryRegistry(); private final MetadataRegistry metadataRegistry; private final Storage storage; private HomekitAccessoryUpdater updater = new HomekitAccessoryUpdater(); private HomekitSettings settings; + private int lastAccessoryCount; private Set pendingUpdates = new HashSet<>(); @@ -79,13 +81,12 @@ public class HomekitChangeListener implements ItemRegistryChangeListener { this.settings = settings; this.metadataRegistry = metadataRegistry; storage = storageService.getStorage("homekit"); - initialiseRevision(); - this.applyUpdatesDebouncer = new Debouncer("update-homekit-devices", scheduler, Duration.ofMillis(1000), Clock.systemUTC(), this::applyUpdates); itemRegistry.addRegistryChangeListener(this); itemRegistry.getItems().stream().forEach(this::createRootAccessories); + initialiseRevision(); logger.info("Created {} HomeKit items.", accessoryRegistry.getAllAccessories().size()); } @@ -97,6 +98,12 @@ private void initialiseRevision() { revision = 1; storage.put(REVISION_CONFIG, "" + revision); } + try { + lastAccessoryCount = Integer.valueOf(storage.get(ACCESSORY_COUNT)); + } catch (java.lang.NumberFormatException e) { + lastAccessoryCount = 0; + storage.put(ACCESSORY_COUNT, "" + accessoryRegistry.getAllAccessories().size()); + } accessoryRegistry.setConfigurationRevision(revision); } @@ -143,6 +150,12 @@ private Optional getItemOptional(String name) { } } + public void makeNewConfigurationRevision() { + storage.put(REVISION_CONFIG, "" + accessoryRegistry.makeNewConfigurationRevision()); + lastAccessoryCount = accessoryRegistry.getAllAccessories().size(); + storage.put(ACCESSORY_COUNT, "" + lastAccessoryCount); + } + private synchronized void applyUpdates() { logger.trace("apply updates"); Iterator iter = pendingUpdates.iterator(); @@ -154,7 +167,7 @@ private synchronized void applyUpdates() { getItemOptional(name).ifPresent(this::createRootAccessories); } if (!pendingUpdates.isEmpty()) { - storage.put(REVISION_CONFIG, "" + accessoryRegistry.makeNewConfigurationRevision()); + makeNewConfigurationRevision(); pendingUpdates.clear(); } } @@ -165,6 +178,10 @@ public void updated(Item oldElement, Item element) { markDirty(element); } + public int getLastAccessoryCount() { + return lastAccessoryCount; + } + public synchronized void clearAccessories() { accessoryRegistry.clear(); } diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java index ae6d3e8bc9285..0c345685c3cab 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java @@ -19,11 +19,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.config.core.ConfigurableService; import org.eclipse.smarthome.config.core.Configuration; +import org.eclipse.smarthome.core.common.ThreadPoolManager; import org.eclipse.smarthome.core.items.ItemRegistry; import org.eclipse.smarthome.core.items.MetadataRegistry; import org.eclipse.smarthome.core.net.NetworkAddressService; @@ -66,6 +69,9 @@ public class HomekitImpl implements Homekit { private @Nullable HomekitServer homekitServer; private @Nullable HomekitRoot bridge; + private final ScheduledExecutorService scheduler = ThreadPoolManager + .getScheduledPool(ThreadPoolManager.THREAD_POOL_NAME_COMMON); + @Activate public HomekitImpl(@Reference StorageService storageService, @Reference ItemRegistry itemRegistry, @Reference NetworkAddressService networkAddressService, Map config, @@ -120,13 +126,29 @@ private void startBridge() throws InvalidAlgorithmParameterException, IOExceptio final HomekitServer homekitServer = this.homekitServer; if (homekitServer != null && bridge == null) { final HomekitRoot bridge = homekitServer.createBridge(new HomekitAuthInfoImpl(storageService, settings.pin), - settings.name, HomekitSettings.MANUFACTURER, - FrameworkUtil.getBundle(getClass()).getVersion().toString(), HomekitSettings.SERIAL_NUMBER, - HomekitSettings.FIRMWARE_REVISION, HomekitSettings.HARDWARE_REVISION); + settings.name, HomekitSettings.MANUFACTURER, HomekitSettings.MODEL, HomekitSettings.SERIAL_NUMBER, + FrameworkUtil.getBundle(getClass()).getVersion().toString(), HomekitSettings.HARDWARE_REVISION); changeListener.setBridge(bridge); - bridge.setConfigurationIndex(changeListener.getConfigurationRevision()); - bridge.start(); this.bridge = bridge; + bridge.setConfigurationIndex(changeListener.getConfigurationRevision()); + + final int lastAccessoryCount = changeListener.getLastAccessoryCount(); + int currentAccessoryCount = changeListener.getAccessories().size(); + if (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(); + } } else { logger.warn( "trying to start bridge but HomeKit server is not initialized or bridge is already initialized"); diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitSettings.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitSettings.java index ebfc9d5111957..a0eddbb580c85 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitSettings.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitSettings.java @@ -18,14 +18,15 @@ * @author Andy Lintner - Initial contribution */ public class HomekitSettings { - public static final String MANUFACTURER = "openHAB"; + public static final String MANUFACTURER = "openHAB Community"; public static final String SERIAL_NUMBER = "none"; - public static final String FIRMWARE_REVISION = "2.5.3"; + public static final String MODEL = "openHAB"; public static final String HARDWARE_REVISION = "2.5"; public String name = "openHAB"; public int port = 9123; public String pin = "031-45-154"; + public int startDelay = 30; public boolean useFahrenheitTemperature = false; public double minimumTemperature = -100; public double maximumTemperature = 100; diff --git a/bundles/org.openhab.io.homekit/src/main/resources/ESH-INF/config/config.xml b/bundles/org.openhab.io.homekit/src/main/resources/ESH-INF/config/config.xml index b71c33aabf131..08837e2bd4cab 100644 --- a/bundles/org.openhab.io.homekit/src/main/resources/ESH-INF/config/config.xml +++ b/bundles/org.openhab.io.homekit/src/main/resources/ESH-INF/config/config.xml @@ -37,7 +37,11 @@ Defines the IP address of the network interface to expose the HomeKit integration on. - + + + HomeKit start delay in case of item configuration differences. + 30 + Defines whether or not to direct HomeKit clients to use fahrenheit temperatures instead of celsius.