]> git.basschouten.com Git - openhab-addons.git/blob
7fa9ef6e6f27e9d1b68e9cafcdaaa51f694f935b
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.nest.internal.wwn.handler;
14
15 import java.time.Instant;
16 import java.time.ZonedDateTime;
17 import java.util.Collection;
18 import java.util.Date;
19 import java.util.TimeZone;
20 import java.util.stream.Collectors;
21
22 import javax.measure.Quantity;
23 import javax.measure.Unit;
24
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.nest.internal.wwn.config.WWNDeviceConfiguration;
29 import org.openhab.binding.nest.internal.wwn.dto.WWNIdentifiable;
30 import org.openhab.binding.nest.internal.wwn.dto.WWNUpdateRequest;
31 import org.openhab.binding.nest.internal.wwn.listener.WWNThingDataListener;
32 import org.openhab.core.library.types.DateTimeType;
33 import org.openhab.core.library.types.DecimalType;
34 import org.openhab.core.library.types.OnOffType;
35 import org.openhab.core.library.types.QuantityType;
36 import org.openhab.core.library.types.StringType;
37 import org.openhab.core.thing.Bridge;
38 import org.openhab.core.thing.ChannelUID;
39 import org.openhab.core.thing.Thing;
40 import org.openhab.core.thing.ThingStatus;
41 import org.openhab.core.thing.ThingStatusDetail;
42 import org.openhab.core.thing.ThingStatusInfo;
43 import org.openhab.core.thing.binding.BaseThingHandler;
44 import org.openhab.core.types.State;
45 import org.openhab.core.types.UnDefType;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 /**
50  * Deals with the structures on the WWN API, turning them into a thing in openHAB.
51  *
52  * @author David Bennett - Initial contribution
53  * @author Martin van Wingerden - Splitted of NestBaseHandler
54  * @author Wouter Born - Add generic update data type
55  *
56  * @param <T> the type of update data
57  */
58 @NonNullByDefault
59 public abstract class WWNBaseHandler<@NonNull T> extends BaseThingHandler
60         implements WWNThingDataListener<T>, WWNIdentifiable {
61     private final Logger logger = LoggerFactory.getLogger(WWNBaseHandler.class);
62
63     private String deviceId = "";
64     private Class<T> dataClass;
65
66     WWNBaseHandler(Thing thing, Class<T> dataClass) {
67         super(thing);
68         this.dataClass = dataClass;
69     }
70
71     @Override
72     public void initialize() {
73         logger.debug("Initializing handler for {}", getClass().getName());
74
75         WWNAccountHandler handler = getAccountHandler();
76         if (handler != null) {
77             boolean success = handler.addThingDataListener(dataClass, getId(), this);
78             logger.debug("Adding {} with ID '{}' as device data listener, result: {}", getClass().getSimpleName(),
79                     getId(), success);
80         } else {
81             logger.debug("Unable to add {} with ID '{}' as device data listener because bridge is null",
82                     getClass().getSimpleName(), getId());
83         }
84
85         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Waiting for refresh");
86
87         final @Nullable T lastUpdate = getLastUpdate();
88         if (lastUpdate != null) {
89             update(null, lastUpdate);
90         }
91     }
92
93     @Override
94     public void dispose() {
95         WWNAccountHandler handler = getAccountHandler();
96         if (handler != null) {
97             handler.removeThingDataListener(dataClass, getId(), this);
98         }
99     }
100
101     protected @Nullable T getLastUpdate() {
102         WWNAccountHandler handler = getAccountHandler();
103         if (handler != null) {
104             return handler.getLastUpdate(dataClass, getId());
105         }
106         return null;
107     }
108
109     protected void addUpdateRequest(String updatePath, String field, Object value) {
110         WWNAccountHandler handler = getAccountHandler();
111         if (handler != null) {
112             handler.addUpdateRequest(new WWNUpdateRequest.Builder() //
113                     .withBasePath(updatePath) //
114                     .withIdentifier(getId()) //
115                     .withAdditionalValue(field, value) //
116                     .build());
117         }
118     }
119
120     @Override
121     public String getId() {
122         return getDeviceId();
123     }
124
125     protected String getDeviceId() {
126         String localDeviceId = deviceId;
127         if (localDeviceId.isEmpty()) {
128             localDeviceId = getConfigAs(WWNDeviceConfiguration.class).deviceId;
129             deviceId = localDeviceId;
130         }
131         return localDeviceId;
132     }
133
134     protected @Nullable WWNAccountHandler getAccountHandler() {
135         Bridge bridge = getBridge();
136         return bridge != null ? (WWNAccountHandler) bridge.getHandler() : null;
137     }
138
139     protected abstract State getChannelState(ChannelUID channelUID, T data);
140
141     protected State getAsDateTimeTypeOrNull(@Nullable Date date) {
142         if (date == null) {
143             return UnDefType.NULL;
144         }
145
146         long offsetMillis = TimeZone.getDefault().getOffset(date.getTime());
147         Instant instant = date.toInstant().plusMillis(offsetMillis);
148         return new DateTimeType(ZonedDateTime.ofInstant(instant, TimeZone.getDefault().toZoneId()));
149     }
150
151     protected State getAsDecimalTypeOrNull(@Nullable Integer value) {
152         return value == null ? UnDefType.NULL : new DecimalType(value);
153     }
154
155     protected State getAsOnOffTypeOrNull(@Nullable Boolean value) {
156         return value == null ? UnDefType.NULL : value ? OnOffType.ON : OnOffType.OFF;
157     }
158
159     protected <U extends Quantity<U>> State getAsQuantityTypeOrNull(@Nullable Number value, Unit<U> unit) {
160         return value == null ? UnDefType.NULL : new QuantityType<>(value, unit);
161     }
162
163     protected State getAsStringTypeOrNull(@Nullable Object value) {
164         return value == null ? UnDefType.NULL : new StringType(value.toString());
165     }
166
167     protected State getAsStringTypeListOrNull(@Nullable Collection<@NonNull ?> values) {
168         return values == null || values.isEmpty() ? UnDefType.NULL
169                 : new StringType(values.stream().map(value -> value.toString()).collect(Collectors.joining(",")));
170     }
171
172     protected boolean isNotHandling(WWNIdentifiable nestIdentifiable) {
173         return !(getId().equals(nestIdentifiable.getId()));
174     }
175
176     protected void updateLinkedChannels(@Nullable T oldData, T data) {
177         getThing().getChannels().stream().map(channel -> channel.getUID()).filter(this::isLinked)
178                 .forEach(channelUID -> {
179                     State newState = getChannelState(channelUID, data);
180                     if (oldData == null || !getChannelState(channelUID, oldData).equals(newState)) {
181                         logger.debug("Updating {}", channelUID);
182                         updateState(channelUID, newState);
183                     }
184                 });
185     }
186
187     @Override
188     public void onNewData(T data) {
189         update(null, data);
190     }
191
192     @Override
193     public void onUpdatedData(T oldData, T data) {
194         update(oldData, data);
195     }
196
197     @Override
198     public void onMissingData(String nestId) {
199         thing.setStatusInfo(
200                 new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.GONE, "Missing from streaming updates"));
201     }
202
203     protected abstract void update(@Nullable T oldData, T data);
204 }