]> git.basschouten.com Git - openhab-addons.git/blob
ffe0da67fcd15eb122afa8c6d33e4738e0991de9
[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.openweathermap.internal.handler;
14
15 import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*;
16
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.regex.Matcher;
20 import java.util.regex.Pattern;
21
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;
40
41 import com.google.gson.JsonSyntaxException;
42
43 /**
44  * The {@link OpenWeatherMapUVIndexHandler} is responsible for handling commands, which are sent to one of the
45  * channels.
46  *
47  * @author Christoph Weitkamp - Initial contribution
48  */
49 @NonNullByDefault
50 public class OpenWeatherMapUVIndexHandler extends AbstractOpenWeatherMapHandler {
51
52     private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapUVIndexHandler.class);
53
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]*)");
57
58     // keeps track of the parsed count
59     private int forecastDays = 6;
60
61     private @Nullable OpenWeatherMapJsonUVIndexData uvindexData;
62     private @Nullable List<OpenWeatherMapJsonUVIndexData> uvindexForecastData;
63
64     public OpenWeatherMapUVIndexHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
65         super(thing, timeZoneProvider);
66     }
67
68     @Override
69     public void initialize() {
70         super.initialize();
71         logger.debug("Initialize OpenWeatherMapUVIndexHandler handler '{}'.", getThing().getUID());
72         OpenWeatherMapUVIndexConfiguration config = getConfigAs(OpenWeatherMapUVIndexConfiguration.class);
73
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");
79             configValid = false;
80         }
81
82         if (configValid) {
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));
91                     }
92                     for (int i = newForecastDays; i < forecastDays; ++i) {
93                         toBeRemovedChannels
94                                 .addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_PREFIX + Integer.toString(i)));
95                     }
96                 } else {
97                     if (forecastDays <= 1 && newForecastDays > 1) {
98                         toBeAddedChannels.addAll(
99                                 createChannelsForGroup(CHANNEL_GROUP_FORECAST_TOMORROW, CHANNEL_GROUP_TYPE_UVINDEX));
100                     }
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));
104                     }
105                 }
106                 forecastDays = newForecastDays;
107             }
108             ThingBuilder builder = editThing().withoutChannels(toBeRemovedChannels);
109             for (Channel channel : toBeAddedChannels) {
110                 builder.withChannel(channel);
111             }
112             updateThing(builder.build());
113         }
114     }
115
116     @Override
117     protected boolean requestData(OpenWeatherMapConnection connection)
118             throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
119         logger.debug("Update UV Index data of thing '{}'.", getThing().getUID());
120         try {
121             uvindexData = connection.getUVIndexData(location);
122             if (forecastDays > 0) {
123                 uvindexForecastData = connection.getUVIndexForecastData(location, forecastDays);
124             }
125             return true;
126         } catch (JsonSyntaxException e) {
127             logger.debug("JsonSyntaxException occurred during execution: {}", e.getLocalizedMessage(), e);
128             return false;
129         }
130     }
131
132     @Override
133     protected void updateChannel(ChannelUID channelUID) {
134         switch (channelUID.getGroupId()) {
135             case CHANNEL_GROUP_CURRENT_UVINDEX:
136                 updateUVIndexChannel(channelUID);
137                 break;
138             case CHANNEL_GROUP_FORECAST_TOMORROW:
139                 updateUVIndexForecastChannel(channelUID, 1);
140                 break;
141             default:
142                 Matcher m = CHANNEL_GROUP_FORECAST_PREFIX_PATTERN.matcher(channelUID.getGroupId());
143                 int i;
144                 if (m.find() && (i = Integer.parseInt(m.group(1))) > 1 && i <= 8) {
145                     updateUVIndexForecastChannel(channelUID, i);
146                 }
147                 break;
148         }
149     }
150
151     /**
152      * Update the channel from the last OpenWeatherMap data retrieved.
153      *
154      * @param channelUID the id identifying the channel to be updated
155      */
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;
162             switch (channelId) {
163                 case CHANNEL_TIME_STAMP:
164                     state = getDateTimeTypeState(localUVIndexData.getDate());
165                     break;
166                 case CHANNEL_UVINDEX:
167                     state = getDecimalTypeState(localUVIndexData.getValue());
168                     break;
169             }
170             logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
171             updateState(channelUID, state);
172         } else {
173             logger.debug("No UV Index data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
174         }
175     }
176
177     /**
178      * Update the channel from the last OpenWeatherMap data retrieved.
179      *
180      * @param channelUID the id identifying the channel to be updated
181      * @param count
182      */
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;
190             switch (channelId) {
191                 case CHANNEL_TIME_STAMP:
192                     state = getDateTimeTypeState(forecastData.getDate());
193                     break;
194                 case CHANNEL_UVINDEX:
195                     state = getDecimalTypeState(forecastData.getValue());
196                     break;
197             }
198             logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
199             updateState(channelUID, state);
200         } else {
201             logger.debug("No UV Index data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
202         }
203     }
204 }