2 * Copyright (c) 2010-2020 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.dwdunwetter.internal.handler;
15 import static org.openhab.binding.dwdunwetter.internal.DwdUnwetterBindingConstants.*;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
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;
43 * The {@link DwdUnwetterHandler} is responsible for handling commands, which are sent to one of the channels.
45 * @author Martin Koehler - Initial contribution
48 public class DwdUnwetterHandler extends BaseThingHandler {
50 private final Logger logger = LoggerFactory.getLogger(DwdUnwetterHandler.class);
52 private @Nullable ScheduledFuture<?> refreshJob;
53 private int warningCount;
54 private @Nullable DwdWarningsData data;
56 private boolean inRefresh;
57 private boolean initializing;
59 public DwdUnwetterHandler(Thing thing) {
64 public void handleCommand(ChannelUID channelUID, Command command) {
65 if (command instanceof RefreshType) {
66 scheduler.submit(this::refresh);
71 * Refreshes the Warning Data.
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.
76 private void refresh() {
78 logger.trace("Already refreshing. Ignoring refresh request.");
83 logger.trace("Still initializing. Ignoring refresh request.");
87 ThingStatus status = getThing().getStatus();
88 if (status != ThingStatus.ONLINE && status != ThingStatus.UNKNOWN) {
89 logger.debug("Unable to refresh. Thing status is {}", status);
93 final DwdWarningsData warningsData = data;
94 if (warningsData == null) {
95 logger.debug("Unable to refresh. No data to use.");
101 boolean refreshSucceeded = warningsData.refresh();
102 if (!refreshSucceeded) {
103 logger.debug("Failed to retrieve new data from the server.");
108 if (status == ThingStatus.UNKNOWN) {
109 updateStatus(ThingStatus.ONLINE);
112 updateState(getChannelUuid(CHANNEL_LAST_UPDATED), new DateTimeType());
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);
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);
133 if (warningsData.isNew(i)) {
134 triggerChannel(getChannelUuid(CHANNEL_UPDATED, i), "NEW");
138 warningsData.updateCache();
143 public void initialize() {
144 logger.debug("Start initializing!");
146 updateStatus(ThingStatus.UNKNOWN);
148 DwdUnwetterConfiguration config = getConfigAs(DwdUnwetterConfiguration.class);
149 warningCount = config.warningCount;
151 data = new DwdWarningsData(config.cellId);
153 updateThing(editThing().withChannels(createChannels()).build());
155 refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, config.refresh, TimeUnit.MINUTES);
156 initializing = false;
157 logger.debug("Finished initializing!");
160 private ChannelUID getChannelUuid(String typeId, int warningNumber) {
161 return new ChannelUID(getThing().getUID(), typeId + (warningNumber + 1));
164 private ChannelUID getChannelUuid(String typeId) {
165 return new ChannelUID(getThing().getUID(), typeId);
169 * Creates a trigger Channel.
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) //
181 * Creates a normal, state based, channel associated with a warning.
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) + ")")//
192 * Creates a normal, state based, channel not associated with a warning.
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)) //
203 * Creates the ChannelsT for each warning.
205 * @return The List of Channels
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));
229 public void dispose() {
230 final ScheduledFuture<?> job = refreshJob;