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.openweathermap.internal.handler;
15 import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.regex.Matcher;
20 import java.util.regex.Pattern;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapUVIndexConfiguration;
25 import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapCommunicationException;
26 import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConfigurationException;
27 import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConnection;
28 import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonUVIndexData;
29 import org.openhab.core.i18n.TimeZoneProvider;
30 import org.openhab.core.thing.Channel;
31 import org.openhab.core.thing.ChannelUID;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingStatus;
34 import org.openhab.core.thing.ThingStatusDetail;
35 import org.openhab.core.thing.binding.builder.ThingBuilder;
36 import org.openhab.core.types.State;
37 import org.openhab.core.types.UnDefType;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 import com.google.gson.JsonSyntaxException;
44 * The {@link OpenWeatherMapUVIndexHandler} is responsible for handling commands, which are sent to one of the
47 * @author Christoph Weitkamp - Initial contribution
50 public class OpenWeatherMapUVIndexHandler extends AbstractOpenWeatherMapHandler {
52 private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapUVIndexHandler.class);
54 private static final String CHANNEL_GROUP_FORECAST_PREFIX = "forecastDay";
55 private static final Pattern CHANNEL_GROUP_FORECAST_PREFIX_PATTERN = Pattern
56 .compile(CHANNEL_GROUP_FORECAST_PREFIX + "([0-9]*)");
58 // keeps track of the parsed count
59 private int forecastDays = 6;
61 private @Nullable OpenWeatherMapJsonUVIndexData uvindexData;
62 private @Nullable List<OpenWeatherMapJsonUVIndexData> uvindexForecastData;
64 public OpenWeatherMapUVIndexHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
65 super(thing, timeZoneProvider);
69 public void initialize() {
71 logger.debug("Initialize OpenWeatherMapUVIndexHandler handler '{}'.", getThing().getUID());
72 OpenWeatherMapUVIndexConfiguration config = getConfigAs(OpenWeatherMapUVIndexConfiguration.class);
74 boolean configValid = true;
75 int newForecastDays = config.forecastDays;
76 if (newForecastDays < 1 || newForecastDays > 8) {
77 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
78 "@text/offline.conf-error-not-supported-uvindex-number-of-days");
83 logger.debug("Rebuilding thing '{}'.", getThing().getUID());
84 List<Channel> toBeAddedChannels = new ArrayList<>();
85 List<Channel> toBeRemovedChannels = new ArrayList<>();
86 if (forecastDays != newForecastDays) {
87 logger.debug("Rebuilding UV index channel groups.");
88 if (forecastDays > newForecastDays) {
89 if (newForecastDays < 2) {
90 toBeRemovedChannels.addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_TOMORROW));
92 for (int i = newForecastDays; i < forecastDays; ++i) {
94 .addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_PREFIX + Integer.toString(i)));
97 if (forecastDays <= 1 && newForecastDays > 1) {
98 toBeAddedChannels.addAll(
99 createChannelsForGroup(CHANNEL_GROUP_FORECAST_TOMORROW, CHANNEL_GROUP_TYPE_UVINDEX));
101 for (int i = (forecastDays < 2) ? 2 : forecastDays; i < newForecastDays; ++i) {
102 toBeAddedChannels.addAll(createChannelsForGroup(
103 CHANNEL_GROUP_FORECAST_PREFIX + Integer.toString(i), CHANNEL_GROUP_TYPE_UVINDEX));
106 forecastDays = newForecastDays;
108 ThingBuilder builder = editThing().withoutChannels(toBeRemovedChannels);
109 for (Channel channel : toBeAddedChannels) {
110 builder.withChannel(channel);
112 updateThing(builder.build());
117 protected boolean requestData(OpenWeatherMapConnection connection)
118 throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
119 logger.debug("Update UV Index data of thing '{}'.", getThing().getUID());
121 uvindexData = connection.getUVIndexData(location);
122 if (forecastDays > 0) {
123 uvindexForecastData = connection.getUVIndexForecastData(location, forecastDays);
126 } catch (JsonSyntaxException e) {
127 logger.debug("JsonSyntaxException occurred during execution: {}", e.getLocalizedMessage(), e);
133 protected void updateChannel(ChannelUID channelUID) {
134 switch (channelUID.getGroupId()) {
135 case CHANNEL_GROUP_CURRENT_UVINDEX:
136 updateUVIndexChannel(channelUID);
138 case CHANNEL_GROUP_FORECAST_TOMORROW:
139 updateUVIndexForecastChannel(channelUID, 1);
142 Matcher m = CHANNEL_GROUP_FORECAST_PREFIX_PATTERN.matcher(channelUID.getGroupId());
144 if (m.find() && (i = Integer.parseInt(m.group(1))) > 1 && i <= 8) {
145 updateUVIndexForecastChannel(channelUID, i);
152 * Update the channel from the last OpenWeatherMap data retrieved.
154 * @param channelUID the id identifying the channel to be updated
156 private void updateUVIndexChannel(ChannelUID channelUID) {
157 String channelId = channelUID.getIdWithoutGroup();
158 String channelGroupId = channelUID.getGroupId();
159 OpenWeatherMapJsonUVIndexData localUVIndexData = uvindexData;
160 if (localUVIndexData != null) {
161 State state = UnDefType.UNDEF;
163 case CHANNEL_TIME_STAMP:
164 state = getDateTimeTypeState(localUVIndexData.getDate());
166 case CHANNEL_UVINDEX:
167 state = getDecimalTypeState(localUVIndexData.getValue());
170 logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
171 updateState(channelUID, state);
173 logger.debug("No UV Index data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
178 * Update the channel from the last OpenWeatherMap data retrieved.
180 * @param channelUID the id identifying the channel to be updated
183 private void updateUVIndexForecastChannel(ChannelUID channelUID, int count) {
184 String channelId = channelUID.getIdWithoutGroup();
185 String channelGroupId = channelUID.getGroupId();
186 List<OpenWeatherMapJsonUVIndexData> localUVIndexForecastData = uvindexForecastData;
187 if (localUVIndexForecastData != null && localUVIndexForecastData.size() >= count) {
188 OpenWeatherMapJsonUVIndexData forecastData = localUVIndexForecastData.get(count - 1);
189 State state = UnDefType.UNDEF;
191 case CHANNEL_TIME_STAMP:
192 state = getDateTimeTypeState(forecastData.getDate());
194 case CHANNEL_UVINDEX:
195 state = getDecimalTypeState(forecastData.getValue());
198 logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
199 updateState(channelUID, state);
201 logger.debug("No UV Index data available to update channel '{}' of group '{}'.", channelId, channelGroupId);