Skip to content

Commit

Permalink
Merge branch hive/develop into hive/master
Browse files Browse the repository at this point in the history
  • Loading branch information
rbrownwsws committed Apr 19, 2020
1 parent abf12dc commit c984c89
Show file tree
Hide file tree
Showing 127 changed files with 4,349 additions and 1,130 deletions.
30 changes: 19 additions & 11 deletions bundles/org.openhab.binding.hive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ _N.B. You can only get the nodeId of things by querying the Hive API. This is w

### Hive Account

No channels (just acts as a bridge)
#### Advanced channels

| Channel | Type | Read/Write | Description |
|----------------------------|--------------------------|--------------|------------------------------|
| last_poll_timestamp | DateTime | Read Only | The last time this Hive Account thing polled the Hive API. (Mainly for debugging) |
| dump_nodes | Switch | Read/Write | Turning this on triggers dumping the nodes reported by the Hive API for this account to a file in the "userdata" directory. (For debugging) |


### Hive Boiler Module

Expand All @@ -76,16 +82,17 @@ No channels (just acts as a bridge)

#### Basic channels

| Channel | Type | Read/Write | Description |
|--------------------------|--------------------|--------------|------------------------------|
| temperature-current | Number:Temperature | Read Only | The current temperature of the zone. Only in Celsius for now. |
| temperature-target | Number:Temperature | Read/Write | The temperature you want the zone to be heated to. Only in Celsius for now. |
| easy-mode-operating | String | Read/Write | The operating mode of heating in this zone as in app (Manual / Schedule/ Off). |
| easy-mode-boost | Switch | Read/Write | Is the transient override (boost) active for this zone. (Handles API trickiness for you). |
| easy-state-is_on | Switch | Read Only | Is the heating currently active in this zone? |
| temperature-target-boost | Number:Temperature | Read/Write | The temperature you want the zone to be heated to when the transient override (boost) is active. Only in Celsius for now. |
| transient-duration | Number | Read/Write | How long in minutes the transient override (boost) should be active for once started. |
| transient-remaining | Number | Read Only | If `transient-end_time` is in the future and the transient override (boost) is active: the time between now and `transient-end_time` in minutes, otherwise 0. |
| Channel | Type | Read/Write | Description |
|-------------------------------|--------------------|--------------|------------------------------|
| temperature-current | Number:Temperature | Read Only | The current temperature of the zone. Only in Celsius for now. |
| temperature-target | Number:Temperature | Read/Write | The temperature you want the zone to be heated to. Only in Celsius for now. |
| easy-mode-operating | String | Read/Write | The operating mode of heating in this zone as in app (Manual / Schedule/ Off). |
| easy-mode-boost | Switch | Read/Write | Is the transient override (boost) active for this zone. (Handles API trickiness for you). |
| easy-state-is_on | Switch | Read Only | Is the heating currently active in this zone? |
| temperature-target-boost | Number:Temperature | Read/Write | The temperature you want the zone to be heated to when the transient override (boost) is active. Only in Celsius for now. |
| transient-duration | Number | Read/Write | How long in minutes the transient override (boost) should be active for once started. |
| transient-remaining | Number | Read Only | If `transient-end_time` is in the future and the transient override (boost) is active: the time between now and `transient-end_time` in minutes, otherwise 0. |
| auto_boost-temperature-target | Number:Temperature | Read/Write | The max temperature you want the zone to be heated to when auto boost (heating-on-demand) is active. Only in Celsius for now. |

#### Advanced Channels

Expand All @@ -98,6 +105,7 @@ No channels (just acts as a bridge)
| transient-enabled | Switch | Read/Write | Is the transient override (boost) enabled for this zone. |
| transient-start_time | DateTime | Read Only | The last time the transient override (boost) was started. |
| transient-end_time | DateTime | Read Only | The last time the transient override (boost) was scheduled to end (even if it was cancelled). |
| auto_boost-duration | Number | Read/Write | How long in minutes the auto boost (heating-on-demand boost) should be active for once started. |

### Hive Hot Water

