added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.icloud-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-icloud" description="iCloud Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.icloud/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,67 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link ICloudBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Patrik Gfeller - Initial contribution
* @author Patrik Gfeller
* - Class renamed to be more consistent
* - Constant FIND_MY_DEVICE_REQUEST_SUBJECT introduced
* @author Gaël L'hopital - Added low battery
*/
@NonNullByDefault
public class ICloudBindingConstants {
private static final String BINDING_ID = "icloud";
public static final String BRIDGE_ID = "account";
public static final String DEVICE_ID = "device";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_ICLOUD = new ThingTypeUID(BINDING_ID, BRIDGE_ID);
public static final ThingTypeUID THING_TYPE_ICLOUDDEVICE = new ThingTypeUID(BINDING_ID, DEVICE_ID);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<>(
Arrays.asList(THING_TYPE_ICLOUD, THING_TYPE_ICLOUDDEVICE));
// List of all Channel IDs
public static final String BATTERY_STATUS = "batteryStatus";
public static final String BATTERY_LEVEL = "batteryLevel";
public static final String LOW_BATTERY = "lowBattery";
public static final String FIND_MY_PHONE = "findMyPhone";
public static final String LOCATION = "location";
public static final String LOCATION_ACCURACY = "locationAccuracy";
public static final String LOCATION_LASTUPDATE = "locationLastUpdate";
public static final String DEVICE_NAME = "deviceName";
// Device properties
public static final String DEVICE_PROPERTY_IDHASH = "deviceIdHash";
public static final String DEVICE_PROPERTY_ID = "deviceId";
// i18n
public static final String DEVICE_PROPERTY_ID_LABEL = "icloud.device-thing.parameter.id.label";
public static final String DEVICE_PROPERTY_OWNER_LABEL = "icloud.account-thing.property.owner";
// Miscellaneous
public static final String FIND_MY_DEVICE_REQUEST_SUBJECT = "Find My Device alert";
}

View File

