[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.resol/ @ramack
|
||||||
/bundles/org.openhab.binding.revogi/ @openhab/add-ons-maintainers
|
/bundles/org.openhab.binding.revogi/ @openhab/add-ons-maintainers
|
||||||
/bundles/org.openhab.binding.rfxcom/ @martinvw @paulianttila
|
/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.rme/ @kgoderis
|
||||||
/bundles/org.openhab.binding.robonect/ @reyem
|
/bundles/org.openhab.binding.robonect/ @reyem
|
||||||
/bundles/org.openhab.binding.roku/ @mlobstein
|
/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.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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.binding.ring.internal.errors.DeviceNotFoundException;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
|
import org.openhab.core.thing.Bridge;
|
||||||
import org.openhab.core.thing.Thing;
|
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.BaseThingHandler;
|
||||||
|
import org.openhab.core.thing.binding.BridgeHandler;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -104,15 +105,18 @@ public abstract class AbstractRingHandler extends BaseThingHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleRemoval() {
|
public void handleRemoval() {
|
||||||
updateStatus(ThingStatus.OFFLINE);
|
String id = getThing().getUID().getId();
|
||||||
final String id = getThing().getUID().getId();
|
Bridge bridge = getBridge();
|
||||||
final RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
if (bridge != null) {
|
||||||
|
BridgeHandler bridgeHandler = bridge.getHandler();
|
||||||
|
if (bridgeHandler instanceof RingAccount ringAccount) {
|
||||||
try {
|
try {
|
||||||
registry.removeRingDevice(id);
|
ringAccount.getDeviceRegistry().removeRingDevice(id);
|
||||||
} catch (final DeviceNotFoundException e) {
|
} catch (DeviceNotFoundException ignored) {
|
||||||
logger.debug("Exception occurred during execution of handleRemoval(): {}", e.getMessage(), e);
|
logger.warn("Tried to remove a device that was not present in the ring account: {}", id);
|
||||||
} finally {
|
|
||||||
updateStatus(ThingStatus.REMOVED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
super.handleRemoval();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,9 @@ import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
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.RingDeviceRegistry;
|
||||||
import org.openhab.binding.ring.internal.RingVideoServlet;
|
import org.openhab.binding.ring.internal.RingVideoServlet;
|
||||||
import org.openhab.binding.ring.internal.data.Profile;
|
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.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.AuthenticationException;
|
||||||
import org.openhab.binding.ring.internal.errors.DuplicateIdException;
|
import org.openhab.binding.ring.internal.errors.DuplicateIdException;
|
||||||
import org.openhab.binding.ring.internal.utils.RingUtils;
|
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.ThingStatus;
|
||||||
import org.openhab.core.thing.ThingStatusDetail;
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
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.Command;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
import org.osgi.service.http.HttpService;
|
import org.osgi.service.http.HttpService;
|
||||||
|
@ -75,7 +79,6 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
||||||
private @Nullable Runnable runnableVideo = null;
|
private @Nullable Runnable runnableVideo = null;
|
||||||
private @Nullable RingVideoServlet ringVideoServlet;
|
private @Nullable RingVideoServlet ringVideoServlet;
|
||||||
private final HttpService httpService;
|
private final HttpService httpService;
|
||||||
private final String thingId;
|
|
||||||
|
|
||||||
// Current status
|
// Current status
|
||||||
protected OnOffType status = OnOffType.OFF;
|
protected OnOffType status = OnOffType.OFF;
|
||||||
|
@ -92,7 +95,7 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
||||||
/**
|
/**
|
||||||
* The registry.
|
* The registry.
|
||||||
*/
|
*/
|
||||||
private final RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
private final RingDeviceRegistry registry;
|
||||||
/**
|
/**
|
||||||
* The RestClient is used to connect to the Ring Account.
|
* 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.networkAddressService = networkAddressService;
|
||||||
this.httpService = httpService;
|
this.httpService = httpService;
|
||||||
this.videoExecutorService = Executors.newCachedThreadPool();
|
this.videoExecutorService = Executors.newCachedThreadPool();
|
||||||
this.thingId = this.getThing().getUID().getId();
|
this.registry = new RingDeviceRegistry();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -227,7 +230,7 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
||||||
|
|
||||||
private void saveRefreshTokenToFile(String refreshToken) {
|
private void saveRefreshTokenToFile(String refreshToken) {
|
||||||
String folderName = OpenHAB.getUserDataFolder() + "/ring";
|
String folderName = OpenHAB.getUserDataFolder() + "/ring";
|
||||||
String thingId = this.thingId;
|
String thingId = getThing().getUID().getId();
|
||||||
File folder = new File(folderName);
|
File folder = new File(folderName);
|
||||||
String fileName = folderName + "/ring." + thingId + ".refreshToken";
|
String fileName = folderName + "/ring." + thingId + ".refreshToken";
|
||||||
|
|
||||||
|
@ -246,7 +249,7 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
||||||
private String getRefreshTokenFromFile() {
|
private String getRefreshTokenFromFile() {
|
||||||
String refreshToken = "";
|
String refreshToken = "";
|
||||||
String folderName = OpenHAB.getUserDataFolder() + "/ring";
|
String folderName = OpenHAB.getUserDataFolder() + "/ring";
|
||||||
String thingId = this.thingId;
|
String thingId = getThing().getUID().getId();
|
||||||
String fileName = folderName + "/ring." + thingId + ".refreshToken";
|
String fileName = folderName + "/ring." + thingId + ".refreshToken";
|
||||||
File file = new File(fileName);
|
File file = new File(fileName);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
|
@ -398,8 +401,8 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
||||||
|
|
||||||
private void refreshRegistry() throws JsonParseException, AuthenticationException, DuplicateIdException {
|
private void refreshRegistry() throws JsonParseException, AuthenticationException, DuplicateIdException {
|
||||||
logger.debug("AccountHandler - refreshRegistry");
|
logger.debug("AccountHandler - refreshRegistry");
|
||||||
RingDevices ringDevices = restClient.getRingDevices(userProfile, this);
|
RingDevicesTO ringDevices = restClient.getRingDevices(userProfile, this);
|
||||||
registry.addRingDevices(ringDevices.getRingDevices());
|
registry.addOrUpdateRingDevices(ringDevices);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void minuteTick() {
|
protected void minuteTick() {
|
||||||
|
@ -578,21 +581,6 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
||||||
return "";
|
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.
|
* Dispose of the refreshJob nicely.
|
||||||
*/
|
*/
|
||||||
|
@ -607,4 +595,14 @@ public class AccountHandler extends BaseBridgeHandler implements RingAccount {
|
||||||
this.videoExecutorService = null;
|
this.videoExecutorService = null;
|
||||||
super.dispose();
|
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");
|
logger.debug("Initializing Chime handler");
|
||||||
super.initialize();
|
super.initialize();
|
||||||
|
|
||||||
RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
RingDeviceRegistry registry = getDeviceRegistry();
|
||||||
String id = getThing().getUID().getId();
|
String id = getThing().getUID().getId();
|
||||||
if (registry.isInitialized()) {
|
if (registry != null && registry.isInitialized()) {
|
||||||
try {
|
try {
|
||||||
linkDevice(id, Chime.class);
|
linkDevice(id, Chime.class);
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
|
|
@ -54,9 +54,9 @@ public class DoorbellHandler extends RingDeviceHandler {
|
||||||
logger.debug("Initializing Doorbell handler");
|
logger.debug("Initializing Doorbell handler");
|
||||||
super.initialize();
|
super.initialize();
|
||||||
|
|
||||||
RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
RingDeviceRegistry registry = getDeviceRegistry();
|
||||||
String id = getThing().getUID().getId();
|
String id = getThing().getUID().getId();
|
||||||
if (registry.isInitialized()) {
|
if (registry != null && registry.isInitialized()) {
|
||||||
try {
|
try {
|
||||||
linkDevice(id, Doorbell.class);
|
linkDevice(id, Doorbell.class);
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
@ -102,13 +102,13 @@ public class DoorbellHandler extends RingDeviceHandler {
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||||
if ((deviceTO != null) && (deviceTO.health.batteryPercentage != lastBattery)) {
|
if (deviceTO.health.batteryPercentage != lastBattery) {
|
||||||
logger.debug("Battery Level: {}", deviceTO.health.batteryPercentage);
|
logger.debug("Battery Level: {}", deviceTO.health.batteryPercentage);
|
||||||
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_STATUS_BATTERY);
|
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_STATUS_BATTERY);
|
||||||
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
||||||
lastBattery = deviceTO.health.batteryPercentage;
|
lastBattery = deviceTO.health.batteryPercentage;
|
||||||
} else if (deviceTO != null) {
|
} else {
|
||||||
logger.debug("Battery Level Unchanged for {} - {} vs {}", getThing().getUID().getId(),
|
logger.debug("Battery Level Unchanged for {} - {} vs {}", getThing().getUID().getId(),
|
||||||
deviceTO.health.batteryPercentage, lastBattery);
|
deviceTO.health.batteryPercentage, lastBattery);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,9 @@ public class OtherDeviceHandler extends RingDeviceHandler {
|
||||||
logger.debug("Initializing Other Device handler");
|
logger.debug("Initializing Other Device handler");
|
||||||
super.initialize();
|
super.initialize();
|
||||||
|
|
||||||
RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
RingDeviceRegistry registry = getDeviceRegistry();
|
||||||
String id = getThing().getUID().getId();
|
String id = getThing().getUID().getId();
|
||||||
if (registry.isInitialized()) {
|
if (registry != null && registry.isInitialized()) {
|
||||||
try {
|
try {
|
||||||
linkDevice(id, OtherDevice.class);
|
linkDevice(id, OtherDevice.class);
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
@ -102,13 +102,13 @@ public class OtherDeviceHandler extends RingDeviceHandler {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||||
if ((deviceTO != null) && (deviceTO.health.batteryPercentage != lastBattery)) {
|
if (deviceTO.health.batteryPercentage != lastBattery) {
|
||||||
logger.debug("Battery Level: {}", deviceTO.health.batteryPercentage);
|
logger.debug("Battery Level: {}", deviceTO.health.batteryPercentage);
|
||||||
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_STATUS_BATTERY);
|
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_STATUS_BATTERY);
|
||||||
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
||||||
lastBattery = deviceTO.health.batteryPercentage;
|
lastBattery = deviceTO.health.batteryPercentage;
|
||||||
} else if (deviceTO != null) {
|
} else {
|
||||||
logger.debug("Battery Level Unchanged for {} - {} vs {}", getThing().getUID().getId(),
|
logger.debug("Battery Level Unchanged for {} - {} vs {}", getThing().getUID().getId(),
|
||||||
deviceTO.health.batteryPercentage, lastBattery);
|
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.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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.RingDeviceRegistry;
|
||||||
import org.openhab.binding.ring.internal.data.RingDevice;
|
import org.openhab.binding.ring.internal.data.RingDevice;
|
||||||
import org.openhab.binding.ring.internal.data.RingDeviceTO;
|
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.IncreaseDecreaseType;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.library.types.UpDownType;
|
import org.openhab.core.library.types.UpDownType;
|
||||||
|
import org.openhab.core.thing.Bridge;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
|
import org.openhab.core.thing.binding.BridgeHandler;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
|
|
||||||
|
@ -53,6 +56,17 @@ public abstract class RingDeviceHandler extends AbstractRingHandler {
|
||||||
super(thing, gson);
|
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.
|
* 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)
|
protected void linkDevice(String id, Class<?> deviceClass)
|
||||||
throws DeviceNotFoundException, IllegalDeviceClassException {
|
throws DeviceNotFoundException, IllegalDeviceClassException {
|
||||||
device = RingDeviceRegistry.getInstance().getRingDevice(id);
|
RingDeviceRegistry registry = getDeviceRegistry();
|
||||||
if (device != null) {
|
if (registry != null) {
|
||||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
device = registry.getRingDevice(id);
|
||||||
|
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||||
if (deviceClass.equals(device.getClass())) {
|
if (deviceClass.equals(device.getClass())) {
|
||||||
device.setRegistrationStatus(RingDeviceRegistry.Status.CONFIGURED);
|
device.setRegistrationStatus(RingDeviceRegistry.Status.CONFIGURED);
|
||||||
device.setRingDeviceHandler(this);
|
|
||||||
if (deviceTO != null) {
|
|
||||||
thing.setProperty("Description", deviceTO.description);
|
thing.setProperty("Description", deviceTO.description);
|
||||||
thing.setProperty("Kind", deviceTO.kind);
|
thing.setProperty("Kind", deviceTO.kind);
|
||||||
thing.setProperty("Device ID", deviceTO.deviceId);
|
thing.setProperty("Device ID", deviceTO.deviceId);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalDeviceClassException("Class '" + deviceClass.getName() + "' expected but '"
|
throw new IllegalDeviceClassException("Class '" + deviceClass.getName() + "' expected but '"
|
||||||
+ device.getClass().getName() + "' found.");
|
+ device.getClass().getName() + "' found.");
|
||||||
|
@ -93,10 +105,8 @@ public abstract class RingDeviceHandler extends AbstractRingHandler {
|
||||||
updateState(channelUID, enabled);
|
updateState(channelUID, enabled);
|
||||||
break;
|
break;
|
||||||
case CHANNEL_STATUS_BATTERY:
|
case CHANNEL_STATUS_BATTERY:
|
||||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||||
if (deviceTO != null) {
|
|
||||||
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger.debug("Command received for an unknown channel: {}", channelUID.getId());
|
logger.debug("Command received for an unknown channel: {}", channelUID.getId());
|
||||||
|
|
|
@ -54,9 +54,9 @@ public class StickupcamHandler extends RingDeviceHandler {
|
||||||
logger.debug("Initializing Stickupcam handler");
|
logger.debug("Initializing Stickupcam handler");
|
||||||
super.initialize();
|
super.initialize();
|
||||||
|
|
||||||
RingDeviceRegistry registry = RingDeviceRegistry.getInstance();
|
RingDeviceRegistry registry = getDeviceRegistry();
|
||||||
String id = getThing().getUID().getId();
|
String id = getThing().getUID().getId();
|
||||||
if (registry.isInitialized()) {
|
if (registry != null && registry.isInitialized()) {
|
||||||
try {
|
try {
|
||||||
linkDevice(id, Stickupcam.class);
|
linkDevice(id, Stickupcam.class);
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
@ -102,13 +102,13 @@ public class StickupcamHandler extends RingDeviceHandler {
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
RingDeviceTO deviceTO = device.getDeviceStatus();
|
||||||
if ((deviceTO != null) && (deviceTO.health.batteryPercentage != lastBattery)) {
|
if (deviceTO.health.batteryPercentage != lastBattery) {
|
||||||
logger.debug("Battery Level: {}", deviceTO.battery);
|
logger.debug("Battery Level: {}", deviceTO.battery);
|
||||||
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_STATUS_BATTERY);
|
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_STATUS_BATTERY);
|
||||||
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
updateState(channelUID, new DecimalType(deviceTO.health.batteryPercentage));
|
||||||
lastBattery = deviceTO.health.batteryPercentage;
|
lastBattery = deviceTO.health.batteryPercentage;
|
||||||
} else if (deviceTO != null) {
|
} else {
|
||||||
logger.debug("Battery Level Unchanged for {} - {} vs {}", getThing().getUID().getId(),
|
logger.debug("Battery Level Unchanged for {} - {} vs {}", getThing().getUID().getId(),
|
||||||
deviceTO.health.batteryPercentage, lastBattery);
|
deviceTO.health.batteryPercentage, lastBattery);
|
||||||
|
|
||||||
|
|
|
@ -46,10 +46,9 @@ import javax.net.ssl.TrustManager;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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.ParamBuilder;
|
||||||
import org.openhab.binding.ring.internal.data.Profile;
|
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.data.RingEventTO;
|
||||||
import org.openhab.binding.ring.internal.errors.AuthenticationException;
|
import org.openhab.binding.ring.internal.errors.AuthenticationException;
|
||||||
import org.openhab.binding.ring.internal.utils.RingUtils;
|
import org.openhab.binding.ring.internal.utils.RingUtils;
|
||||||
|
@ -277,12 +276,7 @@ public class RestClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject oauthToken = getOauthToken(username, password, refToken);
|
JsonObject oauthToken = getOauthToken(username, password, refToken);
|
||||||
String jsonResult = postRequest(ApiConstants.URL_SESSION, DataFactory.getSessionParams(hardwareId),
|
return new Profile(oauthToken.get("refresh_token").getAsString(), oauthToken.get("access_token").getAsString());
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -522,12 +516,11 @@ public class RestClient {
|
||||||
* @throws AuthenticationException when request is invalid.
|
* @throws AuthenticationException when request is invalid.
|
||||||
* @throws JsonParseException when response is invalid JSON.
|
* @throws JsonParseException when response is invalid JSON.
|
||||||
*/
|
*/
|
||||||
public RingDevices getRingDevices(Profile profile, RingAccount ringAccount)
|
public RingDevicesTO getRingDevices(Profile profile, RingAccount ringAccount)
|
||||||
throws JsonParseException, AuthenticationException {
|
throws JsonParseException, AuthenticationException {
|
||||||
logger.debug("RestClient - getRingDevices");
|
logger.debug("RestClient - getRingDevices");
|
||||||
String jsonResult = getRequest(ApiConstants.URL_DEVICES, profile);
|
String jsonResult = getRequest(ApiConstants.URL_DEVICES, profile);
|
||||||
JsonObject obj = JsonParser.parseString(jsonResult).getAsJsonObject();
|
return Objects.requireNonNull(gson.fromJson(jsonResult, RingDevicesTO.class));
|
||||||
return new RingDevices(obj, ringAccount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
package org.openhab.binding.ring.internal;
|
package org.openhab.binding.ring.internal;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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
|
* The AccountHandler implements this interface to facilitate the
|
||||||
|
@ -25,26 +23,10 @@ import org.openhab.binding.ring.internal.data.Profile;
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public interface RingAccount {
|
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();
|
RingDeviceRegistry getDeviceRegistry();
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,19 +13,22 @@
|
||||||
package org.openhab.binding.ring.internal;
|
package org.openhab.binding.ring.internal;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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.RingDevice;
|
||||||
import org.openhab.binding.ring.internal.data.RingDeviceTO;
|
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.DeviceNotFoundException;
|
||||||
import org.openhab.binding.ring.internal.errors.DuplicateIdException;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton registry of found devices.
|
* Singleton registry of found devices.
|
||||||
*
|
*
|
||||||
|
@ -35,15 +38,6 @@ import com.google.gson.Gson;
|
||||||
|
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class RingDeviceRegistry {
|
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);
|
private final Logger logger = LoggerFactory.getLogger(RingDeviceRegistry.class);
|
||||||
/**
|
/**
|
||||||
* Will be set after initialization.
|
* Will be set after initialization.
|
||||||
|
@ -51,51 +45,35 @@ public class RingDeviceRegistry {
|
||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key: device id.
|
* Key: device id. Value: the RingDevice implementation object.
|
||||||
* Value: the RingDevice implementation object.
|
|
||||||
*/
|
*/
|
||||||
private ConcurrentHashMap<String, RingDevice> devices = new ConcurrentHashMap<>();
|
private final Map<String, RingDevice> devices = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
private void addOrUpdateRingDevice(RingDeviceTO deviceTO, Function<RingDeviceTO, RingDevice> creator) {
|
||||||
* Return a singleton instance of RingDeviceRegistry.
|
devices.compute(deviceTO.id, (id, existing) -> {
|
||||||
*/
|
if (existing == null) {
|
||||||
public static RingDeviceRegistry getInstance() {
|
RingDevice device = creator.apply(deviceTO);
|
||||||
return INSTANCE;
|
device.setRegistrationStatus(Status.ADDED);
|
||||||
}
|
return device;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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");
|
|
||||||
} else {
|
} else {
|
||||||
ringDevice.setRegistrationStatus(Status.ADDED);
|
logger.debug(
|
||||||
devices.put(deviceTO.id, ringDevice);
|
"RingDeviceRegistry - addRingDevices - Ring device with duplicate id {} ignored. Updating Json.",
|
||||||
}
|
deviceTO.id);
|
||||||
|
existing.setDeviceStatus(deviceTO);
|
||||||
|
return existing;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new ring device collection.
|
* Add a new ring device collection.
|
||||||
*/
|
*/
|
||||||
public synchronized void addRingDevices(Collection<RingDevice> ringDevices) {
|
public synchronized void addOrUpdateRingDevices(RingDevicesTO ringDevices) {
|
||||||
for (RingDevice device : ringDevices) {
|
ringDevices.doorbells.forEach(deviceTO -> addOrUpdateRingDevice(deviceTO, Doorbell::new));
|
||||||
RingDeviceTO deviceTO = gson.fromJson(device.getJsonObject(), RingDeviceTO.class);
|
ringDevices.chimes.forEach(deviceTO -> addOrUpdateRingDevice(deviceTO, Chime::new));
|
||||||
if (deviceTO != null) {
|
ringDevices.stickupCams.forEach(deviceTO -> addOrUpdateRingDevice(deviceTO, Stickupcam::new));
|
||||||
logger.debug("RingDeviceRegistry - addRingDevices - Trying: {}", deviceTO.id);
|
ringDevices.other.forEach(deviceTO -> addOrUpdateRingDevice(deviceTO, OtherDevice::new));
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,9 +93,10 @@ public class RingDeviceRegistry {
|
||||||
* @return the RingDevice instance from the registry.
|
* @return the RingDevice instance from the registry.
|
||||||
* @throws DeviceNotFoundException
|
* @throws DeviceNotFoundException
|
||||||
*/
|
*/
|
||||||
public @Nullable RingDevice getRingDevice(String id) throws DeviceNotFoundException {
|
public RingDevice getRingDevice(String id) throws DeviceNotFoundException {
|
||||||
if (devices.containsKey(id)) {
|
RingDevice device = devices.get(id);
|
||||||
return devices.get(id);
|
if (device != null) {
|
||||||
|
return device;
|
||||||
} else {
|
} else {
|
||||||
throw new DeviceNotFoundException("Device with id '" + id + "' not found");
|
throw new DeviceNotFoundException("Device with id '" + id + "' not found");
|
||||||
}
|
}
|
||||||
|
@ -130,8 +109,9 @@ public class RingDeviceRegistry {
|
||||||
* @throws DeviceNotFoundException
|
* @throws DeviceNotFoundException
|
||||||
*/
|
*/
|
||||||
public void removeRingDevice(String id) throws DeviceNotFoundException {
|
public void removeRingDevice(String id) throws DeviceNotFoundException {
|
||||||
if (devices.containsKey(id)) {
|
RingDevice device = devices.get(id);
|
||||||
devices.remove(id);
|
if (device != null) {
|
||||||
|
device.setRegistrationStatus(Status.ADDED);
|
||||||
} else {
|
} else {
|
||||||
throw new DeviceNotFoundException("Device with id '" + id + "' not found");
|
throw new DeviceNotFoundException("Device with id '" + id + "' not found");
|
||||||
}
|
}
|
||||||
|
@ -164,7 +144,6 @@ public class RingDeviceRegistry {
|
||||||
* The registry status of the device.
|
* The registry status of the device.
|
||||||
*
|
*
|
||||||
* @author Wim Vissers
|
* @author Wim Vissers
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public enum Status {
|
public enum Status {
|
||||||
/**
|
/**
|
||||||
|
@ -172,8 +151,7 @@ public class RingDeviceRegistry {
|
||||||
*/
|
*/
|
||||||
ADDED,
|
ADDED,
|
||||||
/**
|
/**
|
||||||
* When reported to the system as discovered device. It will show up
|
* When reported to the system as discovered device. It will show up in the inbox.
|
||||||
* in the inbox.
|
|
||||||
*/
|
*/
|
||||||
DISCOVERED,
|
DISCOVERED,
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,16 +13,10 @@
|
||||||
package org.openhab.binding.ring.internal.data;
|
package org.openhab.binding.ring.internal.data;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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.binding.ring.internal.RingDeviceRegistry;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface common to all Ring devices.
|
* Interface common to all Ring devices.
|
||||||
*
|
*
|
||||||
|
@ -32,31 +26,12 @@ import com.google.gson.JsonObject;
|
||||||
|
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public abstract class AbstractRingDevice implements RingDevice {
|
public abstract class AbstractRingDevice implements RingDevice {
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(AbstractRingDevice.class);
|
private final Logger logger = LoggerFactory.getLogger(AbstractRingDevice.class);
|
||||||
public final Gson gson = new Gson();
|
private RingDeviceTO deviceStatus;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 RingDeviceRegistry.Status registrationStatus = RingDeviceRegistry.Status.ADDED;
|
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) {
|
protected AbstractRingDevice(RingDeviceTO jsonObject) {
|
||||||
this.jsonObject = jsonObject;
|
this.deviceStatus = jsonObject;
|
||||||
this.ringAccount = ringAccount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,52 +47,21 @@ public abstract class AbstractRingDevice implements RingDevice {
|
||||||
/**
|
/**
|
||||||
* Set the registration status.
|
* Set the registration status.
|
||||||
*
|
*
|
||||||
* @param status
|
* @param registrationStatus
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setRegistrationStatus(RingDeviceRegistry.Status registrationStatus) {
|
public void setRegistrationStatus(RingDeviceRegistry.Status registrationStatus) {
|
||||||
this.registrationStatus = registrationStatus;
|
this.registrationStatus = registrationStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the linked Ring Device Handler.
|
|
||||||
*
|
|
||||||
* @return the handler.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
public void setDeviceStatus(RingDeviceTO ringDeviceTO) {
|
||||||
public RingDeviceHandler getRingDeviceHandler() {
|
this.deviceStatus = ringDeviceTO;
|
||||||
return ringDeviceHandler;
|
logger.trace("AbstractRingDevice - setJsonObject - Updated JSON: {}", ringDeviceTO);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setJsonObject(JsonObject jsonObject) {
|
public RingDeviceTO getDeviceStatus() {
|
||||||
this.jsonObject = jsonObject;
|
return deviceStatus;
|
||||||
logger.trace("AbstractRingDevice - setJsonObject - Updated JSON: {}", this.jsonObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonObject getJsonObject() {
|
|
||||||
return this.jsonObject;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,6 @@
|
||||||
package org.openhab.binding.ring.internal.data;
|
package org.openhab.binding.ring.internal.data;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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
|
* @author Ben Rosenblum - Initial contribution
|
||||||
|
@ -29,24 +23,9 @@ public class Chime extends AbstractRingDevice {
|
||||||
/**
|
/**
|
||||||
* Create Chime instance from JSON object.
|
* Create Chime instance from JSON object.
|
||||||
*
|
*
|
||||||
* @param jsonChime the JSON Chime retrieved from the Ring API.
|
* @param deviceTO the JSON Chime retrieved from the Ring API.
|
||||||
* @param ringAccount the Ring Account in use
|
|
||||||
*/
|
*/
|
||||||
public Chime(JsonObject jsonChime, RingAccount ringAccount) {
|
public Chime(RingDeviceTO deviceTO) {
|
||||||
super(jsonChime, ringAccount);
|
super(deviceTO);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package org.openhab.binding.ring.internal.data;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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
|
* @author Wim Vissers - Initial contribution
|
||||||
|
@ -27,28 +21,12 @@ import com.google.gson.JsonObject;
|
||||||
|
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class Doorbell extends AbstractRingDevice {
|
public class Doorbell extends AbstractRingDevice {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Doorbell instance from JSON object.
|
* Create Doorbell instance from JSON object.
|
||||||
*
|
*
|
||||||
* @param jsonDoorbell the JSON doorbell (doorbot) retrieved from the Ring API.
|
* @param deviceTO the JSON doorbell (doorbot) retrieved from the Ring API.
|
||||||
* @param ringAccount the Ring Account in use
|
|
||||||
*/
|
*/
|
||||||
public Doorbell(JsonObject jsonDoorbell, RingAccount ringAccount) {
|
public Doorbell(RingDeviceTO deviceTO) {
|
||||||
super(jsonDoorbell, ringAccount);
|
super(deviceTO);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package org.openhab.binding.ring.internal.data;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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
|
* @author Ben Rosenblum - Initial contribution
|
||||||
|
@ -29,24 +23,9 @@ public class OtherDevice extends AbstractRingDevice {
|
||||||
/**
|
/**
|
||||||
* Create OtherDevice instance from JSON object.
|
* Create OtherDevice instance from JSON object.
|
||||||
*
|
*
|
||||||
* @param jsonOtherDevice the JSON Other retrieved from the Ring API.
|
* @param deviceTO the JSON Other retrieved from the Ring API.
|
||||||
* @param ringAccount the Ring Account in use
|
|
||||||
*/
|
*/
|
||||||
public OtherDevice(JsonObject jsonOtherDevice, RingAccount ringAccount) {
|
public OtherDevice(RingDeviceTO deviceTO) {
|
||||||
super(jsonOtherDevice, ringAccount);
|
super(deviceTO);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,6 @@ package org.openhab.binding.ring.internal.data;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {"profile":{
|
* {"profile":{
|
||||||
* "id":4445516,
|
* "id":4445516,
|
||||||
|
@ -83,23 +81,18 @@ import com.google.gson.JsonObject;
|
||||||
|
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class Profile {
|
public class Profile {
|
||||||
private JsonObject jsonProfile = new JsonObject();
|
|
||||||
private JsonObject jsonFeatures = new JsonObject();
|
|
||||||
private String refreshToken = "";
|
private String refreshToken = "";
|
||||||
private String accessToken = "";
|
private String accessToken = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Profile instance from JSON String.
|
* 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.
|
* @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.
|
* 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.
|
* @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.
|
* Needed as a separate parameter because it's not part of the jsonProfile object.
|
||||||
*/
|
*/
|
||||||
public Profile(JsonObject jsonProfile, String refreshToken, String accessToken) {
|
public Profile(String refreshToken, String accessToken) {
|
||||||
this.jsonProfile = jsonProfile;
|
|
||||||
this.jsonFeatures = (JsonObject) jsonProfile.get("features");
|
|
||||||
this.refreshToken = refreshToken;
|
this.refreshToken = refreshToken;
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,7 @@
|
||||||
package org.openhab.binding.ring.internal.data;
|
package org.openhab.binding.ring.internal.data;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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.binding.ring.internal.RingDeviceRegistry;
|
||||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface common to all Ring devices.
|
* Interface common to all Ring devices.
|
||||||
|
@ -29,15 +23,6 @@ import com.google.gson.JsonObject;
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public interface RingDevice {
|
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.
|
* Get the registration status.
|
||||||
*
|
*
|
||||||
|
@ -52,29 +37,7 @@ public interface RingDevice {
|
||||||
*/
|
*/
|
||||||
void setRegistrationStatus(RingDeviceRegistry.Status registrationStatus);
|
void setRegistrationStatus(RingDeviceRegistry.Status registrationStatus);
|
||||||
|
|
||||||
/**
|
void setDeviceStatus(RingDeviceTO ringDeviceTO);
|
||||||
* Get the linked Ring account.
|
|
||||||
*
|
|
||||||
* @return the account.
|
|
||||||
*/
|
|
||||||
RingAccount getRingAccount();
|
|
||||||
|
|
||||||
/**
|
RingDeviceTO getDeviceStatus();
|
||||||
* 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();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package org.openhab.binding.ring.internal.data;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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
|
* @author Chris Milbert - Initial contribution
|
||||||
|
@ -31,24 +25,9 @@ public class Stickupcam extends AbstractRingDevice {
|
||||||
/**
|
/**
|
||||||
* Create Stickup Cam instance from JSON object.
|
* Create Stickup Cam instance from JSON object.
|
||||||
*
|
*
|
||||||
* @param jsonStickupcam the JSON Stickup Cam retrieved from the Ring API.
|
* @param deviceTO the JSON Stickup Cam retrieved from the Ring API.
|
||||||
* @param ringAccount the Ring Account in use
|
|
||||||
*/
|
*/
|
||||||
public Stickupcam(JsonObject jsonStickupcam, RingAccount ringAccount) {
|
public Stickupcam(RingDeviceTO deviceTO) {
|
||||||
super(jsonStickupcam, ringAccount);
|
super(deviceTO);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,21 +14,24 @@ package org.openhab.binding.ring.internal.discovery;
|
||||||
|
|
||||||
import static org.openhab.binding.ring.RingBindingConstants.*;
|
import static org.openhab.binding.ring.RingBindingConstants.*;
|
||||||
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.time.Instant;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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.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.RingDevice;
|
||||||
import org.openhab.binding.ring.internal.data.RingDeviceTO;
|
import org.openhab.binding.ring.internal.data.RingDeviceTO;
|
||||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
import org.openhab.binding.ring.internal.data.Stickupcam;
|
||||||
import org.openhab.core.config.discovery.DiscoveryService;
|
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.osgi.service.component.annotations.Component;
|
||||||
import org.slf4j.Logger;
|
import org.osgi.service.component.annotations.ServiceScope;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The RingDiscoveryService is responsible for auto detecting a Ring
|
* The RingDiscoveryService is responsible for auto detecting a Ring
|
||||||
|
@ -37,68 +40,39 @@ import com.google.gson.Gson;
|
||||||
* @author Wim Vissers - Initial contribution
|
* @author Wim Vissers - Initial contribution
|
||||||
* @author Chris Milbert - Stickupcam contribution
|
* @author Chris Milbert - Stickupcam contribution
|
||||||
* @author Ben Rosenblum - Updated for OH4 / New Maintainer
|
* @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
|
@NonNullByDefault
|
||||||
public class RingDiscoveryService extends AbstractDiscoveryService {
|
public class RingDiscoveryService extends AbstractThingHandlerDiscoveryService<AccountHandler> {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(RingDiscoveryService.class);
|
|
||||||
private @Nullable ScheduledFuture<?> discoveryJob;
|
|
||||||
|
|
||||||
private final Gson gson = new Gson();
|
|
||||||
|
|
||||||
public RingDiscoveryService() {
|
public RingDiscoveryService() {
|
||||||
super(SUPPORTED_THING_TYPES_UIDS, 5, true);
|
super(AccountHandler.class, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startScan() {
|
protected void startScan() {
|
||||||
logger.debug("Starting device search...");
|
ThingHandler thingHandler = getThingHandler();
|
||||||
discover();
|
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
|
@Override
|
||||||
|
@ -106,4 +80,10 @@ public class RingDiscoveryService extends AbstractDiscoveryService {
|
||||||
removeOlderResults(getTimestampOfLastScan());
|
removeOlderResults(getTimestampOfLastScan());
|
||||||
super.stopScan();
|
super.stopScan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
removeOlderResults(Instant.now().toEpochMilli());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue