[homekit] delay starting until a particular StartLevel (#13877)

* [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>
This commit is contained in:
Cody Cutrer
2022-12-11 07:54:10 -07:00
committed by GitHub
parent 438552d485
commit 1dbcaf8f0c
5 changed files with 63 additions and 50 deletions

View 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)) {

View 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;

View File

@@ -68,12 +68,6 @@
<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.

View 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