[ring] Refactor discovery and allow multiple accounts (#18767)
With this refactoring the device registry is bound to the account bridge, making it possible to use multiple ring accounts. It also changes the discovery service to a `ThingHandlerService, simplifying code. Signed-off-by: Jan N. Klug <github@klug.nrw>pull/18778/head
parent
886c170631
commit
5437a6685c
|
@ -331,7 +331,7 @@
|
|||
/bundles/org.openhab.binding.resol/ @ramack
|
||||
/bundles/org.openhab.binding.revogi/ @openhab/add-ons-maintainers
|
||||
/bundles/org.openhab.binding.rfxcom/ @martinvw @paulianttila
|
||||
/bundles/org.openhab.binding.ring/ @morph166955
|
||||
/bundles/org.openhab.binding.ring/ @psmedley
|
||||
/bundles/org.openhab.binding.rme/ @kgoderis
|
||||
/bundles/org.openhab.binding.robonect/ @reyem
|
||||
/bundles/org.openhab.binding.roku/ @mlobstein
|
||||
|
|
|
@ -17,12 +17,13 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.ring.internal.RingDeviceRegistry;
|
||||
import org.openhab.binding.ring.internal.RingAccount;
|
||||
import org.openhab.binding.ring.internal.errors.DeviceNotFoundException;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.BridgeHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -104,15 +105,18 @@ public abstract class AbstractRingHandler extends BaseThingHandler {
|
|||
|
||||
@Override
|
||||
public void handleRemoval() {
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
final String id = getThing().getUID().getId();
|
||||
final RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
||||
try {
|
||||
registry.removeRingDevice(id);
|
||||
} catch (final DeviceNotFoundException e) {
|
||||
logger.debug("Exception occurred during execution of handleRemoval(): {}", e.getMessage(), e);
|
||||
} finally {
|
||||
updateStatus(ThingStatus.REMOVED);
|
||||
String id = getThing().getUID().getId();
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null) {
|
||||
BridgeHandler bridgeHandler = bridge.getHandler();
|
||||
if (bridgeHandler instanceof RingAccount ringAccount) {
|
||||
try {
|
||||
ringAccount.getDeviceRegistry().removeRingDevice(id);
|
||||
} catch (DeviceNotFoundException ignored) {
|
||||
logger.warn("Tried to remove a device that was not present in the ring account: {}", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.handleRemoval();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@ import java.net.InetAddress;
|
|||
import java.net.NetworkInterface;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
@ -34,8 +36,9 @@ import org.openhab.binding.ring.internal.RingAccount;
|
|||
import org.openhab.binding.ring.internal.RingDeviceRegistry;
|
||||
import org.openhab.binding.ring.internal.RingVideoServlet;
|
||||
import org.openhab.binding.ring.internal.data.Profile;
|
||||
import org.openhab.binding.ring.internal.data.RingDevices;
|
||||
import org.openhab.binding.ring.internal.data.RingDevicesTO;
|
||||
import org.openhab.binding.ring.internal.data.RingEventTO;
|
||||
import org.openhab.binding.ring.internal.discovery.RingDiscoveryService;
|
||||
import org.openhab.binding.ring.internal.errors.AuthenticationException;
|
||||
import org.openhab.binding.ring.internal.errors.DuplicateIdException;
|
||||
import org.openhab.binding.ring.internal.utils.RingUtils;
|
||||
|
@ -50,6 +53,7 @@ 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.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.osgi.service.http.HttpService;
|
||||
|
@ -75,7 +79,6 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
|||
private @Nullable Runnable runnableVideo = null;
|
||||
private @Nullable RingVideoServlet ringVideoServlet;
|
||||
private final HttpService httpService;
|
||||
private final String thingId;
|
||||
|
||||
// Current status
|
||||
protected OnOffType status = OnOffType.OFF;
|
||||
|
@ -92,7 +95,7 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
|||
/**
|
||||
* The registry.
|
||||
*/
|
||||
private final RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
||||
private final RingDeviceRegistry registry;
|
||||
/**
|
||||
* The RestClient is used to connect to the Ring Account.
|
||||
*/
|
||||
|
@ -129,7 +132,7 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
|||
this.networkAddressService = networkAddressService;
|
||||
this.httpService = httpService;
|
||||
this.videoExecutorService = Executors.newCachedThreadPool();
|
||||
this.thingId = this.getThing().getUID().getId();
|
||||
this.registry = new RingDeviceRegistry();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -227,7 +230,7 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
|||
|
||||
private void saveRefreshTokenToFile(String refreshToken) {
|
||||
String folderName = OpenHAB.getUserDataFolder() + "/ring";
|
||||
String thingId = this.thingId;
|
||||
String thingId = getThing().getUID().getId();
|
||||
File folder = new File(folderName);
|
||||
String fileName = folderName + "/ring." + thingId + ".refreshToken";
|
||||
|
||||
|
@ -246,7 +249,7 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
|||
private String getRefreshTokenFromFile() {
|
||||
String refreshToken = "";
|
||||
String folderName = OpenHAB.getUserDataFolder() + "/ring";
|
||||
String thingId = this.thingId;
|
||||
String thingId = getThing().getUID().getId();
|
||||
String fileName = folderName + "/ring." + thingId + ".refreshToken";
|
||||
File file = new File(fileName);
|
||||
if (!file.exists()) {
|
||||
|
@ -398,8 +401,8 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
|||
|
||||
private void refreshRegistry() throws JsonParseException, AuthenticationException, DuplicateIdException {
|
||||
logger.debug("AccountHandler - refreshRegistry");
|
||||
RingDevices ringDevices = restClient.getRingDevices(userProfile, this);
|
||||
registry.addRingDevices(ringDevices.getRingDevices());
|
||||
RingDevicesTO ringDevices = restClient.getRingDevices(userProfile, this);
|
||||
registry.addOrUpdateRingDevices(ringDevices);
|
||||
}
|
||||
|
||||
protected void minuteTick() {
|
||||
|
@ -578,21 +581,6 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
|||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable RestClient getRestClient() {
|
||||
return restClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Profile getProfile() {
|
||||
return userProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThingId() {
|
||||
return thingId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose of the refreshJob nicely.
|
||||
*/
|
||||
|
@ -607,4 +595,14 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
|||
this.videoExecutorService = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RingDeviceRegistry getDeviceRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Set.of(RingDiscoveryService.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,9 +47,9 @@ public class ChimeHandler extends RingDeviceHandler {
|
|||
logger.debug("Initializing Chime handler");
|
||||
super.initialize();
|
||||
|
||||
RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
||||
RingDeviceRegistry registry = getDeviceRegistry();
|
||||
String id = getThing().getUID().getId();
|
||||
if (registry.isInitialized()) {
|
||||
if (registry != null && registry.isInitialized()) {
|
||||
try {
|
||||
linkDevice(id, Chime.class);
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
|
|
@ -54,9 +54,9 @@ public class DoorbellHandler extends RingDeviceHandler {
|
|||
logger.debug("Initializing Doorbell handler");
|
||||
super.initialize();
|
||||
|
||||
RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
||||
RingDeviceRegistry registry = getDeviceRegistry();
|
||||
String id = getThing().getUID().getId();
|
||||
if (registry.isInitialized()) {
|
||||
if (registry != null && registry.isInitialized()) {
|
||||
try {
|
||||
linkDevice(id, Doorbell.class);
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
@ -102,13 +102,13 @@ public class DoorbellHandler extends RingDeviceHandler {
|
|||
if (device == null) {
|
||||
initialize();
|
||||
}
|
||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
||||
if ((deviceTO != null) && (deviceTO.health.batteryPercentage != lastBattery)) {
|
||||
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||
if (deviceTO.health.batteryPercentage != lastBattery) {
|
||||
logger.debug("Battery Level: {}", deviceTO.health.batteryPercentage);
|
||||
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_STATUS_BATTERY);
|
||||
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
||||
lastBattery = deviceTO.health.batteryPercentage;
|
||||
} else if (deviceTO != null) {
|
||||
} else {
|
||||
logger.debug("Battery Level Unchanged for {} - {} vs {}", getThing().getUID().getId(),
|
||||
deviceTO.health.batteryPercentage, lastBattery);
|
||||
}
|
||||
|
|
|
@ -53,9 +53,9 @@ public class OtherDeviceHandler extends RingDeviceHandler {
|
|||
logger.debug("Initializing Other Device handler");
|
||||
super.initialize();
|
||||
|
||||
RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
||||
RingDeviceRegistry registry = getDeviceRegistry();
|
||||
String id = getThing().getUID().getId();
|
||||
if (registry.isInitialized()) {
|
||||
if (registry != null && registry.isInitialized()) {
|
||||
try {
|
||||
linkDevice(id, OtherDevice.class);
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
@ -102,13 +102,13 @@ public class OtherDeviceHandler extends RingDeviceHandler {
|
|||
initialize();
|
||||
}
|
||||
|
||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
||||
if ((deviceTO != null) && (deviceTO.health.batteryPercentage != lastBattery)) {
|
||||
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||
if (deviceTO.health.batteryPercentage != lastBattery) {
|
||||
logger.debug("Battery Level: {}", deviceTO.health.batteryPercentage);
|
||||
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_STATUS_BATTERY);
|
||||
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
||||
lastBattery = deviceTO.health.batteryPercentage;
|
||||
} else if (deviceTO != null) {
|
||||
} else {
|
||||
logger.debug("Battery Level Unchanged for {} - {} vs {}", getThing().getUID().getId(),
|
||||
deviceTO.health.batteryPercentage, lastBattery);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import static org.openhab.binding.ring.RingBindingConstants.*;
|
|||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.ring.internal.RingAccount;
|
||||
import org.openhab.binding.ring.internal.RingDeviceRegistry;
|
||||
import org.openhab.binding.ring.internal.data.RingDevice;
|
||||
import org.openhab.binding.ring.internal.data.RingDeviceTO;
|
||||
|
@ -26,8 +27,10 @@ import org.openhab.core.library.types.DecimalType;
|
|||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.UpDownType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.binding.BridgeHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
|
||||
|
@ -53,6 +56,17 @@ public abstract class RingDeviceHandler extends AbstractRingHandler {
|
|||
super(thing, gson);
|
||||
}
|
||||
|
||||
protected @Nullable RingDeviceRegistry getDeviceRegistry() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null) {
|
||||
BridgeHandler bridgeHandler = bridge.getHandler();
|
||||
if (bridgeHandler instanceof RingAccount ringAccount) {
|
||||
return ringAccount.getDeviceRegistry();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link the device, and update the device with the status CONFIGURED.
|
||||
*
|
||||
|
@ -63,17 +77,15 @@ public abstract class RingDeviceHandler extends AbstractRingHandler {
|
|||
*/
|
||||
protected void linkDevice(String id, Class<?> deviceClass)
|
||||
throws DeviceNotFoundException, IllegalDeviceClassException {
|
||||
device = RingDeviceRegistry.getInstance().getRingDevice(id);
|
||||
if (device != null) {
|
||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
||||
RingDeviceRegistry registry = getDeviceRegistry();
|
||||
if (registry != null) {
|
||||
device = registry.getRingDevice(id);
|
||||
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||
if (deviceClass.equals(device.getClass())) {
|
||||
device.setRegistrationStatus(RingDeviceRegistry.Status.CONFIGURED);
|
||||
device.setRingDeviceHandler(this);
|
||||
if (deviceTO != null) {
|
||||
thing.setProperty("Description", deviceTO.description);
|
||||
thing.setProperty("Kind", deviceTO.kind);
|
||||
thing.setProperty("Device ID", deviceTO.deviceId);
|
||||
}
|
||||
thing.setProperty("Description", deviceTO.description);
|
||||
thing.setProperty("Kind", deviceTO.kind);
|
||||
thing.setProperty("Device ID", deviceTO.deviceId);
|
||||
} else {
|
||||
throw new IllegalDeviceClassException("Class '" + deviceClass.getName() + "' expected but '"
|
||||
+ device.getClass().getName() + "' found.");
|
||||
|
@ -93,10 +105,8 @@ public abstract class RingDeviceHandler extends AbstractRingHandler {
|
|||
updateState(channelUID, enabled);
|
||||
break;
|
||||
case CHANNEL_STATUS_BATTERY:
|
||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
||||
if (deviceTO != null) {
|
||||
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
||||
}
|
||||
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
||||
break;
|
||||
default:
|
||||
logger.debug("Command received for an unknown channel: {}", channelUID.getId());
|
||||
|
|
|
@ -54,9 +54,9 @@ public class StickupcamHandler extends RingDeviceHandler {
|
|||
logger.debug("Initializing Stickupcam handler");
|
||||
super.initialize();
|
||||
|
||||
RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
||||
RingDeviceRegistry registry = getDeviceRegistry();
|
||||
String id = getThing().getUID().getId();
|
||||
if (registry.isInitialized()) {
|
||||
if (registry != null && registry.isInitialized()) {
|
||||
try {
|
||||
linkDevice(id, Stickupcam.class);
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
@ -102,13 +102,13 @@ public class StickupcamHandler extends RingDeviceHandler {
|
|||
if (device == null) {
|
||||
initialize();
|
||||
}
|
||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
||||
if ((deviceTO != null) && (deviceTO.health.batteryPercentage != lastBattery)) {
|
||||
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||
if (deviceTO.health.batteryPercentage != lastBattery) {
|
||||
logger.debug("Battery Level: {}", deviceTO.battery);
|
||||
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_STATUS_BATTERY);
|
||||
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
||||
lastBattery = deviceTO.health.batteryPercentage;
|
||||
} else if (deviceTO != null) {
|
||||
} else {
|
||||
logger.debug("Battery Level Unchanged for {} - {} vs {}", getThing().getUID().getId(),
|
||||
deviceTO.health.batteryPercentage, lastBattery);
|
||||
|
||||
|
|
|
@ -46,10 +46,9 @@ import javax.net.ssl.TrustManager;
|
|||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.ring.internal.data.DataFactory;
|
||||
import org.openhab.binding.ring.internal.data.ParamBuilder;
|
||||
import org.openhab.binding.ring.internal.data.Profile;
|
||||
import org.openhab.binding.ring.internal.data.RingDevices;
|
||||
import org.openhab.binding.ring.internal.data.RingDevicesTO;
|
||||
import org.openhab.binding.ring.internal.data.RingEventTO;
|
||||
import org.openhab.binding.ring.internal.errors.AuthenticationException;
|
||||
import org.openhab.binding.ring.internal.utils.RingUtils;
|
||||
|
@ -277,12 +276,7 @@ public class RestClient {
|
|||
}
|
||||
|
||||
JsonObject oauthToken = getOauthToken(username, password, refToken);
|
||||
String jsonResult = postRequest(ApiConstants.URL_SESSION, DataFactory.getSessionParams(hardwareId),
|
||||
oauthToken.get("access_token").getAsString());
|
||||
|
||||
JsonObject obj = JsonParser.parseString(jsonResult).getAsJsonObject();
|
||||
return new Profile((JsonObject) obj.get("profile"), oauthToken.get("refresh_token").getAsString(),
|
||||
oauthToken.get("access_token").getAsString());
|
||||
return new Profile(oauthToken.get("refresh_token").getAsString(), oauthToken.get("access_token").getAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -522,12 +516,11 @@ public class RestClient {
|
|||
* @throws AuthenticationException when request is invalid.
|
||||
* @throws JsonParseException when response is invalid JSON.
|
||||
*/
|
||||
public RingDevices getRingDevices(Profile profile, RingAccount ringAccount)
|
||||
public RingDevicesTO getRingDevices(Profile profile, RingAccount ringAccount)
|
||||
throws JsonParseException, AuthenticationException {
|
||||
logger.debug("RestClient - getRingDevices");
|
||||
String jsonResult = getRequest(ApiConstants.URL_DEVICES, profile);
|
||||
JsonObject obj = JsonParser.parseString(jsonResult).getAsJsonObject();
|
||||
return new RingDevices(obj, ringAccount);
|
||||
return Objects.requireNonNull(gson.fromJson(jsonResult, RingDevicesTO.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
package org.openhab.binding.ring.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.ring.internal.data.Profile;
|
||||
|
||||
/**
|
||||
* The AccountHandler implements this interface to facilitate the
|
||||
|
@ -25,26 +23,10 @@ import org.openhab.binding.ring.internal.data.Profile;
|
|||
*/
|
||||
@NonNullByDefault
|
||||
public interface RingAccount {
|
||||
|
||||
/**
|
||||
* Get the linked REST client.
|
||||
* Get the Device Registry
|
||||
*
|
||||
* @return the REST client.
|
||||
* @return the ring device registry
|
||||
*/
|
||||
public @Nullable RestClient getRestClient();
|
||||
|
||||
/**
|
||||
* Get the linked user profile.
|
||||
*
|
||||
* @return the user profile.
|
||||
*/
|
||||
public @Nullable Profile getProfile();
|
||||
|
||||
/**
|
||||
* Get the Account Handler Thing ID
|
||||
* *
|
||||
*
|
||||
* @return the ring account thing id.
|
||||
*/
|
||||
public String getThingId();
|
||||
RingDeviceRegistry getDeviceRegistry();
|
||||
}
|
||||
|
|
|
@ -13,19 +13,22 @@
|
|||
package org.openhab.binding.ring.internal;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.ring.internal.data.Chime;
|
||||
import org.openhab.binding.ring.internal.data.Doorbell;
|
||||
import org.openhab.binding.ring.internal.data.OtherDevice;
|
||||
import org.openhab.binding.ring.internal.data.RingDevice;
|
||||
import org.openhab.binding.ring.internal.data.RingDeviceTO;
|
||||
import org.openhab.binding.ring.internal.data.RingDevicesTO;
|
||||
import org.openhab.binding.ring.internal.data.Stickupcam;
|
||||
import org.openhab.binding.ring.internal.errors.DeviceNotFoundException;
|
||||
import org.openhab.binding.ring.internal.errors.DuplicateIdException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* Singleton registry of found devices.
|
||||
*
|
||||
|
@ -35,15 +38,6 @@ import com.google.gson.Gson;
|
|||
|
||||
@NonNullByDefault
|
||||
public class RingDeviceRegistry {
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
/**
|
||||
* static Singleton instance.
|
||||
*/
|
||||
private static final RingDeviceRegistry INSTANCE = new RingDeviceRegistry();
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(RingDeviceRegistry.class);
|
||||
/**
|
||||
* Will be set after initialization.
|
||||
|
@ -51,51 +45,35 @@ public class RingDeviceRegistry {
|
|||
private boolean initialized;
|
||||
|
||||
/**
|
||||
* Key: device id.
|
||||
* Value: the RingDevice implementation object.
|
||||
* Key: device id. Value: the RingDevice implementation object.
|
||||
*/
|
||||
private ConcurrentHashMap<String, RingDevice> devices = new ConcurrentHashMap<>();
|
||||
private final Map<String, RingDevice> devices = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Return a singleton instance of RingDeviceRegistry.
|
||||
*/
|
||||
public static RingDeviceRegistry getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new ring device.
|
||||
*/
|
||||
public void addRingDevice(RingDevice ringDevice) throws DuplicateIdException {
|
||||
RingDeviceTO deviceTO = gson.fromJson(ringDevice.getJsonObject(), RingDeviceTO.class);
|
||||
if (deviceTO != null) {
|
||||
if (devices.containsKey(deviceTO.id)) {
|
||||
throw new DuplicateIdException("Ring device with duplicate id " + deviceTO.id + " ignored");
|
||||
private void addOrUpdateRingDevice(RingDeviceTO deviceTO, Function<RingDeviceTO, RingDevice> creator) {
|
||||
devices.compute(deviceTO.id, (id, existing) -> {
|
||||
if (existing == null) {
|
||||
RingDevice device = creator.apply(deviceTO);
|
||||
device.setRegistrationStatus(Status.ADDED);
|
||||
return device;
|
||||
} else {
|
||||
ringDevice.setRegistrationStatus(Status.ADDED);
|
||||
devices.put(deviceTO.id, ringDevice);
|
||||
logger.debug(
|
||||
"RingDeviceRegistry - addRingDevices - Ring device with duplicate id {} ignored. Updating Json.",
|
||||
deviceTO.id);
|
||||
existing.setDeviceStatus(deviceTO);
|
||||
return existing;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new ring device collection.
|
||||
*/
|
||||
public synchronized void addRingDevices(Collection<RingDevice> ringDevices) {
|
||||
for (RingDevice device : ringDevices) {
|
||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
||||
if (deviceTO != null) {
|
||||
logger.debug("RingDeviceRegistry - addRingDevices - Trying: {}", deviceTO.id);
|
||||
try {
|
||||
addRingDevice(device);
|
||||
} catch (DuplicateIdException e) {
|
||||
logger.debug(
|
||||
"RingDeviceRegistry - addRingDevices - Ring device with duplicate id {} ignored. Updating Json.",
|
||||
deviceTO.id);
|
||||
devices.get(deviceTO.id).setJsonObject(device.getJsonObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
public synchronized void addOrUpdateRingDevices(RingDevicesTO ringDevices) {
|
||||
ringDevices.doorbells.forEach(deviceTO -> addOrUpdateRingDevice(deviceTO, Doorbell::new));
|
||||
ringDevices.chimes.forEach(deviceTO -> addOrUpdateRingDevice(deviceTO, Chime::new));
|
||||
ringDevices.stickupCams.forEach(deviceTO -> addOrUpdateRingDevice(deviceTO, Stickupcam::new));
|
||||
ringDevices.other.forEach(deviceTO -> addOrUpdateRingDevice(deviceTO, OtherDevice::new));
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
|
@ -115,9 +93,10 @@ public class RingDeviceRegistry {
|
|||
* @return the RingDevice instance from the registry.
|
||||
* @throws DeviceNotFoundException
|
||||
*/
|
||||
public @Nullable RingDevice getRingDevice(String id) throws DeviceNotFoundException {
|
||||
if (devices.containsKey(id)) {
|
||||
return devices.get(id);
|
||||
public RingDevice getRingDevice(String id) throws DeviceNotFoundException {
|
||||
RingDevice device = devices.get(id);
|
||||
if (device != null) {
|
||||
return device;
|
||||
} else {
|
||||
throw new DeviceNotFoundException("Device with id '" + id + "' not found");
|
||||
}
|
||||
|
@ -130,8 +109,9 @@ public class RingDeviceRegistry {
|
|||
* @throws DeviceNotFoundException
|
||||
*/
|
||||
public void removeRingDevice(String id) throws DeviceNotFoundException {
|
||||
if (devices.containsKey(id)) {
|
||||
devices.remove(id);
|
||||
RingDevice device = devices.get(id);
|
||||
if (device != null) {
|
||||
device.setRegistrationStatus(Status.ADDED);
|
||||
} else {
|
||||
throw new DeviceNotFoundException("Device with id '" + id + "' not found");
|
||||
}
|
||||
|
@ -164,7 +144,6 @@ public class RingDeviceRegistry {
|
|||
* The registry status of the device.
|
||||
*
|
||||
* @author Wim Vissers
|
||||
*
|
||||
*/
|
||||
public enum Status {
|
||||
/**
|
||||
|
@ -172,8 +151,7 @@ public class RingDeviceRegistry {
|
|||
*/
|
||||
ADDED,
|
||||
/**
|
||||
* When reported to the system as discovered device. It will show up
|
||||
* in the inbox.
|
||||
* When reported to the system as discovered device. It will show up in the inbox.
|
||||
*/
|
||||
DISCOVERED,
|
||||
/**
|
||||
|
|
|
@ -13,16 +13,10 @@
|
|||
package org.openhab.binding.ring.internal.data;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.ring.handler.RingDeviceHandler;
|
||||
import org.openhab.binding.ring.internal.RingAccount;
|
||||
import org.openhab.binding.ring.internal.RingDeviceRegistry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* Interface common to all Ring devices.
|
||||
*
|
||||
|
@ -32,31 +26,12 @@ import com.google.gson.JsonObject;
|
|||
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractRingDevice implements RingDevice {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AbstractRingDevice.class);
|
||||
public final Gson gson = new Gson();
|
||||
|
||||
/**
|
||||
* The JsonObject contains the data retrieved from the Ring API,
|
||||
* or the data to send to the API.
|
||||
*/
|
||||
protected JsonObject jsonObject = new JsonObject();
|
||||
/**
|
||||
* The registration status.
|
||||
*/
|
||||
private RingDeviceTO deviceStatus;
|
||||
private RingDeviceRegistry.Status registrationStatus = RingDeviceRegistry.Status.ADDED;
|
||||
/**
|
||||
* The linked Ring account.
|
||||
*/
|
||||
private final RingAccount ringAccount;
|
||||
/**
|
||||
* The linked RingDeviceHandler.
|
||||
*/
|
||||
private @Nullable RingDeviceHandler ringDeviceHandler;
|
||||
|
||||
protected AbstractRingDevice(JsonObject jsonObject, RingAccount ringAccount) {
|
||||
this.jsonObject = jsonObject;
|
||||
this.ringAccount = ringAccount;
|
||||
protected AbstractRingDevice(RingDeviceTO jsonObject) {
|
||||
this.deviceStatus = jsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,52 +47,21 @@ public abstract class AbstractRingDevice implements RingDevice {
|
|||
/**
|
||||
* Set the registration status.
|
||||
*
|
||||
* @param status
|
||||
* @param registrationStatus
|
||||
*/
|
||||
@Override
|
||||
public void setRegistrationStatus(RingDeviceRegistry.Status registrationStatus) {
|
||||
this.registrationStatus = registrationStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the linked Ring Device Handler.
|
||||
*
|
||||
* @return the handler.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public RingDeviceHandler getRingDeviceHandler() {
|
||||
return ringDeviceHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the linked Ring Device Handler.
|
||||
*
|
||||
* @param ringDeviceHandler the handler.
|
||||
*/
|
||||
@Override
|
||||
public void setRingDeviceHandler(RingDeviceHandler ringDeviceHandler) {
|
||||
this.ringDeviceHandler = ringDeviceHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the linked Ring account.
|
||||
*
|
||||
* @return the account.
|
||||
*/
|
||||
@Override
|
||||
public RingAccount getRingAccount() {
|
||||
return ringAccount;
|
||||
public void setDeviceStatus(RingDeviceTO ringDeviceTO) {
|
||||
this.deviceStatus = ringDeviceTO;
|
||||
logger.trace("AbstractRingDevice - setJsonObject - Updated JSON: {}", ringDeviceTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJsonObject(JsonObject jsonObject) {
|
||||
this.jsonObject = jsonObject;
|
||||
logger.trace("AbstractRingDevice - setJsonObject - Updated JSON: {}", this.jsonObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getJsonObject() {
|
||||
return this.jsonObject;
|
||||
public RingDeviceTO getDeviceStatus() {
|
||||
return deviceStatus;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,12 +13,6 @@
|
|||
package org.openhab.binding.ring.internal.data;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.ring.internal.RingAccount;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* @author Ben Rosenblum - Initial contribution
|
||||
|
@ -29,24 +23,9 @@ public class Chime extends AbstractRingDevice {
|
|||
/**
|
||||
* Create Chime instance from JSON object.
|
||||
*
|
||||
* @param jsonChime the JSON Chime retrieved from the Ring API.
|
||||
* @param ringAccount the Ring Account in use
|
||||
* @param deviceTO the JSON Chime retrieved from the Ring API.
|
||||
*/
|
||||
public Chime(JsonObject jsonChime, RingAccount ringAccount) {
|
||||
super(jsonChime, ringAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DiscoveryResult object to identify the device as
|
||||
* discovered thing.
|
||||
*
|
||||
* @return the device as DiscoveryResult instance.
|
||||
*/
|
||||
@Override
|
||||
public DiscoveryResult getDiscoveryResult(RingDeviceTO deviceTO) {
|
||||
DiscoveryResult result = DiscoveryResultBuilder
|
||||
.create(new ThingUID("ring:chime:" + getRingAccount().getThingId() + ":" + deviceTO.id))
|
||||
.withLabel("Ring Chime - " + deviceTO.description).build();
|
||||
return result;
|
||||
public Chime(RingDeviceTO deviceTO) {
|
||||
super(deviceTO);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.ring.internal.data;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.ring.internal.ApiConstants;
|
||||
|
||||
/**
|
||||
* @author Wim Vissers - Initial contribution
|
||||
* @author Ben Rosenblum - Updated for OH4 / New Maintainer
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class DataFactory {
|
||||
public static String getOauthData(String username, String password) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GET parameters for the session API resource.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getSessionParams(String hardwareId) {
|
||||
ParamBuilder pb = new ParamBuilder(false);
|
||||
pb.add("device[os]", "android");
|
||||
pb.add("device[hardware_id]", hardwareId);
|
||||
pb.add("device[app_brand]", "ring");
|
||||
pb.add("device[metadata][device_model]", "VirtualBox");
|
||||
pb.add("device[metadata][resolution]", "600x800");
|
||||
pb.add("device[metadata][app_version]", "1.7.29");
|
||||
pb.add("device[metadata][app_installation_date]", "");
|
||||
pb.add("device[metadata][os_version]", "4.4.4");
|
||||
pb.add("device[metadata][manufacturer]", "innotek GmbH");
|
||||
pb.add("device[metadata][is_tablet]", "true");
|
||||
pb.add("device[metadata][linphone_initialized]", "true");
|
||||
pb.add("device[metadata][language]", "en");
|
||||
pb.add("api_version", "" + ApiConstants.API_VERSION);
|
||||
return pb.toString();
|
||||
}
|
||||
}
|
|
@ -13,12 +13,6 @@
|
|||
package org.openhab.binding.ring.internal.data;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.ring.internal.RingAccount;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* @author Wim Vissers - Initial contribution
|
||||
|
@ -27,28 +21,12 @@ import com.google.gson.JsonObject;
|
|||
|
||||
@NonNullByDefault
|
||||
public class Doorbell extends AbstractRingDevice {
|
||||
|
||||
/**
|
||||
* Create Doorbell instance from JSON object.
|
||||
*
|
||||
* @param jsonDoorbell the JSON doorbell (doorbot) retrieved from the Ring API.
|
||||
* @param ringAccount the Ring Account in use
|
||||
* @param deviceTO the JSON doorbell (doorbot) retrieved from the Ring API.
|
||||
*/
|
||||
public Doorbell(JsonObject jsonDoorbell, RingAccount ringAccount) {
|
||||
super(jsonDoorbell, ringAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DiscoveryResult object to identify the device as
|
||||
* discovered thing.
|
||||
*
|
||||
* @return the device as DiscoveryResult instance.
|
||||
*/
|
||||
@Override
|
||||
public DiscoveryResult getDiscoveryResult(RingDeviceTO deviceTO) {
|
||||
DiscoveryResult result = DiscoveryResultBuilder
|
||||
.create(new ThingUID("ring:doorbell:" + getRingAccount().getThingId() + ":" + deviceTO.id))
|
||||
.withLabel("Ring Video Doorbell - " + deviceTO.description).build();
|
||||
return result;
|
||||
public Doorbell(RingDeviceTO deviceTO) {
|
||||
super(deviceTO);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.ring.internal.data;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* @author Wim Vissers - Initial contribution
|
||||
* @author Ben Rosenblum - Updated for OH4 / New Maintainer
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum Feature {
|
||||
|
||||
REMOTE_LOGGING_FORMAT_STORING,
|
||||
REMOTE_LOGGING_LEVEL,
|
||||
SUBSCRIPTIONS_ENABLED,
|
||||
STICKUPCAM_SETUP_ENABLED,
|
||||
VOD_ENABLED,
|
||||
NW_ENABLED,
|
||||
NW_V2_ENABLED,
|
||||
NW_USER_ACTIVATED,
|
||||
RINGPLUS_ENABLED,
|
||||
LPD_ENABLED,
|
||||
REACTIVE_SNOOZING_ENABLED,
|
||||
PROACTIVE_SNOOZING_ENABLED,
|
||||
OWNER_PROACTIVE_SNOOZING_ENABLED,
|
||||
LIVE_VIEW_SETTINGS_ENABLED,
|
||||
DELETE_ALL_SETTINGS_ENABLED,
|
||||
POWER_CABLE_ENABLED,
|
||||
DEVICE_HEALTH_ALERTS_ENABLED,
|
||||
CHIME_PRO_ENABLED,
|
||||
MULTIPLE_CALLS_ENABLED,
|
||||
UJET_ENABLED,
|
||||
MULTIPLE_DELETE_ENABLED,
|
||||
DELETE_ALL_ENABLED,
|
||||
LPD_MOTION_ANNOUNCEMENT_ENABLED,
|
||||
STARRED_EVENTS_ENABLED,
|
||||
CHIME_DND_ENABLED,
|
||||
VIDEO_SEARCH_ENABLED,
|
||||
FLOODLIGHT_CAM_ENABLED,
|
||||
NW_LARGER_AREA_ENABLED,
|
||||
RING_CAM_BATTERY_ENABLED,
|
||||
ELITE_CAM_ENABLED,
|
||||
DOORBELL_V2_ENABLED,
|
||||
SPOTLIGHT_BATTERY_DASHBOARD_CONTROLS_ENABLED,
|
||||
BYPASS_ACCOUNT_VERIFICATION,
|
||||
LEGACY_CVR_RETENTION_ENABLED,
|
||||
NEW_DASHBOARD_ENABLED,
|
||||
RING_CAM_ENABLED,
|
||||
RING_SEARCH_ENABLED,
|
||||
RING_CAM_MOUNT_ENABLED,
|
||||
RING_ALARM_ENABLED,
|
||||
IN_APP_CALL_NOTIFICATIONS,
|
||||
RING_CASH_ELIGIBLE_ENABLED,
|
||||
NEW_RING_PLAYER_ENABLED,
|
||||
APP_ALERT_TONES_ENABLED,
|
||||
MOTION_SNOOZING_ENABLED;
|
||||
|
||||
/**
|
||||
* The enum is named according to the json names retrieved from
|
||||
* the Ring API, but in upper case.
|
||||
*
|
||||
* @return the json name.
|
||||
*/
|
||||
public String getJsonName() {
|
||||
return this.toString().toLowerCase();
|
||||
}
|
||||
}
|
|
@ -13,12 +13,6 @@
|
|||
package org.openhab.binding.ring.internal.data;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.ring.internal.RingAccount;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* @author Ben Rosenblum - Initial contribution
|
||||
|
@ -29,24 +23,9 @@ public class OtherDevice extends AbstractRingDevice {
|
|||
/**
|
||||
* Create OtherDevice instance from JSON object.
|
||||
*
|
||||
* @param jsonOtherDevice the JSON Other retrieved from the Ring API.
|
||||
* @param ringAccount the Ring Account in use
|
||||
* @param deviceTO the JSON Other retrieved from the Ring API.
|
||||
*/
|
||||
public OtherDevice(JsonObject jsonOtherDevice, RingAccount ringAccount) {
|
||||
super(jsonOtherDevice, ringAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DiscoveryResult object to identify the device as
|
||||
* discovered thing.
|
||||
*
|
||||
* @return the device as DiscoveryResult instance.
|
||||
*/
|
||||
@Override
|
||||
public DiscoveryResult getDiscoveryResult(RingDeviceTO deviceTO) {
|
||||
DiscoveryResult result = DiscoveryResultBuilder
|
||||
.create(new ThingUID("ring:otherdevice:" + getRingAccount().getThingId() + ":" + deviceTO.id))
|
||||
.withLabel("Ring Other Device - " + deviceTO.description).build();
|
||||
return result;
|
||||
public OtherDevice(RingDeviceTO deviceTO) {
|
||||
super(deviceTO);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,6 @@ package org.openhab.binding.ring.internal.data;
|
|||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* {"profile":{
|
||||
* "id":4445516,
|
||||
|
@ -83,23 +81,18 @@ import com.google.gson.JsonObject;
|
|||
|
||||
@NonNullByDefault
|
||||
public class Profile {
|
||||
private JsonObject jsonProfile = new JsonObject();
|
||||
private JsonObject jsonFeatures = new JsonObject();
|
||||
private String refreshToken = "";
|
||||
private String accessToken = "";
|
||||
|
||||
/**
|
||||
* Create Profile instance from JSON String.
|
||||
*
|
||||
* @param jsonProfile the JSON profile retrieved from the Ring API.
|
||||
* @param refreshToken needed for the refresh token so we aren't logging in every time.
|
||||
* Needed as a separate parameter because it's not part of the jsonProfile object.
|
||||
* @param accessToken needed for the access token so we aren't logging in every time.
|
||||
* Needed as a separate parameter because it's not part of the jsonProfile object.
|
||||
*/
|
||||
public Profile(JsonObject jsonProfile, String refreshToken, String accessToken) {
|
||||
this.jsonProfile = jsonProfile;
|
||||
this.jsonFeatures = (JsonObject) jsonProfile.get("features");
|
||||
public Profile(String refreshToken, String accessToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
|
|
@ -13,13 +13,7 @@
|
|||
package org.openhab.binding.ring.internal.data;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.ring.handler.RingDeviceHandler;
|
||||
import org.openhab.binding.ring.internal.RingAccount;
|
||||
import org.openhab.binding.ring.internal.RingDeviceRegistry;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* Interface common to all Ring devices.
|
||||
|
@ -29,15 +23,6 @@ import com.google.gson.JsonObject;
|
|||
*/
|
||||
@NonNullByDefault
|
||||
public interface RingDevice {
|
||||
|
||||
/**
|
||||
* Get the DiscoveryResult object to identify the device as
|
||||
* discovered thing.
|
||||
*
|
||||
* @return the device as DiscoveryResult instance.
|
||||
*/
|
||||
DiscoveryResult getDiscoveryResult(RingDeviceTO deviceTO);
|
||||
|
||||
/**
|
||||
* Get the registration status.
|
||||
*
|
||||
|
@ -52,29 +37,7 @@ public interface RingDevice {
|
|||
*/
|
||||
void setRegistrationStatus(RingDeviceRegistry.Status registrationStatus);
|
||||
|
||||
/**
|
||||
* Get the linked Ring account.
|
||||
*
|
||||
* @return the account.
|
||||
*/
|
||||
RingAccount getRingAccount();
|
||||
void setDeviceStatus(RingDeviceTO ringDeviceTO);
|
||||
|
||||
/**
|
||||
* Get the linked Ring Device Handler.
|
||||
*
|
||||
* @return the handler.
|
||||
*/
|
||||
@Nullable
|
||||
RingDeviceHandler getRingDeviceHandler();
|
||||
|
||||
/**
|
||||
* Set the linked Ring Device Handler.
|
||||
*
|
||||
* @param ringDeviceHandler the handler.
|
||||
*/
|
||||
void setRingDeviceHandler(RingDeviceHandler ringDeviceHandler);
|
||||
|
||||
void setJsonObject(JsonObject jsonObject);
|
||||
|
||||
JsonObject getJsonObject();
|
||||
RingDeviceTO getDeviceStatus();
|
||||
}
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.ring.internal.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.ring.internal.ApiConstants;
|
||||
import org.openhab.binding.ring.internal.RingAccount;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Wim Vissers - Initial contribution
|
||||
* @author Chris Milbert - stickupcam contribution
|
||||
* @author Ben Rosenblum - Updated for OH4 / New Maintainer
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class RingDevices {
|
||||
private List<Doorbell> doorbells = new ArrayList<>();
|
||||
private List<Stickupcam> stickupcams = new ArrayList<>();
|
||||
private List<Chime> chimes = new ArrayList<>();
|
||||
private List<OtherDevice> otherdevices = new ArrayList<>();
|
||||
|
||||
public RingDevices(JsonObject jsonRingDevices, RingAccount ringAccount) {
|
||||
addDoorbells((JsonArray) jsonRingDevices.get(ApiConstants.DEVICES_DOORBOTS), ringAccount);
|
||||
addStickupCams((JsonArray) jsonRingDevices.get(ApiConstants.DEVICES_STICKUP_CAMS), ringAccount);
|
||||
addChimes((JsonArray) jsonRingDevices.get(ApiConstants.DEVICES_CHIMES), ringAccount);
|
||||
addOtherDevices((JsonArray) jsonRingDevices.get(ApiConstants.DEVICES_OTHERDEVICE), ringAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create the doorbell list.
|
||||
*
|
||||
* @param jsonDoorbells
|
||||
* @param ringAccount
|
||||
*/
|
||||
private void addDoorbells(JsonArray jsonDoorbells, RingAccount ringAccount) {
|
||||
for (Object obj : jsonDoorbells) {
|
||||
Doorbell doorbell = new Doorbell((JsonObject) obj, ringAccount);
|
||||
doorbells.add(doorbell);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Doorbells Collection.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<Doorbell> getDoorbells() {
|
||||
return doorbells;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create the stickupcam list.
|
||||
*
|
||||
* @param jsonStickupcams
|
||||
* @param ringAccount
|
||||
*/
|
||||
private void addStickupCams(JsonArray jsonStickupcams, RingAccount ringAccount) {
|
||||
for (Object obj : jsonStickupcams) {
|
||||
Stickupcam stickupcam = new Stickupcam((JsonObject) obj, ringAccount);
|
||||
stickupcams.add(stickupcam);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Stickupcams Collection.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<Stickupcam> getStickupcams() {
|
||||
return stickupcams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create the chime list.
|
||||
*
|
||||
* @param jsonChimes
|
||||
* @param ringAccount
|
||||
*/
|
||||
private void addChimes(JsonArray jsonChimes, RingAccount ringAccount) {
|
||||
for (Object obj : jsonChimes) {
|
||||
Chime chime = new Chime((JsonObject) obj, ringAccount);
|
||||
chimes.add(chime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Chimes Collection.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<Chime> getChimes() {
|
||||
return chimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create the other list.
|
||||
*
|
||||
* @param jsonOther
|
||||
* @param ringAccount
|
||||
*/
|
||||
private void addOtherDevices(JsonArray jsonOtherDevices, RingAccount ringAccount) {
|
||||
for (Object obj : jsonOtherDevices) {
|
||||
OtherDevice otherdevice = new OtherDevice((JsonObject) obj, ringAccount);
|
||||
otherdevices.add(otherdevice);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Others Collection.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<OtherDevice> getOtherDevices() {
|
||||
return otherdevices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a collection of all devices.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<RingDevice> getRingDevices() {
|
||||
List<RingDevice> result = new ArrayList<>();
|
||||
result.addAll(doorbells);
|
||||
result.addAll(stickupcams);
|
||||
result.addAll(chimes);
|
||||
result.addAll(otherdevices);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.ring.internal.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link RingDevicesTO} class is a TO containing all devices for an account
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RingDevicesTO {
|
||||
@SerializedName("doorbots")
|
||||
public List<RingDeviceTO> doorbells = List.of();
|
||||
public List<RingDeviceTO> chimes = List.of();
|
||||
@SerializedName("stickup_cams")
|
||||
public List<RingDeviceTO> stickupCams = List.of();
|
||||
public List<RingDeviceTO> other = List.of();
|
||||
}
|
|
@ -13,12 +13,6 @@
|
|||
package org.openhab.binding.ring.internal.data;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.ring.internal.RingAccount;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* @author Chris Milbert - Initial contribution
|
||||
|
@ -31,24 +25,9 @@ public class Stickupcam extends AbstractRingDevice {
|
|||
/**
|
||||
* Create Stickup Cam instance from JSON object.
|
||||
*
|
||||
* @param jsonStickupcam the JSON Stickup Cam retrieved from the Ring API.
|
||||
* @param ringAccount the Ring Account in use
|
||||
* @param deviceTO the JSON Stickup Cam retrieved from the Ring API.
|
||||
*/
|
||||
public Stickupcam(JsonObject jsonStickupcam, RingAccount ringAccount) {
|
||||
super(jsonStickupcam, ringAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DiscoveryResult object to identify the device as
|
||||
* discovered thing.
|
||||
*
|
||||
* @return the device as DiscoveryResult instance.
|
||||
*/
|
||||
@Override
|
||||
public DiscoveryResult getDiscoveryResult(RingDeviceTO deviceTO) {
|
||||
DiscoveryResult result = DiscoveryResultBuilder
|
||||
.create(new ThingUID("ring:stickupcam:" + getRingAccount().getThingId() + ":" + deviceTO.id))
|
||||
.withLabel("Ring Video Stickup Cam - " + deviceTO.description).build();
|
||||
return result;
|
||||
public Stickupcam(RingDeviceTO deviceTO) {
|
||||
super(deviceTO);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,21 +14,24 @@ package org.openhab.binding.ring.internal.discovery;
|
|||
|
||||
import static org.openhab.binding.ring.RingBindingConstants.*;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.ring.handler.AccountHandler;
|
||||
import org.openhab.binding.ring.internal.RingDeviceRegistry;
|
||||
import org.openhab.binding.ring.internal.data.Chime;
|
||||
import org.openhab.binding.ring.internal.data.Doorbell;
|
||||
import org.openhab.binding.ring.internal.data.RingDevice;
|
||||
import org.openhab.binding.ring.internal.data.RingDeviceTO;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.binding.ring.internal.data.Stickupcam;
|
||||
import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.osgi.service.component.annotations.ServiceScope;
|
||||
|
||||
/**
|
||||
* The RingDiscoveryService is responsible for auto detecting a Ring
|
||||
|
@ -37,68 +40,39 @@ import com.google.gson.Gson;
|
|||
* @author Wim Vissers - Initial contribution
|
||||
* @author Chris Milbert - Stickupcam contribution
|
||||
* @author Ben Rosenblum - Updated for OH4 / New Maintainer
|
||||
* @author Jan N. Klug - Refactored to ThingHandlerService
|
||||
*/
|
||||
|
||||
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.ring")
|
||||
@Component(scope = ServiceScope.PROTOTYPE, service = RingDiscoveryService.class)
|
||||
@NonNullByDefault
|
||||
public class RingDiscoveryService extends AbstractDiscoveryService {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(RingDiscoveryService.class);
|
||||
private @Nullable ScheduledFuture<?> discoveryJob;
|
||||
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
public class RingDiscoveryService extends AbstractThingHandlerDiscoveryService<AccountHandler> {
|
||||
public RingDiscoveryService() {
|
||||
super(SUPPORTED_THING_TYPES_UIDS, 5, true);
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
logger.debug("Starting Ring discovery...");
|
||||
startScan();
|
||||
startBackgroundDiscovery();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
logger.debug("Stopping Ring discovery...");
|
||||
stopBackgroundDiscovery();
|
||||
stopScan();
|
||||
}
|
||||
|
||||
private void discover() {
|
||||
RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
||||
for (RingDevice device : registry.getRingDevices(RingDeviceRegistry.Status.ADDED)) {
|
||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
||||
if (deviceTO != null) {
|
||||
thingDiscovered(device.getDiscoveryResult(deviceTO));
|
||||
registry.setStatus(deviceTO.id, RingDeviceRegistry.Status.DISCOVERED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
discover();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
discoveryJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, 120, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopBackgroundDiscovery() {
|
||||
logger.info("Stop Ring background discovery");
|
||||
ScheduledFuture<?> job = discoveryJob;
|
||||
if (job != null) {
|
||||
job.cancel(true);
|
||||
}
|
||||
discoveryJob = null;
|
||||
super(AccountHandler.class, SUPPORTED_THING_TYPES_UIDS, 5, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
logger.debug("Starting device search...");
|
||||
discover();
|
||||
ThingHandler thingHandler = getThingHandler();
|
||||
if (thingHandler instanceof AccountHandler accountHandler) {
|
||||
RingDeviceRegistry registry = accountHandler.getDeviceRegistry();
|
||||
ThingUID bridgeUID = accountHandler.getThing().getUID();
|
||||
for (RingDevice device : registry.getRingDevices(RingDeviceRegistry.Status.ADDED)) {
|
||||
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||
ThingTypeUID thingTypeUID = switch (device) {
|
||||
case Chime chime -> THING_TYPE_CHIME;
|
||||
case Doorbell doorbell -> THING_TYPE_DOORBELL;
|
||||
case Stickupcam stickupcam -> THING_TYPE_STICKUPCAM;
|
||||
default -> THING_TYPE_OTHERDEVICE;
|
||||
};
|
||||
|
||||
DiscoveryResult result = DiscoveryResultBuilder
|
||||
.create(new ThingUID(thingTypeUID, bridgeUID, deviceTO.id)).withLabel(deviceTO.description)
|
||||
.withBridge(bridgeUID).build();
|
||||
|
||||
thingDiscovered(result);
|
||||
registry.setStatus(deviceTO.id, RingDeviceRegistry.Status.DISCOVERED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -106,4 +80,10 @@ public class RingDiscoveryService extends AbstractDiscoveryService {
|
|||
removeOlderResults(getTimestampOfLastScan());
|
||||
super.stopScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
removeOlderResults(Instant.now().toEpochMilli());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue