]> git.basschouten.com Git - openhab-addons.git/blob
9a9e045ca88275c39cef1bff029cfa664ed1d485
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.boschshc.internal.services;
14
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.TimeoutException;
17 import java.util.function.Consumer;
18
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;
27
28 import com.google.gson.JsonElement;
29
30 /**
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/
34  * 
35  * @author Christian Oeing - Initial contribution
36  */
37 @NonNullByDefault
38 public abstract class BoschSHCService<TState extends BoschSHCServiceState> {
39
40     protected final Logger logger = LoggerFactory.getLogger(BoschSHCService.class);
41
42     /**
43      * Unique service name
44      */
45     private final String serviceName;
46
47     /**
48      * Class of service state
49      */
50     private final Class<TState> stateClass;
51
52     /**
53      * Bridge to use for communication from/to the device
54      */
55     private @Nullable BridgeHandler bridgeHandler;
56
57     /**
58      * Id of device the service belongs to
59      */
60     private @Nullable String deviceId;
61
62     /**
63      * Function to call after receiving state updates from the device
64      */
65     private @Nullable Consumer<TState> stateUpdateListener;
66
67     /**
68      * Constructor
69      * 
70      * @param serviceName Unique name of the service.
71      * @param stateClass State class that this service uses for data transfers
72      *            from/to the device.
73      */
74     protected BoschSHCService(String serviceName, Class<TState> stateClass) {
75         this.serviceName = serviceName;
76         this.stateClass = stateClass;
77     }
78
79     /**
80      * Initializes the service
81      * 
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
85      *            from the device.
86      */
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;
92     }
93
94     /**
95      * Returns the unique name of this service.
96      * 
97      * @return Unique name of the service.
98      */
99     public String getServiceName() {
100         return this.serviceName;
101     }
102
103     /**
104      * Returns the class of the state this service provides.
105      * 
106      * @return Class of the state this service provides.
107      */
108     public Class<TState> getStateClass() {
109         return this.stateClass;
110     }
111
112     /**
113      * Requests the current state of the service and updates it.
114      * 
115      * @throws ExecutionException
116      * @throws TimeoutException
117      * @throws InterruptedException
118      * @throws BoschSHCException
119      */
120     public void refreshState() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
121         @Nullable
122         TState state = this.getState();
123         if (state != null) {
124             this.onStateUpdate(state);
125         }
126     }
127
128     /**
129      * Requests the current state of the device with the specified id.
130      * 
131      * @return Current state of the device.
132      * @throws ExecutionException
133      * @throws TimeoutException
134      * @throws InterruptedException
135      * @throws BoschSHCException
136      */
137     public @Nullable TState getState()
138             throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
139         String deviceId = this.deviceId;
140         if (deviceId == null) {
141             return null;
142         }
143         BridgeHandler bridgeHandler = this.bridgeHandler;
144         if (bridgeHandler == null) {
145             return null;
146         }
147         return bridgeHandler.getState(deviceId, this.serviceName, this.stateClass);
148     }
149
150     /**
151      * Sets the state of the device with the specified id.
152      * 
153      * @param state State to set.
154      * @throws InterruptedException
155      * @throws ExecutionException
156      * @throws TimeoutException
157      */
158     public void setState(TState state) throws InterruptedException, TimeoutException, ExecutionException {
159         String deviceId = this.deviceId;
160         if (deviceId == null) {
161             return;
162         }
163         BridgeHandler bridgeHandler = this.bridgeHandler;
164         if (bridgeHandler == null) {
165             return;
166         }
167         bridgeHandler.putState(deviceId, this.serviceName, state);
168     }
169
170     /**
171      * A state update was received from the bridge
172      * 
173      * @param stateData Current state of service. Serialized as JSON.
174      */
175     public void onStateUpdate(JsonElement stateData) {
176         @Nullable
177         TState state = BoschSHCServiceState.fromJson(stateData, this.stateClass);
178         if (state == null) {
179             this.logger.warn("Received invalid, expected type {}", this.stateClass.getName());
180             return;
181         }
182         this.onStateUpdate(state);
183     }
184
185     /**
186      * A state update was received from the bridge.
187      * 
188      * @param state Current state of service as an instance of the state class.
189      */
190     private void onStateUpdate(TState state) {
191         Consumer<TState> stateUpdateListener = this.stateUpdateListener;
192         if (stateUpdateListener != null) {
193             stateUpdateListener.accept(state);
194         }
195     }
196
197     /**
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.
200      * 
201      * @param command Command to handle
202      * @throws BoschSHCException If service can not handle command
203      */
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()));
207     }
208 }