diff --git a/CODEOWNERS b/CODEOWNERS index d161df2f0f618..d3054bde7c512 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -63,6 +63,7 @@ /bundles/org.openhab.binding.hdpowerview/ @beowulfe /bundles/org.openhab.binding.helios/ @kgoderis /bundles/org.openhab.binding.heos/ @Wire82 +/bundles/org.openhab.binding.hive/ @rbrownwsws /bundles/org.openhab.binding.homematic/ @FStolte @gerrieg @mdicke2s /bundles/org.openhab.binding.hpprinter/ @cossey /bundles/org.openhab.binding.hue/ @cweitkamp diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index aa79d5c99b3a2..7e79c8416dda9 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -308,6 +308,11 @@ org.openhab.addons.bundles org.openhab.binding.heos ${project.version} + + + org.openhab.addons.bundles + org.openhab.binding.hive + ${project.version} org.openhab.addons.bundles diff --git a/bundles/org.openhab.binding.hive/.classpath b/bundles/org.openhab.binding.hive/.classpath new file mode 100644 index 0000000000000..a5d95095ccaaf --- /dev/null +++ b/bundles/org.openhab.binding.hive/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.hive/.project b/bundles/org.openhab.binding.hive/.project new file mode 100644 index 0000000000000..92b99de245ff5 --- /dev/null +++ b/bundles/org.openhab.binding.hive/.project @@ -0,0 +1,23 @@ + + + org.openhab.binding.hive + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/bundles/org.openhab.binding.hive/NOTICE b/bundles/org.openhab.binding.hive/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.hive/NOTICE @@ -0,0 +1,13 @@ +This content is produced and maintained by the openHAB project. + +* Project home: https://www.openhab.org + +== Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License 2.0 which is available at +https://www.eclipse.org/legal/epl-2.0/. + +== Source Code + +https://github.com/openhab/openhab-addons diff --git a/bundles/org.openhab.binding.hive/README.md b/bundles/org.openhab.binding.hive/README.md new file mode 100644 index 0000000000000..c2309a289e97d --- /dev/null +++ b/bundles/org.openhab.binding.hive/README.md @@ -0,0 +1,86 @@ +# Hive Binding + +

+Centrica Hive Limited logo +

