]> git.basschouten.com Git - openhab-addons.git/blob
7ae12b2f783d9560cd251a179fe933417f666055
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.dwdunwetter.internal.handler;
14
15 import static org.openhab.binding.dwdunwetter.internal.DwdUnwetterBindingConstants.*;
16
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.dwdunwetter.internal.config.DwdUnwetterConfiguration;
25 import org.openhab.binding.dwdunwetter.internal.data.DwdWarningsData;
26 import org.openhab.core.library.types.DateTimeType;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.thing.Channel;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingStatus;
32 import org.openhab.core.thing.binding.BaseThingHandler;
33 import org.openhab.core.thing.binding.builder.ChannelBuilder;
34 import org.openhab.core.thing.type.ChannelKind;
35 import org.openhab.core.thing.type.ChannelTypeUID;
36 import org.openhab.core.types.Command;
37 import org.openhab.core.types.RefreshType;
38 import org.openhab.core.types.State;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * The {@link DwdUnwetterHandler} is responsible for handling commands, which are sent to one of the channels.
44  *
45  * @author Martin Koehler - Initial contribution
46  */
47 @NonNullByDefault
48 public class DwdUnwetterHandler extends BaseThingHandler {
49
50     private final Logger logger = LoggerFactory.getLogger(DwdUnwetterHandler.class);
51
52     private @Nullable ScheduledFuture<?> refreshJob;
53     private int warningCount;
54     private @Nullable DwdWarningsData data;
55
56     private boolean inRefresh;
57     private boolean initializing;
58
59     public DwdUnwetterHandler(Thing thing) {
60         super(thing);
61     }
62
63     @Override
64     public void handleCommand(ChannelUID channelUID, Command command) {
65         if (command instanceof RefreshType) {
66             scheduler.submit(this::refresh);
67         }
68     }
69
70     /**
71      * Refreshes the Warning Data.
72      *
73      * The Switch Channel is switched to ON only after all other Channels are updated.
74      * The Switch Channel is switched to OFF before all other Channels are updated.
75      */
76     private void refresh() {
77         if (inRefresh) {
78             logger.trace("Already refreshing. Ignoring refresh request.");
79             return;
80         }
81
82         if (initializing) {
83             logger.trace("Still initializing. Ignoring refresh request.");
84             return;
85         }
86
87         ThingStatus status = getThing().getStatus();
88         if (status != ThingStatus.ONLINE && status != ThingStatus.UNKNOWN) {
89             logger.debug("Unable to refresh. Thing status is {}", status);
90             return;
91         }
92
93         final DwdWarningsData warningsData = data;
94         if (warningsData == null) {
95             logger.debug("Unable to refresh. No data to use.");
96             return;
97         }
98
99         inRefresh = true;
100
101         boolean refreshSucceeded = warningsData.refresh();
102         if (!refreshSucceeded) {
103             logger.debug("Failed to retrieve new data from the server.");
104             inRefresh = false;
105             return;
106         }
107
108         if (status == ThingStatus.UNKNOWN) {
109             updateStatus(ThingStatus.ONLINE);
110         }
111
112         updateState(getChannelUuid(CHANNEL_LAST_UPDATED), new DateTimeType());
113
114         for (int i = 0; i < warningCount; i++) {
115             State warning = warningsData.getWarning(i);
116             if (warning == OnOffType.OFF) {
117                 updateState(getChannelUuid(CHANNEL_WARNING, i), warning);
118             }
119             updateState(getChannelUuid(CHANNEL_SEVERITY, i), warningsData.getSeverity(i));
120             updateState(getChannelUuid(CHANNEL_DESCRIPTION, i), warningsData.getDescription(i));
121             updateState(getChannelUuid(CHANNEL_EFFECTIVE, i), warningsData.getEffective(i));
122             updateState(getChannelUuid(CHANNEL_EXPIRES, i), warningsData.getExpires(i));
123             updateState(getChannelUuid(CHANNEL_ONSET, i), warningsData.getOnset(i));
124             updateState(getChannelUuid(CHANNEL_EVENT, i), warningsData.getEvent(i));
125             updateState(getChannelUuid(CHANNEL_HEADLINE, i), warningsData.getHeadline(i));
126             updateState(getChannelUuid(CHANNEL_ALTITUDE, i), warningsData.getAltitude(i));
127             updateState(getChannelUuid(CHANNEL_CEILING, i), warningsData.getCeiling(i));
128             updateState(getChannelUuid(CHANNEL_INSTRUCTION, i), warningsData.getInstruction(i));
129             updateState(getChannelUuid(CHANNEL_URGENCY, i), warningsData.getUrgency(i));
130             if (warning == OnOffType.ON) {
131                 updateState(getChannelUuid(CHANNEL_WARNING, i), warning);
132             }
133             if (warningsData.isNew(i)) {
134                 triggerChannel(getChannelUuid(CHANNEL_UPDATED, i), "NEW");
135             }
136         }
137
138         warningsData.updateCache();
139         inRefresh = false;
140     }
141
142     @Override
143     public void initialize() {
144         logger.debug("Start initializing!");
145         initializing = true;
146         updateStatus(ThingStatus.UNKNOWN);
147
148         DwdUnwetterConfiguration config = getConfigAs(DwdUnwetterConfiguration.class);
149         warningCount = config.warningCount;
150
151         data = new DwdWarningsData(config.cellId);
152
153         updateThing(editThing().withChannels(createChannels()).build());
154
155         refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, config.refresh, TimeUnit.MINUTES);
156         initializing = false;
157         logger.debug("Finished initializing!");
158     }
159
160     private ChannelUID getChannelUuid(String typeId, int warningNumber) {
161         return new ChannelUID(getThing().getUID(), typeId + (warningNumber + 1));
162     }
163
164     private ChannelUID getChannelUuid(String typeId) {
165         return new ChannelUID(getThing().getUID(), typeId);
166     }
167
168     /**
169      * Creates a trigger Channel.
170      */
171     private Channel createTriggerChannel(String typeId, String label, int warningNumber) {
172         ChannelUID channelUID = getChannelUuid(typeId, warningNumber);
173         return ChannelBuilder.create(channelUID, "String") //
174                 .withType(new ChannelTypeUID(BINDING_ID, typeId)) //
175                 .withLabel(label + " (" + (warningNumber + 1) + ")")//
176                 .withKind(ChannelKind.TRIGGER) //
177                 .build();
178     }
179
180     /**
181      * Creates a normal, state based, channel associated with a warning.
182      */
183     private Channel createChannel(String typeId, String itemType, String label, int warningNumber) {
184         ChannelUID channelUID = getChannelUuid(typeId, warningNumber);
185         return ChannelBuilder.create(channelUID, itemType) //
186                 .withType(new ChannelTypeUID(BINDING_ID, typeId)) //
187                 .withLabel(label + " (" + (warningNumber + 1) + ")")//
188                 .build();
189     }
190
191     /**
192      * Creates a normal, state based, channel not associated with a warning.
193      */
194     private Channel createChannel(String typeId, String itemType, String label) {
195         ChannelUID channelUID = getChannelUuid(typeId);
196         return ChannelBuilder.create(channelUID, itemType) //
197                 .withType(new ChannelTypeUID(BINDING_ID, typeId)) //
198                 .withLabel(label)//
199                 .build();
200     }
201
202     /**
203      * Creates the ChannelsT for each warning.
204      *
205      * @return The List of Channels
206      */
207     private List<Channel> createChannels() {
208         List<Channel> channels = new ArrayList<>(warningCount * 11 + 1);
209         channels.add(createChannel(CHANNEL_LAST_UPDATED, "DateTime", "Last Updated"));
210         for (int i = 0; i < warningCount; i++) {
211             channels.add(createChannel(CHANNEL_WARNING, "Switch", "Warning", i));
212             channels.add(createTriggerChannel(CHANNEL_UPDATED, "Updated", i));
213             channels.add(createChannel(CHANNEL_SEVERITY, "String", "Severity", i));
214             channels.add(createChannel(CHANNEL_DESCRIPTION, "String", "Description", i));
215             channels.add(createChannel(CHANNEL_EFFECTIVE, "DateTime", "Issued", i));
216             channels.add(createChannel(CHANNEL_ONSET, "DateTime", "Valid From", i));
217             channels.add(createChannel(CHANNEL_EXPIRES, "DateTime", "Valid To", i));
218             channels.add(createChannel(CHANNEL_EVENT, "String", "Type", i));
219             channels.add(createChannel(CHANNEL_HEADLINE, "String", "Headline", i));
220             channels.add(createChannel(CHANNEL_ALTITUDE, "Number:Length", "Height (from)", i));
221             channels.add(createChannel(CHANNEL_CEILING, "Number:Length", "Height (to)", i));
222             channels.add(createChannel(CHANNEL_INSTRUCTION, "String", "Instruction", i));
223             channels.add(createChannel(CHANNEL_URGENCY, "String", "Urgency", i));
224         }
225         return channels;
226     }
227
228     @Override
229     public void dispose() {
230         final ScheduledFuture<?> job = refreshJob;
231
232         if (job != null) {
233             job.cancel(true);
234         }
235         super.dispose();
236     }
237 }