2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.boschshc.internal.services;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.TimeoutException;
17 import java.util.function.Consumer;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
22 import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
23 import org.openhab.binding.boschshc.internal.services.dto.BoschSHCServiceState;
24 import org.openhab.core.types.Command;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
28 import com.google.gson.JsonElement;
31 * Base class of a service of a Bosch Smart Home device. The services of the
32 * devices and their official APIs can be found here:
33 * https://apidocs.bosch-smarthome.com/local/
35 * @author Christian Oeing - Initial contribution
38 public abstract class BoschSHCService<TState extends BoschSHCServiceState> {
40 protected final Logger logger = LoggerFactory.getLogger(BoschSHCService.class);
45 private final String serviceName;
48 * Class of service state
50 private final Class<TState> stateClass;
53 * Bridge to use for communication from/to the device
55 private @Nullable BridgeHandler bridgeHandler;
58 * Id of device the service belongs to
60 private @Nullable String deviceId;
63 * Function to call after receiving state updates from the device
65 private @Nullable Consumer<TState> stateUpdateListener;
70 * @param serviceName Unique name of the service.
71 * @param stateClass State class that this service uses for data transfers
74 protected BoschSHCService(String serviceName, Class<TState> stateClass) {
75 this.serviceName = serviceName;
76 this.stateClass = stateClass;
80 * Initializes the service
82 * @param bridgeHandler Bridge to use for communication from/to the device
83 * @param deviceId Id of device this service is for
84 * @param stateUpdateListener Function to call when a state update was received
87 public void initialize(BridgeHandler bridgeHandler, String deviceId,
88 @Nullable Consumer<TState> stateUpdateListener) {
89 this.bridgeHandler = bridgeHandler;
90 this.deviceId = deviceId;
91 this.stateUpdateListener = stateUpdateListener;
95 * Returns the unique name of this service.
97 * @return Unique name of the service.
99 public String getServiceName() {
100 return this.serviceName;
104 * Returns the class of the state this service provides.
106 * @return Class of the state this service provides.
108 public Class<TState> getStateClass() {
109 return this.stateClass;
113 * Requests the current state of the service and updates it.
115 * @throws ExecutionException
116 * @throws TimeoutException
117 * @throws InterruptedException
118 * @throws BoschSHCException
120 public void refreshState() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
122 TState state = this.getState();
124 this.onStateUpdate(state);
129 * Requests the current state of the device with the specified id.
131 * @return Current state of the device.
132 * @throws ExecutionException
133 * @throws TimeoutException
134 * @throws InterruptedException
135 * @throws BoschSHCException
137 public @Nullable TState getState()
138 throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
139 String deviceId = this.deviceId;
140 if (deviceId == null) {
143 BridgeHandler bridgeHandler = this.bridgeHandler;
144 if (bridgeHandler == null) {
147 return bridgeHandler.getState(deviceId, this.serviceName, this.stateClass);
151 * Sets the state of the device with the specified id.
153 * @param state State to set.
154 * @throws InterruptedException
155 * @throws ExecutionException
156 * @throws TimeoutException
158 public void setState(TState state) throws InterruptedException, TimeoutException, ExecutionException {
159 String deviceId = this.deviceId;
160 if (deviceId == null) {
163 BridgeHandler bridgeHandler = this.bridgeHandler;
164 if (bridgeHandler == null) {
167 bridgeHandler.putState(deviceId, this.serviceName, state);
171 * A state update was received from the bridge
173 * @param stateData Current state of service. Serialized as JSON.
175 public void onStateUpdate(JsonElement stateData) {
177 TState state = BoschSHCServiceState.fromJson(stateData, this.stateClass);
179 this.logger.warn("Received invalid, expected type {}", this.stateClass.getName());
182 this.onStateUpdate(state);
186 * A state update was received from the bridge.
188 * @param state Current state of service as an instance of the state class.
190 private void onStateUpdate(TState state) {
191 Consumer<TState> stateUpdateListener = this.stateUpdateListener;
192 if (stateUpdateListener != null) {
193 stateUpdateListener.accept(state);
198 * Allows a service to handle a command and create a new state out of it.
199 * The new state still has to be set via setState.
201 * @param command Command to handle
202 * @throws BoschSHCException If service can not handle command
204 public TState handleCommand(Command command) throws BoschSHCException {
205 throw new BoschSHCException(
206 String.format("%s: Can not handle command %s", this.getServiceName(), command.getClass().getName()));