+ +This binding integrates the [Hive smart home system](https://www.hivehome.com) using the Hive REST API. + +_N.B. As this binding uses the Hive REST API it can only integrate Hive branded devices connected to a Hive Hub. +Setups that do not include a Hive Hub or connect to a different brand of Zigbee hub/bridge will not work with this binding._ + +| Hub Type | Image | +|--------------|-------| +| Hive Hub | Hive Hub | +| Hive Hub 360 | Hive Hub 360 | + +## Supported Things + +_Please describe the different supported things / devices within this section._ +_Which different types are supported, which models were tested etc.?_ +_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/ESH-INF/thing``` of your binding._ + +hive active heating receiver + +| Thing | Image | Supported | Tested | +|--------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|--------| +| Hive Thermostat V1 | Hive Thermostat V1 | ✓ | ✗ | +| Hive Thermostat V2 | Hive Thermostat | ✓ | ✓ | +| Hive Radiator Valve | Hive Radiator Valve | ✓ | ✓ | +| Hive Plug | Hive Plug | ✗ | ✗ | +| Hive Motion Sensor | Hive Motion Sensor | ✗ | ✗ | +| Hive Window or Door Sensor | Hive Window or Door Sensor | ✗ | ✗ | +| Hive Dimmable Light Bulb\* | Hive Dimmable Light Bulb | ✗ | ✗ | +| Hive Cool to Warm White Light Bulb\* | Hive Cool to Warm Whit Light Bulb | ✗ | ✗ | +| Hive Colour Changing Light Bulb\* | Hive Colour Changing Light Bulb | ✗ | ✗ | +| Hive View | Hive View | ✗ | ✗ | +| Hive View Outdoor | Hive View Outdoor | ✗ | ✗ | + +\*Hive Light Bulbs come in B22, E27, E14 and GU10 variants. Only one of these variants is pictured. + +## Discovery + +_Describe the available auto-discovery features here. Mention for what it works and what needs to be kept in mind when using it._ + +## Binding Configuration + +_If your binding requires or supports general configuration settings, please create a folder ```cfg``` and place the configuration file ```.cfg``` inside it. In this section, you should link to this file and provide some information about the options. The file could e.g. look like:_ + +``` +# Configuration for the Philips Hue Binding +# +# Default secret key for the pairing of the Philips Hue Bridge. +# It has to be between 10-40 (alphanumeric) characters +# This may be changed by the user for security reasons. +secret=openHABSecret +``` + +_Note that it is planned to generate some part of this based on the information that is available within ```src/main/resources/ESH-INF/binding``` of your binding._ + +_If your binding does not offer any generic configurations, you can remove this section completely._ + +## Thing Configuration + +_Describe what is needed to manually configure a thing, either through the (Paper) UI or via a thing-file. This should be mainly about its mandatory and optional configuration parameters. A short example entry for a thing file can help!_ + +_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/ESH-INF/thing``` of your binding._ + +## Channels + +_Here you should provide information about available channel types, what their meaning is and how they can be used._ + +_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/ESH-INF/thing``` of your binding._ + +| channel | type | description | +|----------|--------|------------------------------| +| control | Switch | This is the control channel | + +## Full Example + +_Provide a full usage example based on textual configuration files (*.things, *.items, *.sitemap)._ + +## Any custom content here! + +_Feel free to add additional sections for whatever you think should also be mentioned about your binding!_ + +[hive-hub]: "" \ No newline at end of file diff --git a/bundles/org.openhab.binding.hive/pom.xml b/bundles/org.openhab.binding.hive/pom.xml new file mode 100644 index 0000000000000..2dc277b4c0390 --- /dev/null +++ b/bundles/org.openhab.binding.hive/pom.xml @@ -0,0 +1,73 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 2.5.3-SNAPSHOT + + + org.openhab.binding.hive + + openHAB Add-ons :: Bundles :: Hive Binding + + + 0.8.5 + + + + + org.assertj + assertj-core + 3.15.0 + test + + + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + + prepare-agent + + + + report + prepare-package + + report + + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 3.0.0-M4 + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + + + diff --git a/bundles/org.openhab.binding.hive/src/main/feature/feature.xml b/bundles/org.openhab.binding.hive/src/main/feature/feature.xml new file mode 100644 index 0000000000000..3218b5d1e7275 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.hive/${project.version} + + diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/HiveAccountConfig.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/HiveAccountConfig.java new file mode 100644 index 0000000000000..fcb3743983eed --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/HiveAccountConfig.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * The {@link HiveAccountConfig} class contains fields mapping thing configuration parameters. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveAccountConfig { + public @Nullable String username; + public @Nullable String password; + public @Nullable Integer pollingInterval; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/HiveBindingConstants.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/HiveBindingConstants.java new file mode 100644 index 0000000000000..1ccc070e77c09 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/HiveBindingConstants.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.ThingTypeUID; + +import java.time.Duration; +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * The {@link HiveBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveBindingConstants { + public static final String BINDING_ID = "hive"; + + /* ######## Type UIDs ######## */ + public static final ThingTypeUID THING_TYPE_ACCOUNT = new ThingTypeUID(BINDING_ID, "account"); + public static final ThingTypeUID THING_TYPE_BOILER_MODULE = new ThingTypeUID(BINDING_ID, "boiler_module"); + public static final ThingTypeUID THING_TYPE_HEATING = new ThingTypeUID(BINDING_ID, "heating"); + public static final ThingTypeUID THING_TYPE_HOT_WATER = new ThingTypeUID(BINDING_ID, "hot_water"); + public static final ThingTypeUID THING_TYPE_HUB = new ThingTypeUID(BINDING_ID, "hub"); + public static final ThingTypeUID THING_TYPE_THERMOSTAT = new ThingTypeUID(BINDING_ID, "thermostat"); + public static final ThingTypeUID THING_TYPE_TRV = new ThingTypeUID(BINDING_ID, "trv"); + public static final ThingTypeUID THING_TYPE_TRV_GROUP = new ThingTypeUID(BINDING_ID, "trv_group"); + + /** + * The set of {@link ThingTypeUID}s supported by this binding. + */ + // @formatter:off + public static final Set SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(Stream.of( + THING_TYPE_ACCOUNT, + THING_TYPE_BOILER_MODULE, + THING_TYPE_HEATING, + THING_TYPE_HOT_WATER, + THING_TYPE_HUB, + THING_TYPE_THERMOSTAT, + THING_TYPE_TRV, + THING_TYPE_TRV_GROUP + ).collect(Collectors.toSet())); + // @formatter:on + + /** + * The set of {@link ThingTypeUID}s that can be discovered + * (everything but accounts). + */ + public static final Set DISCOVERABLE_THING_TYPES_UIDS = Collections.unmodifiableSet( + SUPPORTED_THING_TYPES_UIDS.stream() + .filter(it -> it != THING_TYPE_ACCOUNT) + .collect(Collectors.toSet()) + ); + + /* ######## Channel ids ######## */ + public static final String CHANNEL_BATTERY_LEVEL = "battery-level"; + public static final String CHANNEL_BATTERY_LOW = "battery-low"; + public static final String CHANNEL_MODE_ON_OFF = "mode-on_off"; + public static final String CHANNEL_MODE_OPERATING = "mode-operating"; + public static final String CHANNEL_MODE_OPERATING_OVERRIDE = "mode-operating-override"; + public static final String CHANNEL_STATE_OPERATING = "state-operating"; + public static final String CHANNEL_TEMPERATURE_CURRENT = "temperature-current"; + public static final String CHANNEL_TEMPERATURE_TARGET = "temperature-target"; + public static final String CHANNEL_TEMPERATURE_TARGET_BOOST = "temperature-target-boost"; + public static final String CHANNEL_IS_ON = "is_on"; + public static final String CHANNEL_TRANSIENT_DURATION = "transient-duration"; + public static final String CHANNEL_TRANSIENT_REMAINING = "transient-remaining"; + public static final String CHANNEL_TRANSIENT_ENABLED = "transient-enabled"; + public static final String CHANNEL_TRANSIENT_START_TIME = "transient-start_time"; + public static final String CHANNEL_TRANSIENT_END_TIME = "transient-end_time"; + public static final String CHANNEL_RADIO_LQI_AVERAGE = "radio-lqi-average"; + public static final String CHANNEL_RADIO_LQI_LAST_KNOWN = "radio-lqi-last_known"; + public static final String CHANNEL_RADIO_RSSI_AVERAGE = "radio-rssi-average"; + public static final String CHANNEL_RADIO_RSSI_LAST_KNOWN = "radio-rssi-last_known"; + + + /* ######## Config params ######## */ + public static final String CONFIG_NODE_ID = "nodeId"; + + public static final Duration SETTLE_TIME = Duration.ofSeconds(5); + + private HiveBindingConstants() { + throw new AssertionError(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/HiveHandlerFactory.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/HiveHandlerFactory.java new file mode 100644 index 0000000000000..10e0a0601abf7 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/HiveHandlerFactory.java @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.config.discovery.DiscoveryService; +import org.eclipse.smarthome.core.thing.Bridge; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.ThingTypeUID; +import org.eclipse.smarthome.core.thing.ThingUID; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; +import org.eclipse.smarthome.core.thing.binding.ThingHandler; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory; +import org.openhab.binding.hive.internal.handler.*; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +/** + * The {@link HiveHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.hive", service = ThingHandlerFactory.class) +public final class HiveHandlerFactory extends BaseThingHandlerFactory { + private final Logger logger = LoggerFactory.getLogger(HiveHandlerFactory.class); + + private final Map> discoveryServices = new HashMap<>(); + + public HiveHandlerFactory() { + super(); + } + + @Override + protected void activate(final ComponentContext componentContext) { + super.activate(componentContext); + + // Help keep track of when openHAB reloads binding while debugging. + logger.debug("Handler has been activated"); + } + + @Override + protected void deactivate(final ComponentContext componentContext) { + super.deactivate(componentContext); + + // Help keep track of when openHAB reloads binding while debugging. + logger.debug("Handler has been deactivated"); + } + + @Override + public boolean supportsThingType(final ThingTypeUID thingTypeUID) { + return HiveBindingConstants.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); + } + + @Override + protected @Nullable ThingHandler createHandler(final Thing thing) { + final ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + + if (HiveBindingConstants.THING_TYPE_ACCOUNT.equals(thingTypeUID)) { + // Create the handler + final HiveAccountHandler handler = new HiveAccountHandler((Bridge) thing); + + // Register the discovery service and keep track of it so we can + // unregister it later. + final ServiceRegistration serviceReg = bundleContext.registerService( + DiscoveryService.class.getName(), + handler.getDiscoveryService(), + new Hashtable<>() + ); + final ThingUID uid = thing.getUID(); + this.discoveryServices.put(uid, serviceReg); + + return handler; + } else if (HiveBindingConstants.THING_TYPE_BOILER_MODULE.equals(thingTypeUID)) { + return new HiveBoilerModuleHandler(thing); + } else if (HiveBindingConstants.THING_TYPE_HEATING.equals(thingTypeUID)) { + return new HiveHeatingHandler(thing); + } else if (HiveBindingConstants.THING_TYPE_HOT_WATER.equals(thingTypeUID)) { + return new HiveHotWaterHandler(thing); + } else if (HiveBindingConstants.THING_TYPE_HUB.equals(thingTypeUID)) { + return new HiveHubHandler(thing); + } else if (HiveBindingConstants.THING_TYPE_THERMOSTAT.equals(thingTypeUID)) { + return new HiveThermostatHandler(thing); + } else if (HiveBindingConstants.THING_TYPE_TRV.equals(thingTypeUID)) { + return new HiveTrvHandler(thing); + } else if (HiveBindingConstants.THING_TYPE_TRV_GROUP.equals(thingTypeUID)) { + return new HiveTrvGroupHandler(thing); + } + + return null; + } + + @Override + protected void removeHandler(final ThingHandler thingHandler) { + logger.debug("Removing handler"); + if (thingHandler instanceof HiveAccountHandler) { + logger.debug("Handler is bridge"); + // Clean up associated discovery service. + final @Nullable ServiceRegistration serviceReg = this.discoveryServices.remove(thingHandler.getThing().getUID()); + + if (serviceReg != null) { + logger.debug("Unregistered service"); + serviceReg.unregister(); + } + } + + super.removeHandler(thingHandler); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/ActionType.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/ActionType.java new file mode 100644 index 0000000000000..a50151f08f2aa --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/ActionType.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class ActionType extends URITypeBase { + public static final ActionType GENERIC = new ActionType("http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#"); + + public ActionType(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/AttributeName.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/AttributeName.java new file mode 100644 index 0000000000000..f90f86b0f8c90 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/AttributeName.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class AttributeName extends StringTypeBase { + public static final AttributeName ATTRIBUTE_NAME_TARGET_HEAT_TEMPERATURE = new AttributeName("targetHeatTemperature"); + + public AttributeName(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/BatteryLevel.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/BatteryLevel.java new file mode 100644 index 0000000000000..48f369f67d1e1 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/BatteryLevel.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class BatteryLevel { + private int value; + + public BatteryLevel(int value) { + if (value < 0 || value > 100) { + throw new IllegalArgumentException("Battery level is must be between 0-100 (inclusive)"); + } + + this.value = value; + } + + public int intValue() { + return value; + } + + @NonNullByDefault({}) + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BatteryLevel that = (BatteryLevel) o; + return value == that.value; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return this.value + "%"; + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/DefaultHiveClient.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/DefaultHiveClient.java new file mode 100644 index 0000000000000..d2bea68cec677 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/DefaultHiveClient.java @@ -0,0 +1,169 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hive.internal.client.exception.HiveApiAuthenticationException; +import org.openhab.binding.hive.internal.client.exception.HiveApiNotAuthorisedException; +import org.openhab.binding.hive.internal.client.exception.HiveApiUnknownException; +import org.openhab.binding.hive.internal.client.repository.NodeRepository; +import org.openhab.binding.hive.internal.client.repository.SessionRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; +import java.util.Set; +import java.util.function.Supplier; + +/** + * The default implementation of {@link HiveClient} + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +final class DefaultHiveClient implements HiveClient { + private final Logger logger = LoggerFactory.getLogger(DefaultHiveClient.class); + + private final SessionAuthenticationManager authenticationManager; + + private final Username username; + private final Password password; + + private final SessionRepository sessionRepository; + private final NodeRepository nodeRepository; + + private @Nullable Session session; + + /** + * Indicated whether the client is currently authenticated with the Hive + * API. + */ + private boolean authenticated = false; + + /** + * + * + * @throws HiveApiAuthenticationException + * If we failed to authenticate with the provided username and password. + * + * @throws HiveApiUnknownException + * If something unexpected happens while communicating with the Hive + * API. + */ + public DefaultHiveClient( + final SessionAuthenticationManager authenticationManager, + final Username username, + final Password password, + final SessionRepository sessionRepository, + final NodeRepository nodeRepository + ) { + Objects.requireNonNull(authenticationManager); + Objects.requireNonNull(sessionRepository); + Objects.requireNonNull(nodeRepository); + + this.authenticationManager = authenticationManager; + + this.username = username; + this.password = password; + + this.sessionRepository = sessionRepository; + this.nodeRepository = nodeRepository; + + authenticate(); + } + + @Override + public void close() throws Exception { + // TODO: Clean up + } + + /** + * Try to authenticate with the Hive API. + * + * @throws HiveApiAuthenticationException + * If we failed to authenticate with the stored username and password. + * + * @throws HiveApiUnknownException + * If something unexpected happens while communicating with the Hive + * API. + */ + private void authenticate() { + this.authenticationManager.clearSession(); + + final Session session = this.sessionRepository.createSession( + this.username, + this.password + ); + + this.session = session; + this.authenticationManager.setSession(session); + + this.authenticated = true; + } + + private T makeAuthenticatedApiCall(final Supplier apiCall) { + // If we get a valid result return it. + // If we are not authorised check if session has expired, reauthenticate and try again. + // Otherwise let other exceptions bubble up. + boolean reauthenticated = false; + while (true) { + try { + return apiCall.get(); + } catch (final HiveApiNotAuthorisedException ex) { + if (reauthenticated || this.sessionRepository.isValidSession(this.authenticationManager.getSession())) { + // We are either not authorised for this resource or + // something has gone wrong with the client logic. + // Pass on the exception. + throw ex; + } else { + // Session seems to no longer be valid. + // Reauthenticate and try again. + authenticate(); + reauthenticated = true; + } + } + } + } + + private void makeAuthenticatedApiCall(final Runnable apiCall) { + makeAuthenticatedApiCall(() -> { + apiCall.run(); + return null; + }); + } + + @Override + public UserId getUserId() { + return this.session.getUserId(); + } + + @Override + public Set getAllNodes() { + return makeAuthenticatedApiCall(this.nodeRepository::getAllNodes); + } + + @Override + public @Nullable Node getNode(final NodeId nodeId) { + Objects.requireNonNull(nodeId); + + return makeAuthenticatedApiCall(() -> this.nodeRepository.getNode(nodeId)); + } + + @Override + public @Nullable Node updateNode(final Node node) { + Objects.requireNonNull(node); + + return makeAuthenticatedApiCall(() -> this.nodeRepository.updateNode(node)); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/DefaultNode.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/DefaultNode.java new file mode 100644 index 0000000000000..cc7a07f394fa9 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/DefaultNode.java @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hive.internal.client.feature.Feature; + +import java.util.*; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class DefaultNode implements Node { + private final NodeId id; + private final NodeName name; + private final NodeType nodeType; + private final ProductType productType; + private final Protocol protocol; + private final NodeId parentNodeId; + private final Map, Feature> features; + + public DefaultNode( + final NodeId id, + final NodeName name, + final NodeType nodeType, + final ProductType productType, + final Protocol protocol, + final NodeId parentNodeId, + final Map, Feature> features + ) { + Objects.requireNonNull(id); + Objects.requireNonNull(name); + Objects.requireNonNull(nodeType); + Objects.requireNonNull(productType); + Objects.requireNonNull(protocol); + Objects.requireNonNull(parentNodeId); + Objects.requireNonNull(features); + + this.id = id; + this.name = name; + this.nodeType = nodeType; + this.productType = productType; + this.protocol = protocol; + this.parentNodeId = parentNodeId; + this.features = features; + } + + @Override + public NodeId getId() { + return this.id; + } + + @Override + public NodeName getName() { + return this.name; + } + + @Override + public NodeType getNodeType() { + return this.nodeType; + } + + @Override + public ProductType getProductType() { + return this.productType; + } + + @Override + public Protocol getProtocol() { + return this.protocol; + } + + @Override + public NodeId getParentNodeId() { + return this.parentNodeId; + } + + @Override + public Set getFeatures() { + return Collections.unmodifiableSet(new HashSet<>(this.features.values())); + } + + @SuppressWarnings("unchecked") + @Override + public @Nullable T getFeature(final Class classOfFeature) { + // N.B. "Unchecked cast" warning suppressed because we should be + // ensuring that the class of the value matches the key + // when they are put in the map. + return (T) this.features.get(classOfFeature); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FeatureAttribute.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FeatureAttribute.java new file mode 100644 index 0000000000000..8864acedaae44 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FeatureAttribute.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.time.Instant; +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class FeatureAttribute { + private final T reportedValue; + private final Instant reportReceivedTime; + private final Instant reportChangedTime; + + private final T displayValue; + + FeatureAttribute( + final T reportedValue, + final Instant reportChangedTime, + final Instant reportReceivedTime, + final T displayValue + ) { + Objects.requireNonNull(reportedValue); + Objects.requireNonNull(reportChangedTime); + Objects.requireNonNull(reportReceivedTime); + Objects.requireNonNull(displayValue); + + this.reportedValue = reportedValue; + this.reportChangedTime = reportChangedTime; + this.reportReceivedTime = reportReceivedTime; + this.displayValue = displayValue; + } + + public final T getReportedValue() { + return this.reportedValue; + } + + public final Instant getReportReceivedTime() { + return this.reportReceivedTime; + } + + public final Instant getReportChangedTime() { + return this.reportChangedTime; + } + + public final T getDisplayValue() { + return this.displayValue; + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FeatureAttributeFactory.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FeatureAttributeFactory.java new file mode 100644 index 0000000000000..26ee6abdeee11 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FeatureAttributeFactory.java @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.dto.FeatureAttributeDto; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class FeatureAttributeFactory { + private FeatureAttributeFactory() { + throw new AssertionError(); + } + + @FunctionalInterface + public interface Adapter { + T adapt(F from); + } + + public static FeatureAttribute getReadOnlyFromDto(final FeatureAttributeDto dto) { + Objects.requireNonNull(dto); + + return new FeatureAttribute<>( + dto.reportedValue, + dto.reportChangedTime.asInstant(), + dto.reportReceivedTime.asInstant(), + dto.displayValue + ); + } + + public static FeatureAttribute getReadOnlyFromDtoWithAdapter( + final Adapter adapter, + final FeatureAttributeDto dto + ) { + Objects.requireNonNull(adapter); + Objects.requireNonNull(dto); + + return new FeatureAttribute<>( + adapter.adapt(dto.reportedValue), + dto.reportChangedTime.asInstant(), + dto.reportReceivedTime.asInstant(), + adapter.adapt(dto.displayValue) + ); + } + + public static SettableFeatureAttribute getSettableFromDto(final FeatureAttributeDto dto) { + Objects.requireNonNull(dto); + + return new SettableFeatureAttribute<>( + dto.reportedValue, + dto.reportChangedTime.asInstant(), + dto.reportReceivedTime.asInstant(), + dto.displayValue + ); + } + + public static SettableFeatureAttribute getSettableFromDtoWithAdapter( + final Adapter adapter, + final FeatureAttributeDto dto + ) { + Objects.requireNonNull(adapter); + Objects.requireNonNull(dto); + + return new SettableFeatureAttribute<>( + adapter.adapt(dto.reportedValue), + dto.reportChangedTime.asInstant(), + dto.reportReceivedTime.asInstant(), + adapter.adapt(dto.displayValue) + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FeatureType.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FeatureType.java new file mode 100644 index 0000000000000..9ccd185826665 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FeatureType.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class FeatureType extends URITypeBase { + public static final FeatureType BATTERY_DEVICE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.battery_device.v1.json#"); + public static final FeatureType CHILD_LOCK_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.child_lock.v1.json#"); + public static final FeatureType DEVICE_MANAGEMENT_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.device_management.v1.json#"); + public static final FeatureType DISPLAY_ORIENTATION_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.display_orientation.v1.json#"); + public static final FeatureType ETHERNET_DEVICE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.ethernet_device.v1.json#"); + public static final FeatureType FROST_PROTECT_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.frost_protect.v1.json#"); + public static final FeatureType GROUP_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.group.v1.json#"); + public static final FeatureType HEATING_TEMPERATURE_CONTROL_DEVICE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.heating_temperature_control_device.v1.json#"); + public static final FeatureType HEATING_TEMPERATURE_CONTROL_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.heating_temperature_control.v1.json#"); + public static final FeatureType HEATING_THERMOSTAT_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#"); + public static final FeatureType HIVE_HUB_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.hive_hub.v1.json#"); + public static final FeatureType LIFECYCLE_STATE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.lifecycle_state.v1.json#"); + public static final FeatureType LINKS_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.links.v1.json#"); + public static final FeatureType MOUNTING_MODE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.mounting_mode.v1.json#"); + public static final FeatureType ON_OFF_DEVICE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#"); + public static final FeatureType PI_HEATING_DEMAND_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.pi_heating_demand.v1.json#"); + public static final FeatureType PHYSICAL_DEVICE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.physical_device.v1.json#"); + public static final FeatureType RADIO_DEVICE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.radio_device.v1.json#"); + public static final FeatureType STANDBY_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.standby.v1.json#"); + public static final FeatureType TEMPERATURE_SENSOR_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.temperature_sensor.v1.json#"); + public static final FeatureType TRANSIENT_MODE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.transient_mode.v1.json#"); + public static final FeatureType TRV_CALIBRATION_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.trv_calibration.v1.json#"); + public static final FeatureType TRV_ERROR_DIAGNOSTICS_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.trv_error_diagnostics.v1.json#"); + public static final FeatureType WATER_HEATER_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.water_heater.v1.json#"); + public static final FeatureType ZIGBEE_DEVICE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.zigbee_device.v1.json#"); + public static final FeatureType ZIGBEE_ROUTING_DEVICE_V1 = new FeatureType("http://alertme.com/schema/json/feature/node.feature.zigbee_routing_device.v1.json#"); + + public FeatureType(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FromStringTypeBase.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FromStringTypeBase.java new file mode 100644 index 0000000000000..8e61eaaf8162f --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/FromStringTypeBase.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.util.Objects; + +/** + * A base class for simple value types constructed from strings. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +abstract class FromStringTypeBase { + private final T value; + + public FromStringTypeBase(final String stringValue) { + Objects.requireNonNull(stringValue); + + this.value = transform(stringValue); + + validate(this.value); + } + + protected abstract T transform(final String stringValue); + + protected void validate(final T value) {} + + @Override + public String toString() { + return value.toString(); + } + + @NonNullByDefault({}) + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || this.getClass() != o.getClass()) return false; + final FromStringTypeBase other = (FromStringTypeBase) o; + return value.equals(other.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/GsonJsonService.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/GsonJsonService.java new file mode 100644 index 0000000000000..e2905e06a79a3 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/GsonJsonService.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.adapter.*; +import org.openhab.binding.hive.internal.client.dto.HiveApiInstant; + +import java.time.ZonedDateTime; +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +final class GsonJsonService implements JsonService { + private final Gson gson; + + public GsonJsonService() { + this.gson = (new GsonBuilder()) + .registerTypeAdapter(HiveApiInstant.class, new HiveApiInstantGsonAdapter()) + .registerTypeAdapter(UserId.class, new UserIdGsonAdapter()) + .registerTypeAdapter(SessionId.class, new SessionIdGsonAdapter()) + .registerTypeAdapter(Username.class, new UsernameGsonAdapter()) + .registerTypeAdapter(Password.class, new PasswordGsonAdapter()) + .registerTypeAdapter(NodeId.class, new NodeIdGsonAdapter()) + .registerTypeAdapter(NodeName.class, new NodeNameGsonAdapter()) + .registerTypeAdapter(NodeType.class, new NodeTypeGsonAdapter()) + .registerTypeAdapter(FeatureType.class, new FeatureTypeGsonAdapter()) + .registerTypeAdapter(ProductType.class, new ProductTypeGsonAdapter()) + .registerTypeAdapter(ActionType.class, new ActionTypeGsonAdapter()) + .registerTypeAdapter(AttributeName.class, new AttributeNameGsonAdapter()) + .registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeGsonAdapter()) + .create(); + } + + @Override + public String toJson(final Object object) { + Objects.requireNonNull(object); + + return this.gson.toJson(object); + } + + @Override + public T fromJson(final String json, final Class classOfT) { + Objects.requireNonNull(json); + Objects.requireNonNull(classOfT); + + return this.gson.fromJson(json, classOfT); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiConstants.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiConstants.java new file mode 100644 index 0000000000000..489f835021885 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiConstants.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.net.URI; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveApiConstants { + private HiveApiConstants() { + throw new AssertionError(); + } + + /** + * The location of the real Hive API. + */ + public static final URI DEFAULT_BASE_PATH = URI.create("https://api.prod.bgchprod.info/omnia/"); + + + public static final URI ENDPOINT_ACCESS_TOKENS = URI.create("accessTokens"); + + public static final URI ENDPOINT_CALLBACK_TOKENS = URI.create("callbackTokens"); + + public static final URI ENDPOINT_CHANNELS = URI.create("channels"); + + public static final URI ENDPOINT_CONTACTS = URI.create("contacts"); + + public static final URI ENDPOINT_DEVICE_TOKENS = URI.create("deviceTokens"); + + public static final URI ENDPOINT_EVENTS = URI.create("events"); + + public static final URI ENDPOINT_MEDIA = URI.create("media"); + + public static final URI ENDPOINT_MIGRATION = URI.create("migrations"); + + public static final URI ENDPOINT_NODES = URI.create("nodes"); + public static final URI ENDPOINT_NODE = URI.create("nodes/"); + + public static final URI ENDPOINT_PASSWORDS = URI.create("auth/passwordReset"); + + public static final URI ENDPOINT_RESERVATIONS = URI.create("nodes/reservation"); + + public static final URI ENDPOINT_RULES = URI.create("rules"); + + public static final URI ENDPOINT_SESSIONS = URI.create("auth/sessions"); + public static final URI ENDPOINT_SESSION = URI.create("auth/sessions/"); + + public static final URI ENDPOINT_TOPOLOGY = URI.create("topology"); + + public static final URI ENDPOINT_USERS = URI.create("users"); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiRequest.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiRequest.java new file mode 100644 index 0000000000000..567b46da52e76 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiRequest.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.exception.HiveClientRequestException; + +/** + * A facade for HTTP requests to the Hive API + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface HiveApiRequest { + HiveApiRequest accept(MediaType mediaType); + + /** + * + * @throws HiveClientRequestException + */ + HiveApiResponse get(); + + + /** + * + * @throws HiveClientRequestException + */ + HiveApiResponse post(Object requestBody); + + /** + * + * @throws HiveClientRequestException + */ + HiveApiResponse put(Object requestBody); + + + /** + * + * @throws HiveClientRequestException + */ + HiveApiResponse delete(); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiRequestFactory.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiRequestFactory.java new file mode 100644 index 0000000000000..58ddf6248e486 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiRequestFactory.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.net.URI; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface HiveApiRequestFactory { + HiveApiRequest newRequest(URI endpointPath); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiResponse.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiResponse.java new file mode 100644 index 0000000000000..cf0aad143d1d8 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveApiResponse.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A facade for HTTP responses from the Hive API + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface HiveApiResponse { + int getStatusCode(); + + T getContent(Class contentType); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveClient.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveClient.java new file mode 100644 index 0000000000000..6645d6e192f7d --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveClient.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +import java.util.Set; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface HiveClient extends AutoCloseable { + UserId getUserId(); + + Set getAllNodes(); + @Nullable Node getNode(NodeId nodeId); + @Nullable Node updateNode(Node node); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveClientFactory.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveClientFactory.java new file mode 100644 index 0000000000000..3ee24ccb097db --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/HiveClientFactory.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.openhab.binding.hive.internal.client.repository.DefaultNodeRepository; +import org.openhab.binding.hive.internal.client.repository.DefaultSessionRepository; +import org.openhab.binding.hive.internal.client.repository.NodeRepository; +import org.openhab.binding.hive.internal.client.repository.SessionRepository; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveClientFactory { + public static HiveClient newClient( + final Username username, + final Password password + ) { + Objects.requireNonNull(username); + Objects.requireNonNull(password); + + final HttpClient httpClient = new HttpClient(new SslContextFactory()); + try { + httpClient.start(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + final JettyHiveApiRequestFactory requestFactory = new JettyHiveApiRequestFactory( + httpClient, + HiveApiConstants.DEFAULT_BASE_PATH, + new GsonJsonService(), + "openHAB" + ); + + final SessionRepository sessionRepository = new DefaultSessionRepository( + requestFactory + ); + + final NodeRepository nodeRepository = new DefaultNodeRepository( + requestFactory + ); + + return new DefaultHiveClient( + requestFactory, + username, + password, + sessionRepository, + nodeRepository + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JettyHiveApiRequest.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JettyHiveApiRequest.java new file mode 100644 index 0000000000000..452a0efcc024e --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JettyHiveApiRequest.java @@ -0,0 +1,104 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; +import org.openhab.binding.hive.internal.client.exception.HiveClientRequestException; + +import java.util.Objects; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +final class JettyHiveApiRequest implements HiveApiRequest { + private final JsonService jsonService; + private final Request request; + + public JettyHiveApiRequest( + final JsonService jsonService, + final Request request + ) { + Objects.requireNonNull(jsonService); + Objects.requireNonNull(request); + + this.jsonService = jsonService; + this.request = request; + } + + private void setContent(final Object content) { + this.request.content( + new StringContentProvider(this.jsonService.toJson(content)), + MediaType.JSON.toString() + ); + } + + @Override + public HiveApiRequest accept(final MediaType mediaType) { + this.request.accept(mediaType.toString()); + + return this; + } + + @Override + public HiveApiResponse get() { + this.request.method(HttpMethod.GET); + + return this.sendRequest(); + } + + @Override + public HiveApiResponse post(final Object requestBody) { + Objects.requireNonNull(requestBody); + + this.request.method(HttpMethod.POST); + this.setContent(requestBody); + + return this.sendRequest(); + } + + @Override + public HiveApiResponse put(final Object requestBody) { + Objects.requireNonNull(requestBody); + + this.request.method(HttpMethod.PUT); + this.setContent(requestBody); + + return this.sendRequest(); + } + + @Override + public HiveApiResponse delete() { + this.request.method(HttpMethod.DELETE); + + return this.sendRequest(); + } + + private HiveApiResponse sendRequest() { + try { + final ContentResponse response = this.request.send(); + + return new JettyHiveApiResponse(this.jsonService, response); + } catch (InterruptedException | TimeoutException | ExecutionException ex) { + throw new HiveClientRequestException(ex); + } + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JettyHiveApiRequestFactory.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JettyHiveApiRequestFactory.java new file mode 100644 index 0000000000000..923a3a64d707c --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JettyHiveApiRequestFactory.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.WWWAuthenticationProtocolHandler; +import org.eclipse.jetty.client.api.Request; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +final class JettyHiveApiRequestFactory implements HiveApiRequestFactory, SessionAuthenticationManager { + private static final String ACCESS_TOKEN_HEADER = "X-Omnia-Access-Token"; + private static final String CLIENT_ID_HEADER = "X-Omnia-Client"; + + private final Logger logger = LoggerFactory.getLogger(JettyHiveApiRequestFactory.class); + + private final HttpClient httpClient; + private final URI apiBasePath; + private final JsonService jsonService; + private final String clientId; + + @Nullable + private Session session = null; + + public JettyHiveApiRequestFactory( + final HttpClient httpClient, + final URI apiBasePath, + final JsonService jsonService, + final String clientId + ) { + Objects.requireNonNull(httpClient); + Objects.requireNonNull(apiBasePath); + Objects.requireNonNull(jsonService); + Objects.requireNonNull(clientId); + + if (!apiBasePath.isAbsolute()) { + throw new IllegalArgumentException("API base path must be absolute"); + } + + this.httpClient = httpClient; + this.apiBasePath = apiBasePath; + this.jsonService = jsonService; + this.clientId = clientId; + + // Remove jetty's default authentication handler as it will be confused + // by the Hive API's lack of "WWW-Authenticate" header and will mess + // up manual authentication. + this.httpClient.getProtocolHandlers().remove(WWWAuthenticationProtocolHandler.NAME); + } + + @Override + public void clearSession() { + this.session = null; + } + + @Override + public @Nullable Session getSession() { + return this.session; + } + + @Override + public void setSession(final Session session) { + Objects.requireNonNull(session); + + this.session = session; + } + + @Override + public HiveApiRequest newRequest(final URI endpointPath) { + final URI target = this.apiBasePath.resolve(endpointPath); + + final Request request = this.httpClient.newRequest(target); + + // Add X-Omnia-Client header + request.header(CLIENT_ID_HEADER, this.clientId); + + // If we have a session ID add X-Omnia-Access-Token header. + if (this.session != null) { + request.header(ACCESS_TOKEN_HEADER, this.session.getSessionId().toString()); + } + + return new JettyHiveApiRequest( + this.jsonService, + request + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JettyHiveApiResponse.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JettyHiveApiResponse.java new file mode 100644 index 0000000000000..683e4ff95806b --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JettyHiveApiResponse.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jetty.client.api.ContentResponse; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +final class JettyHiveApiResponse implements HiveApiResponse { + private final JsonService jsonService; + private final ContentResponse response; + + public JettyHiveApiResponse( + final JsonService jsonService, + final ContentResponse response + ) { + Objects.requireNonNull(jsonService); + Objects.requireNonNull(response); + + this.jsonService = jsonService; + this.response = response; + } + + @Override + public int getStatusCode() { + return this.response.getStatus(); + } + + @Override + public T getContent(Class contentType) { + return this.jsonService.fromJson(this.response.getContentAsString(), contentType); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JsonService.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JsonService.java new file mode 100644 index 0000000000000..272148b648963 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/JsonService.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A facade for JSON serialisation/deserialisation. + * + *

+ * Used to decouple from Gson and make testing easier. + * ({@code Gson} is final and so annoying to replace with a test double) + *

+ * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface JsonService { + String toJson(Object object); + T fromJson(String json, Class classOfT); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/MediaType.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/MediaType.java new file mode 100644 index 0000000000000..98058fb97f485 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/MediaType.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class MediaType extends StringTypeBase { + public static final MediaType JSON = new MediaType("application/json"); + public static final MediaType API_V6_0_0_JSON = new MediaType("application/vnd.alertme.zoo-6.0.0+json"); + public static final MediaType API_V6_1_0_JSON = new MediaType("application/vnd.alertme.zoo-6.1.0+json"); + public static final MediaType API_V6_2_0_JSON = new MediaType("application/vnd.alertme.zoo-6.2.0+json"); + public static final MediaType API_V6_3_0_JSON = new MediaType("application/vnd.alertme.zoo-6.3.0+json"); + public static final MediaType API_V6_4_0_JSON = new MediaType("application/vnd.alertme.zoo-6.4.0+json"); + public static final MediaType API_V6_5_0_JSON = new MediaType("application/vnd.alertme.zoo-6.5.0+json"); + public static final MediaType API_V6_6_0_JSON = new MediaType("application/vnd.alertme.zoo-6.6.0+json"); + + public MediaType(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Node.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Node.java new file mode 100644 index 0000000000000..25702ef7be317 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Node.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hive.internal.client.feature.Feature; + +import java.util.Set; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface Node { + NodeId getId(); + NodeName getName(); + NodeType getNodeType(); + ProductType getProductType(); + Protocol getProtocol(); + NodeId getParentNodeId(); + + Set getFeatures(); + @Nullable T getFeature(Class classOfFeature); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/NodeId.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/NodeId.java new file mode 100644 index 0000000000000..4d6cc158ce512 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/NodeId.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class NodeId extends UuidTypeBase { + public NodeId(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/NodeName.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/NodeName.java new file mode 100644 index 0000000000000..a3f66b223ff44 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/NodeName.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class NodeName extends StringTypeBase { + public NodeName(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/NodeType.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/NodeType.java new file mode 100644 index 0000000000000..553871cdf6261 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/NodeType.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class NodeType extends URITypeBase { + public static final NodeType HUB = new NodeType("http://alertme.com/schema/json/node.class.hub.json#"); + public static final NodeType THERMOSTAT = new NodeType("http://alertme.com/schema/json/node.class.thermostat.json#"); + public static final NodeType THERMOSTAT_UI = new NodeType("http://alertme.com/schema/json/node.class.thermostatui.json#"); + public static final NodeType RADIATOR_VALVE = new NodeType("http://alertme.com/schema/json/node.class.trv.json#"); + + public NodeType(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/OnOffMode.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/OnOffMode.java new file mode 100644 index 0000000000000..18650909179ec --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/OnOffMode.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public enum OnOffMode { + ON, + OFF +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/OperatingMode.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/OperatingMode.java new file mode 100644 index 0000000000000..12b72b0d13d95 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/OperatingMode.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public enum OperatingMode { + SCHEDULE, + MANUAL +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/OverrideMode.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/OverrideMode.java new file mode 100644 index 0000000000000..b34337ca39338 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/OverrideMode.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public enum OverrideMode { + NONE, + TRANSIENT +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Password.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Password.java new file mode 100644 index 0000000000000..19e62a69df0f0 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Password.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A password value type. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class Password extends StringTypeBase { + public Password(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/ProductType.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/ProductType.java new file mode 100644 index 0000000000000..fb05531498631 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/ProductType.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class ProductType extends StringTypeBase { + public static final ProductType BOILER_MODULE = new ProductType("BOILER_MODULE"); + public static final ProductType DAYLIGHT_SD = new ProductType("DAYLIGHT_SD"); + public static final ProductType HEATING = new ProductType("HEATING"); + public static final ProductType HOT_WATER = new ProductType("HOT_WATER"); + public static final ProductType HUB = new ProductType("HUB"); + public static final ProductType THERMOSTAT_UI = new ProductType("THERMOSTAT_UI"); + public static final ProductType TRV = new ProductType("TRV"); + public static final ProductType TRV_GROUP = new ProductType("TRV_GROUP"); + + public ProductType(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Protocol.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Protocol.java new file mode 100644 index 0000000000000..86a516f8d0285 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Protocol.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class Protocol extends StringTypeBase { + public static final Protocol SYNTHETIC = new Protocol("SYNTHETIC"); + public static final Protocol ZIGBEE = new Protocol("ZIGBEE"); + public static final Protocol PROXIED = new Protocol("PROXIED"); + public static final Protocol MQTT = new Protocol("MQTT"); + public static final Protocol XMPP = new Protocol("XMPP"); + public static final Protocol VIRTUAL = new Protocol("VIRTUAL"); + + public static final Protocol NONE = new Protocol("NONE"); + + public Protocol(String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Session.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Session.java new file mode 100644 index 0000000000000..d6e3870fd1330 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Session.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class Session { + private SessionId sessionId; + private UserId userId; + + public Session( + final SessionId sessionId, + final UserId userId + ) { + Objects.requireNonNull(sessionId); + Objects.requireNonNull(userId); + + this.sessionId = sessionId; + this.userId = userId; + } + + public SessionId getSessionId() { + return sessionId; + } + + public UserId getUserId() { + return userId; + } + + @NonNullByDefault({}) + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final Session session = (Session) o; + return sessionId.equals(session.sessionId) && + userId.equals(session.userId); + } + + @Override + public int hashCode() { + return Objects.hash(sessionId, userId); + } + + @Override + public String toString() { + return "Session{" + + "sessionId=" + sessionId + + ", userId=" + userId + + '}'; + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/SessionAuthenticationManager.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/SessionAuthenticationManager.java new file mode 100644 index 0000000000000..29a1081d59351 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/SessionAuthenticationManager.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +interface SessionAuthenticationManager { + void clearSession(); + @Nullable Session getSession(); + void setSession(Session session); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/SessionId.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/SessionId.java new file mode 100644 index 0000000000000..bc95c3f019d85 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/SessionId.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class SessionId extends StringTypeBase { + public SessionId(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/SettableFeatureAttribute.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/SettableFeatureAttribute.java new file mode 100644 index 0000000000000..f5ed8ac7e6b1d --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/SettableFeatureAttribute.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +import java.time.Instant; +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class SettableFeatureAttribute extends FeatureAttribute { + private @Nullable T targetValue = null; + + SettableFeatureAttribute( + final T reportedValue, + final Instant changedTime, + final Instant receivedTime, + final T displayValue + ) { + super(reportedValue,changedTime,receivedTime,displayValue); + } + + public void setTargetValue(final T targetValue) { + Objects.requireNonNull(targetValue); + + this.targetValue = targetValue; + } + + public void clearTargetValue() { + this.targetValue = null; + } + + public @Nullable T getTargetValue() { + return this.targetValue; + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/StringTypeBase.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/StringTypeBase.java new file mode 100644 index 0000000000000..045089fe51e3d --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/StringTypeBase.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +abstract class StringTypeBase extends FromStringTypeBase { + public StringTypeBase(final String stringValue) { + super(stringValue); + } + + protected String transform(final String stringValue) { + if (stringValue.isEmpty()) { + throw new IllegalArgumentException("Value must not be empty"); + } + + return stringValue; + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Temperature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Temperature.java new file mode 100644 index 0000000000000..d72e1ccc35661 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Temperature.java @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.math.BigDecimal; +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class Temperature { + public enum Unit { + CELSIUS + } + + private final BigDecimal value; + private final Unit unit; + + /** + * Create a new temperature using the default unit of Celsius. + * + * @param value + * The value of the temperature. + */ + public Temperature(final BigDecimal value) { + this.value = value; + this.unit = Unit.CELSIUS; + } + + public BigDecimal getValue() { + return this.value; + } + + public Unit getUnit() { + return this.unit; + } + + @Override + public String toString() { + String out = this.value.toString(); + + switch (this.unit) { + case CELSIUS: + out += "\u00B0C"; + break; + } + + return out; + } + + @NonNullByDefault({}) + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final Temperature that = (Temperature) o; + return value.equals(that.value) && + unit == that.unit; + } + + @Override + public int hashCode() { + return Objects.hash(value, unit); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/URITypeBase.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/URITypeBase.java new file mode 100644 index 0000000000000..f41bc3b8d322d --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/URITypeBase.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.net.URI; +import java.net.URISyntaxException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +abstract class URITypeBase extends FromStringTypeBase { + public URITypeBase(final String stringValue) { + super(stringValue); + } + + protected URI transform(final String stringValue) { + try { + return new URI(stringValue); + } catch (final URISyntaxException ex) { + throw new IllegalArgumentException(ex); + } + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/UserId.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/UserId.java new file mode 100644 index 0000000000000..aac459b5eb459 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/UserId.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class UserId extends UuidTypeBase { + public UserId(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Username.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Username.java new file mode 100644 index 0000000000000..26ab106299e03 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/Username.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A username value type. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class Username extends StringTypeBase { + public Username(final String stringValue) { + super(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/UuidTypeBase.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/UuidTypeBase.java new file mode 100644 index 0000000000000..531236a1ee624 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/UuidTypeBase.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.util.UUID; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +abstract class UuidTypeBase extends FromStringTypeBase { + public UuidTypeBase(final String stringValue) { + super(stringValue); + } + + protected UUID transform(final String stringValue) { + return UUID.fromString(stringValue); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/ActionTypeGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/ActionTypeGsonAdapter.java new file mode 100644 index 0000000000000..f635c65a792c7 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/ActionTypeGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.ActionType; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class ActionTypeGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public ActionType read(final JsonReader in) throws IOException { + return new ActionType(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/AttributeNameGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/AttributeNameGsonAdapter.java new file mode 100644 index 0000000000000..759b9ef186955 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/AttributeNameGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.AttributeName; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class AttributeNameGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public AttributeName read(final JsonReader in) throws IOException { + return new AttributeName(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/FeatureTypeGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/FeatureTypeGsonAdapter.java new file mode 100644 index 0000000000000..ead1e027f95c3 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/FeatureTypeGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.FeatureType; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class FeatureTypeGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public FeatureType read(final JsonReader in) throws IOException { + return new FeatureType(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/HiveApiInstantGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/HiveApiInstantGsonAdapter.java new file mode 100644 index 0000000000000..63271dae86748 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/HiveApiInstantGsonAdapter.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hive.internal.client.dto.HiveApiInstant; + +import java.io.IOException; +import java.time.Instant; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveApiInstantGsonAdapter extends TypeAdapter { + @NonNullByDefault({}) + @Override + public void write(final JsonWriter out, final @Nullable HiveApiInstant hiveApiInstant) throws IOException { + if (hiveApiInstant != null) { + out.value(hiveApiInstant.asInstant().toEpochMilli()); + } else { + out.nullValue(); + } + } + + @NonNullByDefault({}) + @Override + public HiveApiInstant read(final JsonReader in) throws IOException { + return new HiveApiInstant(Instant.ofEpochMilli(in.nextLong())); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/NodeIdGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/NodeIdGsonAdapter.java new file mode 100644 index 0000000000000..266a4ec39017d --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/NodeIdGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.NodeId; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class NodeIdGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public NodeId read(final JsonReader in) throws IOException { + return new NodeId(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/NodeNameGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/NodeNameGsonAdapter.java new file mode 100644 index 0000000000000..a3bc6fe864c2d --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/NodeNameGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.NodeName; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class NodeNameGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public NodeName read(final JsonReader in) throws IOException { + return new NodeName(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/NodeTypeGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/NodeTypeGsonAdapter.java new file mode 100644 index 0000000000000..edca05261fdfd --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/NodeTypeGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.NodeType; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class NodeTypeGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public NodeType read(final JsonReader in) throws IOException { + return new NodeType(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/PasswordGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/PasswordGsonAdapter.java new file mode 100644 index 0000000000000..2b19790f95b2a --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/PasswordGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.Password; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class PasswordGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public Password read(final JsonReader in) throws IOException { + return new Password(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/ProductTypeGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/ProductTypeGsonAdapter.java new file mode 100644 index 0000000000000..b18fdc68fe9cf --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/ProductTypeGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.ProductType; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class ProductTypeGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public ProductType read(final JsonReader in) throws IOException { + return new ProductType(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/SessionIdGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/SessionIdGsonAdapter.java new file mode 100644 index 0000000000000..fabebed60b629 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/SessionIdGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.SessionId; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class SessionIdGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public SessionId read(final JsonReader in) throws IOException { + return new SessionId(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/SimpleGsonTypeAdapterBase.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/SimpleGsonTypeAdapterBase.java new file mode 100644 index 0000000000000..540847bb24d88 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/SimpleGsonTypeAdapterBase.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonWriter; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +abstract class SimpleGsonTypeAdapterBase extends TypeAdapter { + @NonNullByDefault({}) + @Override + public void write(final JsonWriter out, final @Nullable T value) throws IOException { + if (value != null) { + out.value(value.toString()); + } else { + out.nullValue(); + } + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/UserIdGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/UserIdGsonAdapter.java new file mode 100644 index 0000000000000..40b6aa9c79625 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/UserIdGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.UserId; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class UserIdGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public UserId read(final JsonReader in) throws IOException { + return new UserId(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/UsernameGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/UsernameGsonAdapter.java new file mode 100644 index 0000000000000..2008311b2ec41 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/UsernameGsonAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.stream.JsonReader; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.Username; + +import java.io.IOException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class UsernameGsonAdapter extends SimpleGsonTypeAdapterBase { + @NonNullByDefault({}) + @Override + public Username read(final JsonReader in) throws IOException { + return new Username(in.nextString()); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/ZonedDateTimeGsonAdapter.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/ZonedDateTimeGsonAdapter.java new file mode 100644 index 0000000000000..7b9e22e18ad68 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/adapter/ZonedDateTimeGsonAdapter.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +import java.io.IOException; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +/** + *2020-03-04T19:13:47.462+0000 + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class ZonedDateTimeGsonAdapter extends TypeAdapter { + private static final DateTimeFormatter HIVE_DATETIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + + @NonNullByDefault({}) + @Override + public void write(final JsonWriter out, final @Nullable ZonedDateTime zonedDateTime) throws IOException { + if (zonedDateTime != null) { + out.value(zonedDateTime.format(HIVE_DATETIME_FORMAT)); + } else { + out.nullValue(); + } + } + + @NonNullByDefault({}) + @Override + public ZonedDateTime read(final JsonReader in) throws IOException { + return ZonedDateTime.parse(in.nextString(), HIVE_DATETIME_FORMAT); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/ActionDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/ActionDto.java new file mode 100644 index 0000000000000..131f180774c14 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/ActionDto.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.ActionType; +import org.openhab.binding.hive.internal.client.AttributeName; +import org.openhab.binding.hive.internal.client.FeatureType; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class ActionDto { + public ActionType actionType; + public FeatureType featureType; + public AttributeName attribute; + public String value; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/BatteryDeviceV1FeatureDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/BatteryDeviceV1FeatureDto.java new file mode 100644 index 0000000000000..28d0d0b038127 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/BatteryDeviceV1FeatureDto.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.math.BigDecimal; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class BatteryDeviceV1FeatureDto extends FeatureDtoBase { + public FeatureAttributeDto batteryLevel; + public FeatureAttributeDto batteryState; + public FeatureAttributeDto batteryVoltage; + public FeatureAttributeDto notificationState; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/DeviceManagementV1FeatureDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/DeviceManagementV1FeatureDto.java new file mode 100644 index 0000000000000..d6d12d2636abf --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/DeviceManagementV1FeatureDto.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.ProductType; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class DeviceManagementV1FeatureDto extends FeatureDtoBase { + public FeatureAttributeDto productType; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/FeatureAttributeDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/FeatureAttributeDto.java new file mode 100644 index 0000000000000..0edb36af26575 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/FeatureAttributeDto.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class FeatureAttributeDto { + public T reportedValue; + public T targetValue; + public T displayValue; + + public HiveApiInstant reportReceivedTime; + public HiveApiInstant reportChangedTime; + public HiveApiInstant targetSetTime; + public HiveApiInstant targetExpiryTime; + + public String targetSetTXId; + public String propertyStatus; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/FeatureDtoBase.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/FeatureDtoBase.java new file mode 100644 index 0000000000000..0a8dcf2ab6662 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/FeatureDtoBase.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.FeatureType; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public abstract class FeatureDtoBase { + public FeatureAttributeDto featureType; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/FeaturesDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/FeaturesDto.java new file mode 100644 index 0000000000000..4bc17eb5105cf --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/FeaturesDto.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class FeaturesDto { + public BatteryDeviceV1FeatureDto battery_device_v1; + public DeviceManagementV1FeatureDto device_management_v1; + public HeatingThermostatV1FeatureDto heating_thermostat_v1; + public OnOffDeviceV1FeatureDto on_off_device_v1; + public TemperatureSensorV1FeatureDto temperature_sensor_v1; + public TransientModeV1FeatureDto transient_mode_v1; + public WaterHeaterV1FeatureDto water_heater_v1; + public ZigbeeDeviceV1FeatureDto zigbee_device_v1; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/HeatingThermostatV1FeatureDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/HeatingThermostatV1FeatureDto.java new file mode 100644 index 0000000000000..e5234091c7acb --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/HeatingThermostatV1FeatureDto.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.OperatingMode; +import org.openhab.binding.hive.internal.client.OverrideMode; + +import java.math.BigDecimal; +import java.util.List; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class HeatingThermostatV1FeatureDto extends FeatureDtoBase { + public FeatureAttributeDto operatingMode; + public FeatureAttributeDto operatingState; + public FeatureAttributeDto temporaryOperatingModeOverride; + public FeatureAttributeDto targetHeatTemperature; + public FeatureAttributeDto maxHeatTargetTemperature; + public FeatureAttributeDto minHeatTargetTemperature; + + public FeatureAttributeDto> previousConfiguration; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/HiveApiInstant.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/HiveApiInstant.java new file mode 100644 index 0000000000000..c55b985bd3cdf --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/HiveApiInstant.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.time.Instant; +import java.util.Objects; + +/** + * A class representing absolute times returned by the Hive API. + * + *

+ * N.B. This should only be used by DTOs. + *

+ * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveApiInstant { + private Instant instant; + + public HiveApiInstant(final Instant instant) { + Objects.requireNonNull(instant); + + this.instant = instant; + } + + public Instant asInstant() { + return this.instant; + } + + @NonNullByDefault({}) + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final HiveApiInstant that = (HiveApiInstant) o; + return instant.equals(that.instant); + } + + @NonNullByDefault({}) + @Override + public int hashCode() { + return Objects.hash(instant); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/NodeDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/NodeDto.java new file mode 100644 index 0000000000000..8e888caa8e37f --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/NodeDto.java @@ -0,0 +1,140 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.NodeId; +import org.openhab.binding.hive.internal.client.NodeName; +import org.openhab.binding.hive.internal.client.NodeType; +import org.openhab.binding.hive.internal.client.UserId; + +/** + * A model of a "Node" + * + * Based on the Hive API Swagger model. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class NodeDto { + /** + * address (string, optional): Internal node ID, read-only. + * The first part of node ID can be hub ID or node address. + * Hub ID conforms following pattern: ([0-9]{19}). + * Node address conforms following pattern: ::([a-f0-9]{1,4}):([a-f0-9]{1,4}):([a-f0-9]{1,4}):([a-f0-9]{1,4}). + * Admin access required. + */ + public String address; + + /* + * brokers (inline_model_26, optional): Brokers address map + * e.g.: {"greengrass": {"url": "mqtt://10.0.0.7:8883", "topic": "hub/deviceid/userid"}} + */ + + /** + * createdOn (integer, optional): Timestamp of when the node state was created. + * UTC Unix timestamp (in milliseconds) + */ + public HiveApiInstant createdOn; + + public FeaturesDto features; + + /** + * firstInstall (integer, optional): Timestamp of when the device was discovered. + * UTC Unix timestamp (in milliseconds) + */ + public HiveApiInstant firstInstall; + + /** + * homeId (string, optional): Home ID, read-only + */ + public String homeId; + + /** + * href (string, optional, read only): URL of the API call for retrieving this object + */ + public String href; + + /** + * id (string, optional): Object identifier + */ + public NodeId id; + + /** + * lastSeen (integer, optional): Timestamp of when the node was last seen. + * UTC Unix timestamp (in milliseconds) + */ + public HiveApiInstant lastSeen; + + /** + * lastUpgradeSucceeded (boolean, optional): Last upgrade succeeded + */ + public Boolean lastUpgradeSucceeded; + + /* + * links (inline_model_27, optional): URL Templates for links to other entities + * e.g.: "users.nodes": "https://api.example.com/nodes/{users.nodes}" + */ + + /** + * name (string, optional): Node name + */ + public NodeName name; + + /** + * nodeType (string, optional): Node type + */ + public NodeType nodeType; + + /** + * ownerId (string, optional): Original owner UUID + */ + public UserId ownerId; + + /** + * parentNodeId (string, optional): Parent node UUID + */ + public NodeId parentNodeId; + + /** + * protocol (string, optional): Node protocol, optional, read-only + * ['SYNTHETIC', 'ZIGBEE', 'PROXIED', 'MQTT', 'XMPP', 'VIRTUAL', 'any other provided by hub'] + */ + public String protocol; + + /* + * relationships (inline_model_28, optional): Node relationships + * e.g.: "boundNodes" : [{ "type" : "node", "id" : "1b3b3c30-740a-11e5-8a3b-f46d042e952c"}] , + */ + + /** + * upgradeAvailable (boolean, optional): Is upgrade available + */ + public Boolean upgradeAvailable; + + /** + * upgradeProgress (number, optional): Upgrade progress in percentages + */ + public Double upgradeProgress; + + /** + * upgradeStatus (string, optional): Upgrade status, read-only + * ['PENDING', 'DEFERRED', 'STARTING', 'IN_PROGRESS', 'COMPLETE', 'FAILED', 'UNSUPPORTED', 'INVALID'] + */ + public String upgradeStatus; + + /** + * userId (string, optional): User UUID + */ + public UserId userId; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/NodesDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/NodesDto.java new file mode 100644 index 0000000000000..ec4a3fbbe6519 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/NodesDto.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.util.List; + +/** + * A model of a "NodeRequestEntity"/"NodeResponseEntity" + * + * Based on the Hive API Swagger model. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class NodesDto { + /* + * linked (object, optional): Linked entities grouped by entity type. Used when side-loading entities + */ + + /* + * links (inline_model_34, optional): URL Templates for links to other entities e.g.: "users.nodes": "https://api.example.com/nodes/{users.nodes}" , + */ + + /* + * meta (object, optional): Meta information about this entity + */ + + /** + * sessions (Array[Session], optional): List of sessions + */ + public List nodes; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/OnOffDeviceV1FeatureDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/OnOffDeviceV1FeatureDto.java new file mode 100644 index 0000000000000..cfacb410784d3 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/OnOffDeviceV1FeatureDto.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.OnOffMode; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class OnOffDeviceV1FeatureDto extends FeatureDtoBase { + public FeatureAttributeDto mode; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/SessionDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/SessionDto.java new file mode 100644 index 0000000000000..f80074748293c --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/SessionDto.java @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.Password; +import org.openhab.binding.hive.internal.client.SessionId; +import org.openhab.binding.hive.internal.client.UserId; +import org.openhab.binding.hive.internal.client.Username; + +/** + * A model of a "Session" + * + * Based on the Hive API Swagger model. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class SessionDto { + /** + * extCustomerLevel (integer, optional): The user's account level in a third party's database (default value 1) + */ + public Integer extCustomerLevel; + + /** + * href (string, optional, read only): URL of the API call for retrieving this object + */ + public String href; + + /** + * id (string, optional) + */ + public SessionId id; + + /** + * latestSupportedApiVersion (string, optional): The API version which the user's account and data are compatible with + */ + public String latestSupportedApiVersion; + + /* + * links (inline_model_33, optional): URL Templates for links to other entities e.g.: "users.nodes": "https://api.example.com/nodes/{users.nodes}" , + */ + + /** + * password (string, optional): Password + */ + public Password password; + + /** + * sessionDuration (integer, optional): Session duration in minutes + */ + public Integer sessionDuration; + + /** + * sessionId (string, optional): UUID of this session + */ + public SessionId sessionId; + + /** + * userId (string, optional): User UUID + */ + public UserId userId; + + /** + * username (string, optional): Username + */ + public Username username; + + /** + * uuid (string, optional): User UUID + */ + public UserId uuid; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/SessionsDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/SessionsDto.java new file mode 100644 index 0000000000000..c547379cce658 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/SessionsDto.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.util.List; + +/** + * A model of a "SessionRequestEntity"/"SessionResponseEntity" + * + * Based on the Hive API Swagger model. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class SessionsDto { + /* + * linked (object, optional): Linked entities grouped by entity type. Used when side-loading entities + */ + + /* + * links (inline_model_34, optional): URL Templates for links to other entities e.g.: "users.nodes": "https://api.example.com/nodes/{users.nodes}" , + */ + + /* + * meta (object, optional): Meta information about this entity + */ + + /** + * sessions (Array[Session], optional): List of sessions + */ + public List sessions; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/TemperatureSensorV1FeatureDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/TemperatureSensorV1FeatureDto.java new file mode 100644 index 0000000000000..f634bdc6950ac --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/TemperatureSensorV1FeatureDto.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.math.BigDecimal; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class TemperatureSensorV1FeatureDto extends FeatureDtoBase { + public FeatureAttributeDto temperature; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/TransientModeV1FeatureDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/TransientModeV1FeatureDto.java new file mode 100644 index 0000000000000..7a33522394e9e --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/TransientModeV1FeatureDto.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import java.time.ZonedDateTime; +import java.util.List; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class TransientModeV1FeatureDto extends FeatureDtoBase { + public FeatureAttributeDto> actions; + public FeatureAttributeDto duration; + public FeatureAttributeDto isEnabled; + public FeatureAttributeDto> previousConfiguration; + public FeatureAttributeDto startDatetime; + public FeatureAttributeDto endDatetime; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/WaterHeaterV1FeatureDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/WaterHeaterV1FeatureDto.java new file mode 100644 index 0000000000000..85e438d952b23 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/WaterHeaterV1FeatureDto.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.OperatingMode; +import org.openhab.binding.hive.internal.client.OverrideMode; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class WaterHeaterV1FeatureDto extends FeatureDtoBase { + public FeatureAttributeDto operatingMode; + public FeatureAttributeDto isOn; + public FeatureAttributeDto temporaryOperatingModeOverride; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/ZigbeeDeviceV1FeatureDto.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/ZigbeeDeviceV1FeatureDto.java new file mode 100644 index 0000000000000..bdd2ecc9b3066 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/dto/ZigbeeDeviceV1FeatureDto.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault({}) +public final class ZigbeeDeviceV1FeatureDto extends FeatureDtoBase { + public FeatureAttributeDto averageLQI; + public FeatureAttributeDto lastKnownLQI; + public FeatureAttributeDto averageRSSI; + public FeatureAttributeDto lastKnownRSSI; +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiAuthenticationException.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiAuthenticationException.java new file mode 100644 index 0000000000000..e2f623e63507e --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiAuthenticationException.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.exception; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Thrown to indicate something has gone wrong while authenticating with the + * Hive API. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveApiAuthenticationException extends HiveApiException { + public HiveApiAuthenticationException() { + super(); + } + + public HiveApiAuthenticationException(final String message) { + super(message); + } + + public HiveApiAuthenticationException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiException.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiException.java new file mode 100644 index 0000000000000..a52fc86a341aa --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiException.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.exception; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Thrown to indicate something has gone wrong with a call to the Hive API. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public abstract class HiveApiException extends RuntimeException { + public static final long serialVersionUID = 1L; + + public HiveApiException() { + super(); + } + + public HiveApiException(final String message) { + super(message); + } + + public HiveApiException(final Throwable cause) { + super(cause); + } + + public HiveApiException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiNotAuthorisedException.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiNotAuthorisedException.java new file mode 100644 index 0000000000000..923998863327d --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiNotAuthorisedException.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.exception; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Thrown to indicate a call to the Hive API has failed because the client is not authorised. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveApiNotAuthorisedException extends HiveApiException { + public HiveApiNotAuthorisedException() { + super(); + } + + public HiveApiNotAuthorisedException(final String message) { + super(message); + } + + public HiveApiNotAuthorisedException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiUnknownException.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiUnknownException.java new file mode 100644 index 0000000000000..1c4768c04797e --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveApiUnknownException.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.exception; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Thrown to indicate something of an unknown nature has gone wrong while + * making a call to the Hive API (and it is the client's fault). + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveApiUnknownException extends HiveApiException { + public static final long serialVersionUID = 1L; + + public HiveApiUnknownException() { + super(); + } + + public HiveApiUnknownException(final String message) { + super(message); + } + + public HiveApiUnknownException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientException.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientException.java new file mode 100644 index 0000000000000..b603e48b296f2 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientException.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.exception; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public abstract class HiveClientException extends RuntimeException { + public HiveClientException() { + super(); + } + + public HiveClientException(final String message) { + super(message); + } + + public HiveClientException(final Throwable cause) { + super(cause); + } + + public HiveClientException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientRequestException.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientRequestException.java new file mode 100644 index 0000000000000..a8854642a2340 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientRequestException.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.exception; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Thrown to indicate a HTTP request to the Hive API has failed before it + * could be completed. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveClientRequestException extends HiveClientException { + public HiveClientRequestException() { + super(); + } + + public HiveClientRequestException(final String message) { + super(message); + } + + public HiveClientRequestException(final Throwable cause) { + super(cause); + } + + public HiveClientRequestException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientResponseException.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientResponseException.java new file mode 100644 index 0000000000000..eb35ac2027435 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientResponseException.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.exception; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Thrown to indicate that the {@link org.openhab.binding.hive.internal.client.HiveClient} + * got a "success" response from the Hive API but either does not understand + * the response or thinks it is malformed. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveClientResponseException extends HiveClientException { + public HiveClientResponseException() { + super(); + } + + public HiveClientResponseException(final String message) { + super(message); + } + + public HiveClientResponseException(final Throwable cause) { + super(cause); + } + + public HiveClientResponseException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientUnknownException.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientUnknownException.java new file mode 100644 index 0000000000000..4024b17c37746 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/exception/HiveClientUnknownException.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.exception; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Thrown to indicate that the {@link org.openhab.binding.hive.internal.client.HiveClient} + * got a "success" response from the Hive API but either does not understand + * the response or thinks it is malformed. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveClientUnknownException extends HiveClientException { + public HiveClientUnknownException() { + super(); + } + + public HiveClientUnknownException(final String message) { + super(message); + } + + public HiveClientUnknownException(final Throwable cause) { + super(cause); + } + + public HiveClientUnknownException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/BatteryDeviceFeature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/BatteryDeviceFeature.java new file mode 100644 index 0000000000000..28f91f4e044b7 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/BatteryDeviceFeature.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.feature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.BatteryLevel; +import org.openhab.binding.hive.internal.client.FeatureAttribute; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class BatteryDeviceFeature implements Feature { + private final FeatureAttribute batteryLevel; + private final FeatureAttribute batteryState; + + public BatteryDeviceFeature( + final FeatureAttribute batteryLevel, + final FeatureAttribute batteryState + ) { + Objects.requireNonNull(batteryLevel); + Objects.requireNonNull(batteryState); + + this.batteryLevel = batteryLevel; + this.batteryState = batteryState; + } + + public FeatureAttribute getBatteryLevelAttribute() { + return this.batteryLevel; + } + + public BatteryLevel getBatteryLevel() { + return this.batteryLevel.getDisplayValue(); + } + + public FeatureAttribute getBatteryStateAttribute() { + return this.batteryState; + } + + public String getBatteryState() { + return this.batteryState.getDisplayValue(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/Feature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/Feature.java new file mode 100644 index 0000000000000..967f10531d682 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/Feature.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.feature; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface Feature {} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/HeatingThermostatFeature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/HeatingThermostatFeature.java new file mode 100644 index 0000000000000..55337e3c3c966 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/HeatingThermostatFeature.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.feature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.*; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HeatingThermostatFeature implements Feature { + private final SettableFeatureAttribute operatingMode; + private final FeatureAttribute operatingState; + private final SettableFeatureAttribute targetHeatTemperature; + private final SettableFeatureAttribute temporaryOperatingModeOverride; + + public HeatingThermostatFeature( + final SettableFeatureAttribute operatingMode, + final FeatureAttribute operatingState, + final SettableFeatureAttribute targetHeatTemperature, + final SettableFeatureAttribute temporaryOperatingModeOverride + ) { + Objects.requireNonNull(operatingMode); + Objects.requireNonNull(operatingState); + Objects.requireNonNull(targetHeatTemperature); + Objects.requireNonNull(temporaryOperatingModeOverride); + + this.operatingMode = operatingMode; + this.operatingState = operatingState; + this.targetHeatTemperature = targetHeatTemperature; + this.temporaryOperatingModeOverride = temporaryOperatingModeOverride; + } + + public SettableFeatureAttribute getOperatingModeAttribute() { + return this.operatingMode; + } + + public OperatingMode getOperatingMode() { + return this.operatingMode.getDisplayValue(); + } + + public void setOperatingMode(final OperatingMode operatingMode) { + Objects.requireNonNull(operatingMode); + + this.operatingMode.setTargetValue(operatingMode); + } + + public FeatureAttribute getOperatingStateAttribute() { + return this.operatingState; + } + + public String getOperatingState() { + return this.operatingState.getDisplayValue(); + } + + public SettableFeatureAttribute getTargetHeatTemperatureAttribute() { + return this.targetHeatTemperature; + } + + public Temperature getTargetHeatTemperature() { + return this.targetHeatTemperature.getDisplayValue(); + } + + public void setTargetHeatTemperature(final Temperature targetHeatTemperature) { + Objects.requireNonNull(targetHeatTemperature); + + this.targetHeatTemperature.setTargetValue(targetHeatTemperature); + } + + public SettableFeatureAttribute getTemporaryOperatingModeOverrideAttribute() { + return this.temporaryOperatingModeOverride; + } + + public OverrideMode getTemporaryOperatingModeOverride() { + return this.temporaryOperatingModeOverride.getDisplayValue(); + } + + public void setTemporaryOperatingModeOverride(final OverrideMode overrideMode) { + Objects.requireNonNull(overrideMode); + + this.temporaryOperatingModeOverride.setTargetValue(overrideMode); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/HeatingTransientModeFeature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/HeatingTransientModeFeature.java new file mode 100644 index 0000000000000..89a555ad62232 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/HeatingTransientModeFeature.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.feature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.FeatureAttribute; +import org.openhab.binding.hive.internal.client.SettableFeatureAttribute; +import org.openhab.binding.hive.internal.client.Temperature; + +import java.time.Duration; +import java.time.ZonedDateTime; +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HeatingTransientModeFeature extends TransientModeFeature { + private final SettableFeatureAttribute boostTargetTemperature; + + public HeatingTransientModeFeature( + final SettableFeatureAttribute boostTargetTemperature, + final SettableFeatureAttribute duration, + final FeatureAttribute isEnabled, + final FeatureAttribute startDatetime, + final FeatureAttribute endDatetime + ) { + super( + duration, + isEnabled, + startDatetime, + endDatetime + ); + + Objects.requireNonNull(boostTargetTemperature); + + this.boostTargetTemperature = boostTargetTemperature; + } + + public final SettableFeatureAttribute getBoostTargetTemperatureAttribute() { + return this.boostTargetTemperature; + } + + public final Temperature getBoostTargetTemperature() { + return this.boostTargetTemperature.getDisplayValue(); + } + + public final void setBoostTargetTemperature(final Temperature boostTargetTemperature) { + Objects.requireNonNull(boostTargetTemperature); + + this.boostTargetTemperature.setTargetValue(boostTargetTemperature); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/OnOffDeviceFeature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/OnOffDeviceFeature.java new file mode 100644 index 0000000000000..b9702bb0030b5 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/OnOffDeviceFeature.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.feature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.OnOffMode; +import org.openhab.binding.hive.internal.client.SettableFeatureAttribute; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class OnOffDeviceFeature implements Feature { + private final SettableFeatureAttribute mode; + + public OnOffDeviceFeature( + final SettableFeatureAttribute mode + ) { + Objects.requireNonNull(mode); + + this.mode = mode; + } + + public SettableFeatureAttribute getModeAttribute() { + return this.mode; + } + + public OnOffMode getMode() { + return this.mode.getDisplayValue(); + } + + public void setMode(final OnOffMode mode) { + Objects.requireNonNull(mode); + + this.mode.setTargetValue(mode); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/TemperatureSensorFeature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/TemperatureSensorFeature.java new file mode 100644 index 0000000000000..e25404e4d0e89 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/TemperatureSensorFeature.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.feature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.FeatureAttribute; +import org.openhab.binding.hive.internal.client.Temperature; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class TemperatureSensorFeature implements Feature { + private final FeatureAttribute temperature; + + public TemperatureSensorFeature( + final FeatureAttribute temperature + ) { + Objects.requireNonNull(temperature); + + this.temperature = temperature; + } + + public FeatureAttribute getTemperatureAttribute() { + return this.temperature; + } + + public Temperature getTemperature() { + return this.temperature.getDisplayValue(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/TransientModeFeature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/TransientModeFeature.java new file mode 100644 index 0000000000000..72bdc0afbac12 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/TransientModeFeature.java @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.feature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.FeatureAttribute; +import org.openhab.binding.hive.internal.client.SettableFeatureAttribute; + +import java.time.Duration; +import java.time.ZonedDateTime; +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class TransientModeFeature implements Feature { + private final SettableFeatureAttribute duration; + private final FeatureAttribute isEnabled; + private final FeatureAttribute startDatetime; + private final FeatureAttribute endDatetime; + + public TransientModeFeature( + final SettableFeatureAttribute duration, + final FeatureAttribute isEnabled, + final FeatureAttribute startDatetime, + final FeatureAttribute endDatetime + ) { + Objects.requireNonNull(duration); + Objects.requireNonNull(isEnabled); + Objects.requireNonNull(startDatetime); + Objects.requireNonNull(endDatetime); + + this.duration = duration; + this.isEnabled = isEnabled; + this.startDatetime = startDatetime; + this.endDatetime = endDatetime; + } + + public final SettableFeatureAttribute getDurationAttribute() { + return this.duration; + } + + public final Duration getDuration() { + return this.duration.getDisplayValue(); + } + + public final void setDuration(final Duration duration) { + Objects.requireNonNull(duration); + + this.duration.setTargetValue(duration); + } + + public final FeatureAttribute getIsEnabledAttribute() { + return this.isEnabled; + } + + public final boolean getIsEnabled() { + return this.isEnabled.getDisplayValue(); + } + + public final FeatureAttribute getStartDatetimeAttribute() { + return this.startDatetime; + } + + public final ZonedDateTime getStartDatetime() { + return this.startDatetime.getDisplayValue(); + } + + public final FeatureAttribute getEndDatetimeAttribute() { + return this.endDatetime; + } + + public final ZonedDateTime getEndDatetime() { + return this.endDatetime.getDisplayValue(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/WaterHeaterFeature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/WaterHeaterFeature.java new file mode 100644 index 0000000000000..dd331eb389595 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/WaterHeaterFeature.java @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.feature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.FeatureAttribute; +import org.openhab.binding.hive.internal.client.OperatingMode; +import org.openhab.binding.hive.internal.client.OverrideMode; +import org.openhab.binding.hive.internal.client.SettableFeatureAttribute; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class WaterHeaterFeature implements Feature { + private final SettableFeatureAttribute operatingMode; + private final FeatureAttribute isOn; + private final SettableFeatureAttribute temporaryOperatingModeOverride; + + public WaterHeaterFeature( + final SettableFeatureAttribute operatingMode, + final FeatureAttribute isOn, + final SettableFeatureAttribute temporaryOperatingModeOverride + ) { + Objects.requireNonNull(operatingMode); + Objects.requireNonNull(isOn); + Objects.requireNonNull(temporaryOperatingModeOverride); + + this.operatingMode = operatingMode; + this.isOn = isOn; + this.temporaryOperatingModeOverride = temporaryOperatingModeOverride; + } + + public SettableFeatureAttribute getOperatingModeAttribute() { + return this.operatingMode; + } + + public OperatingMode getOperatingMode() { + return this.operatingMode.getDisplayValue(); + } + + public void setOperatingMode(final OperatingMode operatingMode) { + Objects.requireNonNull(operatingMode); + + this.operatingMode.setTargetValue(operatingMode); + } + + public FeatureAttribute getIsOnAttribute() { + return this.isOn; + } + + public boolean isOn() { + return this.isOn.getDisplayValue(); + } + + public SettableFeatureAttribute getTemporaryOperatingModeOverrideAttribute() { + return this.temporaryOperatingModeOverride; + } + + public OverrideMode getTemporaryOperatingModeOverride() { + return this.temporaryOperatingModeOverride.getDisplayValue(); + } + + public void setTemporaryOperatingModeOverride(final OverrideMode overrideMode) { + Objects.requireNonNull(overrideMode); + + this.temporaryOperatingModeOverride.setTargetValue(overrideMode); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/ZigbeeDeviceFeature.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/ZigbeeDeviceFeature.java new file mode 100644 index 0000000000000..7e9d7ec1cc979 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/feature/ZigbeeDeviceFeature.java @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.feature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.hive.internal.client.FeatureAttribute; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class ZigbeeDeviceFeature implements Feature { + private final FeatureAttribute averageLQI; + private final FeatureAttribute lastKnownLQI; + private final FeatureAttribute averageRSSI; + private final FeatureAttribute lastKnownRSSI; + + public ZigbeeDeviceFeature( + final FeatureAttribute averageLQI, + final FeatureAttribute lastKnownLQI, + final FeatureAttribute averageRSSI, + final FeatureAttribute lastKnownRSSI + ) { + Objects.requireNonNull(averageLQI); + Objects.requireNonNull(lastKnownLQI); + Objects.requireNonNull(averageRSSI); + Objects.requireNonNull(lastKnownRSSI); + + this.averageLQI = averageLQI; + this.lastKnownLQI = lastKnownLQI; + this.averageRSSI = averageRSSI; + this.lastKnownRSSI = lastKnownRSSI; + } + + public FeatureAttribute getAverageLQIAttribute() { + return this.averageLQI; + } + + public int getAverageLQI() { + return this.averageLQI.getDisplayValue(); + } + + public FeatureAttribute getLastKnownLQIAttribute() { + return this.lastKnownLQI; + } + + public int getLastKnownLQI() { + return this.lastKnownLQI.getDisplayValue(); + } + + public FeatureAttribute getAverageRSSIAttribute() { + return this.averageRSSI; + } + + public int getAverageRSSI() { + return this.averageRSSI.getDisplayValue(); + } + + public FeatureAttribute getLastKnownRSSIAttribute() { + return this.lastKnownRSSI; + } + + public int getLastKnownRSSI() { + return this.lastKnownRSSI.getDisplayValue(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/DefaultNodeRepository.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/DefaultNodeRepository.java new file mode 100644 index 0000000000000..e56aaed5eb66e --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/DefaultNodeRepository.java @@ -0,0 +1,361 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.repository; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hive.internal.client.*; +import org.openhab.binding.hive.internal.client.dto.*; +import org.openhab.binding.hive.internal.client.exception.HiveApiNotAuthorisedException; +import org.openhab.binding.hive.internal.client.exception.HiveApiUnknownException; +import org.openhab.binding.hive.internal.client.exception.HiveClientResponseException; +import org.openhab.binding.hive.internal.client.feature.*; + +import java.math.BigDecimal; +import java.net.URI; +import java.time.Duration; +import java.util.*; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class DefaultNodeRepository implements NodeRepository { + private final HiveApiRequestFactory requestFactory; + + public DefaultNodeRepository( + final HiveApiRequestFactory requestFactory + ) { + Objects.requireNonNull(requestFactory); + + this.requestFactory = requestFactory; + } + + private URI getEndpointPathForNode(final NodeId nodeId) { + return HiveApiConstants.ENDPOINT_NODE.resolve(nodeId.toString()); + } + + private BatteryDeviceFeature getBatteryDeviceFeature( + final BatteryDeviceV1FeatureDto batteryDeviceV1FeatureDto + ) { + return new BatteryDeviceFeature( + FeatureAttributeFactory.getReadOnlyFromDtoWithAdapter( + BatteryLevel::new, + batteryDeviceV1FeatureDto.batteryLevel + ), + FeatureAttributeFactory.getReadOnlyFromDto(batteryDeviceV1FeatureDto.batteryState) + ); + } + + private OnOffDeviceFeature getOnOffDeviceFeature( + final OnOffDeviceV1FeatureDto onOffDeviceV1FeatureDto + ) { + return new OnOffDeviceFeature( + FeatureAttributeFactory.getSettableFromDto(onOffDeviceV1FeatureDto.mode) + ); + } + + private HeatingThermostatFeature getHeatingThermostatFeature( + final HeatingThermostatV1FeatureDto heatingThermostatV1FeatureDto + ) { + return new HeatingThermostatFeature( + FeatureAttributeFactory.getSettableFromDto(heatingThermostatV1FeatureDto.operatingMode), + FeatureAttributeFactory.getReadOnlyFromDto(heatingThermostatV1FeatureDto.operatingState), + FeatureAttributeFactory.getSettableFromDtoWithAdapter( + Temperature::new, + heatingThermostatV1FeatureDto.targetHeatTemperature + ), + FeatureAttributeFactory.getSettableFromDto(heatingThermostatV1FeatureDto.temporaryOperatingModeOverride) + ); + } + + private TemperatureSensorFeature getTemperatureSensorFeature( + final TemperatureSensorV1FeatureDto temperatureSensorV1FeatureDto + ) { + return new TemperatureSensorFeature( + FeatureAttributeFactory.getReadOnlyFromDtoWithAdapter( + Temperature::new, + temperatureSensorV1FeatureDto.temperature + ) + ); + } + + private TransientModeFeature getTransientModeFeature( + final TransientModeV1FeatureDto transientModeV1FeatureDto + ) { + return new TransientModeFeature( + FeatureAttributeFactory.getSettableFromDtoWithAdapter( + Duration::ofSeconds, + transientModeV1FeatureDto.duration + ), + FeatureAttributeFactory.getReadOnlyFromDto(transientModeV1FeatureDto.isEnabled), + FeatureAttributeFactory.getReadOnlyFromDto(transientModeV1FeatureDto.startDatetime), + FeatureAttributeFactory.getReadOnlyFromDto(transientModeV1FeatureDto.endDatetime) + ); + } + + private HeatingTransientModeFeature getHeatingTransientModeFeature( + final TransientModeV1FeatureDto transientModeV1FeatureDto + ) { + // FIXME: Check the DTO is valid before blindly using it. + final Temperature targetHeatTemperature = new Temperature(new BigDecimal(transientModeV1FeatureDto.actions.reportedValue.get(0).value)); + + return new HeatingTransientModeFeature( + FeatureAttributeFactory.getSettableFromDtoWithAdapter( + (val) -> targetHeatTemperature, + transientModeV1FeatureDto.actions + ), + FeatureAttributeFactory.getSettableFromDtoWithAdapter( + Duration::ofSeconds, + transientModeV1FeatureDto.duration + ), + FeatureAttributeFactory.getReadOnlyFromDto(transientModeV1FeatureDto.isEnabled), + FeatureAttributeFactory.getReadOnlyFromDto(transientModeV1FeatureDto.startDatetime), + FeatureAttributeFactory.getReadOnlyFromDto(transientModeV1FeatureDto.endDatetime) + ); + } + + private WaterHeaterFeature getWaterHeaterFeature( + final WaterHeaterV1FeatureDto waterHeaterV1FeatureDto + ) { + return new WaterHeaterFeature( + FeatureAttributeFactory.getSettableFromDto(waterHeaterV1FeatureDto.operatingMode), + FeatureAttributeFactory.getReadOnlyFromDto(waterHeaterV1FeatureDto.isOn), + FeatureAttributeFactory.getSettableFromDto(waterHeaterV1FeatureDto.temporaryOperatingModeOverride) + ); + } + + private ZigbeeDeviceFeature getZigbeeDeviceFeature( + final ZigbeeDeviceV1FeatureDto zigbeeDeviceV1FeatureDto + ) { + return new ZigbeeDeviceFeature( + FeatureAttributeFactory.getReadOnlyFromDto(zigbeeDeviceV1FeatureDto.averageLQI), + FeatureAttributeFactory.getReadOnlyFromDto(zigbeeDeviceV1FeatureDto.lastKnownLQI), + FeatureAttributeFactory.getReadOnlyFromDto(zigbeeDeviceV1FeatureDto.averageRSSI), + FeatureAttributeFactory.getReadOnlyFromDto(zigbeeDeviceV1FeatureDto.lastKnownRSSI) + ); + } + + private Set parseNodesDto( + final NodesDto nodesDto + ) { + final Set nodes = new HashSet<>(); + // For each node + for (NodeDto nodeDto : nodesDto.nodes) { + final Protocol protocol; + if (nodeDto.protocol != null) { + protocol = new Protocol(nodeDto.protocol); + } else { + protocol = Protocol.NONE; + } + + final Map, Feature> features = new HashMap<>(); + + if (nodeDto.features.battery_device_v1 != null) { + features.put(BatteryDeviceFeature.class, getBatteryDeviceFeature(nodeDto.features.battery_device_v1)); + } + if (nodeDto.features.heating_thermostat_v1 != null) { + features.put(HeatingThermostatFeature.class, getHeatingThermostatFeature(nodeDto.features.heating_thermostat_v1)); + } + if (nodeDto.features.on_off_device_v1 != null) { + features.put(OnOffDeviceFeature.class, getOnOffDeviceFeature(nodeDto.features.on_off_device_v1)); + } + if (nodeDto.features.temperature_sensor_v1 != null) { + features.put(TemperatureSensorFeature.class, getTemperatureSensorFeature(nodeDto.features.temperature_sensor_v1)); + } + if (nodeDto.features.transient_mode_v1 != null) { + if (nodeDto.features.heating_thermostat_v1 != null) { + features.put(HeatingTransientModeFeature.class, getHeatingTransientModeFeature(nodeDto.features.transient_mode_v1)); + } else { + features.put(TransientModeFeature.class, getTransientModeFeature(nodeDto.features.transient_mode_v1)); + } + } + if (nodeDto.features.water_heater_v1 != null) { + features.put(WaterHeaterFeature.class, getWaterHeaterFeature(nodeDto.features.water_heater_v1)); + } + if (nodeDto.features.zigbee_device_v1 != null) { + features.put(ZigbeeDeviceFeature.class, getZigbeeDeviceFeature(nodeDto.features.zigbee_device_v1)); + } + + nodes.add(new DefaultNode( + nodeDto.id, + nodeDto.name, + nodeDto.nodeType, + nodeDto.features.device_management_v1.productType.reportedValue, + protocol, + nodeDto.parentNodeId, + features + )); + } + + return Collections.unmodifiableSet(nodes); + } + + @Override + public Set getAllNodes() { + /* Send our get nodes request to the Hive API. */ + final HiveApiResponse response = this.requestFactory.newRequest(HiveApiConstants.ENDPOINT_NODES) + .accept(MediaType.API_V6_5_0_JSON) + .get(); + + if (response.getStatusCode() == 401) { + throw new HiveApiNotAuthorisedException(); + } else if (response.getStatusCode() != 200) { + throw new HiveApiUnknownException("Getting nodes failed for an unknown reason"); + } + + final NodesDto nodesDto = response.getContent(NodesDto.class); + + return parseNodesDto(nodesDto); + } + + @Override + public @Nullable Node getNode(final NodeId nodeId) { + /* Send our get node request to the Hive API. */ + final HiveApiResponse response = this.requestFactory.newRequest(getEndpointPathForNode(nodeId)) + .accept(MediaType.API_V6_5_0_JSON) + .get(); + + if (response.getStatusCode() == 401) { + throw new HiveApiNotAuthorisedException(); + } else if (response.getStatusCode() != 200) { + throw new HiveApiUnknownException("Getting nodes failed for an unknown reason"); + } + + final NodesDto nodesDto = response.getContent(NodesDto.class); + final Set nodes = parseNodesDto(nodesDto); + + if (nodes.isEmpty()) { + // There is no node with that ID + return null; + } else if (nodes.size() == 1) { + return nodes.iterator().next(); + } else { + // Something has gone wrong. + throw new HiveClientResponseException("Got multiple nodes when requesting node by ID!"); + } + } + + @Override + public @Nullable Node updateNode(final Node node) { + /* Prepare DTO to send Hive API */ + final NodeDto nodeDto = new NodeDto(); + nodeDto.features = new FeaturesDto(); + + for (final Feature feature : node.getFeatures()) { + final Class featureClass = feature.getClass(); + + if (featureClass.equals(OnOffDeviceFeature.class)) { + final OnOffDeviceFeature onOffDeviceFeature = (OnOffDeviceFeature) feature; + + if (onOffDeviceFeature.getModeAttribute().getTargetValue() != null) { + nodeDto.features.on_off_device_v1 = new OnOffDeviceV1FeatureDto(); + + nodeDto.features.on_off_device_v1.mode = new FeatureAttributeDto<>(); + nodeDto.features.on_off_device_v1.mode.targetValue = onOffDeviceFeature.getModeAttribute().getTargetValue(); + } + } else if (featureClass.equals(HeatingThermostatFeature.class)) { + final HeatingThermostatFeature heatingThermostatFeature = (HeatingThermostatFeature) feature; + + if (heatingThermostatFeature.getOperatingModeAttribute().getTargetValue() != null + || heatingThermostatFeature.getTargetHeatTemperatureAttribute().getTargetValue() != null + || heatingThermostatFeature.getTemporaryOperatingModeOverrideAttribute().getTargetValue() != null + ) { + nodeDto.features.heating_thermostat_v1 = new HeatingThermostatV1FeatureDto(); + + if (heatingThermostatFeature.getOperatingModeAttribute().getTargetValue() != null) { + nodeDto.features.heating_thermostat_v1.operatingMode = new FeatureAttributeDto<>(); + nodeDto.features.heating_thermostat_v1.operatingMode.targetValue = heatingThermostatFeature.getOperatingModeAttribute().getTargetValue(); + } + + if (heatingThermostatFeature.getTargetHeatTemperatureAttribute().getTargetValue() != null) { + // FIXME: Check temperature units. + nodeDto.features.heating_thermostat_v1.targetHeatTemperature = new FeatureAttributeDto<>(); + nodeDto.features.heating_thermostat_v1.targetHeatTemperature.targetValue = heatingThermostatFeature.getTargetHeatTemperatureAttribute().getTargetValue().getValue(); + } + + if (heatingThermostatFeature.getTemporaryOperatingModeOverrideAttribute().getTargetValue() != null) { + nodeDto.features.heating_thermostat_v1.temporaryOperatingModeOverride = new FeatureAttributeDto<>(); + nodeDto.features.heating_thermostat_v1.temporaryOperatingModeOverride.targetValue = heatingThermostatFeature.getTemporaryOperatingModeOverrideAttribute().getTargetValue(); + } + } + } else if (featureClass.equals(TransientModeFeature.class) || featureClass.equals(HeatingTransientModeFeature.class)) { + final TransientModeFeature transientModeFeature = (TransientModeFeature) feature; + + if (transientModeFeature.getDurationAttribute().getTargetValue() != null) { + nodeDto.features.transient_mode_v1 = new TransientModeV1FeatureDto(); + + nodeDto.features.transient_mode_v1.duration = new FeatureAttributeDto<>(); + nodeDto.features.transient_mode_v1.duration.targetValue = Math.max(1, transientModeFeature.getDurationAttribute().getTargetValue().getSeconds()); + } + + if (featureClass.equals(HeatingTransientModeFeature.class)) { + final HeatingTransientModeFeature heatingTransientModeFeature = (HeatingTransientModeFeature) feature; + + if (heatingTransientModeFeature.getBoostTargetTemperatureAttribute().getTargetValue() != null) { + if (nodeDto.features.transient_mode_v1 == null) { + nodeDto.features.transient_mode_v1 = new TransientModeV1FeatureDto(); + } + + final ActionDto actionDto = new ActionDto(); + actionDto.actionType = ActionType.GENERIC; + actionDto.featureType = FeatureType.HEATING_THERMOSTAT_V1; + actionDto.attribute = AttributeName.ATTRIBUTE_NAME_TARGET_HEAT_TEMPERATURE; + actionDto.value = heatingTransientModeFeature.getBoostTargetTemperatureAttribute().getTargetValue().getValue().toString(); + + nodeDto.features.transient_mode_v1.actions = new FeatureAttributeDto<>(); + nodeDto.features.transient_mode_v1.actions.targetValue = Collections.singletonList(actionDto); + } + } + } else if (featureClass.equals(WaterHeaterFeature.class)) { + final WaterHeaterFeature waterHeaterFeature = (WaterHeaterFeature) feature; + + if (waterHeaterFeature.getOperatingModeAttribute().getTargetValue() != null) { + nodeDto.features.water_heater_v1 = new WaterHeaterV1FeatureDto(); + + nodeDto.features.water_heater_v1.operatingMode.targetValue = waterHeaterFeature.getOperatingModeAttribute().getTargetValue(); + } + + if (waterHeaterFeature.getTemporaryOperatingModeOverrideAttribute().getTargetValue() != null) { + nodeDto.features.water_heater_v1.temporaryOperatingModeOverride = new FeatureAttributeDto<>(); + nodeDto.features.water_heater_v1.temporaryOperatingModeOverride.targetValue = waterHeaterFeature.getTemporaryOperatingModeOverrideAttribute().getTargetValue(); + } + } + } + + final NodesDto nodesDto = new NodesDto(); + nodesDto.nodes = Collections.singletonList(nodeDto); + + final HiveApiResponse response = this.requestFactory.newRequest(getEndpointPathForNode(node.getId())) + .accept(MediaType.API_V6_5_0_JSON) + .put(nodesDto); + + if (response.getStatusCode() == 401) { + throw new HiveApiNotAuthorisedException(); + } else if (response.getStatusCode() != 200) { + throw new HiveApiUnknownException("Updating node failed for an unknown reason. Response code: " + response.getStatusCode()); + } + + final NodesDto responseNodesDto = response.getContent(NodesDto.class); + final Set responseNodes = parseNodesDto(responseNodesDto); + + if (responseNodes.size() == 1) { + return responseNodes.iterator().next(); + } else { + // Something has gone wrong. + throw new HiveClientResponseException("The parsed response is malformed."); + } + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/DefaultSessionRepository.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/DefaultSessionRepository.java new file mode 100644 index 0000000000000..881d466fcbed4 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/DefaultSessionRepository.java @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.repository; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hive.internal.client.*; +import org.openhab.binding.hive.internal.client.dto.SessionDto; +import org.openhab.binding.hive.internal.client.dto.SessionsDto; +import org.openhab.binding.hive.internal.client.exception.HiveApiAuthenticationException; +import org.openhab.binding.hive.internal.client.exception.HiveApiNotAuthorisedException; +import org.openhab.binding.hive.internal.client.exception.HiveApiUnknownException; +import org.openhab.binding.hive.internal.client.exception.HiveClientUnknownException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; +import java.util.Collections; +import java.util.Objects; + +/** + * Default implementation of {@link SessionRepository}. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class DefaultSessionRepository implements SessionRepository { + private final Logger logger = LoggerFactory.getLogger(DefaultSessionRepository.class); + + private final HiveApiRequestFactory requestFactory; + + public DefaultSessionRepository( + final HiveApiRequestFactory requestFactory + ) { + Objects.requireNonNull(requestFactory); + + this.requestFactory = requestFactory; + } + + private URI getEndpointPathForSession(final SessionId sessionId) { + return HiveApiConstants.ENDPOINT_SESSION.resolve(sessionId.toString()); + } + + @Override + public Session createSession(final Username username, final Password password) { + /* Build our request entity with our user credentials */ + final SessionDto credentials = new SessionDto(); + credentials.username = username; + credentials.password = password; + + final SessionsDto requestEntity = new SessionsDto(); + requestEntity.sessions = Collections.singletonList(credentials); + + /* Send our new session request to the Hive API. */ + final HiveApiResponse response = this.requestFactory.newRequest(HiveApiConstants.ENDPOINT_SESSIONS) + .accept(MediaType.API_V6_5_0_JSON) + .post(requestEntity); + + if (response.getStatusCode() == 400) { + throw new HiveApiAuthenticationException( + "Creating a new session failed because an incorrect username or password was provided" + ); + } else if (response.getStatusCode() != 200) { + throw new HiveApiUnknownException("Creating a new session failed with response code: " + response.getStatusCode()); + } + + /* Try to convert DTO into a domain object */ + final SessionsDto responseEntity = response.getContent(SessionsDto.class); + try { + final SessionDto sessionDto = responseEntity.sessions.get(0); + + logger.debug("Created new Hive API session with sessionId: {}", sessionDto.sessionId); + + return new Session( + sessionDto.sessionId, + sessionDto.userId + ); + } catch (NullPointerException | IllegalArgumentException | IndexOutOfBoundsException ex) { + throw new HiveClientUnknownException("Something went wrong parsing the Hive API response.", ex); + } + } + + @Override + public void deleteSession(final Session session) { + /* Send our delete session request to the Hive API. */ + final HiveApiResponse response = this.requestFactory.newRequest(getEndpointPathForSession(session.getSessionId())) + .accept(MediaType.API_V6_5_0_JSON) + .delete(); + + if (response.getStatusCode() == 401) { + throw new HiveApiNotAuthorisedException(); + } else if (response.getStatusCode() != 200) { + throw new HiveApiUnknownException("Deleting session failed with response code: " + response.getStatusCode()); + } + } + + @Override + public boolean isValidSession(final @Nullable Session session) { + if (session == null) { + return false; + } + + /* Try to get our own session from the Hive API. */ + final HiveApiResponse response = this.requestFactory.newRequest(getEndpointPathForSession(session.getSessionId())) + .accept(MediaType.API_V6_5_0_JSON) + .get(); + + if (response.getStatusCode() == 200) { + // If we succeeded the session is still valid. + return true; + } else if (response.getStatusCode() == 401 || response.getStatusCode() == 403) { + // If we failed our session has expired (or was never valid). + return false; + } + + throw new HiveApiUnknownException("Checking session failed for an unknown reason"); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/NodeRepository.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/NodeRepository.java new file mode 100644 index 0000000000000..009d661838c93 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/NodeRepository.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.repository; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hive.internal.client.Node; +import org.openhab.binding.hive.internal.client.NodeId; + +import java.util.Set; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface NodeRepository { + Set getAllNodes(); + + @Nullable Node getNode(NodeId nodeId); + @Nullable Node updateNode(Node node); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/SessionRepository.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/SessionRepository.java new file mode 100644 index 0000000000000..fa1dc8bc5752c --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/client/repository/SessionRepository.java @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.repository; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hive.internal.client.Password; +import org.openhab.binding.hive.internal.client.Session; +import org.openhab.binding.hive.internal.client.Username; +import org.openhab.binding.hive.internal.client.exception.HiveApiAuthenticationException; +import org.openhab.binding.hive.internal.client.exception.HiveApiNotAuthorisedException; +import org.openhab.binding.hive.internal.client.exception.HiveApiUnknownException; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface SessionRepository { + /** + * Open a new session using a username and password. + * + * @param username + * The user's Hive username (email). + * + * @param password + * The user's Hive password. + * + * @return + * The the newly created Session. + * + * @throws HiveApiAuthenticationException + * If the provided username and password are not valid. + * + * @throws HiveApiUnknownException + * If the call to the Hive API fails for an unknown reason. + * + * @throws IllegalStateException + * If the call the the Hive API was a success but we do not understand + * the response. + */ + Session createSession(Username username, Password password); + + /** + * Delete a session with a given ID. + * + *

+ * N.B. This method does not seem to work how I expect. + * The API returns 200 but the session still works. + *

+ * + * @param session + * The session to delete. + * + * @throws HiveApiNotAuthorisedException + * If you are not authorised to delete the provided session. + * + * @throws HiveApiUnknownException + * If the call to the Hive API fails for an unknown reason. + */ + void deleteSession(Session session); + + /** + * Checks if a session is valid. + * + * @param session + * The session to check. + * + * @return + * {@code true} if the session is valid or {@code false} if it is not. + * + * @throws HiveApiUnknownException + * If the call to the Hive API fails for an unknown reason. + */ + boolean isValidSession(@Nullable Session session); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/discovery/HiveDiscoveryService.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/discovery/HiveDiscoveryService.java new file mode 100644 index 0000000000000..b9fa4f4982c59 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/discovery/HiveDiscoveryService.java @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.discovery; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService; +import org.eclipse.smarthome.config.discovery.DiscoveryResult; +import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; +import org.eclipse.smarthome.core.thing.ThingTypeUID; +import org.eclipse.smarthome.core.thing.ThingUID; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.Node; +import org.openhab.binding.hive.internal.client.NodeId; +import org.openhab.binding.hive.internal.client.ProductType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Instant; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class HiveDiscoveryService extends AbstractDiscoveryService { + private static final String NODE_ID = "nodeId"; + + /** + * Number of seconds before discovery should timeout. + * + *

+ * N.B. Set to 0 because I want to manually mark when discovery is + * finished. + *

+ */ + private static final int DISCOVERY_TIMEOUT_SECONDS = 0; + + private final Logger logger = LoggerFactory.getLogger(HiveDiscoveryService.class); + + private final ThingUID bridgeUid; + private final AtomicReference> lastKnownNodes = new AtomicReference<>(Collections.emptyMap()); + + public HiveDiscoveryService(final ThingUID bridgeUid) { + super( + HiveBindingConstants.DISCOVERABLE_THING_TYPES_UIDS, + DISCOVERY_TIMEOUT_SECONDS + ); + + Objects.requireNonNull(bridgeUid); + + this.bridgeUid = bridgeUid; + } + + public void updateKnownNodes(final Set knownNodes) { + Objects.requireNonNull(knownNodes); + + this.scheduler.execute(() -> { + // Create a map from NodeId -> Node to help with following links later. + final Map nodeMap = new HashMap<>(); + for (final Node node : knownNodes) { + nodeMap.put(node.getId(), node); + } + this.lastKnownNodes.set(nodeMap); + + // Trigger a new scan with the updated information. + this.scheduler.execute(() -> this.startScan(null)); + }); + } + + @Override + protected void startScan() { + // Get a local copy of nodes to prevent concurrency problems + final Map nodes = this.lastKnownNodes.get(); + + // Go through the set of nodes and report their discovery. + for (final Node node : nodes.values()) { + final ThingUID thingUID = new ThingUID("hive:node:" + node.getId().toString()); + + // Convert Hive API ProductTypes into ThingTypes. + final ThingTypeUID thingTypeUID; + if (node.getProductType().equals(ProductType.BOILER_MODULE)) { + thingTypeUID = HiveBindingConstants.THING_TYPE_BOILER_MODULE; + } else if (node.getProductType().equals(ProductType.HEATING)) { + thingTypeUID = HiveBindingConstants.THING_TYPE_HEATING; + } else if (node.getProductType().equals(ProductType.HOT_WATER)) { + thingTypeUID = HiveBindingConstants.THING_TYPE_HOT_WATER; + } else if (node.getProductType().equals(ProductType.HUB)) { + thingTypeUID = HiveBindingConstants.THING_TYPE_HUB; + } else if (node.getProductType().equals(ProductType.THERMOSTAT_UI)) { + thingTypeUID = HiveBindingConstants.THING_TYPE_THERMOSTAT; + } else if (node.getProductType().equals(ProductType.TRV)) { + thingTypeUID = HiveBindingConstants.THING_TYPE_TRV; + } else if (node.getProductType().equals(ProductType.TRV_GROUP)) { + thingTypeUID = HiveBindingConstants.THING_TYPE_TRV_GROUP; + } else { + logger.trace("Found a node that I cannot handle: {} ({})", node.getName(), node.getId()); + + // We do not have a thing type for this yet so skip. + continue; + } + + // Do some fiddling with node names to get more descriptive + // thing labels. + final String label; + if (node.getProductType().equals(ProductType.BOILER_MODULE)) { + label = node.getName().toString() + " (Boiler Module)"; + } else if (node.getProductType().equals(ProductType.HEATING)) { + // If node is heating node use the parent name because + // the real name is just a generic Thermostat X. + final Node parentNode = nodes.get(node.getParentNodeId()); + + label = parentNode.getName().toString() + " (Thermostat Heating Zone)"; + } else if (node.getProductType().equals(ProductType.HOT_WATER)) { + label = "Hot Water"; + } else if (node.getProductType().equals(ProductType.THERMOSTAT_UI)) { + label = node.getName().toString() + " (Thermostat)"; + } else if (node.getProductType().equals(ProductType.TRV)) { + label = node.getName().toString() + " (Radiator Valve)"; + } else if (node.getProductType().equals(ProductType.TRV_GROUP)) { + label = node.getName().toString() + " (Radiator Valve Heating Zone)"; + } else { + label = node.getName().toString(); + } + + final DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID) + .withThingType(thingTypeUID) + .withBridge(this.bridgeUid) + .withLabel(label) + .withProperty(NODE_ID, node.getId().toString()) + .withRepresentationProperty(NODE_ID) + .build(); + + thingDiscovered(discoveryResult); + } + + stopScan(); + } + + @Override + protected synchronized void stopScan() { + super.stopScan(); + removeOlderResults(getTimestampOfLastScan()); + } + + @Override + public void deactivate() { + super.deactivate(); + + // Remove Things from the inbox were discovered by this service. + removeOlderResults(Instant.now().toEpochMilli(), this.bridgeUid); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveAccountHandler.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveAccountHandler.java new file mode 100644 index 0000000000000..150538b7f3eff --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveAccountHandler.java @@ -0,0 +1,216 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.config.discovery.DiscoveryService; +import org.eclipse.smarthome.core.thing.Bridge; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.ThingStatus; +import org.eclipse.smarthome.core.thing.ThingStatusDetail; +import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; +import org.eclipse.smarthome.core.thing.binding.ThingHandler; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.hive.internal.HiveAccountConfig; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.*; +import org.openhab.binding.hive.internal.client.exception.HiveApiAuthenticationException; +import org.openhab.binding.hive.internal.client.exception.HiveApiException; +import org.openhab.binding.hive.internal.discovery.HiveDiscoveryService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +/** + * The {@link HiveAccountHandler} is responsible for handling interaction with + * the Hive API. + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveAccountHandler extends BaseBridgeHandler { + private final Logger logger = LoggerFactory.getLogger(HiveAccountHandler.class); + + private final Map hiveHandlers = new HashMap<>(); + private final ReentrantLock accountStateLock = new ReentrantLock(); + + private final HiveDiscoveryService discoveryService; + + private @Nullable ScheduledFuture pollingJob = null; + + private @Nullable HiveClient hiveClient = null; + + /** + * @param bridge + * @see BaseThingHandler + */ + public HiveAccountHandler(final Bridge bridge) { + super(bridge); + + this.discoveryService = new HiveDiscoveryService(this.getThing().getUID()); + } + + @Override + public void initialize() { + updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING); + + scheduler.execute(() -> { + // The the openHAB runtime should ensure none of this are null. + // Do a little dance to make the null checker happy. + final HiveAccountConfig config = getConfigAs(HiveAccountConfig.class); + assert config != null; + final String username = config.username; + final String password = config.password; + final int pollingInterval = config.pollingInterval; + assert username != null; + assert password != null; + + try { + this.hiveClient = HiveClientFactory.newClient( + new Username(username), + new Password(password) + ); + + this.pollingJob = this.scheduler.scheduleWithFixedDelay( + this::poll, + 0, + Math.max(pollingInterval, 1), + TimeUnit.SECONDS + ); + + updateStatus(ThingStatus.ONLINE); + } catch (final HiveApiAuthenticationException ex) { + updateStatus( + ThingStatus.OFFLINE, + ThingStatusDetail.CONFIGURATION_ERROR, + "Username and Password are not correct." + ); + } catch (final HiveApiException ex) { + updateStatus( + ThingStatus.OFFLINE, + ThingStatusDetail.COMMUNICATION_ERROR, + "Something went wrong communicating with the Hive Api. Details: " + ex.getMessage() + ); + } catch (final RuntimeException ex) { + updateStatus( + ThingStatus.OFFLINE, + ThingStatusDetail.NONE, + "Something went very wrong. Details: " + ex.getMessage() + ); + } + }); + } + + @Override + public void handleCommand(final ChannelUID channelUID, final Command command) { + // Do nothing. + } + + @Override + public void dispose() { + final ScheduledFuture pollingJob = this.pollingJob; + if (pollingJob != null) { + this.pollingJob.cancel(true); + } + + super.dispose(); + } + + public DiscoveryService getDiscoveryService() { + return this.discoveryService; + } + + public void addHiveHandler(final HiveHandlerBase hiveHandler) { + Objects.requireNonNull(hiveHandler); + + final NodeId nodeId = getNodeIdFromHiveHandler(hiveHandler); + this.hiveHandlers.put(nodeId, hiveHandler); + } + + public void removeHiveHandler(final HiveHandlerBase nodeHandler) { + Objects.requireNonNull(nodeHandler); + + final NodeId nodeId = getNodeIdFromHiveHandler(nodeHandler); + this.hiveHandlers.remove(nodeId); + } + + public void updateNode(final Node node) { + Objects.requireNonNull(node); + + final HiveClient hiveClient = this.hiveClient; + + if (hiveClient == null) { + throw new IllegalStateException("UpdateNode called before HiveClient has been initialised."); + } + + final @Nullable Node updatedNode = hiveClient.updateNode(node); + + /* Send updated node state to handlers */ + final @Nullable HiveHandlerBase hiveHandler = hiveHandlers.get(node.getId()); + + // Give the handler an updated version of the node. + if (hiveHandler != null && updatedNode != null) { + hiveHandler.updateState(updatedNode); + } + } + + public ReentrantLock getAccountStateLock() { + return accountStateLock; + } + + private void poll() { + this.accountStateLock.lock(); + try { + final HiveClient hiveClient = this.hiveClient; + if (hiveClient == null) { + throw new IllegalStateException("Poll called before HiveClient has been initialised."); + } + + // Get all nodes from the Hive API. + final Set nodes = hiveClient.getAllNodes(); + + // Tell the discovery service about the nodes we found. + this.discoveryService.updateKnownNodes(nodes); + + /* Send updated node state to handlers */ + for (final Node node : nodes) { + // Try to find a handler responsible for this node. + final @Nullable HiveHandlerBase hiveHandler = hiveHandlers.get(node.getId()); + + // Give the handler an updated version of the node. + if (hiveHandler != null) { + hiveHandler.updateState(node); + } + } + } catch (final Exception ex) { + logger.debug("Polling failed with exception", ex); + } finally { + this.accountStateLock.unlock(); + } + } + + private NodeId getNodeIdFromHiveHandler(final ThingHandler handler) { + Objects.requireNonNull(handler); + + return new NodeId((String) handler.getThing().getConfiguration().get(HiveBindingConstants.CONFIG_NODE_ID)); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveBoilerModuleHandler.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveBoilerModuleHandler.java new file mode 100644 index 0000000000000..11817d87b56b1 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveBoilerModuleHandler.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.Thing; +import org.openhab.binding.hive.internal.handler.strategy.ZigbeeDeviceHandlerStrategy; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveBoilerModuleHandler extends HiveHandlerBase { + public HiveBoilerModuleHandler(final Thing thing) { + super( + thing, + Stream.of( + ZigbeeDeviceHandlerStrategy.getInstance() + ).collect(Collectors.toSet()) + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHandlerBase.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHandlerBase.java new file mode 100644 index 0000000000000..16f9588642b6c --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHandlerBase.java @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.core.thing.*; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.hive.internal.client.Node; +import org.openhab.binding.hive.internal.handler.strategy.ThingHandlerStrategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +abstract class HiveHandlerBase extends BaseThingHandler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final Set handlerStrategies; + + private @Nullable Node hiveNode = null; + + public HiveHandlerBase(final Thing thing, final Set handlerStrategies) { + super(thing); + + this.handlerStrategies = Collections.unmodifiableSet(new HashSet<>(handlerStrategies)); + } + + @Override + public void initialize() { + final @Nullable HiveAccountHandler accountHandler = getAccountHandler(); + + if (accountHandler != null) { + accountHandler.addHiveHandler(this); + updateStatus(ThingStatus.ONLINE); + } + } + + @Override + public final void handleCommand(final ChannelUID channelUID, final Command command) { + final HiveAccountHandler accountHandler = getAccountHandler(); + if (accountHandler == null) { + return; + } + + accountHandler.getAccountStateLock().lock(); + try { + final Node hiveNode = this.hiveNode; + if (hiveNode == null) { + return; + } + + boolean commandHandled = false; + final Iterator strategyIterator = handlerStrategies.iterator(); + while (strategyIterator.hasNext() && !commandHandled) { + final ThingHandlerStrategy strategy = strategyIterator.next(); + + commandHandled = strategy.handleCommand(channelUID, command, hiveNode); + } + + if (commandHandled) { + accountHandler.updateNode(hiveNode); + } + } finally { + accountHandler.getAccountStateLock().unlock(); + } + } + + @Override + public void dispose() { + // Clean up the HiveAccountHandler reference to this handler. + final @Nullable HiveAccountHandler accountHandler = getAccountHandler(); + if (accountHandler != null) { + accountHandler.removeHiveHandler(this); + } + + super.dispose(); + } + + public final void updateState(final Node hiveNode) { + Objects.requireNonNull(hiveNode); + + // Save the node for use by handleCommand. + this.hiveNode = hiveNode; + + // Update channel states using the handler strategies. + final @Nullable ThingHandlerCallback thingHandlerCallback = this.getCallback(); + if (thingHandlerCallback != null) { + for (final ThingHandlerStrategy strategy : this.handlerStrategies) { + strategy.handleUpdate(this.getThing(), thingHandlerCallback, hiveNode); + } + } + } + + /** + * Get the HiveAccountHandler that is acting as a BridgeHandler for this thing. + * + * @return + * {@code null} If the bridge has not been set. + */ + protected final @Nullable HiveAccountHandler getAccountHandler() { + final @Nullable Bridge bridge = getBridge(); + if (bridge == null) { + logger.debug("getAccountHandler() called but bridge is null. Has something gone wrong? Setting status to offline."); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED); + return null; + } else { + return (HiveAccountHandler) bridge.getHandler(); + } + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHeatingHandler.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHeatingHandler.java new file mode 100644 index 0000000000000..744c16f0c7547 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHeatingHandler.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.Thing; +import org.openhab.binding.hive.internal.handler.strategy.HeatingThermostatHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.HeatingTransientModeHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.OnOffDeviceHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.TemperatureSensorHandlerStrategy; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveHeatingHandler extends HiveHandlerBase { + public HiveHeatingHandler(final Thing thing) { + super( + thing, + Stream.of( + HeatingThermostatHandlerStrategy.getInstance(), + OnOffDeviceHandlerStrategy.getInstance(), + TemperatureSensorHandlerStrategy.getInstance(), + HeatingTransientModeHandlerStrategy.getInstance() + ).collect(Collectors.toSet()) + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHotWaterHandler.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHotWaterHandler.java new file mode 100644 index 0000000000000..b149be48a5f56 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHotWaterHandler.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.Thing; +import org.openhab.binding.hive.internal.handler.strategy.OnOffDeviceHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.TransientModeHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.WaterHeaterHandlerStrategy; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveHotWaterHandler extends HiveHandlerBase { + public HiveHotWaterHandler(final Thing thing) { + super( + thing, + Stream.of( + OnOffDeviceHandlerStrategy.getInstance(), + TransientModeHandlerStrategy.getInstance(), + WaterHeaterHandlerStrategy.getInstance() + ).collect(Collectors.toSet()) + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHubHandler.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHubHandler.java new file mode 100644 index 0000000000000..f20f6f147216b --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveHubHandler.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.Thing; + +import java.util.Collections; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveHubHandler extends HiveHandlerBase { + public HiveHubHandler(final Thing thing) { + super( + thing, + Collections.emptySet() + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveThermostatHandler.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveThermostatHandler.java new file mode 100644 index 0000000000000..912e7d462ee3e --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveThermostatHandler.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.Thing; +import org.openhab.binding.hive.internal.handler.strategy.BatteryDeviceHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.ZigbeeDeviceHandlerStrategy; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveThermostatHandler extends HiveHandlerBase { + public HiveThermostatHandler(final Thing thing) { + super( + thing, + Stream.of( + BatteryDeviceHandlerStrategy.getInstance(), + ZigbeeDeviceHandlerStrategy.getInstance() + ).collect(Collectors.toSet()) + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveTrvGroupHandler.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveTrvGroupHandler.java new file mode 100644 index 0000000000000..28b9b09f565f1 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveTrvGroupHandler.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.Thing; +import org.openhab.binding.hive.internal.handler.strategy.HeatingThermostatHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.HeatingTransientModeHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.OnOffDeviceHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.TemperatureSensorHandlerStrategy; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveTrvGroupHandler extends HiveHandlerBase { + public HiveTrvGroupHandler(final Thing thing) { + super( + thing, + Stream.of( + HeatingThermostatHandlerStrategy.getInstance(), + OnOffDeviceHandlerStrategy.getInstance(), + TemperatureSensorHandlerStrategy.getInstance(), + HeatingTransientModeHandlerStrategy.getInstance() + ).collect(Collectors.toSet()) + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveTrvHandler.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveTrvHandler.java new file mode 100644 index 0000000000000..ae7dde8e911d4 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/HiveTrvHandler.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.Thing; +import org.openhab.binding.hive.internal.handler.strategy.BatteryDeviceHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.TemperatureSensorHandlerStrategy; +import org.openhab.binding.hive.internal.handler.strategy.ZigbeeDeviceHandlerStrategy; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HiveTrvHandler extends HiveHandlerBase { + public HiveTrvHandler(final Thing thing) { + super( + thing, + Stream.of( + BatteryDeviceHandlerStrategy.getInstance(), + TemperatureSensorHandlerStrategy.getInstance(), + ZigbeeDeviceHandlerStrategy.getInstance() + ).collect(Collectors.toSet()) + ); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/BatteryDeviceHandlerStrategy.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/BatteryDeviceHandlerStrategy.java new file mode 100644 index 0000000000000..c9a741f352f47 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/BatteryDeviceHandlerStrategy.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.DecimalType; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.feature.BatteryDeviceFeature; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class BatteryDeviceHandlerStrategy extends ThingHandlerStrategyBase { + private static final BatteryDeviceHandlerStrategy INSTANCE = new BatteryDeviceHandlerStrategy(); + + public static BatteryDeviceHandlerStrategy getInstance() { + return INSTANCE; + } + + private BatteryDeviceHandlerStrategy() { + super(BatteryDeviceFeature.class); + } + + @Override + public void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final BatteryDeviceFeature batteryDeviceFeature + ) { + final ChannelUID batteryLevelChannel = thing.getChannel(HiveBindingConstants.CHANNEL_BATTERY_LEVEL).getUID(); + thingHandlerCallback.stateUpdated(batteryLevelChannel, new DecimalType(batteryDeviceFeature.getBatteryLevel().intValue())); + + + final boolean batteryLow = !(batteryDeviceFeature.getBatteryState().equals("FULL") || batteryDeviceFeature.getBatteryState().equals("NORMAL")); + final ChannelUID batteryLowChannel = thing.getChannel(HiveBindingConstants.CHANNEL_BATTERY_LOW).getUID(); + thingHandlerCallback.stateUpdated(batteryLowChannel, OnOffType.from(batteryLow)); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/HeatingThermostatHandlerStrategy.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/HeatingThermostatHandlerStrategy.java new file mode 100644 index 0000000000000..b0c63a666c5a5 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/HeatingThermostatHandlerStrategy.java @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.library.types.QuantityType; +import org.eclipse.smarthome.core.library.types.StringType; +import org.eclipse.smarthome.core.library.unit.SIUnits; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.Node; +import org.openhab.binding.hive.internal.client.OperatingMode; +import org.openhab.binding.hive.internal.client.OverrideMode; +import org.openhab.binding.hive.internal.client.Temperature; +import org.openhab.binding.hive.internal.client.feature.HeatingThermostatFeature; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HeatingThermostatHandlerStrategy extends ThingHandlerStrategyBase { + private static final HeatingThermostatHandlerStrategy INSTANCE = new HeatingThermostatHandlerStrategy(); + + public static HeatingThermostatHandlerStrategy getInstance() { + return INSTANCE; + } + + public HeatingThermostatHandlerStrategy() { + super(HeatingThermostatFeature.class); + } + + @Override + public boolean handleCommand( + final ChannelUID channelUID, + final Command command, + final Node hiveNode, + final HeatingThermostatFeature heatingThermostatFeature + ) { + boolean needUpdate = false; + + if (channelUID.getId().equals(HiveBindingConstants.CHANNEL_TEMPERATURE_TARGET) + && command instanceof QuantityType + ) { + final QuantityType newTargetHeatTemperature = (QuantityType) command; + heatingThermostatFeature.setTargetHeatTemperature(new Temperature(newTargetHeatTemperature.toBigDecimal())); + + needUpdate = true; + } else if (channelUID.getId().equals(HiveBindingConstants.CHANNEL_MODE_OPERATING) + && command instanceof StringType + ) { + final StringType newOperatingMode = (StringType) command; + heatingThermostatFeature.setOperatingMode(OperatingMode.valueOf(newOperatingMode.toString())); + + needUpdate = true; + } else if (channelUID.getId().equals(HiveBindingConstants.CHANNEL_MODE_OPERATING_OVERRIDE) + && command instanceof OnOffType + ) { + final OnOffType newOverrideMode = (OnOffType) command; + heatingThermostatFeature.setTemporaryOperatingModeOverride(newOverrideMode == OnOffType.ON ? OverrideMode.TRANSIENT : OverrideMode.NONE); + + needUpdate = true; + } + + return needUpdate; + } + + @Override + public void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final HeatingThermostatFeature heatingThermostatFeature + ) { + final ChannelUID operatingModeChannel = thing.getChannel(HiveBindingConstants.CHANNEL_MODE_OPERATING).getUID(); + thingHandlerCallback.stateUpdated(operatingModeChannel, new StringType(heatingThermostatFeature.getOperatingMode().toString())); + + final ChannelUID operatingStateChannel = thing.getChannel(HiveBindingConstants.CHANNEL_STATE_OPERATING).getUID(); + thingHandlerCallback.stateUpdated(operatingStateChannel, new StringType(heatingThermostatFeature.getOperatingState())); + + // FIXME: Actually check temperature unit. + final ChannelUID targetHeatTemperatureChannel = thing.getChannel(HiveBindingConstants.CHANNEL_TEMPERATURE_TARGET).getUID(); + thingHandlerCallback.stateUpdated(targetHeatTemperatureChannel, new QuantityType<>(heatingThermostatFeature.getTargetHeatTemperature().getValue(), SIUnits.CELSIUS)); + + final ChannelUID operatingModeOverrideChannel = thing.getChannel(HiveBindingConstants.CHANNEL_MODE_OPERATING_OVERRIDE).getUID(); + thingHandlerCallback.stateUpdated(operatingModeOverrideChannel, OnOffType.from(heatingThermostatFeature.getTemporaryOperatingModeOverride() == OverrideMode.TRANSIENT)); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/HeatingTransientModeHandlerStrategy.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/HeatingTransientModeHandlerStrategy.java new file mode 100644 index 0000000000000..865bc162cad63 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/HeatingTransientModeHandlerStrategy.java @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.QuantityType; +import org.eclipse.smarthome.core.library.unit.SIUnits; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.Node; +import org.openhab.binding.hive.internal.client.Temperature; +import org.openhab.binding.hive.internal.client.feature.HeatingTransientModeFeature; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class HeatingTransientModeHandlerStrategy extends ThingHandlerStrategyBase { + private static final HeatingTransientModeHandlerStrategy INSTANCE = new HeatingTransientModeHandlerStrategy(); + + public static HeatingTransientModeHandlerStrategy getInstance() { + return INSTANCE; + } + + private HeatingTransientModeHandlerStrategy() { + super(HeatingTransientModeFeature.class); + } + + @Override + public boolean handleCommand( + final ChannelUID channelUID, + final Command command, + final Node hiveNode, + final HeatingTransientModeFeature transientModeFeature + ) { + boolean needUpdate = TransientModeHandlerStrategy.getInstance().handleCommand(channelUID, command, hiveNode, transientModeFeature); + + if (channelUID.getId().equals(HiveBindingConstants.CHANNEL_TEMPERATURE_TARGET_BOOST) + && command instanceof QuantityType + ) { + final QuantityType newTargetHeatTemperature = (QuantityType) command; + transientModeFeature.setBoostTargetTemperature(new Temperature(newTargetHeatTemperature.toBigDecimal())); + + needUpdate = true; + } + + return needUpdate; + } + + @Override + public void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final HeatingTransientModeFeature transientModeFeature + ) { + TransientModeHandlerStrategy.getInstance().handleUpdate(thing, thingHandlerCallback, transientModeFeature); + + // FIXME: Actually check temperature unit. + final ChannelUID boostTargetHeatTemperatureChannel = thing.getChannel(HiveBindingConstants.CHANNEL_TEMPERATURE_TARGET_BOOST).getUID(); + thingHandlerCallback.stateUpdated(boostTargetHeatTemperatureChannel, new QuantityType<>(transientModeFeature.getBoostTargetTemperature().getValue(), SIUnits.CELSIUS)); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/OnOffDeviceHandlerStrategy.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/OnOffDeviceHandlerStrategy.java new file mode 100644 index 0000000000000..6a141f6e3381f --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/OnOffDeviceHandlerStrategy.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.Node; +import org.openhab.binding.hive.internal.client.OnOffMode; +import org.openhab.binding.hive.internal.client.feature.OnOffDeviceFeature; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class OnOffDeviceHandlerStrategy extends ThingHandlerStrategyBase { + private static final OnOffDeviceHandlerStrategy INSTANCE = new OnOffDeviceHandlerStrategy(); + + public static OnOffDeviceHandlerStrategy getInstance() { + return INSTANCE; + } + + public OnOffDeviceHandlerStrategy() { + super(OnOffDeviceFeature.class); + } + + @Override + public boolean handleCommand( + final ChannelUID channelUID, + final Command command, + final Node hiveNode, + final OnOffDeviceFeature onOffDeviceFeature + ) { + if (channelUID.getId().equals(HiveBindingConstants.CHANNEL_MODE_ON_OFF) + && command instanceof OnOffType) { + // Set the new target heating temperature. + final OnOffType value = (OnOffType) command; + final OnOffMode mode = value == OnOffType.ON ? OnOffMode.ON : OnOffMode.OFF; + + onOffDeviceFeature.setMode(mode); + + return true; + } + + return false; + } + + @Override + public void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final OnOffDeviceFeature onOffDeviceFeature + ) { + final ChannelUID onOffModeChannel = thing.getChannel(HiveBindingConstants.CHANNEL_MODE_ON_OFF).getUID(); + final OnOffType value = onOffDeviceFeature.getMode() == OnOffMode.ON ? OnOffType.ON : OnOffType.OFF; + thingHandlerCallback.stateUpdated(onOffModeChannel, value); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/TemperatureSensorHandlerStrategy.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/TemperatureSensorHandlerStrategy.java new file mode 100644 index 0000000000000..6ad1eaf728f08 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/TemperatureSensorHandlerStrategy.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.QuantityType; +import org.eclipse.smarthome.core.library.unit.SIUnits; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.feature.TemperatureSensorFeature; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class TemperatureSensorHandlerStrategy extends ThingHandlerStrategyBase { + private static final TemperatureSensorHandlerStrategy INSTANCE = new TemperatureSensorHandlerStrategy(); + + public static TemperatureSensorHandlerStrategy getInstance() { + return INSTANCE; + } + + public TemperatureSensorHandlerStrategy() { + super(TemperatureSensorFeature.class); + } + + @Override + public void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final TemperatureSensorFeature temperatureSensorFeature + ) { + // FIXME: Actually check temperature unit. + final ChannelUID temperatureChannel = thing.getChannel(HiveBindingConstants.CHANNEL_TEMPERATURE_CURRENT).getUID(); + thingHandlerCallback.stateUpdated(temperatureChannel, new QuantityType<>(temperatureSensorFeature.getTemperature().getValue(), SIUnits.CELSIUS)); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/ThingHandlerStrategy.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/ThingHandlerStrategy.java new file mode 100644 index 0000000000000..4ee892f84aec6 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/ThingHandlerStrategy.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.hive.internal.client.Node; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public interface ThingHandlerStrategy { + boolean handleCommand( + final ChannelUID channelUID, + final Command command, + final Node hiveNode + ); + + void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final Node hiveNode + ); +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/ThingHandlerStrategyBase.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/ThingHandlerStrategyBase.java new file mode 100644 index 0000000000000..2b3387cc16686 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/ThingHandlerStrategyBase.java @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.hive.internal.client.Node; +import org.openhab.binding.hive.internal.client.feature.Feature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public abstract class ThingHandlerStrategyBase implements ThingHandlerStrategy { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final Class featureClass; + + public ThingHandlerStrategyBase(final Class featureClass) { + Objects.requireNonNull(featureClass); + + this.featureClass = featureClass; + } + + @Override + public final boolean handleCommand( + final ChannelUID channelUID, + final Command command, + final Node hiveNode + ) { + final @Nullable F feature = hiveNode.getFeature(featureClass); + + if (feature == null) { + logger.warn("Could not get {} for {} ({}). Has it been given the wrong kind of handler?", featureClass.getName(), hiveNode.getName(), hiveNode.getId()); + return false; + } + + return handleCommand( + channelUID, + command, + hiveNode, + feature + ); + } + + @Override + public final void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final Node hiveNode + ) { + final @Nullable F feature = hiveNode.getFeature(featureClass); + + if (feature == null) { + logger.warn("Could not get {} for {} ({}). Has it been given the wrong kind of handler?", featureClass.getName(), hiveNode.getName(), hiveNode.getId()); + return; + } + + handleUpdate( + thing, + thingHandlerCallback, + feature + ); + } + + public boolean handleCommand( + final ChannelUID channelUID, + final Command command, + final Node hiveNode, + final F feature + ) { + return false; + } + + public void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final F feature + ) { + // Do nothing. + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/TransientModeHandlerStrategy.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/TransientModeHandlerStrategy.java new file mode 100644 index 0000000000000..d46da08d5112a --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/TransientModeHandlerStrategy.java @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.DateTimeType; +import org.eclipse.smarthome.core.library.types.DecimalType; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.Node; +import org.openhab.binding.hive.internal.client.feature.TransientModeFeature; + +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class TransientModeHandlerStrategy extends ThingHandlerStrategyBase { + private static final int SECONDS_PER_MINUTE = 60; + + private static final TransientModeHandlerStrategy INSTANCE = new TransientModeHandlerStrategy(); + + public static TransientModeHandlerStrategy getInstance() { + return INSTANCE; + } + + private TransientModeHandlerStrategy() { + super(TransientModeFeature.class); + } + + @Override + public boolean handleCommand( + final ChannelUID channelUID, + final Command command, + final Node hiveNode, + final TransientModeFeature transientModeFeature + ) { + if (channelUID.getId().equals(HiveBindingConstants.CHANNEL_TRANSIENT_DURATION) + && command instanceof DecimalType + ) { + final DecimalType newDurationMins = (DecimalType) command; + + transientModeFeature.setDuration(Duration.ofSeconds(newDurationMins.longValue() * SECONDS_PER_MINUTE)); + + return true; + } + + return false; + } + + @Override + public void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final TransientModeFeature transientModeFeature + ) { + final long durationMins = transientModeFeature.getDuration().getSeconds() / SECONDS_PER_MINUTE; + final ChannelUID transientDurationChannel = thing.getChannel(HiveBindingConstants.CHANNEL_TRANSIENT_DURATION).getUID(); + thingHandlerCallback.stateUpdated(transientDurationChannel, new DecimalType(durationMins)); + + final ChannelUID transientEnabledChannel = thing.getChannel(HiveBindingConstants.CHANNEL_TRANSIENT_ENABLED).getUID(); + thingHandlerCallback.stateUpdated(transientEnabledChannel, OnOffType.from(transientModeFeature.getIsEnabled())); + + final ChannelUID transientStartTimeChannel = thing.getChannel(HiveBindingConstants.CHANNEL_TRANSIENT_START_TIME).getUID(); + thingHandlerCallback.stateUpdated(transientStartTimeChannel, new DateTimeType(transientModeFeature.getStartDatetime())); + + final ChannelUID transientEndTimeChannel = thing.getChannel(HiveBindingConstants.CHANNEL_TRANSIENT_END_TIME).getUID(); + thingHandlerCallback.stateUpdated(transientEndTimeChannel, new DateTimeType(transientModeFeature.getEndDatetime())); + + final ChannelUID transientRemainingChannel = thing.getChannel(HiveBindingConstants.CHANNEL_TRANSIENT_REMAINING).getUID(); + thingHandlerCallback.stateUpdated(transientRemainingChannel, new DecimalType(Math.max(0, Instant.now().until(transientModeFeature.getEndDatetime(), ChronoUnit.MINUTES)))); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/WaterHeaterHandlerStrategy.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/WaterHeaterHandlerStrategy.java new file mode 100644 index 0000000000000..7d2e00e835757 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/WaterHeaterHandlerStrategy.java @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.library.types.StringType; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.Node; +import org.openhab.binding.hive.internal.client.OperatingMode; +import org.openhab.binding.hive.internal.client.OverrideMode; +import org.openhab.binding.hive.internal.client.feature.WaterHeaterFeature; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class WaterHeaterHandlerStrategy extends ThingHandlerStrategyBase { + private static final WaterHeaterHandlerStrategy INSTANCE = new WaterHeaterHandlerStrategy(); + + public static WaterHeaterHandlerStrategy getInstance() { + return INSTANCE; + } + + public WaterHeaterHandlerStrategy() { + super(WaterHeaterFeature.class); + } + + @Override + public boolean handleCommand( + final ChannelUID channelUID, + final Command command, + final Node hiveNode, + final WaterHeaterFeature waterHeaterFeature + ) { + boolean needUpdate = false; + + if (channelUID.getId().equals(HiveBindingConstants.CHANNEL_MODE_OPERATING) + && command instanceof StringType + ) { + final StringType newOperatingMode = (StringType) command; + + waterHeaterFeature.setOperatingMode(OperatingMode.valueOf(newOperatingMode.toString())); + + needUpdate = true; + } else if (channelUID.getId().equals(HiveBindingConstants.CHANNEL_MODE_OPERATING_OVERRIDE) + && command instanceof OnOffType + ) { + final OnOffType newOverrideMode = (OnOffType) command; + waterHeaterFeature.setTemporaryOperatingModeOverride(newOverrideMode == OnOffType.ON ? OverrideMode.TRANSIENT : OverrideMode.NONE); + + needUpdate = true; + } + + return needUpdate; + } + + @Override + public void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final WaterHeaterFeature waterHeaterFeature + ) { + final ChannelUID operatingModeChannel = thing.getChannel(HiveBindingConstants.CHANNEL_MODE_OPERATING).getUID(); + thingHandlerCallback.stateUpdated(operatingModeChannel, new StringType(waterHeaterFeature.getOperatingMode().toString())); + + final ChannelUID isOnChannel = thing.getChannel(HiveBindingConstants.CHANNEL_IS_ON).getUID(); + thingHandlerCallback.stateUpdated(isOnChannel, OnOffType.from(waterHeaterFeature.isOn())); + + final ChannelUID operatingModeOverrideChannel = thing.getChannel(HiveBindingConstants.CHANNEL_MODE_OPERATING_OVERRIDE).getUID(); + thingHandlerCallback.stateUpdated(operatingModeOverrideChannel, OnOffType.from(waterHeaterFeature.getTemporaryOperatingModeOverride() == OverrideMode.TRANSIENT)); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/ZigbeeDeviceHandlerStrategy.java b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/ZigbeeDeviceHandlerStrategy.java new file mode 100644 index 0000000000000..c74747cf67b10 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/java/org/openhab/binding/hive/internal/handler/strategy/ZigbeeDeviceHandlerStrategy.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.handler.strategy; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.DecimalType; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; +import org.openhab.binding.hive.internal.HiveBindingConstants; +import org.openhab.binding.hive.internal.client.feature.ZigbeeDeviceFeature; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public final class ZigbeeDeviceHandlerStrategy extends ThingHandlerStrategyBase { + private static final ZigbeeDeviceHandlerStrategy INSTANCE = new ZigbeeDeviceHandlerStrategy(); + + public static ZigbeeDeviceHandlerStrategy getInstance() { + return INSTANCE; + } + + private ZigbeeDeviceHandlerStrategy() { + super(ZigbeeDeviceFeature.class); + } + + @Override + public void handleUpdate( + final Thing thing, + final ThingHandlerCallback thingHandlerCallback, + final ZigbeeDeviceFeature zigbeeDeviceFeature + ) { + final ChannelUID averageLqiChannel = thing.getChannel(HiveBindingConstants.CHANNEL_RADIO_LQI_AVERAGE).getUID(); + thingHandlerCallback.stateUpdated(averageLqiChannel, new DecimalType(zigbeeDeviceFeature.getAverageLQI())); + + final ChannelUID lastKnownLqiChannel = thing.getChannel(HiveBindingConstants.CHANNEL_RADIO_LQI_LAST_KNOWN).getUID(); + thingHandlerCallback.stateUpdated(lastKnownLqiChannel, new DecimalType(zigbeeDeviceFeature.getLastKnownLQI())); + + final ChannelUID averageRssiChannel = thing.getChannel(HiveBindingConstants.CHANNEL_RADIO_RSSI_AVERAGE).getUID(); + thingHandlerCallback.stateUpdated(averageRssiChannel, new DecimalType(zigbeeDeviceFeature.getAverageRSSI())); + + final ChannelUID lastKnownRssiChannel = thing.getChannel(HiveBindingConstants.CHANNEL_RADIO_RSSI_LAST_KNOWN).getUID(); + thingHandlerCallback.stateUpdated(lastKnownRssiChannel, new DecimalType(zigbeeDeviceFeature.getLastKnownRSSI())); + } +} diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/binding/binding.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/binding/binding.xml new file mode 100644 index 0000000000000..9e1353298968c --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/binding/binding.xml @@ -0,0 +1,10 @@ + + + + Hive Binding + Integrates Hive smart home devices. (AKA Centrica Hive / British Gas Hive) + Ross Brown + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/config/hive-node.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/config/hive-node.xml new file mode 100644 index 0000000000000..b15323569c50f --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/config/hive-node.xml @@ -0,0 +1,13 @@ + + + + + + + The Hive API Node ID for this thing + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-heating_thermostat.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-heating_thermostat.xml new file mode 100644 index 0000000000000..d18069ce1a304 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-heating_thermostat.xml @@ -0,0 +1,27 @@ + + + + + Number:Temperature + + Heating + + + + + String + + Heating + + + + + Number:Temperature + + Heating + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-temperature_sensor.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-temperature_sensor.xml new file mode 100644 index 0000000000000..d718aba51e098 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-temperature_sensor.xml @@ -0,0 +1,13 @@ + + + + + Number:Temperature + + Temperature + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-transient_mode.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-transient_mode.xml new file mode 100644 index 0000000000000..314d6c212c308 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-transient_mode.xml @@ -0,0 +1,41 @@ + + + + + Number + + Heating + + + + + Number + + Heating + + + + + Switch + + Heating + + + + + DateTime + + Heating + + + + + DateTime + + Heating + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-water_heater.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-water_heater.xml new file mode 100644 index 0000000000000..5bc5817897739 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-water_heater.xml @@ -0,0 +1,13 @@ + + + + + Switch + + Heating + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-zigbee_device.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-zigbee_device.xml new file mode 100644 index 0000000000000..2ab3822090f95 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-feature-zigbee_device.xml @@ -0,0 +1,30 @@ + + + + + Number + + + + + + Number + + + + + + Number + + + + + + Number + + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-schedulable.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-schedulable.xml new file mode 100644 index 0000000000000..6ddc8c685aef0 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/channels-schedulable.xml @@ -0,0 +1,25 @@ + + + + + String + + Heating + + + + + + + + + + + Switch + + Heating + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-account.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-account.xml new file mode 100644 index 0000000000000..2b27923203679 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-account.xml @@ -0,0 +1,32 @@ + + + + + + + An account for using the Hive REST API. + (This the same account you use to login to the Hive mobile app or my.hivehome.com) + + + + + + Your Hive account username (email address) + + + + Your Hive account password + + + + + How many seconds to wait between polling Hive API for updates + seconds + 10 + + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-boiler_module.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-boiler_module.xml new file mode 100644 index 0000000000000..b13f8ded1bbff --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-boiler_module.xml @@ -0,0 +1,25 @@ + + + + + + + + + + The physical module that controls when your boiler turns on for heating (and optionally hot water) + HVAC + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-heating.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-heating.xml new file mode 100644 index 0000000000000..dfd79ab54966a --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-heating.xml @@ -0,0 +1,36 @@ + + + + + + + + + + A virtual zone that can be heated by the Hive Active Heating system + HVAC + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-hot_water.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-hot_water.xml new file mode 100644 index 0000000000000..702da23776fdd --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-hot_water.xml @@ -0,0 +1,32 @@ + + + + + + + + + + A virtual thing that controls your hot water supply + HVAC + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-hub.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-hub.xml new file mode 100644 index 0000000000000..26baebc9344ab --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-hub.xml @@ -0,0 +1,17 @@ + + + + + + + + + + The physical device that bridges your wireless Hive devices to your home network / the internet + + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-thermostat.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-thermostat.xml new file mode 100644 index 0000000000000..b1fdddafb9b06 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-thermostat.xml @@ -0,0 +1,28 @@ + + + + + + + + + + The physical device with controls for the temperature of a single zone + HVAC + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-trv.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-trv.xml new file mode 100644 index 0000000000000..b38b58eae9f88 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-trv.xml @@ -0,0 +1,29 @@ + + + + + + + + + + The physical device that controls turning an individual radiator on or off + HVAC + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-trv_group.xml b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-trv_group.xml new file mode 100644 index 0000000000000..02bc40376cb27 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/main/resources/ESH-INF/thing/thing-trv_group.xml @@ -0,0 +1,36 @@ + + + + + + + + + + A virtual zone controlled by Hive Radiator Valves that can be heated by the Hive Active Heating system + HVAC + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/TestHiveHandlerFactory.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/TestHiveHandlerFactory.java new file mode 100644 index 0000000000000..2a4d98b39b0bd --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/TestHiveHandlerFactory.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal; + +import static org.mockito.Mockito.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.junit.Before; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class TestHiveHandlerFactory { + private @Nullable HiveHandlerFactory handlerFactory; + + @Before + public void setUp() { + handlerFactory = new HiveHandlerFactory(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/TestUtil.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/TestUtil.java new file mode 100644 index 0000000000000..c930f1ac7fcfe --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/TestUtil.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal; + +import java.io.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class TestUtil { + private TestUtil() { + throw new AssertionError(); + } + + public static String getResourceAsString(final String resource) throws IOException { + try (final InputStream inputStream = TestUtil.class.getResourceAsStream(resource); final Writer writer = new StringWriter()) { + final Reader reader = new BufferedReader(new InputStreamReader(inputStream)); + + char[] buffer = new char[1024]; + int n; + while ((n = reader.read(buffer)) != -1) { + writer.write(buffer, 0, n); + } + + return writer.toString(); + } + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/DefaultHiveClientTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/DefaultHiveClientTest.java new file mode 100644 index 0000000000000..62294fa0ccc7a --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/DefaultHiveClientTest.java @@ -0,0 +1,148 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.Collections; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.openhab.binding.hive.internal.client.exception.*; +import org.openhab.binding.hive.internal.client.repository.*; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class DefaultHiveClientTest { + @NonNullByDefault({}) + @Mock + private SessionAuthenticationManager authenticationManager; + + @NonNullByDefault({}) + @Mock + private SessionRepository sessionRepository; + + @NonNullByDefault({}) + @Mock + private NodeRepository nodeRepository; + + @NonNullByDefault({}) + private Username username; + + @NonNullByDefault({}) + private Password password; + + @NonNullByDefault({}) + private Session session; + + @Before + public void setUp() { + initMocks(this); + this.username = new Username("hiveuser@example.com"); + this.password = new Password("password123"); + this.session = new Session( + new SessionId("deadbeef-dead-beef-dead-beefdeadbeef"), + new UserId("deadbeef-dead-beef-dead-beefdeadbeef") + ); + } + + private DefaultHiveClient createClient() { + return new DefaultHiveClient( + this.authenticationManager, + this.username, + this.password, + this.sessionRepository, + this.nodeRepository + ); + } + + /** + * Test that DefaultHiveClient tries to authenticate when it is created. + */ + @Test + public void testGoodLogin() { + /* Given */ + when(this.sessionRepository.createSession(any(), any())).thenReturn(this.session); + + + /* When */ + final DefaultHiveClient hiveClient = createClient(); + + + /* Then */ + verify(this.sessionRepository, times(1)).createSession(eq(this.username), eq(this.password)); + verify(this.authenticationManager, times(1)).setSession(eq(this.session)); + } + + /** + * Test that DefaultHiveClient passes on authentication exceptions. + */ + @Test(expected = HiveApiAuthenticationException.class) + public void testBadCredentialsLogin() { + /* Given */ + when(this.sessionRepository.createSession(any(), any())).thenThrow(new HiveApiAuthenticationException()); + + + /* When / Then */ + // This should throw HiveApiAuthenticationException. + // No assertThrows in this version of jUnit :( + final DefaultHiveClient hiveClient = createClient(); + } + + /** + * Test that DefaultHiveClient passes on exception when API does something unexpected. + */ + @Test(expected = HiveApiUnknownException.class) + public void testApiErrorLogin() { + /* Given */ + when(this.sessionRepository.createSession(any(), any())).thenThrow(new HiveApiUnknownException()); + + + /* When / Then */ + // This should throw HiveApiUnknownException. + // No assertThrows in this version of jUnit :( + final DefaultHiveClient hiveClient = createClient(); + } + + /** + * Test the DefaultHiveClient passes on the nodes from the NodeRepository. + */ + @Test + public void testGetNodes() { + /* Given */ + final Node expectedNode = mock(Node.class); + final Set expectedResults = Collections.unmodifiableSet(Collections.singleton(expectedNode)); + when(this.nodeRepository.getAllNodes()).thenReturn(expectedResults); + + DefaultHiveClient hiveClient = createClient(); + + + /* When */ + Set returnedResults = hiveClient.getAllNodes(); + + + /* Then */ + assertThat(returnedResults).containsExactly(expectedNode); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/GsonJsonServiceTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/GsonJsonServiceTest.java new file mode 100644 index 0000000000000..ffa12baa2cd9b --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/GsonJsonServiceTest.java @@ -0,0 +1,221 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client; + +import static org.assertj.core.api.Assertions.*; + +import java.io.IOException; +import java.math.BigDecimal; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.openhab.binding.hive.internal.TestUtil; +import org.openhab.binding.hive.internal.client.dto.*; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class GsonJsonServiceTest { + @NonNullByDefault({}) + private JsonService jsonService; + + @Before + public void setUp() { + jsonService = new GsonJsonService(); + } + + @Test + public void testSessions() throws IOException { + /* Given */ + final String json = TestUtil.getResourceAsString("/exampleSessions.json"); + + final SessionId sessionId = new SessionId("mytoken"); + final Username username = new Username("hiveuser@example.com"); + final UserId userId = new UserId("deadbeef-dead-beef-dead-beefdeadbeef"); + + + /* When */ + final SessionsDto sessionsDto = jsonService.fromJson(json, SessionsDto.class); + + + /* Then */ + assertThat(sessionsDto).isNotNull(); + assertThat(sessionsDto.sessions).isNotNull(); + assertThat(sessionsDto.sessions.size()).isEqualTo(1); + + SessionDto sessionDto = sessionsDto.sessions.get(0); + + assertThat(sessionDto.id).isEqualTo(sessionId); + assertThat(sessionDto.sessionId).isEqualTo(sessionId); + assertThat(sessionDto.username).isEqualTo(username); + assertThat(sessionDto.userId).isEqualTo(userId); + assertThat(sessionDto.extCustomerLevel).isEqualTo(1); + assertThat(sessionDto.latestSupportedApiVersion).isEqualTo("6"); + } + + @Test + public void testNodesRoot() throws IOException { + /* Given */ + String json = TestUtil.getResourceAsString("/exampleThermostatNode.json"); + + final NodeId nodeId = new NodeId("deadbeef-dead-beef-dead-beefdeadbeef"); + final NodeName nodeName = new NodeName("Thermostat 1"); + final HiveApiInstant createdOn = new HiveApiInstant(Instant.ofEpochMilli(1513173613796L)); + final HiveApiInstant firstInstall = new HiveApiInstant(Instant.ofEpochMilli(1513173925623L)); + final UserId userId = new UserId("deadbeef-dead-beef-dead-beefdeadbeef"); + + + /* When */ + final NodesDto nodesDto = jsonService.fromJson(json, NodesDto.class); + + + /* Then */ + // Check root fields parsed correctly + assertThat(nodesDto).isNotNull(); + assertThat(nodesDto.nodes).isNotNull(); + assertThat(nodesDto.nodes.size()).isEqualTo(1); + + // Check node level fields parsed correctly + final NodeDto nodeDto = nodesDto.nodes.get(0); + assertThat(nodeDto.id).isEqualTo(nodeId); + assertThat(nodeDto.name).isEqualTo(nodeName); + assertThat(nodeDto.nodeType).isEqualTo(NodeType.THERMOSTAT); + assertThat(nodeDto.parentNodeId).isEqualTo(nodeId); + assertThat(nodeDto.createdOn).isEqualTo(createdOn); + assertThat(nodeDto.firstInstall).isEqualTo(firstInstall); + assertThat(nodeDto.userId).isEqualTo(userId); + assertThat(nodeDto.ownerId).isEqualTo(userId); + assertThat(nodeDto.homeId).isEqualTo("deadbeef-dead-beef-dead-beefdeadbeef"); + assertThat(nodeDto.features).isNotNull(); + assertThat(nodeDto.lastUpgradeSucceeded).isFalse(); + } + + @Test + public void testNodesFeatureDeviceManagement() throws IOException { + /* Given */ + String json = TestUtil.getResourceAsString("/exampleThermostatNode.json"); + + + /* When */ + final NodesDto nodesDto = jsonService.fromJson(json, NodesDto.class); + final NodeDto nodeDto = nodesDto.nodes.get(0); + + + /* Then */ + assertThat(nodeDto.features).isNotNull(); + assertThat(nodeDto.features.device_management_v1).isNotNull(); + assertThat(nodeDto.features.device_management_v1.featureType).isNotNull(); + assertThat(nodeDto.features.device_management_v1.featureType.reportedValue).isEqualTo(FeatureType.DEVICE_MANAGEMENT_V1); + assertThat(nodeDto.features.device_management_v1.productType).isNotNull(); + assertThat(nodeDto.features.device_management_v1.productType.reportedValue).isEqualTo(ProductType.HEATING); + } + + @Test + public void testNodesFeatureHeatingThermostat() throws IOException { + /* Given */ + String json = TestUtil.getResourceAsString("/exampleThermostatNode.json"); + + + /* When */ + final NodesDto nodesDto = jsonService.fromJson(json, NodesDto.class); + final NodeDto nodeDto = nodesDto.nodes.get(0); + + + /* Then */ + assertThat(nodeDto.features).isNotNull(); + assertThat(nodeDto.features.heating_thermostat_v1).isNotNull(); + assertThat(nodeDto.features.heating_thermostat_v1.featureType).isNotNull(); + assertThat(nodeDto.features.heating_thermostat_v1.featureType.reportedValue).isEqualTo(FeatureType.HEATING_THERMOSTAT_V1); + assertThat(nodeDto.features.heating_thermostat_v1.operatingMode).isNotNull(); + assertThat(nodeDto.features.heating_thermostat_v1.operatingMode.reportedValue).isEqualTo(OperatingMode.SCHEDULE); + assertThat(nodeDto.features.heating_thermostat_v1.targetHeatTemperature).isNotNull(); + assertThat(nodeDto.features.heating_thermostat_v1.targetHeatTemperature.reportedValue).isEqualTo(BigDecimal.valueOf(7)); + } + + @Test + public void testNodesFeatureOnOffDevice() throws IOException { + /* Given */ + String json = TestUtil.getResourceAsString("/exampleThermostatNode.json"); + + + /* When */ + final NodesDto nodesDto = jsonService.fromJson(json, NodesDto.class); + final NodeDto nodeDto = nodesDto.nodes.get(0); + + + /* Then */ + assertThat(nodeDto.features).isNotNull(); + assertThat(nodeDto.features.on_off_device_v1).isNotNull(); + assertThat(nodeDto.features.on_off_device_v1.featureType).isNotNull(); + assertThat(nodeDto.features.on_off_device_v1.featureType.reportedValue).isEqualTo(FeatureType.ON_OFF_DEVICE_V1); + assertThat(nodeDto.features.on_off_device_v1.mode).isNotNull(); + assertThat(nodeDto.features.on_off_device_v1.mode.reportedValue).isEqualTo(OnOffMode.ON); + } + + @Test + public void testNodesFeatureTemperatureSensor() throws IOException { + /* Given */ + String json = TestUtil.getResourceAsString("/exampleThermostatNode.json"); + + + /* When */ + final NodesDto nodesDto = jsonService.fromJson(json, NodesDto.class); + final NodeDto nodeDto = nodesDto.nodes.get(0); + + + /* Then */ + assertThat(nodeDto.features).isNotNull(); + assertThat(nodeDto.features.temperature_sensor_v1).isNotNull(); + assertThat(nodeDto.features.temperature_sensor_v1.featureType).isNotNull(); + assertThat(nodeDto.features.temperature_sensor_v1.featureType.reportedValue).isEqualTo(FeatureType.TEMPERATURE_SENSOR_V1); + assertThat(nodeDto.features.temperature_sensor_v1.temperature).isNotNull(); + assertThat(nodeDto.features.temperature_sensor_v1.temperature.reportedValue).isEqualTo(BigDecimal.valueOf(19)); + } + + @Test + public void testNodesFeatureTransientMode() throws IOException { + /* Given */ + String json = TestUtil.getResourceAsString("/exampleThermostatNode.json"); + + + /* When */ + final NodesDto nodesDto = jsonService.fromJson(json, NodesDto.class); + final NodeDto nodeDto = nodesDto.nodes.get(0); + + /* Then */ + assertThat(nodeDto.features).isNotNull(); + assertThat(nodeDto.features.transient_mode_v1).isNotNull(); + assertThat(nodeDto.features.transient_mode_v1.duration).isNotNull(); + assertThat(nodeDto.features.transient_mode_v1.duration.reportedValue).isEqualTo(1800); + assertThat(nodeDto.features.transient_mode_v1.endDatetime).isNotNull(); + assertThat(nodeDto.features.transient_mode_v1.endDatetime.reportedValue).isEqualTo(ZonedDateTime.of( + 2020, + 03, + 01, + 22, + 05, + 44, + 442000000, + ZoneOffset.UTC + )); + + // TODO: Test more properties + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/ActionTypeGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/ActionTypeGsonAdapterTest.java new file mode 100644 index 0000000000000..9c54c30c83e71 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/ActionTypeGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class ActionTypeGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected ActionTypeGsonAdapter getAdapter() { + return new ActionTypeGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/AttributeNameGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/AttributeNameGsonAdapterTest.java new file mode 100644 index 0000000000000..760debe42da6e --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/AttributeNameGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class AttributeNameGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected AttributeNameGsonAdapter getAdapter() { + return new AttributeNameGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/FeatureTypeGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/FeatureTypeGsonAdapterTest.java new file mode 100644 index 0000000000000..5d0908947af68 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/FeatureTypeGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class FeatureTypeGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected FeatureTypeGsonAdapter getAdapter() { + return new FeatureTypeGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/GsonAdapterTestBase.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/GsonAdapterTestBase.java new file mode 100644 index 0000000000000..eb8577fd96713 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/GsonAdapterTestBase.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonWriter; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public abstract class GsonAdapterTestBase> { + @NonNullByDefault({}) + @Mock + protected JsonWriter jsonWriter; + + @Before + public void setUp() { + initMocks(this); + } + + protected abstract T getAdapter(); + + /** + * Makes sure we actually output null instead of throwing a NPE. + */ + @Test + public void testNullValue() throws IOException { + /* Given */ + final T adapter = getAdapter(); + + + /* When */ + adapter.write(this.jsonWriter, null); + + + /* Then */ + verify(this.jsonWriter, times(1)).nullValue(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/HiveApiInstantGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/HiveApiInstantGsonAdapterTest.java new file mode 100644 index 0000000000000..91b638d9fb604 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/HiveApiInstantGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class HiveApiInstantGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected HiveApiInstantGsonAdapter getAdapter() { + return new HiveApiInstantGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/NodeIdGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/NodeIdGsonAdapterTest.java new file mode 100644 index 0000000000000..613046ad2c727 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/NodeIdGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class NodeIdGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected NodeIdGsonAdapter getAdapter() { + return new NodeIdGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/NodeNameGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/NodeNameGsonAdapterTest.java new file mode 100644 index 0000000000000..ab3d2a052cc0b --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/NodeNameGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class NodeNameGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected NodeNameGsonAdapter getAdapter() { + return new NodeNameGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/NodeTypeGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/NodeTypeGsonAdapterTest.java new file mode 100644 index 0000000000000..b804c1aabac17 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/NodeTypeGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class NodeTypeGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected NodeTypeGsonAdapter getAdapter() { + return new NodeTypeGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/PasswordGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/PasswordGsonAdapterTest.java new file mode 100644 index 0000000000000..623528db505d5 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/PasswordGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class PasswordGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected PasswordGsonAdapter getAdapter() { + return new PasswordGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/ProductTypeGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/ProductTypeGsonAdapterTest.java new file mode 100644 index 0000000000000..02ee3525fc042 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/ProductTypeGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class ProductTypeGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected ProductTypeGsonAdapter getAdapter() { + return new ProductTypeGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/SessionIdGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/SessionIdGsonAdapterTest.java new file mode 100644 index 0000000000000..0f63f412368f3 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/SessionIdGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class SessionIdGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected SessionIdGsonAdapter getAdapter() { + return new SessionIdGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/UserIdGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/UserIdGsonAdapterTest.java new file mode 100644 index 0000000000000..fe4493016e0a2 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/UserIdGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class UserIdGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected UserIdGsonAdapter getAdapter() { + return new UserIdGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/UsernameGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/UsernameGsonAdapterTest.java new file mode 100644 index 0000000000000..f0b3355e8f417 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/UsernameGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class UsernameGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected UsernameGsonAdapter getAdapter() { + return new UsernameGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/ZonedDateTimeGsonAdapterTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/ZonedDateTimeGsonAdapterTest.java new file mode 100644 index 0000000000000..19f9845aac5f2 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/adapter/ZonedDateTimeGsonAdapterTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.adapter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class ZonedDateTimeGsonAdapterTest extends GsonAdapterTestBase { + @Override + protected ZonedDateTimeGsonAdapter getAdapter() { + return new ZonedDateTimeGsonAdapter(); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/repository/DefaultNodeRepositoryTest.java b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/repository/DefaultNodeRepositoryTest.java new file mode 100644 index 0000000000000..7c37e53785b16 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/java/org/openhab/binding/hive/internal/client/repository/DefaultNodeRepositoryTest.java @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hive.internal.client.repository; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.net.URI; +import java.util.Collections; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.openhab.binding.hive.internal.client.*; +import org.openhab.binding.hive.internal.client.dto.NodesDto; + +/** + * + * + * @author Ross Brown - Initial contribution + */ +@NonNullByDefault +public class DefaultNodeRepositoryTest { + @NonNullByDefault({}) + @Mock + private HiveApiRequestFactory requestFactory; + + @NonNullByDefault({}) + @Mock + private HiveApiRequest request; + + @NonNullByDefault({}) + @Mock + private HiveApiResponse response; + + @NonNullByDefault({}) + private NodesDto nodesDto; + + @Before + public void setUp() { + initMocks(this); + + this.nodesDto = new NodesDto(); + this.nodesDto.nodes = Collections.emptyList(); + } + + @Test + public void testGetNode() { + /* Given */ + when(this.requestFactory.newRequest(any())).thenReturn(this.request); + + when(this.request.accept(any())).thenReturn(this.request); + when(this.request.get()).thenReturn(this.response); + + when(this.response.getStatusCode()).thenReturn(200); + when(this.response.getContent(any())).thenReturn(this.nodesDto); + + final NodeId nodeId = new NodeId("deadbeef-dead-beef-dead-beefdeadbeef"); + + final DefaultNodeRepository nodeRepository = new DefaultNodeRepository(this.requestFactory); + + + /* When */ + nodeRepository.getNode(nodeId); + + + /* Then */ + verify(this.requestFactory, times(1)).newRequest(URI.create("nodes/deadbeef-dead-beef-dead-beefdeadbeef")); + } +} diff --git a/bundles/org.openhab.binding.hive/src/test/resources/exampleSessions.json b/bundles/org.openhab.binding.hive/src/test/resources/exampleSessions.json new file mode 100644 index 0000000000000..4f51e8b410a1c --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/resources/exampleSessions.json @@ -0,0 +1,15 @@ +{ + "meta": {}, + "links": {}, + "linked": {}, + "sessions": [ + { + "id": "mytoken", + "username": "hiveuser@example.com", + "userId": "deadbeef-dead-beef-dead-beefdeadbeef", + "extCustomerLevel": 1, + "latestSupportedApiVersion": "6", + "sessionId": "mytoken" + } + ] +} \ No newline at end of file diff --git a/bundles/org.openhab.binding.hive/src/test/resources/exampleThermostatNode.json b/bundles/org.openhab.binding.hive/src/test/resources/exampleThermostatNode.json new file mode 100644 index 0000000000000..9ddf01cbfd599 --- /dev/null +++ b/bundles/org.openhab.binding.hive/src/test/resources/exampleThermostatNode.json @@ -0,0 +1,1566 @@ +{ + "meta": {}, + "links": {}, + "linked": {}, + "nodes": [ + { + "id": "deadbeef-dead-beef-dead-beefdeadbeef", + "href": "https://api.prod.bgchprod.info/omnia/nodes/deadbeef-dead-beef-dead-beefdeadbeef", + "name": "Thermostat 1", + "nodeType": "http://alertme.com/schema/json/node.class.thermostat.json#", + "parentNodeId": "deadbeef-dead-beef-dead-beefdeadbeef", + "createdOn": 1513173613796, + "firstInstall": 1513173925623, + "userId": "deadbeef-dead-beef-dead-beefdeadbeef", + "ownerId": "deadbeef-dead-beef-dead-beefdeadbeef", + "homeId": "deadbeef-dead-beef-dead-beefdeadbeef", + "features": { + "autoboost_v1": { + "autoBoostDuration": { + "reportedValue": 30, + "displayValue": 30, + "reportReceivedTime": 1580088557573, + "reportChangedTime": 1580088557423 + }, + "autoBoostTargetHeatTemperature": { + "reportedValue": 19, + "displayValue": 19, + "reportReceivedTime": 1582534962795, + "reportChangedTime": 1582534962698 + }, + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.autoboost.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.autoboost.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.autoboost.v1.json#" + } + }, + "failure_alert_v1": { + "failureStatus": { + "reportedValue": "NORMAL", + "displayValue": "NORMAL", + "reportReceivedTime": 1580088560757, + "reportChangedTime": 1580088560428 + }, + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.failure_alert.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.failure_alert.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.failure_alert.v1.json#" + } + }, + "lifecycle_state_v1": { + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.lifecycle_state.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.lifecycle_state.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.lifecycle_state.v1.json#" + }, + "lifeCycleState": { + "reportedValue": "NORMAL", + "displayValue": "NORMAL", + "reportReceivedTime": 1580088569616, + "reportChangedTime": 1580088569252 + } + }, + "standby_v1": { + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.standby.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.standby.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.standby.v1.json#" + }, + "isActive": { + "reportedValue": false, + "displayValue": false, + "reportReceivedTime": 1582891616180, + "reportChangedTime": 1582891615961 + }, + "previousConfiguration": { + "reportedValue": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "operatingMode", + "value": "SCHEDULE" + }, + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ], + "displayValue": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "operatingMode", + "value": "SCHEDULE" + }, + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ], + "reportReceivedTime": 1582955849075, + "reportChangedTime": 1582955848675 + } + }, + "frost_protect_v1": { + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.frost_protect.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.frost_protect.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.frost_protect.v1.json#" + }, + "frostProtectTemperature": { + "reportedValue": 7, + "displayValue": 7, + "reportReceivedTime": 1580088582935, + "reportChangedTime": 1580088579088 + } + }, + "heating_temperature_control_v1": { + "controlMode": { + "reportedValue": "TPI", + "displayValue": "TPI", + "reportReceivedTime": 1580088577031, + "reportChangedTime": 1580088574442 + }, + "delayCompensatedTemperature": { + "reportedValue": 0, + "displayValue": 0, + "reportReceivedTime": 1580088624129, + "reportChangedTime": 1580088623620 + }, + "delayCompensationTime": { + "reportedValue": 0, + "displayValue": 0, + "reportReceivedTime": 1580088577312, + "reportChangedTime": 1580088574783 + }, + "errorIntegral": { + "reportedValue": 0.27, + "displayValue": 0.27, + "reportReceivedTime": 1583098705492, + "reportChangedTime": 1583098705425 + }, + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.heating_temperature_control.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.heating_temperature_control.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.heating_temperature_control.v1.json#" + }, + "heatingRateEstimate": { + "reportedValue": 124, + "displayValue": 124, + "reportReceivedTime": 1583049923890, + "reportChangedTime": 1583049923798 + }, + "minimumOffCycles": { + "reportedValue": 3, + "displayValue": 3, + "reportReceivedTime": 1580088577496, + "reportChangedTime": 1580088575039 + }, + "optimumStartAdvanceTimeFactor": { + "reportedValue": 100, + "displayValue": 100, + "reportReceivedTime": 1580088579476, + "reportChangedTime": 1580088576012 + }, + "optimumStartAdvanceTimeOffset": { + "reportedValue": 15, + "displayValue": 15, + "reportReceivedTime": 1580088578998, + "reportChangedTime": 1580088575778 + }, + "optimumStartEnabled": { + "reportedValue": false, + "displayValue": false, + "reportReceivedTime": 1580088576937, + "reportChangedTime": 1580088574444 + }, + "optimumStartMaximumAdvanceTime": { + "reportedValue": 60, + "displayValue": 60, + "reportReceivedTime": 1580088577731, + "reportChangedTime": 1580088575294 + }, + "optimumStartMinimumTemperatureChange": { + "reportedValue": 0.5, + "displayValue": 0.5, + "reportReceivedTime": 1580088578570, + "reportChangedTime": 1580088575573 + }, + "proportionalThreshold": { + "reportedValue": 0.05, + "displayValue": 0.05, + "reportReceivedTime": 1583049923780, + "reportChangedTime": 1583049923712 + } + }, + "device_alerts_v1": { + "deviceAlerts": { + "reportedValue": {}, + "displayValue": {}, + "reportReceivedTime": 1581538930290, + "reportChangedTime": 1581538930130 + }, + "deviceStatus": { + "reportedValue": "NORMAL", + "displayValue": "NORMAL", + "reportReceivedTime": 1581538930194, + "reportChangedTime": 1581538930131 + }, + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.device_alerts.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.device_alerts.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.device_alerts.v1.json#" + } + }, + "transient_mode_v1": { + "actions": { + "reportedValue": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "19.0" + } + ], + "displayValue": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "19.0" + } + ], + "reportReceivedTime": 1582924865774, + "reportChangedTime": 1582924865608 + }, + "duration": { + "reportedValue": 1800, + "displayValue": 1800, + "reportReceivedTime": 1582924866820, + "reportChangedTime": 1582924865663 + }, + "endDatetime": { + "reportedValue": "2020-03-01T22:05:44.442+0000", + "displayValue": "2020-03-01T22:05:44.442+0000", + "reportReceivedTime": 1583098545214, + "reportChangedTime": 1583098544465 + }, + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.transient_mode.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.transient_mode.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.transient_mode.v1.json#" + }, + "isEnabled": { + "reportedValue": true, + "displayValue": true, + "reportReceivedTime": 1580088563191, + "reportChangedTime": 1580088563131 + }, + "previousConfiguration": { + "reportedValue": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "operatingMode", + "value": "SCHEDULE" + }, + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ], + "displayValue": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "operatingMode", + "value": "SCHEDULE" + }, + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ], + "reportReceivedTime": 1582955849009, + "reportChangedTime": 1582955848647 + }, + "startDatetime": { + "reportedValue": "2020-03-01T21:35:44.442+0000", + "displayValue": "2020-03-01T21:35:44.442+0000", + "reportReceivedTime": 1583098545133, + "reportChangedTime": 1583098544444 + } + }, + "boilermodule_interlock_v1": { + "callingForHeatUUIDs": { + "reportedValue": [], + "displayValue": [], + "reportReceivedTime": 1583099141612, + "reportChangedTime": 1583099141438 + }, + "enableControlState": { + "reportedValue": "ENABLED", + "displayValue": "ENABLED", + "reportReceivedTime": 1582975130034, + "reportChangedTime": 1582975129955 + }, + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.boilermodule_interlock.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.boilermodule_interlock.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.boilermodule_interlock.v1.json#" + } + }, + "device_management_v1": { + "defaultNameFlag": { + "reportedValue": false, + "displayValue": false, + "reportReceivedTime": 1580088508559, + "reportChangedTime": 1580088468170 + }, + "deviceName": { + "reportedValue": "Thermostat 1", + "displayValue": "Thermostat 1", + "reportReceivedTime": 1580088508560, + "reportChangedTime": 1580088468159 + }, + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.device_management.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.device_management.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.device_management.v1.json#" + }, + "parentNodeId": { + "reportedValue": "deadbeef-dead-beef-dead-beefdeadbeef", + "displayValue": "deadbeef-dead-beef-dead-beefdeadbeef", + "reportReceivedTime": 1580088508560, + "reportChangedTime": 1580088468146 + }, + "productType": { + "reportedValue": "HEATING", + "displayValue": "HEATING", + "reportReceivedTime": 1580088569222, + "reportChangedTime": 1580088569075 + }, + "supportedFeatures": { + "reportedValue": [ + "http://alertme.com/schema/json/feature/node.feature.transient_mode.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.heating_temperature_control.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.lifecycle_state.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.autoboost.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.device_management.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.device_alerts.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.links.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.temperature_sensor.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.failure_alert.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.boilermodule_interlock.v1.json#", + "http://alertme.com/schema/json/node.class.thermostat.json#", + "http://alertme.com/schema/json/feature/node.feature.standby.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.frost_protect.v1.json#" + ], + "displayValue": [ + "http://alertme.com/schema/json/feature/node.feature.transient_mode.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.heating_temperature_control.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.lifecycle_state.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.autoboost.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.device_management.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.device_alerts.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.links.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.temperature_sensor.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.failure_alert.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.boilermodule_interlock.v1.json#", + "http://alertme.com/schema/json/node.class.thermostat.json#", + "http://alertme.com/schema/json/feature/node.feature.standby.v1.json#", + "http://alertme.com/schema/json/feature/node.feature.frost_protect.v1.json#" + ], + "reportReceivedTime": 1582099810519, + "reportChangedTime": 1582099810216 + } + }, + "heating_thermostat_v1": { + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#" + }, + "heatSchedule": { + "reportedValue": { + "scheduleType": "http://alertme.com/schema/json/configuration/configuration.device.schedule.weekly.v1.json#", + "maxNumSetpointsPerDay": 6, + "setpoints": [ + { + "dayIndex": 1, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + } + ], + "setpointOverridden": false + }, + "displayValue": { + "scheduleType": "http://alertme.com/schema/json/configuration/configuration.device.schedule.weekly.v1.json#", + "maxNumSetpointsPerDay": 6, + "setpoints": [ + { + "dayIndex": 1, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 1, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 2, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 3, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 4, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 5, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 6, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "05:45", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + }, + { + "dayIndex": 7, + "time": "22:00", + "actions": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "attribute": "mode", + "value": "OFF" + } + ] + } + ], + "setpointOverridden": false + }, + "reportReceivedTime": 1582896748230, + "reportChangedTime": 1582896748033 + }, + "maxHeatTargetTemperature": { + "reportedValue": 32, + "displayValue": 32, + "reportReceivedTime": 1580088554789, + "reportChangedTime": 1580088554543 + }, + "minHeatTargetTemperature": { + "reportedValue": 5, + "displayValue": 5, + "reportReceivedTime": 1580088554653, + "reportChangedTime": 1580088554593 + }, + "operatingMode": { + "reportedValue": "SCHEDULE", + "displayValue": "SCHEDULE", + "reportReceivedTime": 1582894946674, + "reportChangedTime": 1582894946331 + }, + "operatingState": { + "reportedValue": "OFF", + "displayValue": "OFF", + "reportReceivedTime": 1583099144393, + "reportChangedTime": 1583099143158 + }, + "operatingStateReason": { + "reportedValue": "NORMAL", + "displayValue": "NORMAL", + "reportReceivedTime": 1583099141806, + "reportChangedTime": 1583099141483 + }, + "previousConfiguration": { + "reportedValue": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "operatingMode", + "value": "SCHEDULE" + }, + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ], + "displayValue": [ + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "operatingMode", + "value": "SCHEDULE" + }, + { + "actionType": "http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#", + "featureType": "http://alertme.com/schema/json/feature/node.feature.heating_thermostat.v1.json#", + "attribute": "targetHeatTemperature", + "value": "14.0" + } + ], + "reportReceivedTime": 1582955848949, + "reportChangedTime": 1582955848624 + }, + "targetHeatTemperature": { + "reportedValue": 7, + "displayValue": 7, + "reportReceivedTime": 1583100005689, + "reportChangedTime": 1583100005567 + }, + "temporaryOperatingModeOverride": { + "reportedValue": "NONE", + "displayValue": "NONE", + "reportReceivedTime": 1583099143088, + "reportChangedTime": 1583099142419 + } + }, + "temperature_sensor_v1": { + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.temperature_sensor.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.temperature_sensor.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.temperature_sensor.v1.json#" + }, + "temperature": { + "reportedValue": 19, + "displayValue": 19, + "reportReceivedTime": 1583101678598, + "reportChangedTime": 1583101678475 + } + }, + "on_off_device_v1": { + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.on_off_device.v1.json#" + }, + "mode": { + "reportedValue": "ON", + "displayValue": "ON", + "reportReceivedTime": 1581357337075, + "reportChangedTime": 1581357336967 + } + }, + "links_v1": { + "featureType": { + "reportedValue": "http://alertme.com/schema/json/feature/node.feature.links.v1.json#", + "targetValue": "http://alertme.com/schema/json/feature/node.feature.links.v1.json#", + "displayValue": "http://alertme.com/schema/json/feature/node.feature.links.v1.json#" + }, + "reverseLinks": { + "reportedValue": [ + { + "bindingGroupIds": [ + "trvbm" + ], + "boundNode": "deadbeef-dead-beef-dead-beefdeadbeef" + }, + { + "bindingGroupIds": [ + "trvbm" + ], + "boundNode": "deadbeef-dead-beef-dead-beefdeadbeef" + } + ], + "displayValue": [ + { + "bindingGroupIds": [ + "trvbm" + ], + "boundNode": "deadbeef-dead-beef-dead-beefdeadbeef" + }, + { + "bindingGroupIds": [ + "trvbm" + ], + "boundNode": "deadbeef-dead-beef-dead-beefdeadbeef" + } + ], + "reportReceivedTime": 1582975101358, + "reportChangedTime": 1582975101227 + } + } + }, + "lastUpgradeSucceeded": false + } + ] +} \ No newline at end of file diff --git a/bundles/pom.xml b/bundles/pom.xml index 7cdae25280344..59d2316e64737 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -97,6 +97,7 @@ org.openhab.binding.hdpowerview org.openhab.binding.helios org.openhab.binding.heos + org.openhab.binding.hive org.openhab.binding.homematic org.openhab.binding.hpprinter org.openhab.binding.hue