Expand Down
9 changes: 9 additions & 0 deletions bundles/org.openhab.binding.hive/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,21 @@
</properties>

<dependencies>
<!-- Fluent assertions -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.15.0</version>
<scope>test</scope>
</dependency>

<!-- Automated equals() and hashCode() testing -->
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.1.13</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ public final class HiveBindingConstants {
// @formatter:on

/* ######## Channel ids ######## */
/**
* Name of the channel that represents how long an auto boost
* (heat-on-demand boost) should be in minutes.
*/
public static final String CHANNEL_AUTO_BOOST_DURATION = "auto_boost-duration";

/**
* Name of the channel that represents the target heating temperature for a
* Hive heating zone when auto boost (heating-on-demand) is active.
*/
public static final String CHANNEL_AUTO_BOOST_TEMPERATURE_TARGET = "auto_boost-temperature-target";

/**
* Name of the channel that represents a simplified view of the heating/
* hot water operating mode that matches the app (e.g. ON / SCHEDULE / OFF)
Expand Down Expand Up @@ -250,6 +262,18 @@ public final class HiveBindingConstants {
*/
public static final String CHANNEL_RADIO_RSSI_LAST_KNOWN = "radio-rssi-last_known";

/**
* Name of the channel that represents the last time a HiveAccount thing
* polled the Hive API.
*/
public static final String CHANNEL_LAST_POLL_TIMESTAMP = "last_poll_timestamp";

/**
* Name of the channel used to trigger a dumping all the node information
* for the linked Hive Account.
*/
public static final String CHANNEL_DUMP_NODES = "dump_nodes";


/* ######## Config params ######## */
/**
Expand All @@ -270,6 +294,8 @@ public final class HiveBindingConstants {
public static final String HOT_WATER_EASY_MODE_OPERATING_SCHEDULE = "SCHEDULE";
public static final String HOT_WATER_EASY_MODE_OPERATING_OFF = "OFF";

public static final String PROPERTY_EUI64 = "EUI64";

private HiveBindingConstants() {
throw new AssertionError();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
*/
package org.openhab.binding.hive.internal;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.smarthome.config.discovery.DiscoveryService;
import org.eclipse.smarthome.core.thing.Bridge;
import org.eclipse.smarthome.core.thing.Thing;
Expand All @@ -26,10 +27,18 @@
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.eclipse.smarthome.io.net.http.HttpClientFactory;
import org.openhab.binding.hive.internal.client.DefaultHiveClientFactory;
import org.openhab.binding.hive.internal.client.HiveClientFactory;
import org.openhab.binding.hive.internal.discovery.DefaultHiveDiscoveryService;
import org.openhab.binding.hive.internal.handler.DefaultHiveAccountHandler;
import org.openhab.binding.hive.internal.handler.DefaultHiveThingHandler;
import org.openhab.binding.hive.internal.handler.strategy.*;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -42,28 +51,101 @@
@NonNullByDefault
@Component(configurationPid = "binding.hive", service = ThingHandlerFactory.class)
public final class HiveHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingHandlerStrategy> STRATEGIES_BOILER_MODULE = Collections.unmodifiableSet(Stream.of(
PhysicalDeviceHandlerStrategy.getInstance(),
ZigbeeDeviceHandlerStrategy.getInstance()
).collect(Collectors.toSet()));

private static final Set<ThingHandlerStrategy> STRATEGIES_HEATING = Collections.unmodifiableSet(Stream.of(
AutoBoostHandlerStrategy.getInstance(),
BoostTimeRemainingHandlerStrategy.getInstance(),
HeatingThermostatHandlerStrategy.getInstance(),
OnOffDeviceHandlerStrategy.getInstance(),
TemperatureSensorHandlerStrategy.getInstance(),
TransientModeHandlerStrategy.getInstance(),
HeatingTransientModeHandlerStrategy.getInstance(),
HeatingThermostatEasyHandlerStrategy.getInstance()
).collect(Collectors.toSet()));

private static final Set<ThingHandlerStrategy> STRATEGIES_HOT_WATER = Collections.unmodifiableSet(Stream.of(
BoostTimeRemainingHandlerStrategy.getInstance(),
OnOffDeviceHandlerStrategy.getInstance(),
TransientModeHandlerStrategy.getInstance(),
WaterHeaterHandlerStrategy.getInstance(),
WaterHeaterEasyHandlerStrategy.getInstance()
).collect(Collectors.toSet()));

private static final Set<ThingHandlerStrategy> STRATEGIES_HUB = Collections.unmodifiableSet(Stream.of(
PhysicalDeviceHandlerStrategy.getInstance()
).collect(Collectors.toSet()));

private static final Set<ThingHandlerStrategy> STRATEGIES_THERMOSTAT = Collections.unmodifiableSet(Stream.of(
BatteryDeviceHandlerStrategy.getInstance(),
PhysicalDeviceHandlerStrategy.getInstance(),
ZigbeeDeviceHandlerStrategy.getInstance()
).collect(Collectors.toSet()));

private static final Set<ThingHandlerStrategy> STRATEGIES_TRV_GROUP = Collections.unmodifiableSet(Stream.of(
BoostTimeRemainingHandlerStrategy.getInstance(),
HeatingThermostatHandlerStrategy.getInstance(),
OnOffDeviceHandlerStrategy.getInstance(),
TemperatureSensorHandlerStrategy.getInstance(),
TransientModeHandlerStrategy.getInstance(),
HeatingTransientModeHandlerStrategy.getInstance(),
HeatingThermostatEasyHandlerStrategy.getInstance()
).collect(Collectors.toSet()));

private static final Set<ThingHandlerStrategy> STRATEGIES_TRV = Collections.unmodifiableSet(Stream.of(
BatteryDeviceHandlerStrategy.getInstance(),
PhysicalDeviceHandlerStrategy.getInstance(),
TemperatureSensorHandlerStrategy.getInstance(),
ZigbeeDeviceHandlerStrategy.getInstance()
).collect(Collectors.toSet()));

private final Logger logger = LoggerFactory.getLogger(HiveHandlerFactory.class);

private final Map<ThingUID, @Nullable ServiceRegistration<?>> discoveryServices = new HashMap<>();
private final Map<ThingUID, ServiceRegistration<?>> discoveryServices = new HashMap<>();

private final HttpClient httpClient;
private final HiveClientFactory hiveClientFactory;

@Activate
public HiveHandlerFactory(@Reference final HttpClientFactory httpClientFactory) {
final HttpClient httpClient = httpClientFactory.createHttpClient("HiveBinding");
try {
httpClient.start();
} catch (Exception ex) {
// Wrap up all exceptions and throw a runtime exception as there
// is nothing we can do to recover.
throw new IllegalStateException("Could not start HttpClient.", ex);
}

public HiveHandlerFactory() {
super();
// Keep a copy of HttpClient so we can clean up later
this.httpClient = httpClient;
this.hiveClientFactory = new DefaultHiveClientFactory(httpClient);
}

@Override
protected void activate(final ComponentContext componentContext) {
super.activate(componentContext);

// Help keep track of when openHAB reloads binding while debugging.
logger.trace("Handler has been activated");
this.logger.trace("HandlerFactory has been activated");
}

@Override
protected void deactivate(final ComponentContext componentContext) {
super.deactivate(componentContext);

// Help keep track of when openHAB reloads binding while debugging.
logger.trace("Handler has been deactivated");
this.logger.trace("HandlerFactory has been deactivated");

// Clean up HttpClient
try {
httpClient.stop();
} catch (Exception ignored) {
// Don't care, just trying to clean up.
}
}

@Override
Expand All @@ -77,7 +159,11 @@ public boolean supportsThingType(final ThingTypeUID thingTypeUID) {

if (HiveBindingConstants.THING_TYPE_ACCOUNT.equals(thingTypeUID)) {
// Create the handler
final HiveAccountHandler handler = new HiveAccountHandler((Bridge) thing);
final DefaultHiveAccountHandler handler = new DefaultHiveAccountHandler(
this.hiveClientFactory,
DefaultHiveDiscoveryService::new,
(Bridge) thing
);

// Register the discovery service and keep track of it so we can
// unregister it later.
Expand All @@ -91,34 +177,33 @@ public boolean supportsThingType(final ThingTypeUID thingTypeUID) {

return handler;
} else if (HiveBindingConstants.THING_TYPE_BOILER_MODULE.equals(thingTypeUID)) {
return new HiveBoilerModuleHandler(thing);
return new DefaultHiveThingHandler(thing, STRATEGIES_BOILER_MODULE);
} else if (HiveBindingConstants.THING_TYPE_HEATING.equals(thingTypeUID)) {
return new HiveHeatingHandler(thing);
return new DefaultHiveThingHandler(thing, STRATEGIES_HEATING);
} else if (HiveBindingConstants.THING_TYPE_HOT_WATER.equals(thingTypeUID)) {
return new HiveHotWaterHandler(thing);
return new DefaultHiveThingHandler(thing, STRATEGIES_HOT_WATER);
} else if (HiveBindingConstants.THING_TYPE_HUB.equals(thingTypeUID)) {
return new HiveHubHandler(thing);
return new DefaultHiveThingHandler(thing, STRATEGIES_HUB);
} else if (HiveBindingConstants.THING_TYPE_THERMOSTAT.equals(thingTypeUID)) {
return new HiveThermostatHandler(thing);
return new DefaultHiveThingHandler(thing, STRATEGIES_THERMOSTAT);
} else if (HiveBindingConstants.THING_TYPE_TRV.equals(thingTypeUID)) {
return new HiveTrvHandler(thing);
return new DefaultHiveThingHandler(thing, STRATEGIES_TRV);
} else if (HiveBindingConstants.THING_TYPE_TRV_GROUP.equals(thingTypeUID)) {
return new HiveTrvGroupHandler(thing);
return new DefaultHiveThingHandler(thing, STRATEGIES_TRV_GROUP);
}

return null;
}

@Override
protected void removeHandler(final ThingHandler thingHandler) {
logger.trace("Removing handler");
if (thingHandler instanceof HiveAccountHandler) {
logger.trace("Handler is bridge");
if (thingHandler instanceof DefaultHiveAccountHandler) {
this.logger.trace("Removing bridge");
// Clean up associated discovery service.
final @Nullable ServiceRegistration<?> serviceReg = this.discoveryServices.remove(thingHandler.getThing().getUID());

if (serviceReg != null) {
logger.trace("Unregistered service");
this.logger.trace("Unregistered discovery service");
serviceReg.unregister();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package org.openhab.binding.hive.internal.client;

import java.net.URI;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
Expand All @@ -20,10 +22,10 @@
* @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 final class ActionType extends SimpleValueTypeBase<URI> {
public static final ActionType GENERIC = new ActionType(URI.create("http://alertme.com/schema/json/configuration/configuration.device.action.generic.v1.json#"));

public ActionType(final String stringValue) {
super(stringValue);
public ActionType(final URI actionType) {
super(actionType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
* @author Ross Brown - Initial contribution
*/
@NonNullByDefault
public final class AttributeName extends StringTypeBase {
public final class AttributeName extends SimpleValueTypeBase<String> {
public static final AttributeName ATTRIBUTE_NAME_TARGET_HEAT_TEMPERATURE = new AttributeName("targetHeatTemperature");
public static final AttributeName ATTRIBUTE_NAME_MODE = new AttributeName("mode");

public AttributeName(final String stringValue) {
super(stringValue);
public AttributeName(final String attributeName) {
super(attributeName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.Objects;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

/**
*
Expand All @@ -23,7 +24,7 @@
*/
@NonNullByDefault
public final class BatteryLevel {
private int value;
private final int value;

public BatteryLevel(int value) {
if (value < 0 || value > 100) {
Expand All @@ -37,9 +38,8 @@ public int intValue() {
return value;
}

@NonNullByDefault({})
@Override
public boolean equals(Object o) {
public boolean equals(final @Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
Expand Down
Loading

0 comments on commit c984c89

Please sign in to comment.