@@ -0,0 +1,93 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.Base64;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.icloud.internal.json.request.ICloudAccountDataRequest;
import org.openhab.binding.icloud.internal.json.request.ICloudFindMyDeviceRequest;
import org.openhab.core.io.net.http.HttpRequestBuilder;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* Handles communication with the Apple server. Provides methods to
* get device information and to find a device.
*
* @author Patrik Gfeller - Initial Contribution
* @author Patrik Gfeller - SOCKET_TIMEOUT changed from 2500 to 10000
* @author Martin van Wingerden - add support for custom CA of https://fmipmobile.icloud.com
*/
@NonNullByDefault
public class ICloudConnection {
private static final String ICLOUD_URL = "https://www.icloud.com";
private static final String ICLOUD_API_BASE_URL = "https://fmipmobile.icloud.com";
private static final String ICLOUD_API_URL = ICLOUD_API_BASE_URL + "/fmipservice/device/";
private static final String ICLOUD_API_COMMAND_PING_DEVICE = "/playSound";
private static final String ICLOUD_API_COMMAND_REQUEST_DATA = "/initClient";
private static final int SOCKET_TIMEOUT = 15;
private final Gson gson = new GsonBuilder().create();
private final String iCloudDataRequest = gson.toJson(ICloudAccountDataRequest.defaultInstance());
private final String authorization;
private final String iCloudDataRequestURL;
private final String iCloudFindMyDeviceURL;
public ICloudConnection(String appleId, String password) throws URISyntaxException {
authorization = new String(Base64.getEncoder().encode((appleId + ":" + password).getBytes()), UTF_8);
iCloudDataRequestURL = new URI(ICLOUD_API_URL + appleId + ICLOUD_API_COMMAND_REQUEST_DATA).toASCIIString();
iCloudFindMyDeviceURL = new URI(ICLOUD_API_URL + appleId + ICLOUD_API_COMMAND_PING_DEVICE).toASCIIString();
}
/***
* Sends a "find my device" request.
*
* @throws IOException
*/
public void findMyDevice(String id) throws IOException {
callApi(iCloudFindMyDeviceURL, gson.toJson(new ICloudFindMyDeviceRequest(id)));
}
public String requestDeviceStatusJSON() throws IOException {
return callApi(iCloudDataRequestURL, iCloudDataRequest);
}
private String callApi(String url, String payload) throws IOException {
// @formatter:off
return HttpRequestBuilder.postTo(url)
.withTimeout(Duration.ofSeconds(SOCKET_TIMEOUT))
.withHeader("Authorization", "Basic " + authorization)
.withHeader("User-Agent", "Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)")
.withHeader("Origin", ICLOUD_URL)
.withHeader("charset", "utf-8")
.withHeader("Accept-language", "en-us")
.withHeader("Connection", "keep-alive")
.withHeader("X-Apple-Find-Api-Ver", "2.0")
.withHeader("X-Apple-Authscheme", "UserIdGuest")
.withHeader("X-Apple-Realm-Support", "1.0")
.withHeader("X-Client-Name", "iPad")
.withHeader("Content-Type", "application/json")
.withContent(payload)
.getContentAsString();
// @formatter:on
}
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.icloud.internal.json.response.ICloudDeviceInformation;
/**
* Classes that implement this interface are interested in device information updates.
*
* @author Patrik Gfeller - Initial Contribution
*/
@NonNullByDefault
public interface ICloudDeviceInformationListener {
void deviceInformationUpdate(List<ICloudDeviceInformation> deviceInformationList);
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.icloud.internal.json.response.ICloudAccountDataResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
/**
* Extracts iCloud device information from a given JSON string
*
* @author Patrik Gfeller - Initial Contribution
*
*/
@NonNullByDefault
public class ICloudDeviceInformationParser {
private final Gson gson = new GsonBuilder().create();
public @Nullable ICloudAccountDataResponse parse(String json) throws JsonSyntaxException {
return gson.fromJson(json, ICloudAccountDataResponse.class);
}
}

View File

@@ -0,0 +1,118 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal;
import static org.openhab.binding.icloud.internal.ICloudBindingConstants.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.icloud.internal.discovery.ICloudDeviceDiscovery;
import org.openhab.binding.icloud.internal.handler.ICloudAccountBridgeHandler;
import org.openhab.binding.icloud.internal.handler.ICloudDeviceHandler;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link ICloudHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Patrik Gfeller - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.icloud")
public class ICloudHandlerFactory extends BaseThingHandlerFactory {
private final Map<ThingUID, @Nullable ServiceRegistration<?>> discoveryServiceRegistrations = new HashMap<>();
private LocaleProvider localeProvider;
private TranslationProvider i18nProvider;
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(THING_TYPE_ICLOUD)) {
ICloudAccountBridgeHandler bridgeHandler = new ICloudAccountBridgeHandler((Bridge) thing);
registerDeviceDiscoveryService(bridgeHandler);
return bridgeHandler;
}
if (thingTypeUID.equals(THING_TYPE_ICLOUDDEVICE)) {
return new ICloudDeviceHandler(thing);
}
return null;
}
@Override
protected void removeHandler(ThingHandler thingHandler) {
if (thingHandler instanceof ICloudAccountBridgeHandler) {
unregisterDeviceDiscoveryService((ICloudAccountBridgeHandler) thingHandler);
}
}
private synchronized void registerDeviceDiscoveryService(ICloudAccountBridgeHandler bridgeHandler) {
ICloudDeviceDiscovery discoveryService = new ICloudDeviceDiscovery(bridgeHandler, bundleContext.getBundle(),
i18nProvider, localeProvider);
discoveryService.activate();
this.discoveryServiceRegistrations.put(bridgeHandler.getThing().getUID(),
bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
}
private synchronized void unregisterDeviceDiscoveryService(ICloudAccountBridgeHandler bridgeHandler) {
ServiceRegistration<?> serviceRegistration = this.discoveryServiceRegistrations
.get(bridgeHandler.getThing().getUID());
if (serviceRegistration != null) {
ICloudDeviceDiscovery discoveryService = (ICloudDeviceDiscovery) bundleContext
.getService(serviceRegistration.getReference());
if (discoveryService != null) {
discoveryService.deactivate();
}
serviceRegistration.unregister();
discoveryServiceRegistrations.remove(bridgeHandler.getThing().getUID());
}
}
@Reference
protected void setLocaleProvider(LocaleProvider localeProvider) {
this.localeProvider = localeProvider;
}
protected void unsetLocaleProvider(LocaleProvider localeProvider) {
this.localeProvider = null;
}
@Reference
public void setTranslationProvider(TranslationProvider i18nProvider) {
this.i18nProvider = i18nProvider;
}
public void unsetTranslationProvider(TranslationProvider i18nProvider) {
this.i18nProvider = null;
}
}

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal;
import java.net.URL;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.io.net.http.TlsCertificateProvider;
import org.osgi.service.component.annotations.Component;
/**
* Provides a TrustManager for https://fmipmobile.icloud.com
*
* @author Martin van Wingerden - Initial Contribution
*/
@Component
@NonNullByDefault
public class ICloudTlsCertificateProvider implements TlsCertificateProvider {
@Override
public String getHostName() {
return "fmipmobile.icloud.com";
}
@Override
public URL getCertificate() {
URL resource = Thread.currentThread().getContextClassLoader().getResource("apple_root_ca.cer");
if (resource != null) {
return resource;
} else {
throw new IllegalStateException("Certifcate resource not found or not accessible");
}
}
}

View File

@@ -0,0 +1,29 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.configuration;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Represents the configuration of an iCloud Account Thing.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
@NonNullByDefault
public class ICloudAccountThingConfiguration {
public @Nullable String appleId;
public @Nullable String password;
public int refreshTimeInMinutes = 10;
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.configuration;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Represents the configuration of an iCloud Device Thing.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
@NonNullByDefault
public class ICloudDeviceThingConfiguration {
public @Nullable String deviceId;
}

View File

@@ -0,0 +1,98 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.discovery;
import static org.openhab.binding.icloud.internal.ICloudBindingConstants.*;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.icloud.internal.ICloudDeviceInformationListener;
import org.openhab.binding.icloud.internal.handler.ICloudAccountBridgeHandler;
import org.openhab.binding.icloud.internal.json.response.ICloudDeviceInformation;
import org.openhab.binding.icloud.internal.utilities.ICloudTextTranslator;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.thing.ThingUID;
import org.osgi.framework.Bundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Device discovery creates a thing in the inbox for each icloud device
* found in the data received from {@link ICloudAccountBridgeHandler}.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
@NonNullByDefault
public class ICloudDeviceDiscovery extends AbstractDiscoveryService implements ICloudDeviceInformationListener {
private final Logger logger = LoggerFactory.getLogger(ICloudDeviceDiscovery.class);
private static final int TIMEOUT = 10;
private ThingUID bridgeUID;
private ICloudAccountBridgeHandler handler;
private ICloudTextTranslator translatorService;
public ICloudDeviceDiscovery(ICloudAccountBridgeHandler bridgeHandler, Bundle bundle,
TranslationProvider i18nProvider, LocaleProvider localeProvider) {
super(SUPPORTED_THING_TYPES_UIDS, TIMEOUT);
this.handler = bridgeHandler;
this.bridgeUID = bridgeHandler.getThing().getUID();
this.translatorService = new ICloudTextTranslator(bundle, i18nProvider, localeProvider);
}
@Override
public void deviceInformationUpdate(List<ICloudDeviceInformation> deviceInformationList) {
for (ICloudDeviceInformation deviceInformationRecord : deviceInformationList) {
String deviceTypeName = deviceInformationRecord.getDeviceDisplayName();
String deviceOwnerName = deviceInformationRecord.getName();
String thingLabel = deviceOwnerName + " (" + deviceTypeName + ")";
String deviceId = deviceInformationRecord.getId();
String deviceIdHash = Integer.toHexString(deviceId.hashCode());
logger.debug("iCloud device discovery for [{}]", deviceInformationRecord.getDeviceDisplayName());
ThingUID uid = new ThingUID(THING_TYPE_ICLOUDDEVICE, bridgeUID, deviceIdHash);
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
.withProperty(DEVICE_PROPERTY_ID, deviceId)
.withProperty(translatorService.getText(DEVICE_PROPERTY_ID_LABEL), deviceId)
.withProperty(translatorService.getText(DEVICE_PROPERTY_OWNER_LABEL), deviceOwnerName)
.withRepresentationProperty(DEVICE_PROPERTY_ID).withLabel(thingLabel).build();
logger.debug("Device [{}, {}] found.", deviceIdHash, deviceId);
thingDiscovered(result);
}
}
@Override
protected void startScan() {
}
public void activate() {
handler.registerListener(this);
}
@Override
public void deactivate() {
super.deactivate();
handler.unregisterListener(this);
}
}

View File

@@ -0,0 +1,192 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.handler;
import static java.util.concurrent.TimeUnit.*;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.icloud.internal.ICloudConnection;
import org.openhab.binding.icloud.internal.ICloudDeviceInformationListener;
import org.openhab.binding.icloud.internal.ICloudDeviceInformationParser;
import org.openhab.binding.icloud.internal.configuration.ICloudAccountThingConfiguration;
import org.openhab.binding.icloud.internal.json.response.ICloudAccountDataResponse;
import org.openhab.binding.icloud.internal.json.response.ICloudDeviceInformation;
import org.openhab.core.cache.ExpiringCache;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonSyntaxException;
/**
* Retrieves the data for a given account from iCloud and passes the
* information to {@link org.openhab.binding.icloud.internal.discovery.ICloudDeviceDiscovery} and to the
* {@link ICloudDeviceHandler}s.
*
* @author Patrik Gfeller - Initial contribution
* @author Hans-Jörg Merk - Extended support with initial Contribution
*/
@NonNullByDefault
public class ICloudAccountBridgeHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(ICloudAccountBridgeHandler.class);
private static final int CACHE_EXPIRY = (int) SECONDS.toMillis(10);
private final ICloudDeviceInformationParser deviceInformationParser = new ICloudDeviceInformationParser();
private @Nullable ICloudConnection connection;
private @Nullable ExpiringCache<String> iCloudDeviceInformationCache;
@Nullable
ServiceRegistration<?> service;
private final Object synchronizeRefresh = new Object();
private List<ICloudDeviceInformationListener> deviceInformationListeners = Collections
.synchronizedList(new ArrayList<>());
@Nullable
ScheduledFuture<?> refreshJob;
public ICloudAccountBridgeHandler(Bridge bridge) {
super(bridge);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.trace("Command '{}' received for channel '{}'", command, channelUID);
if (command instanceof RefreshType) {
refreshData();
}
}
@Override
public void initialize() {
logger.debug("iCloud bridge handler initializing ...");
iCloudDeviceInformationCache = new ExpiringCache<>(CACHE_EXPIRY, () -> {
try {
return connection.requestDeviceStatusJSON();
} catch (IOException e) {
logger.warn("Unable to refresh device data", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
return null;
}
});
startHandler();
logger.debug("iCloud bridge initialized.");
}
@Override
public void handleRemoval() {
super.handleRemoval();
}
@Override
public void dispose() {
if (refreshJob != null) {
refreshJob.cancel(true);
}
super.dispose();
}
public void findMyDevice(String deviceId) throws IOException {
if (connection == null) {
logger.debug("Can't send Find My Device request, because connection is null!");
return;
}
connection.findMyDevice(deviceId);
}
public void registerListener(ICloudDeviceInformationListener listener) {
deviceInformationListeners.add(listener);
}
public void unregisterListener(ICloudDeviceInformationListener listener) {
deviceInformationListeners.remove(listener);
}
private void startHandler() {
try {
logger.debug("iCloud bridge starting handler ...");
ICloudAccountThingConfiguration config = getConfigAs(ICloudAccountThingConfiguration.class);
final String localAppleId = config.appleId;
final String localPassword = config.password;
if (localAppleId != null && localPassword != null) {
connection = new ICloudConnection(localAppleId, localPassword);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Apple ID/Password is not set!");
return;
}
refreshJob = scheduler.scheduleWithFixedDelay(this::refreshData, 0, config.refreshTimeInMinutes, MINUTES);
logger.debug("iCloud bridge handler started.");
} catch (URISyntaxException e) {
logger.debug("Something went wrong while constructing the connection object", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
}
}
public void refreshData() {
synchronized (synchronizeRefresh) {
logger.debug("iCloud bridge refreshing data ...");
String json = iCloudDeviceInformationCache.getValue();
logger.trace("json: {}", json);
if (json == null) {
return;
}
try {
ICloudAccountDataResponse iCloudData = deviceInformationParser.parse(json);
if (iCloudData == null) {
return;
}
int statusCode = Integer.parseUnsignedInt(iCloudData.getICloudAccountStatusCode());
if (statusCode == 200) {
updateStatus(ThingStatus.ONLINE);
informDeviceInformationListeners(iCloudData.getICloudDeviceInformationList());
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Status = " + statusCode + ", Response = " + json);
}
logger.debug("iCloud bridge data refresh complete.");
} catch (NumberFormatException | JsonSyntaxException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"iCloud response invalid: " + e.getMessage());
}
}
}
private void informDeviceInformationListeners(List<ICloudDeviceInformation> deviceInformationList) {
this.deviceInformationListeners.forEach(discovery -> discovery.deviceInformationUpdate(deviceInformationList));
}
}

View File

@@ -0,0 +1,216 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.handler;
import static org.openhab.binding.icloud.internal.ICloudBindingConstants.*;
import static org.openhab.core.thing.ThingStatus.OFFLINE;
import static org.openhab.core.thing.ThingStatus.ONLINE;
import static org.openhab.core.thing.ThingStatusDetail.*;
import java.io.IOException;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.icloud.internal.ICloudDeviceInformationListener;
import org.openhab.binding.icloud.internal.configuration.ICloudDeviceThingConfiguration;
import org.openhab.binding.icloud.internal.json.response.ICloudDeviceInformation;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PointType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Handles updates of an iCloud device Thing.
*
* @author Patrik Gfeller - Initial contribution
* @author Hans-Jörg Merk - Helped with testing and feedback
* @author Gaël L'hopital - Added low battery
*
*/
@NonNullByDefault
public class ICloudDeviceHandler extends BaseThingHandler implements ICloudDeviceInformationListener {
private final Logger logger = LoggerFactory.getLogger(ICloudDeviceHandler.class);
private @Nullable String deviceId;
private @Nullable ICloudAccountBridgeHandler icloudAccount;
public ICloudDeviceHandler(Thing thing) {
super(thing);
}
@Override
public void deviceInformationUpdate(List<ICloudDeviceInformation> deviceInformationList) {
ICloudDeviceInformation deviceInformationRecord = getDeviceInformationRecord(deviceInformationList);
if (deviceInformationRecord != null) {
if (deviceInformationRecord.getDeviceStatus() == 200) {
updateStatus(ONLINE);
} else {
updateStatus(OFFLINE, COMMUNICATION_ERROR, "Reported offline by iCloud webservice");
}
updateState(BATTERY_STATUS, new StringType(deviceInformationRecord.getBatteryStatus()));
Double batteryLevel = deviceInformationRecord.getBatteryLevel();
if (batteryLevel != Double.NaN) {
updateState(BATTERY_LEVEL, new DecimalType(deviceInformationRecord.getBatteryLevel() * 100));
updateState(LOW_BATTERY, batteryLevel < 0.2 ? OnOffType.ON : OnOffType.OFF);
}
if (deviceInformationRecord.getLocation() != null) {
updateLocationRelatedStates(deviceInformationRecord);
}
} else {
updateStatus(OFFLINE, CONFIGURATION_ERROR, "The device is not included in the current account");
}
}
@Override
public void initialize() {
Bridge bridge = getBridge();
Object bridgeStatus = (bridge == null) ? null : bridge.getStatus();
logger.debug("initializeThing thing [{}]; bridge status: [{}]", getThing().getUID(), bridgeStatus);
ICloudDeviceThingConfiguration configuration = getConfigAs(ICloudDeviceThingConfiguration.class);
this.deviceId = configuration.deviceId;
ICloudAccountBridgeHandler handler = getIcloudAccount();
if (handler != null) {
refreshData();
} else {
updateStatus(OFFLINE, BRIDGE_UNINITIALIZED, "Bridge not found");
}
}
private void refreshData() {
ICloudAccountBridgeHandler bridge = getIcloudAccount();
if (bridge != null) {
bridge.refreshData();
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.trace("Command '{}' received for channel '{}'", command, channelUID);
ICloudAccountBridgeHandler bridge = getIcloudAccount();
if (bridge == null) {
logger.debug("No bridge found, ignoring command");
return;
}
String channelId = channelUID.getId();
if (channelId.equals(FIND_MY_PHONE)) {
if (command == OnOffType.ON) {
try {
final String deviceId = this.deviceId;
if (deviceId == null) {
logger.debug("Can't send Find My Device request, because deviceId is null!");
return;
}
bridge.findMyDevice(deviceId);
} catch (IOException e) {
logger.warn("Unable to execute find my device request", e);
}
updateState(FIND_MY_PHONE, OnOffType.OFF);
}
}
if (command instanceof RefreshType) {
bridge.refreshData();
}
}
@Override
public void dispose() {
ICloudAccountBridgeHandler bridge = getIcloudAccount();
if (bridge != null) {
bridge.unregisterListener(this);
}
super.dispose();
}
private void updateLocationRelatedStates(ICloudDeviceInformation deviceInformationRecord) {
DecimalType latitude = new DecimalType(deviceInformationRecord.getLocation().getLatitude());
DecimalType longitude = new DecimalType(deviceInformationRecord.getLocation().getLongitude());
DecimalType altitude = new DecimalType(deviceInformationRecord.getLocation().getAltitude());
DecimalType accuracy = new DecimalType(deviceInformationRecord.getLocation().getHorizontalAccuracy());
PointType location = new PointType(latitude, longitude, altitude);
updateState(LOCATION, location);
updateState(LOCATION_ACCURACY, accuracy);
updateState(LOCATION_LASTUPDATE, getLastLocationUpdateDateTimeState(deviceInformationRecord));
}
private @Nullable ICloudDeviceInformation getDeviceInformationRecord(
List<ICloudDeviceInformation> deviceInformationList) {
logger.debug("Device: [{}]", deviceId);
for (ICloudDeviceInformation deviceInformationRecord : deviceInformationList) {
String currentId = deviceInformationRecord.getId();
logger.debug("Current data element: [id = {}]", currentId);
if (currentId != null && currentId.equals(deviceId)) {
return deviceInformationRecord;
}
}
logger.debug("Unable to find device data.");
return null;
}
private State getLastLocationUpdateDateTimeState(ICloudDeviceInformation deviceInformationRecord) {
State dateTime = UnDefType.UNDEF;
if (deviceInformationRecord.getLocation().getTimeStamp() > 0) {
Date date = new Date(deviceInformationRecord.getLocation().getTimeStamp());
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
dateTime = new DateTimeType(zonedDateTime);
}
return dateTime;
}
private @Nullable ICloudAccountBridgeHandler getIcloudAccount() {
if (icloudAccount == null) {
Bridge bridge = getBridge();
if (bridge == null) {
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof ICloudAccountBridgeHandler) {
icloudAccount = (ICloudAccountBridgeHandler) handler;
icloudAccount.registerListener(this);
} else {
return null;
}
}
return icloudAccount;
}
}

View File

@@ -0,0 +1,60 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.json.request;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Serializable request for icloud device data.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
@NonNullByDefault
public class ICloudAccountDataRequest {
@SuppressWarnings("unused")
private ClientContext clientContext;
private ICloudAccountDataRequest() {
this.clientContext = ClientContext.defaultInstance();
}
public static ICloudAccountDataRequest defaultInstance() {
return new ICloudAccountDataRequest();
}
public static class ClientContext {
@SuppressWarnings("unused")
private String appName = "iCloud Find (Web)";
@SuppressWarnings("unused")
private boolean fmly = true;
@SuppressWarnings("unused")
private String appVersion = "2.0";
@SuppressWarnings("unused")
private String timezone = "US/Eastern";
@SuppressWarnings("unused")
private int inactiveTime = 2255;
@SuppressWarnings("unused")
private String apiVersion = "3.0";
@SuppressWarnings("unused")
private String webStats = "0:15";
private ClientContext() {
// empty to hide constructor
}
public static ClientContext defaultInstance() {
return new ClientContext();
}
}
}

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.json.request;
import static org.openhab.binding.icloud.internal.ICloudBindingConstants.FIND_MY_DEVICE_REQUEST_SUBJECT;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
/**
* Serializable class to create a "Find My Device" json request string.
*
* @author Patrik Gfeller - Initial Contribution
*/
@NonNullByDefault
public class ICloudFindMyDeviceRequest {
@SerializedName("device")
@Nullable
String deviceId;
final String subject = FIND_MY_DEVICE_REQUEST_SUBJECT;
public ICloudFindMyDeviceRequest(String id) {
deviceId = id;
}
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.json.response;
import java.util.List;
import com.google.gson.annotations.SerializedName;
/**
* Serializable class to parse the device information json response
* received from the Apple server.
*
* @author Patrik Gfeller - Initial Contribution
*/
public class ICloudAccountDataResponse {
@SerializedName("content")
private List<ICloudDeviceInformation> iCloudDeviceInformationList;
@SerializedName("serverContext")
private ICloudServerContext iCloudServerContext;
@SerializedName("statusCode")
private String iCloudAccountStatusCode;
@SerializedName("userInfo")
private ICloudAccountUserInfo iCloudAccountUserInfo;
public List<ICloudDeviceInformation> getICloudDeviceInformationList() {
return iCloudDeviceInformationList;
}
public String getICloudAccountStatusCode() {
return iCloudAccountStatusCode;
}
public ICloudAccountUserInfo getICloudAccountUserInfo() {
return iCloudAccountUserInfo;
}
}

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.json.response;
/**
* Serializable class to parse json response received from the Apple server.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
public class ICloudAccountUserInfo {
private int accountFormatter;
private String firstName;
private boolean hasMembers;
private String lastName;
private Object membersInfo;
public int getAccountFormatter() {
return this.accountFormatter;
}
public String getFirstName() {
return this.firstName;
}
public boolean getHasMembers() {
return this.hasMembers;
}
public String getLastName() {
return this.lastName;
}
public Object getMembersInfo() {
return this.membersInfo;
}
public void setAccountFormatter(int accountFormatter) {
this.accountFormatter = accountFormatter;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setHasMembers(boolean hasMembers) {
this.hasMembers = hasMembers;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setMembersInfo(Object membersInfo) {
this.membersInfo = membersInfo;
}
}

View File

@@ -0,0 +1,153 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.json.response;
/**
* Serializable class to parse json response received from the Apple server.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
public class ICloudDeviceFeatures {
private boolean CLK;
private boolean CLT;
private boolean CWP;
private boolean KEY;
private boolean KPD;
private boolean LCK;
private boolean LKL;
private boolean LKM;
private boolean LLC;
private boolean LMG;
private boolean LOC;
private boolean LST;
private boolean MCS;
private boolean MSG;
private boolean PIN;
private boolean REM;
private boolean SND;
private boolean SVP;
private boolean TEU;
private boolean WIP;
private boolean WMG;
private boolean XRM;
public boolean getCLK() {
return this.CLK;
}
public boolean getCLT() {
return this.CLT;
}
public boolean getCWP() {
return this.CWP;
}
public boolean getKEY() {
return this.KEY;
}
public boolean getKPD() {
return this.KPD;
}
public boolean getLCK() {
return this.LCK;
}
public boolean getLKL() {
return this.LKL;
}
public boolean getLKM() {
return this.LKM;
}
public boolean getLLC() {
return this.LLC;
}
public boolean getLMG() {
return this.LMG;
}
public boolean getLOC() {
return this.LOC;
}
public boolean getLST() {
return this.LST;
}
public boolean getMCS() {
return this.MCS;
}
public boolean getMSG() {
return this.MSG;
}
public boolean getPIN() {
return this.PIN;
}
public boolean getREM() {
return this.REM;
}
public boolean getSND() {
return this.SND;
}
public boolean getSVP() {
return this.SVP;
}
public boolean getTEU() {
return this.TEU;
}
public boolean getWIP() {
return this.WIP;
}
public boolean getWMG() {
return this.WMG;
}
public boolean getXRM() {
return this.XRM;
}
}

View File

@@ -0,0 +1,270 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.json.response;
import java.util.ArrayList;
/**
* Serializable class to parse json response received from the Apple server.
* Contains device specific status information.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
public class ICloudDeviceInformation {
private boolean activationLocked;
private ArrayList<Object> audioChannels;
private double batteryLevel;
private String batteryStatus;
private boolean canWipeAfterLock;
private boolean darkWake;
private String deviceClass;
private String deviceColor;
private String deviceDisplayName;
private String deviceModel;
private int deviceStatus;
private ICloudDeviceFeatures features;
private boolean fmlyShare;
private String id;
private boolean isLocating;
private boolean isMac;
private ICloudDeviceLocation location;
private boolean locationCapable;
private boolean locationEnabled;
private boolean locFoundEnabled;
private Object lockedTimestamp;
private Object lostDevice;
private boolean lostModeCapable;
private boolean lostModeEnabled;
private String lostTimestamp;
private boolean lowPowerMode;
private int maxMsgChar;
private Object mesg;
private String modelDisplayName;
private Object msg;
private String name;
private int passcodeLength;
private String prsId;
private String rawDeviceModel;
private Object remoteLock;
private Object remoteWipe;
private Object snd;
private boolean thisDevice;
private Object trackingInfo;
private Object wipedTimestamp;
private boolean wipeInProgress;
public boolean getActivationLocked() {
return this.activationLocked;
}
public ArrayList<Object> getAudioChannels() {
return this.audioChannels;
}
public double getBatteryLevel() {
return this.batteryLevel;
}
public String getBatteryStatus() {
return this.batteryStatus;
}
public boolean getCanWipeAfterLock() {
return this.canWipeAfterLock;
}
public boolean getDarkWake() {
return this.darkWake;
}
public String getDeviceClass() {
return this.deviceClass;
}
public String getDeviceColor() {
return this.deviceColor;
}
public String getDeviceDisplayName() {
return this.deviceDisplayName;
}
public String getDeviceModel() {
return this.deviceModel;
}
public int getDeviceStatus() {
return this.deviceStatus;
}
public ICloudDeviceFeatures getFeatures() {
return this.features;
}
public boolean getFmlyShare() {
return this.fmlyShare;
}
public String getId() {
return this.id;
}
public boolean getIsLocating() {
return this.isLocating;
}
public boolean getIsMac() {
return this.isMac;
}
public ICloudDeviceLocation getLocation() {
return this.location;
}
public boolean getLocationCapable() {
return this.locationCapable;
}
public boolean getLocationEnabled() {
return this.locationEnabled;
}
public boolean getLocFoundEnabled() {
return this.locFoundEnabled;
}
public Object getLockedTimestamp() {
return this.lockedTimestamp;
}
public Object getLostDevice() {
return this.lostDevice;
}
public boolean getLostModeCapable() {
return this.lostModeCapable;
}
public boolean getLostModeEnabled() {
return this.lostModeEnabled;
}
public String getLostTimestamp() {
return this.lostTimestamp;
}
public boolean getLowPowerMode() {
return this.lowPowerMode;
}
public int getMaxMsgChar() {
return this.maxMsgChar;
}
public Object getMesg() {
return this.mesg;
}
public String getModelDisplayName() {
return this.modelDisplayName;
}
public Object getMsg() {
return this.msg;
}
public String getName() {
return this.name;
}
public int getPasscodeLength() {
return this.passcodeLength;
}
public String getPrsId() {
return this.prsId;
}
public String getRawDeviceModel() {
return this.rawDeviceModel;
}
public Object getRemoteLock() {
return this.remoteLock;
}
public Object getRemoteWipe() {
return this.remoteWipe;
}
public Object getSnd() {
return this.snd;
}
public boolean getThisDevice() {
return this.thisDevice;
}
public Object getTrackingInfo() {
return this.trackingInfo;
}
public Object getWipedTimestamp() {
return this.wipedTimestamp;
}
public boolean getWipeInProgress() {
return this.wipeInProgress;
}
}

View File

@@ -0,0 +1,94 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.json.response;
/**
* Serializable class to parse json response received from the Apple server.
* Contains device location information.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
public class ICloudDeviceLocation {
private double altitude;
private int floorLevel;
private double horizontalAccuracy;
private boolean isInaccurate;
private boolean isOld;
private double latitude;
private boolean locationFinished;
private String locationType;
private double longitude;
private String positionType;
private long timeStamp;
private double verticalAccuracy;
public double getAltitude() {
return this.altitude;
}
public int getFloorLevel() {
return this.floorLevel;
}
public double getHorizontalAccuracy() {
return this.horizontalAccuracy;
}
public boolean getIsInaccurate() {
return this.isInaccurate;
}
public boolean getIsOld() {
return this.isOld;
}
public double getLatitude() {
return this.latitude;
}
public boolean getLocationFinished() {
return this.locationFinished;
}
public String getLocationType() {
return this.locationType;
}
public double getLongitude() {
return this.longitude;
}
public String getPositionType() {
return this.positionType;
}
public long getTimeStamp() {
return this.timeStamp;
}
public double getVerticalAccuracy() {
return this.verticalAccuracy;
}
}

View File

@@ -0,0 +1,204 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.json.response;
import org.eclipse.jdt.annotation.Nullable;
/**
* Serializable class to parse json response received from the Apple server.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
public class ICloudServerContext {
@Nullable
private String authToken;
private int callbackIntervalInMS;
private boolean classicUser;
private String clientId;
private boolean cloudUser;
private String deviceLoadStatus;
private boolean enable2FAErase;
private boolean enable2FAFamilyActions;
private boolean enable2FAFamilyRemove;
private boolean enableMapStats;
private String imageBaseUrl;
private String info;
private boolean isHSA;
private Object lastSessionExtensionTime;
private int macCount;
private int maxCallbackIntervalInMS;
private int maxDeviceLoadTime;
private int maxLocatingTime;
private int minCallbackIntervalInMS;
private int minTrackLocThresholdInMts;
private String preferredLanguage;
private long prefsUpdateTime;
private String prsId;
private long serverTimestamp;
private int sessionLifespan;
private boolean showSllNow;
private ICloudServerContextTimezone timezone;
private int trackInfoCacheDurationInSecs;
private boolean useAuthWidget;
private boolean validRegion;
public String getAuthToken() {
return this.authToken;
}
public int getCallbackIntervalInMS() {
return this.callbackIntervalInMS;
}
public boolean getClassicUser() {
return this.classicUser;
}
public String getClientId() {
return this.clientId;
}
public boolean getCloudUser() {
return this.cloudUser;
}
public String getDeviceLoadStatus() {
return this.deviceLoadStatus;
}
public boolean getEnable2FAErase() {
return this.enable2FAErase;
}
public boolean getEnable2FAFamilyActions() {
return this.enable2FAFamilyActions;
}
public boolean getEnable2FAFamilyRemove() {
return this.enable2FAFamilyRemove;
}
public boolean getEnableMapStats() {
return this.enableMapStats;
}
public String getImageBaseUrl() {
return this.imageBaseUrl;
}
public String getInfo() {
return this.info;
}
public boolean getIsHSA() {
return this.isHSA;
}
public Object getLastSessionExtensionTime() {
return this.lastSessionExtensionTime;
}
public int getMacCount() {
return this.macCount;
}
public int getMaxCallbackIntervalInMS() {
return this.maxCallbackIntervalInMS;
}
public int getMaxDeviceLoadTime() {
return this.maxDeviceLoadTime;
}
public int getMaxLocatingTime() {
return this.maxLocatingTime;
}
public int getMinCallbackIntervalInMS() {
return this.minCallbackIntervalInMS;
}
public int getMinTrackLocThresholdInMts() {
return this.minTrackLocThresholdInMts;
}
public String getPreferredLanguage() {
return this.preferredLanguage;
}
public long getPrefsUpdateTime() {
return this.prefsUpdateTime;
}
public String getPrsId() {
return this.prsId;
}
public long getServerTimestamp() {
return this.serverTimestamp;
}
public int getSessionLifespan() {
return this.sessionLifespan;
}
public boolean getShowSllNow() {
return this.showSllNow;
}
public ICloudServerContextTimezone getTimezone() {
return this.timezone;
}
public int getTrackInfoCacheDurationInSecs() {
return this.trackInfoCacheDurationInSecs;
}
public boolean getUseAuthWidget() {
return this.useAuthWidget;
}
public boolean getValidRegion() {
return this.validRegion;
}
}

View File

@@ -0,0 +1,51 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.json.response;
/**
* Serializable class to parse json response received from the Apple server.
*
* @author Patrik Gfeller - Initial Contribution
*
*/
public class ICloudServerContextTimezone {
private int currentOffset;
private int previousOffset;
private long previousTransition;
private String tzCurrentName;
private String tzName;
public int getCurrentOffset() {
return this.currentOffset;
}
public int getPreviousOffset() {
return this.previousOffset;
}
public long getPreviousTransition() {
return this.previousTransition;
}
public String getTzCurrentName() {
return this.tzCurrentName;
}
public String getTzName() {
return this.tzName;
}
}

View File

@@ -0,0 +1,47 @@
/**
* Copyright (c) 2010-2020 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.icloud.internal.utilities;
import java.util.Locale;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.osgi.framework.Bundle;
/**
* Utility class to translate strings (i18n).
*
* @author Patrik Gfeller - Initial contribution
*/
public class ICloudTextTranslator {
private final Bundle bundle;
private final TranslationProvider i18nProvider;
private final LocaleProvider localeProvider;
public ICloudTextTranslator(Bundle bundle, TranslationProvider i18nProvider, LocaleProvider localeProvider) {
this.bundle = bundle;
this.i18nProvider = i18nProvider;
this.localeProvider = localeProvider;
}
public String getText(String key, Object... arguments) {
Locale locale = localeProvider != null ? localeProvider.getLocale() : Locale.ENGLISH;
return i18nProvider != null ? i18nProvider.getText(bundle, key, getDefaultText(key), locale, arguments) : key;
}
public String getDefaultText(@Nullable String key) {
return i18nProvider.getText(bundle, key, key, Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="icloud" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>@text/icloud.binding.name</name>
<description>@text/icloud.binding.description</description>
<author>Patrik Gfeller</author>
</binding:binding>

View File

@@ -0,0 +1,34 @@
# Binding
icloud.binding.name=iCloud Binding
icloud.binding.description=The Apple iCloud is used to retrieve data such as the battery level or current location of one or multiple Apple devices connected to an iCloud account. Updates are quick and accurate without significant battery time impact.
# Account Thing
icloud.account-thing.label=iCloud Account
icloud.account-thing.description=The account Thing, more precisely the account Bridge, represents one Apple iCloud account. You may create multiple account Things for multiple accounts.
icloud.account-thing.parameter.apple-id.label=Apple Id
icloud.account-thing.parameter.apple-id.description=Apple Id (e-mail) to access iCloud information.
icloud.account-thing.parameter.password.label=Password
icloud.account-thing.parameter.password.description=Apple iCloud password for the given Id.
icloud.account-thing.parameter.refresh.label=Refresh
icloud.account-thing.parameter.refresh.description=Refresh time in minutes.
icloud.account-thing.property.owner=Owner
# Device Thing
icloud.device-thing.label=iCloud Device
icloud.device-thing.description=The device Thing represents an Apple device, like for example a phone. It needs to be connected to an account Thing to receive updates. Multiple devices can be connected to one account.
icloud.device-thing.parameter.id.label=Device id
icloud.device-thing.channel.battery-status.label=Battery Status
icloud.device-thing.channel.battery-status.state.not-charging=Not charging
icloud.device-thing.channel.battery-status.state.charged=Charged
icloud.device-thing.channel.battery-status.state.charging=Charging
icloud.device-thing.channel.battery-status.state.unknown=Unknown
icloud.device-thing.channel.find-my-phone.label=Find My Phone
icloud.device-thing.channel.location.label=Location
icloud.device-thing.channel.location-accuracy=Location Accuracy
icloud.device-thing.channel.location-last-update=Last Location Update
icloud.device-thing.property.device-name=Device name

View File

@@ -0,0 +1,29 @@
# Binding
icloud.binding.name=Extension iCloud
icloud.binding.description=Apple iCloud est utilisé pour obtenir des données telles que le niveau de la batterie ou la localisation d'un ou plusieurs appareils Apple connectés à un compte iCloud. Les mises à jour sont rapides et précises sans impact notable sur la batterie.
# Account Thing
icloud.account-thing.label=Compte iCloud
icloud.account-thing.description=Ce Bridge vers le compte, représente votre compte Apple iCloud. Vous pouvez en créer plusieurs si vous disposez de plusieurs comptes iCloud.
icloud.account-thing.parameter.apple-id.label=Apple Id
icloud.account-thing.parameter.apple-id.description=Apple Id (e-mail) permettant l'accès aux informations iCloud.
icloud.account-thing.parameter.password.label=Mot de Passe
icloud.account-thing.parameter.password.description=Mot de passe Apple iCloud pour l'Apple Id
icloud.account-thing.parameter.refresh.label=Rafraîchir
icloud.account-thing.parameter.refresh.description=Période de rafraîchissement en minutes.
icloud.account-thing.property.owner=Propriétaire
# Device Thing
icloud.device-thing.label=Equipement iCloud
icloud.device-thing.description=Ce 'Thing' représente un appareil Apple, tel par exemple un téléphone. Il doit être connecté à un 'Thing' Compte pour être mis à jour. Plusieurs équipement peuvent être rattachés à un même compte.
icloud.device-thing.parameter.id.label=Identifiant de l'appareil
icloud.device-thing.channel.battery-status.label=Status de la batterie
icloud.device-thing.channel.battery-status.state.not-charging=Pas en charge
icloud.device-thing.channel.battery-status.state.charged=Chargée
icloud.device-thing.channel.battery-status.state.charging=En charge
icloud.device-thing.channel.battery-status.state.unknown=Inconnu
icloud.device-thing.channel.find-my-phone.label=Trouver mon iPhone
icloud.device-thing.channel.location.label=Localisation
icloud.device-thing.channel.location-accuracy=Precision de localisation
icloud.device-thing.channel.location-last-update=Dernière mise à jour de la localisation
icloud.device-thing.property.device-name=Nom de l'appareil

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="icloud"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="account">
<label>@text/icloud.account-thing.label</label>
<description>@text/icloud.account-thing.description</description>
<config-description>
<parameter name="appleId" type="text" required="true">
<context>email</context>
<label>@text/icloud.account-thing.parameter.apple-id.label</label>
<description>@text/icloud.account-thing.parameter.apple-id.description</description>
</parameter>
<parameter name="password" type="text" required="true">
<context>password</context>
<label>@text/icloud.account-thing.parameter.password.label</label>
<description>@text/icloud.account-thing.parameter.password.description</description>
</parameter>
<parameter name="refreshTimeInMinutes" type="integer" min="5" max="65535" unit="min">
<label>@text/icloud.account-thing.parameter.refresh.label</label>
<description>@text/icloud.account-thing.parameter.refresh.description</description>
<default>5</default>
</parameter>
</config-description>
</bridge-type>
<thing-type id="device">
<supported-bridge-type-refs>
<bridge-type-ref id="account"/>
</supported-bridge-type-refs>
<label>@text/icloud.device-thing.label</label>
<description>@text/icloud.device-thing.description</description>
<channels>
<channel typeId="BatteryStatus" id="batteryStatus"/>
<channel typeId="system.battery-level" id="batteryLevel"/>
<channel typeId="system.low-battery" id="lowBattery"/>
<channel typeId="FindMyPhone" id="findMyPhone"/>
<channel typeId="Location" id="location"/>
<channel typeId="LocationAccuracy" id="locationAccuracy"/>
<channel typeId="LocationLastUpdate" id="locationLastUpdate"/>
</channels>
<representation-property>deviceId</representation-property>
<config-description>
<parameter name="deviceId" type="text" required="true">
<label>@text/icloud.device-thing.parameter.id.label</label>
</parameter>
</config-description>
</thing-type>
<channel-type id="BatteryStatus">
<item-type>String</item-type>
<label>@text/icloud.device-thing.channel.battery-status.label</label>
<state readOnly="true">
<options>
<option value="NotCharging">@text/icloud.device-thing.channel.battery-status.state.not-charging</option>
<option value="Charged">@text/icloud.device-thing.channel.battery-status.state.charged</option>
<option value="Charging">@text/icloud.device-thing.channel.battery-status.state.charging</option>
<option value="Unknown">@text/icloud.device-thing.channel.battery-status.state.unknown</option>
</options>
</state>
</channel-type>
<channel-type id="FindMyPhone">
<item-type>Switch</item-type>
<label>@text/icloud.device-thing.channel.find-my-phone.label</label>
</channel-type>
<channel-type id="Location">
<item-type>Location</item-type>
<label>@text/icloud.device-thing.channel.location.label</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="LocationAccuracy" advanced="true">
<item-type>Number</item-type>
<label>@text/icloud.device-thing.channel.location-accuracy</label>
<state readOnly="true" pattern="%d m"/>
</channel-type>
<channel-type id="LocationLastUpdate" advanced="true">
<item-type>DateTime</item-type>
<label>@text/icloud.device-thing.channel.location-last-update</label>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>