]> git.basschouten.com Git - openhab-addons.git/blob
e328b20801d2721654f08f7def02ebb96ac93640
[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 import static org.openhab.core.library.unit.MetricPrefix.*;
17 import static org.openhab.core.library.unit.SIUnits.*;
18 import static org.openhab.core.library.unit.SmartHomeUnits.*;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapOneCallConfiguration;
28 import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapCommunicationException;
29 import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConfigurationException;
30 import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConnection;
31 import org.openhab.binding.openweathermap.internal.dto.onecall.*;
32 import org.openhab.core.i18n.TimeZoneProvider;
33 import org.openhab.core.library.types.QuantityType;
34 import org.openhab.core.thing.*;
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 OpenWeatherMapOneCallHandler} is responsible for handling commands, which are sent to one of
45  * the channels.
46  *
47  * @author Wolfgang Klimt - Initial contribution
48  */
49 @NonNullByDefault
50 public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler {
51
52     private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapOneCallHandler.class);
53
54     private static final String CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX = "forecastMinutes";
55     private static final String CHANNEL_GROUP_HOURLY_FORECAST_PREFIX = "forecastHours";
56     private static final String CHANNEL_GROUP_DAILY_FORECAST_PREFIX = "forecastDay";
57     private static final Pattern CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN = Pattern
58             .compile(CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + "([0-9]*)");
59     private static final Pattern CHANNEL_GROUP_DAILY_FORECAST_PREFIX_PATTERN = Pattern
60             .compile(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + "([0-9]*)");
61     private static final Pattern CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX_PATTERN = Pattern
62             .compile(CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX + "([0-9]*)");
63
64     private @Nullable OpenWeatherMapOneCallAPIData weatherData;
65
66     private int forecastMinutes = 60;
67     private int forecastHours = 24;
68     private int forecastDays = 8;
69
70     public OpenWeatherMapOneCallHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
71         super(thing, timeZoneProvider);
72     }
73
74     @Override
75     public void initialize() {
76         super.initialize();
77         logger.debug("Initialize OpenWeatherMapOneCallHandler handler '{}'.", getThing().getUID());
78         OpenWeatherMapOneCallConfiguration config = getConfigAs(OpenWeatherMapOneCallConfiguration.class);
79
80         boolean configValid = true;
81         int newForecastMinutes = config.forecastMinutes;
82         if (newForecastMinutes < 0 || newForecastMinutes > 60) {
83             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
84                     "@text/offline.conf-error-not-supported-onecall-number-of-minutes");
85             configValid = false;
86         }
87         int newForecastHours = config.forecastHours;
88         if (newForecastHours < 0 || newForecastHours > 48) {
89             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
90                     "@text/offline.conf-error-not-supported-onecall-number-of-hours");
91             configValid = false;
92         }
93         int newForecastDays = config.forecastDays;
94         if (newForecastDays < 0 || newForecastDays > 8) {
95             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
96                     "@text/offline.conf-error-not-supported-onecall-number-of-days");
97             configValid = false;
98         }
99
100         if (configValid) {
101             logger.debug("Rebuilding thing '{}'.", getThing().getUID());
102             List<Channel> toBeAddedChannels = new ArrayList<>();
103             List<Channel> toBeRemovedChannels = new ArrayList<>();
104             toBeAddedChannels
105                     .addAll(createChannelsForGroup(CHANNEL_GROUP_ONECALL_CURRENT, CHANNEL_GROUP_TYPE_ONECALL_CURRENT));
106
107             if (forecastMinutes != newForecastMinutes) {
108                 logger.debug("forecastMinutes changed from {} to {}. Rebuilding minutely forecast channel groups.",
109                         forecastMinutes, newForecastMinutes);
110                 if (forecastMinutes > newForecastMinutes) {
111                     for (int i = newForecastMinutes + 1; i <= forecastMinutes; i++) {
112                         toBeRemovedChannels.addAll(removeChannelsOfGroup(
113                                 CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i)));
114                     }
115                 } else {
116                     for (int i = forecastMinutes + 1; i <= newForecastMinutes; i++) {
117                         toBeAddedChannels.addAll(createChannelsForGroup(
118                                 CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i),
119                                 CHANNEL_GROUP_TYPE_ONECALL_MINUTELY_FORECAST));
120                     }
121                 }
122                 forecastMinutes = newForecastMinutes;
123             }
124             if (forecastHours != newForecastHours) {
125                 logger.debug("ForecastHours changed from {} to {}. Rebuilding hourly forecast channel groups.",
126                         forecastHours, newForecastHours);
127                 if (forecastHours > newForecastHours) {
128                     for (int i = newForecastHours + 1; i <= forecastHours; i++) {
129                         toBeRemovedChannels.addAll(removeChannelsOfGroup(
130                                 CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i)));
131                     }
132                 } else {
133                     for (int i = forecastHours + 1; i <= newForecastHours; i++) {
134                         toBeAddedChannels.addAll(createChannelsForGroup(
135                                 CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i),
136                                 CHANNEL_GROUP_TYPE_ONECALL_HOURLY_FORECAST));
137                     }
138                 }
139                 forecastHours = newForecastHours;
140             }
141             if (forecastDays != newForecastDays) {
142                 logger.debug("ForecastDays changed from {} to {}. Rebuilding daily forecast channel groups.",
143                         forecastDays, newForecastDays);
144                 if (forecastDays > newForecastDays) {
145                     if (newForecastDays < 1) {
146                         toBeRemovedChannels.addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_TODAY));
147                     }
148                     if (newForecastDays < 2) {
149                         toBeRemovedChannels.addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_TOMORROW));
150                     }
151                     for (int i = newForecastDays; i < forecastDays; ++i) {
152                         toBeRemovedChannels.addAll(
153                                 removeChannelsOfGroup(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + Integer.toString(i)));
154                     }
155                 } else {
156                     if (forecastDays == 0 && newForecastDays > 0) {
157                         toBeAddedChannels.addAll(createChannelsForGroup(CHANNEL_GROUP_FORECAST_TODAY,
158                                 CHANNEL_GROUP_TYPE_ONECALL_DAILY_FORECAST));
159                     }
160                     if (forecastDays <= 1 && newForecastDays > 1) {
161                         toBeAddedChannels.addAll(createChannelsForGroup(CHANNEL_GROUP_FORECAST_TOMORROW,
162                                 CHANNEL_GROUP_TYPE_ONECALL_DAILY_FORECAST));
163                     }
164                     for (int i = Math.max(forecastDays, 2); i < newForecastDays; i++) {
165                         toBeAddedChannels.addAll(
166                                 createChannelsForGroup(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + Integer.toString(i),
167                                         CHANNEL_GROUP_TYPE_ONECALL_DAILY_FORECAST));
168                     }
169                 }
170                 forecastDays = newForecastDays;
171             }
172             logger.debug("toBeRemovedChannels: {}. toBeAddedChannels: {}", toBeRemovedChannels, toBeAddedChannels);
173             ThingBuilder builder = editThing().withoutChannels(toBeRemovedChannels);
174             for (Channel channel : toBeAddedChannels) {
175                 builder.withChannel(channel);
176             }
177             updateThing(builder.build());
178             updateStatus(ThingStatus.ONLINE);
179         }
180     }
181
182     @Override
183     protected boolean requestData(OpenWeatherMapConnection connection)
184             throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
185         logger.debug("Update weather and forecast data of thing '{}'.", getThing().getUID());
186         try {
187             weatherData = connection.getOneCallAPIData(location, forecastMinutes == 0, forecastHours == 0,
188                     forecastDays == 0);
189             return true;
190         } catch (JsonSyntaxException e) {
191             logger.debug("JsonSyntaxException occurred during execution: {}", e.getLocalizedMessage(), e);
192             return false;
193         }
194     }
195
196     @Override
197     protected void updateChannel(ChannelUID channelUID) {
198         String channelGroupId = channelUID.getGroupId();
199         logger.debug("OneCallHandler: updateChannel {}, groupID {}", channelUID, channelGroupId);
200         switch (channelGroupId) {
201             case CHANNEL_GROUP_ONECALL_CURRENT:
202                 updateCurrentChannel(channelUID);
203                 break;
204             case CHANNEL_GROUP_ONECALL_TODAY:
205                 updateDailyForecastChannel(channelUID, 0);
206                 break;
207             case CHANNEL_GROUP_ONECALL_TOMORROW:
208                 updateDailyForecastChannel(channelUID, 1);
209                 break;
210             default:
211                 int i;
212                 Matcher hourlyForecastMatcher = CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN.matcher(channelGroupId);
213                 if (hourlyForecastMatcher.find() && (i = Integer.parseInt(hourlyForecastMatcher.group(1))) >= 1
214                         && i <= 48) {
215                     updateHourlyForecastChannel(channelUID, (i - 1));
216                     break;
217                 }
218                 Matcher dailyForecastMatcher = CHANNEL_GROUP_DAILY_FORECAST_PREFIX_PATTERN.matcher(channelGroupId);
219                 if (dailyForecastMatcher.find() && (i = Integer.parseInt(dailyForecastMatcher.group(1))) >= 1
220                         && i <= 7) {
221                     updateDailyForecastChannel(channelUID, i);
222                     break;
223                 }
224                 Matcher minutelyForecastMatcher = CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX_PATTERN
225                         .matcher(channelGroupId);
226                 if (minutelyForecastMatcher.find() && (i = Integer.parseInt(minutelyForecastMatcher.group(1))) >= 1
227                         && i <= 60) {
228                     updateMinutelyForecastChannel(channelUID, i - 1);
229                     break;
230                 }
231
232                 break;
233         }
234     }
235
236     /**
237      * Update the channel from the last OpenWeatherMap data retrieved.
238      *
239      * @param channelUID the id identifying the channel to be updated
240      */
241     private void updateCurrentChannel(ChannelUID channelUID) {
242         String channelId = channelUID.getIdWithoutGroup();
243         String channelGroupId = channelUID.getGroupId();
244         OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
245         if (localWeatherData != null) {
246             State state = UnDefType.UNDEF;
247             switch (channelId) {
248                 case CHANNEL_STATION_LOCATION:
249                     state = getPointTypeState(localWeatherData.getLat(), localWeatherData.getLon());
250                     break;
251                 case CHANNEL_TIME_STAMP:
252                     state = getDateTimeTypeState(localWeatherData.getCurrent().getDt());
253                     break;
254                 case CHANNEL_SUNRISE:
255                     state = getDateTimeTypeState(localWeatherData.getCurrent().getSunrise());
256                     break;
257                 case CHANNEL_SUNSET:
258                     state = getDateTimeTypeState(localWeatherData.getCurrent().getSunset());
259                     break;
260                 case CHANNEL_CONDITION:
261                     if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
262                         state = getStringTypeState(localWeatherData.getCurrent().getWeather().get(0).getDescription());
263                     }
264                     break;
265                 case CHANNEL_CONDITION_ID:
266                     if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
267                         state = getStringTypeState(
268                                 Integer.toString(localWeatherData.getCurrent().getWeather().get(0).getId()));
269                     }
270                     break;
271                 case CHANNEL_CONDITION_ICON:
272                     if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
273                         state = getRawTypeState(OpenWeatherMapConnection
274                                 .getWeatherIcon(localWeatherData.getCurrent().getWeather().get(0).getIcon()));
275                     }
276                     break;
277                 case CHANNEL_CONDITION_ICON_ID:
278                     if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
279                         state = getStringTypeState(localWeatherData.getCurrent().getWeather().get(0).getIcon());
280                     }
281                     break;
282                 case CHANNEL_TEMPERATURE:
283                     state = getQuantityTypeState(localWeatherData.getCurrent().getTemp(), CELSIUS);
284                     break;
285                 case CHANNEL_APPARENT_TEMPERATURE:
286                     state = getQuantityTypeState(localWeatherData.getCurrent().getFeelsLike(), CELSIUS);
287                     break;
288                 case CHANNEL_PRESSURE:
289                     state = getQuantityTypeState(localWeatherData.getCurrent().getPressure(), HECTO(PASCAL));
290                     break;
291                 case CHANNEL_HUMIDITY:
292                     state = getQuantityTypeState(localWeatherData.getCurrent().getHumidity(), PERCENT);
293                     break;
294                 case CHANNEL_DEW_POINT:
295                     state = getQuantityTypeState(localWeatherData.getCurrent().getDewPoint(), CELSIUS);
296                     break;
297                 case CHANNEL_WIND_SPEED:
298                     state = getQuantityTypeState(localWeatherData.getCurrent().getWindSpeed(), METRE_PER_SECOND);
299                     break;
300                 case CHANNEL_WIND_DIRECTION:
301                     state = getQuantityTypeState(localWeatherData.getCurrent().getWindDeg(), DEGREE_ANGLE);
302                     break;
303                 case CHANNEL_GUST_SPEED:
304                     state = getQuantityTypeState(localWeatherData.getCurrent().getWindGust(), METRE_PER_SECOND);
305                     break;
306                 case CHANNEL_CLOUDINESS:
307                     state = getQuantityTypeState(localWeatherData.getCurrent().getClouds(), PERCENT);
308                     break;
309                 case CHANNEL_UVINDEX:
310                     state = getDecimalTypeState(localWeatherData.getCurrent().getUvi());
311                     break;
312                 case CHANNEL_RAIN:
313                     Rain rain = localWeatherData.getCurrent().getRain();
314                     state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
315                     break;
316                 case CHANNEL_SNOW:
317                     Snow snow = localWeatherData.getCurrent().getSnow();
318                     state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
319                     break;
320                 case CHANNEL_VISIBILITY:
321                     @Nullable
322                     State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
323                             .toUnit(KILO(METRE));
324                     state = (tempstate == null ? state : tempstate);
325                     break;
326                 default:
327                     // This should not happen
328                     logger.warn("Unknown channel id {} in onecall current weather data", channelId);
329                     break;
330             }
331             logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
332             updateState(channelUID, state);
333         } else {
334             logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
335         }
336     }
337
338     private void updateMinutelyForecastChannel(ChannelUID channelUID, int count) {
339         String channelId = channelUID.getIdWithoutGroup();
340         String channelGroupId = channelUID.getGroupId();
341         OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
342         if (forecastMinutes == 0) {
343             logger.warn(
344                     "Can't update channel group {} because forecastMinutes is set to '0'. Please adjust config accordingly",
345                     channelGroupId);
346             return;
347         }
348         if (localWeatherData != null && localWeatherData.getMinutely().size() > count) {
349             org.openhab.binding.openweathermap.internal.dto.onecall.Minutely forecastData = localWeatherData
350                     .getMinutely().get(count);
351             State state = UnDefType.UNDEF;
352             switch (channelId) {
353                 case CHANNEL_TIME_STAMP:
354                     state = getDateTimeTypeState(forecastData.getDt());
355                     break;
356                 case CHANNEL_PRECIPITATION:
357                     double precipitation = forecastData.getPrecipitation();
358                     state = getQuantityTypeState(precipitation, MILLI(METRE));
359                     break;
360                 default:
361                     // This should not happen
362                     logger.warn("Unknown channel id {} in onecall minutely weather data", channelId);
363                     break;
364             }
365             logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
366             updateState(channelUID, state);
367         } else {
368             logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
369         }
370     }
371
372     /**
373      * Update the channel from the last OpenWeatherMap data retrieved.
374      *
375      * @param channelUID the id identifying the channel to be updated
376      * @param count the number of the hour referenced by the channel
377      */
378     private void updateHourlyForecastChannel(ChannelUID channelUID, int count) {
379         String channelId = channelUID.getIdWithoutGroup();
380         String channelGroupId = channelUID.getGroupId();
381         if (forecastHours == 0) {
382             logger.warn(
383                     "Can't update channel group {} because forecastHours is set to '0'. Please adjust config accordingly",
384                     channelGroupId);
385             return;
386         }
387         OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
388         if (localWeatherData != null && localWeatherData.getHourly().size() > count) {
389             org.openhab.binding.openweathermap.internal.dto.onecall.Hourly forecastData = localWeatherData.getHourly()
390                     .get(count);
391             State state = UnDefType.UNDEF;
392             switch (channelId) {
393                 case CHANNEL_TIME_STAMP:
394                     state = getDateTimeTypeState(forecastData.getDt());
395                     break;
396                 case CHANNEL_CONDITION:
397                     if (!forecastData.getWeather().isEmpty()) {
398                         state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
399                     }
400                     break;
401                 case CHANNEL_CONDITION_ID:
402                     if (!forecastData.getWeather().isEmpty()) {
403                         state = getStringTypeState(Integer.toString(forecastData.getWeather().get(0).getId()));
404                     }
405                     break;
406                 case CHANNEL_CONDITION_ICON:
407                     if (!forecastData.getWeather().isEmpty()) {
408                         state = getRawTypeState(
409                                 OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
410                     }
411                     break;
412                 case CHANNEL_CONDITION_ICON_ID:
413                     if (!forecastData.getWeather().isEmpty()) {
414                         state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
415                     }
416                     break;
417                 case CHANNEL_TEMPERATURE:
418                     state = getQuantityTypeState(forecastData.getTemp(), CELSIUS);
419                     break;
420                 case CHANNEL_APPARENT_TEMPERATURE:
421                     state = getQuantityTypeState(forecastData.getFeelsLike(), CELSIUS);
422                     break;
423                 case CHANNEL_PRESSURE:
424                     state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
425                     break;
426                 case CHANNEL_HUMIDITY:
427                     state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
428                     break;
429                 case CHANNEL_DEW_POINT:
430                     state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
431                     break;
432                 case CHANNEL_WIND_SPEED:
433                     state = getQuantityTypeState(forecastData.getWindSpeed(), METRE_PER_SECOND);
434                     break;
435                 case CHANNEL_WIND_DIRECTION:
436                     state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
437                     break;
438                 case CHANNEL_GUST_SPEED:
439                     state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
440                     break;
441                 case CHANNEL_CLOUDINESS:
442                     state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
443                     break;
444                 case CHANNEL_VISIBILITY:
445                     @Nullable
446                     State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
447                             .toUnit(KILO(METRE));
448                     state = (tempstate == null ? state : tempstate);
449                 case CHANNEL_PRECIP_PROBABILITY:
450                     state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
451                     break;
452                 case CHANNEL_RAIN:
453                     Rain rain = forecastData.getRain();
454                     state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
455                     break;
456                 case CHANNEL_SNOW:
457                     Snow snow = forecastData.getSnow();
458                     state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
459                     break;
460                 default:
461                     // This should not happen
462                     logger.warn("Unknown channel id {} in onecall hourly weather data", channelId);
463                     break;
464             }
465             logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
466             updateState(channelUID, state);
467         } else {
468             logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
469         }
470     }
471
472     /**
473      * Update the channel from the last OpenWeatherMap data retrieved.
474      *
475      * @param channelUID the id identifying the channel to be updated
476      * @param count
477      */
478     private void updateDailyForecastChannel(ChannelUID channelUID, int count) {
479         String channelId = channelUID.getIdWithoutGroup();
480         String channelGroupId = channelUID.getGroupId();
481         if (forecastDays == 0) {
482             logger.warn(
483                     "Can't update channel group {} because forecastDays is set to '0'. Please adjust config accordingly",
484                     channelGroupId);
485             return;
486         }
487         @Nullable
488         OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
489         if (localWeatherData != null && localWeatherData.getDaily().size() > count) {
490             org.openhab.binding.openweathermap.internal.dto.onecall.Daily forecastData = localWeatherData.getDaily()
491                     .get(count);
492             State state = UnDefType.UNDEF;
493             Temp temp;
494             FeelsLike feelsLike;
495             switch (channelId) {
496                 case CHANNEL_TIME_STAMP:
497                     state = getDateTimeTypeState(forecastData.getDt());
498                     break;
499                 case CHANNEL_SUNRISE:
500                     state = getDateTimeTypeState(forecastData.getSunrise());
501                     break;
502                 case CHANNEL_SUNSET:
503                     state = getDateTimeTypeState(forecastData.getSunset());
504                     break;
505                 case CHANNEL_CONDITION:
506                     if (!forecastData.getWeather().isEmpty()) {
507                         state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
508                     }
509                     break;
510                 case CHANNEL_CONDITION_ID:
511                     if (!forecastData.getWeather().isEmpty()) {
512                         state = getStringTypeState(Integer.toString(forecastData.getWeather().get(0).getId()));
513                     }
514                     break;
515                 case CHANNEL_CONDITION_ICON:
516                     if (!forecastData.getWeather().isEmpty()) {
517                         state = getRawTypeState(
518                                 OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
519                     }
520                     break;
521                 case CHANNEL_CONDITION_ICON_ID:
522                     if (!forecastData.getWeather().isEmpty()) {
523                         state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
524                     }
525                     break;
526                 case CHANNEL_MIN_TEMPERATURE:
527                     temp = forecastData.getTemp();
528                     if (temp != null) {
529                         state = getQuantityTypeState(temp.getMin(), CELSIUS);
530                     }
531                     break;
532                 case CHANNEL_MAX_TEMPERATURE:
533                     temp = forecastData.getTemp();
534                     if (temp != null) {
535                         state = getQuantityTypeState(temp.getMax(), CELSIUS);
536                     }
537                     break;
538                 case CHANNEL_MORNING_TEMPERATURE:
539                     temp = forecastData.getTemp();
540                     if (temp != null) {
541                         state = getQuantityTypeState(temp.getMorn(), CELSIUS);
542                     }
543                     break;
544                 case CHANNEL_DAY_TEMPERATURE:
545                     temp = forecastData.getTemp();
546                     if (temp != null) {
547                         state = getQuantityTypeState(temp.getDay(), CELSIUS);
548                     }
549                     break;
550                 case CHANNEL_EVENING_TEMPERATURE:
551                     temp = forecastData.getTemp();
552                     if (temp != null) {
553                         state = getQuantityTypeState(temp.getEve(), CELSIUS);
554                     }
555                     break;
556                 case CHANNEL_NIGHT_TEMPERATURE:
557                     temp = forecastData.getTemp();
558                     if (temp != null) {
559                         state = getQuantityTypeState(temp.getNight(), CELSIUS);
560                     }
561                     break;
562
563                 case CHANNEL_APPARENT_DAY:
564                     feelsLike = forecastData.getFeelsLike();
565                     if (feelsLike != null) {
566                         state = getQuantityTypeState(feelsLike.getDay(), CELSIUS);
567                     }
568                     break;
569                 case CHANNEL_APPARENT_MORNING:
570                     feelsLike = forecastData.getFeelsLike();
571                     if (feelsLike != null) {
572                         state = getQuantityTypeState(feelsLike.getMorn(), CELSIUS);
573                     }
574                     break;
575                 case CHANNEL_APPARENT_EVENING:
576                     feelsLike = forecastData.getFeelsLike();
577                     if (feelsLike != null) {
578                         state = getQuantityTypeState(feelsLike.getEve(), CELSIUS);
579                     }
580                     break;
581                 case CHANNEL_APPARENT_NIGHT:
582                     feelsLike = forecastData.getFeelsLike();
583                     if (feelsLike != null) {
584                         state = getQuantityTypeState(feelsLike.getNight(), CELSIUS);
585                     }
586                     break;
587                 case CHANNEL_PRESSURE:
588                     state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
589                     break;
590                 case CHANNEL_HUMIDITY:
591                     state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
592                     break;
593                 case CHANNEL_WIND_SPEED:
594                     state = getQuantityTypeState(forecastData.getWindSpeed(), METRE_PER_SECOND);
595                     break;
596                 case CHANNEL_WIND_DIRECTION:
597                     state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
598                     break;
599                 case CHANNEL_GUST_SPEED:
600                     state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
601                     break;
602                 case CHANNEL_CLOUDINESS:
603                     state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
604                     break;
605                 case CHANNEL_DEW_POINT:
606                     state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
607                     break;
608                 case CHANNEL_UVINDEX:
609                     state = getDecimalTypeState(forecastData.getUvi());
610                     break;
611                 case CHANNEL_VISIBILITY:
612                     @Nullable
613                     State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
614                             .toUnit(KILO(METRE));
615                     state = (tempstate == null ? state : tempstate);
616                 case CHANNEL_PRECIP_PROBABILITY:
617                     state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
618                     break;
619                 case CHANNEL_RAIN:
620                     state = getQuantityTypeState(forecastData.getRain(), MILLI(METRE));
621                     break;
622                 case CHANNEL_SNOW:
623                     state = getQuantityTypeState(forecastData.getSnow(), MILLI(METRE));
624                     break;
625                 default:
626                     // This should not happen
627                     logger.warn("Unknown channel id {} in onecall daily weather data", channelId);
628                     break;
629             }
630             logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
631             updateState(channelUID, state);
632         } else {
633             logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
634         }
635     }
636 }