2 * Copyright (c) 2010-2023 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.*;
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.Units.*;
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
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.OpenWeatherMapConnection;
29 import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapOneCallAPIData;
30 import org.openhab.binding.openweathermap.internal.dto.forecast.daily.FeelsLikeTemp;
31 import org.openhab.binding.openweathermap.internal.dto.forecast.daily.Temp;
32 import org.openhab.binding.openweathermap.internal.dto.onecall.Alert;
33 import org.openhab.binding.openweathermap.internal.dto.onecall.Precipitation;
34 import org.openhab.core.i18n.CommunicationException;
35 import org.openhab.core.i18n.ConfigurationException;
36 import org.openhab.core.i18n.TimeZoneProvider;
37 import org.openhab.core.library.types.QuantityType;
38 import org.openhab.core.thing.Channel;
39 import org.openhab.core.thing.ChannelUID;
40 import org.openhab.core.thing.Thing;
41 import org.openhab.core.thing.ThingStatus;
42 import org.openhab.core.thing.ThingStatusDetail;
43 import org.openhab.core.thing.binding.builder.ThingBuilder;
44 import org.openhab.core.types.State;
45 import org.openhab.core.types.UnDefType;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
49 import com.google.gson.JsonSyntaxException;
52 * The {@link OpenWeatherMapOneCallHandler} is responsible for handling commands, which are sent to one of
55 * @author Wolfgang Klimt - Initial contribution
56 * @author Christoph Weitkamp - Added weather alerts
59 public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler {
61 private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapOneCallHandler.class);
63 private static final String CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX = "forecastMinutes";
64 private static final String CHANNEL_GROUP_HOURLY_FORECAST_PREFIX = "forecastHours";
65 private static final String CHANNEL_GROUP_DAILY_FORECAST_PREFIX = "forecastDay";
66 private static final String CHANNEL_GROUP_ALERTS_PREFIX = "alerts";
67 private static final Pattern CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN = Pattern
68 .compile(CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + "([0-9]*)");
69 private static final Pattern CHANNEL_GROUP_DAILY_FORECAST_PREFIX_PATTERN = Pattern
70 .compile(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + "([0-9]*)");
71 private static final Pattern CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX_PATTERN = Pattern
72 .compile(CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX + "([0-9]*)");
73 private static final Pattern CHANNEL_GROUP_ALERTS_PREFIX_PATTERN = Pattern
74 .compile(CHANNEL_GROUP_ALERTS_PREFIX + "([0-9]*)");
76 private @Nullable OpenWeatherMapOneCallAPIData weatherData;
78 private int forecastMinutes = 60;
79 private int forecastHours = 24;
80 private int forecastDays = 8;
81 private int numberOfAlerts = 0;
83 public OpenWeatherMapOneCallHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
84 super(thing, timeZoneProvider);
88 public void initialize() {
90 logger.debug("Initialize OpenWeatherMapOneCallHandler handler '{}'.", getThing().getUID());
91 OpenWeatherMapOneCallConfiguration config = getConfigAs(OpenWeatherMapOneCallConfiguration.class);
93 boolean configValid = true;
94 int newForecastMinutes = config.forecastMinutes;
95 if (newForecastMinutes < 0 || newForecastMinutes > 60) {
96 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
97 "@text/offline.conf-error-not-supported-onecall-number-of-minutes");
100 int newForecastHours = config.forecastHours;
101 if (newForecastHours < 0 || newForecastHours > 48) {
102 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
103 "@text/offline.conf-error-not-supported-onecall-number-of-hours");
106 int newForecastDays = config.forecastDays;
107 if (newForecastDays < 0 || newForecastDays > 8) {
108 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
109 "@text/offline.conf-error-not-supported-onecall-number-of-days");
112 int newNumberOfAlerts = config.numberOfAlerts;
113 if (newNumberOfAlerts < 0) {
114 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
115 "@text/offline.conf-error-not-supported-onecall-number-of-alerts");
120 logger.debug("Rebuilding thing '{}'.", getThing().getUID());
121 List<Channel> toBeAddedChannels = new ArrayList<>();
122 List<Channel> toBeRemovedChannels = new ArrayList<>();
124 .addAll(createChannelsForGroup(CHANNEL_GROUP_ONECALL_CURRENT, CHANNEL_GROUP_TYPE_ONECALL_CURRENT));
125 if (forecastMinutes != newForecastMinutes) {
126 logger.debug("forecastMinutes changed from {} to {}. Rebuilding minutely forecast channel groups.",
127 forecastMinutes, newForecastMinutes);
128 if (forecastMinutes > newForecastMinutes) {
129 for (int i = newForecastMinutes + 1; i <= forecastMinutes; i++) {
130 toBeRemovedChannels.addAll(removeChannelsOfGroup(
131 CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i)));
134 for (int i = forecastMinutes + 1; i <= newForecastMinutes; i++) {
135 toBeAddedChannels.addAll(createChannelsForGroup(
136 CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i),
137 CHANNEL_GROUP_TYPE_ONECALL_MINUTELY_FORECAST));
140 forecastMinutes = newForecastMinutes;
142 if (forecastHours != newForecastHours) {
143 logger.debug("ForecastHours changed from {} to {}. Rebuilding hourly forecast channel groups.",
144 forecastHours, newForecastHours);
145 if (forecastHours > newForecastHours) {
146 for (int i = newForecastHours + 1; i <= forecastHours; i++) {
147 toBeRemovedChannels.addAll(removeChannelsOfGroup(
148 CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i)));
151 for (int i = forecastHours + 1; i <= newForecastHours; i++) {
152 toBeAddedChannels.addAll(createChannelsForGroup(
153 CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i),
154 CHANNEL_GROUP_TYPE_ONECALL_HOURLY_FORECAST));
157 forecastHours = newForecastHours;
159 if (forecastDays != newForecastDays) {
160 logger.debug("ForecastDays changed from {} to {}. Rebuilding daily forecast channel groups.",
161 forecastDays, newForecastDays);
162 if (forecastDays > newForecastDays) {
163 if (newForecastDays < 1) {
164 toBeRemovedChannels.addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_TODAY));
166 if (newForecastDays < 2) {
167 toBeRemovedChannels.addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_TOMORROW));
169 for (int i = newForecastDays; i < forecastDays; ++i) {
170 toBeRemovedChannels.addAll(
171 removeChannelsOfGroup(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + Integer.toString(i)));
174 if (forecastDays == 0 && newForecastDays > 0) {
175 toBeAddedChannels.addAll(createChannelsForGroup(CHANNEL_GROUP_FORECAST_TODAY,
176 CHANNEL_GROUP_TYPE_ONECALL_DAILY_FORECAST));
178 if (forecastDays <= 1 && newForecastDays > 1) {
179 toBeAddedChannels.addAll(createChannelsForGroup(CHANNEL_GROUP_FORECAST_TOMORROW,
180 CHANNEL_GROUP_TYPE_ONECALL_DAILY_FORECAST));
182 for (int i = Math.max(forecastDays, 2); i < newForecastDays; ++i) {
183 toBeAddedChannels.addAll(
184 createChannelsForGroup(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + Integer.toString(i),
185 CHANNEL_GROUP_TYPE_ONECALL_DAILY_FORECAST));
188 forecastDays = newForecastDays;
189 if (numberOfAlerts != newNumberOfAlerts) {
190 logger.debug("Rebuilding alerts channel groups.");
191 if (numberOfAlerts > newNumberOfAlerts) {
192 for (int i = newNumberOfAlerts + 1; i <= numberOfAlerts; ++i) {
194 .addAll(removeChannelsOfGroup(CHANNEL_GROUP_ALERTS_PREFIX + Integer.toString(i)));
197 for (int i = numberOfAlerts + 1; i <= newNumberOfAlerts; ++i) {
199 .addAll(createChannelsForGroup(CHANNEL_GROUP_ALERTS_PREFIX + Integer.toString(i),
200 CHANNEL_GROUP_TYPE_ONECALL_ALERTS));
203 numberOfAlerts = newNumberOfAlerts;
206 logger.debug("toBeRemovedChannels: {}. toBeAddedChannels: {}", toBeRemovedChannels, toBeAddedChannels);
207 ThingBuilder builder = editThing().withoutChannels(toBeRemovedChannels);
208 for (Channel channel : toBeAddedChannels) {
209 builder.withChannel(channel);
211 updateThing(builder.build());
216 protected boolean requestData(OpenWeatherMapConnection connection)
217 throws CommunicationException, ConfigurationException {
218 logger.debug("Update weather and forecast data of thing '{}'.", getThing().getUID());
220 weatherData = connection.getOneCallAPIData(location, forecastMinutes == 0, forecastHours == 0,
221 forecastDays == 0, numberOfAlerts == 0);
223 } catch (JsonSyntaxException e) {
224 logger.debug("JsonSyntaxException occurred during execution: {}", e.getMessage(), e);
230 protected void updateChannel(ChannelUID channelUID) {
231 String channelGroupId = channelUID.getGroupId();
232 logger.debug("OneCallHandler: updateChannel {}, groupID {}", channelUID, channelGroupId);
233 switch (channelGroupId) {
234 case CHANNEL_GROUP_ONECALL_CURRENT:
235 updateCurrentChannel(channelUID);
237 case CHANNEL_GROUP_ONECALL_TODAY:
238 updateDailyForecastChannel(channelUID, 0);
240 case CHANNEL_GROUP_ONECALL_TOMORROW:
241 updateDailyForecastChannel(channelUID, 1);
245 Matcher hourlyForecastMatcher = CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN.matcher(channelGroupId);
246 if (hourlyForecastMatcher.find() && (i = Integer.parseInt(hourlyForecastMatcher.group(1))) >= 1
248 updateHourlyForecastChannel(channelUID, (i - 1));
251 Matcher dailyForecastMatcher = CHANNEL_GROUP_DAILY_FORECAST_PREFIX_PATTERN.matcher(channelGroupId);
252 if (dailyForecastMatcher.find() && (i = Integer.parseInt(dailyForecastMatcher.group(1))) >= 1
254 updateDailyForecastChannel(channelUID, i);
257 Matcher minutelyForecastMatcher = CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX_PATTERN
258 .matcher(channelGroupId);
259 if (minutelyForecastMatcher.find() && (i = Integer.parseInt(minutelyForecastMatcher.group(1))) >= 1
261 updateMinutelyForecastChannel(channelUID, i - 1);
264 Matcher alertsMatcher = CHANNEL_GROUP_ALERTS_PREFIX_PATTERN.matcher(channelGroupId);
265 if (alertsMatcher.find() && (i = Integer.parseInt(alertsMatcher.group(1))) >= 1) {
266 updateAlertsChannel(channelUID, i - 1);
274 * Update the channel from the last OpenWeatherMap data retrieved.
276 * @param channelUID the id identifying the channel to be updated
278 private void updateCurrentChannel(ChannelUID channelUID) {
279 String channelId = channelUID.getIdWithoutGroup();
280 String channelGroupId = channelUID.getGroupId();
281 OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
282 if (localWeatherData != null) {
283 State state = UnDefType.UNDEF;
285 case CHANNEL_STATION_LOCATION:
286 state = getPointTypeState(localWeatherData.getLat(), localWeatherData.getLon());
288 case CHANNEL_TIME_STAMP:
289 state = getDateTimeTypeState(localWeatherData.getCurrent().getDt());
291 case CHANNEL_SUNRISE:
292 state = getDateTimeTypeState(localWeatherData.getCurrent().getSunrise());
295 state = getDateTimeTypeState(localWeatherData.getCurrent().getSunset());
297 case CHANNEL_CONDITION:
298 if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
299 state = getStringTypeState(localWeatherData.getCurrent().getWeather().get(0).getDescription());
302 case CHANNEL_CONDITION_ID:
303 if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
304 state = getStringTypeState(
305 Integer.toString(localWeatherData.getCurrent().getWeather().get(0).getId()));
308 case CHANNEL_CONDITION_ICON:
309 if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
310 state = getRawTypeState(OpenWeatherMapConnection
311 .getWeatherIcon(localWeatherData.getCurrent().getWeather().get(0).getIcon()));
314 case CHANNEL_CONDITION_ICON_ID:
315 if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
316 state = getStringTypeState(localWeatherData.getCurrent().getWeather().get(0).getIcon());
319 case CHANNEL_TEMPERATURE:
320 state = getQuantityTypeState(localWeatherData.getCurrent().getTemp(), CELSIUS);
322 case CHANNEL_APPARENT_TEMPERATURE:
323 state = getQuantityTypeState(localWeatherData.getCurrent().getFeelsLike(), CELSIUS);
325 case CHANNEL_PRESSURE:
326 state = getQuantityTypeState(localWeatherData.getCurrent().getPressure(), HECTO(PASCAL));
328 case CHANNEL_HUMIDITY:
329 state = getQuantityTypeState(localWeatherData.getCurrent().getHumidity(), PERCENT);
331 case CHANNEL_DEW_POINT:
332 state = getQuantityTypeState(localWeatherData.getCurrent().getDewPoint(), CELSIUS);
334 case CHANNEL_WIND_SPEED:
335 state = getQuantityTypeState(localWeatherData.getCurrent().getWindSpeed(), METRE_PER_SECOND);
337 case CHANNEL_WIND_DIRECTION:
338 state = getQuantityTypeState(localWeatherData.getCurrent().getWindDeg(), DEGREE_ANGLE);
340 case CHANNEL_GUST_SPEED:
341 state = getQuantityTypeState(localWeatherData.getCurrent().getWindGust(), METRE_PER_SECOND);
343 case CHANNEL_CLOUDINESS:
344 state = getQuantityTypeState(localWeatherData.getCurrent().getClouds(), PERCENT);
346 case CHANNEL_UVINDEX:
347 state = getDecimalTypeState(localWeatherData.getCurrent().getUvi());
350 Precipitation rain = localWeatherData.getCurrent().getRain();
351 state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
354 Precipitation snow = localWeatherData.getCurrent().getSnow();
355 state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
357 case CHANNEL_VISIBILITY:
358 State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
359 .toUnit(KILO(METRE));
360 state = (tempstate == null ? state : tempstate);
363 // This should not happen
364 logger.warn("Unknown channel id {} in onecall current weather data", channelId);
367 logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
368 updateState(channelUID, state);
370 logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
375 * Update the channel from the last OpenWeatherMap data retrieved.
377 * @param channelUID the id identifying the channel to be updated
378 * @param count the index of the minutely data referenced by the channel (minute 1 is count 0)
380 private void updateMinutelyForecastChannel(ChannelUID channelUID, int count) {
381 String channelId = channelUID.getIdWithoutGroup();
382 String channelGroupId = channelUID.getGroupId();
383 OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
384 if (forecastMinutes == 0) {
386 "Can't update channel group {} because forecastMinutes is set to '0'. Please adjust config accordingly",
390 if (localWeatherData != null && localWeatherData.getMinutely() != null
391 && localWeatherData.getMinutely().size() > count) {
392 org.openhab.binding.openweathermap.internal.dto.onecall.Minutely forecastData = localWeatherData
393 .getMinutely().get(count);
394 State state = UnDefType.UNDEF;
396 case CHANNEL_TIME_STAMP:
397 state = getDateTimeTypeState(forecastData.getDt());
399 case CHANNEL_PRECIPITATION:
400 double precipitation = forecastData.getPrecipitation();
401 state = getQuantityTypeState(precipitation, MILLI(METRE));
404 // This should not happen
405 logger.warn("Unknown channel id {} in onecall minutely weather data", channelId);
408 logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
409 updateState(channelUID, state);
411 logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
416 * Update the channel from the last OpenWeatherMap data retrieved.
418 * @param channelUID the id identifying the channel to be updated
419 * @param count the index of the hourly data referenced by the channel (hour 1 is count 0)
421 private void updateHourlyForecastChannel(ChannelUID channelUID, int count) {
422 String channelId = channelUID.getIdWithoutGroup();
423 String channelGroupId = channelUID.getGroupId();
424 if (forecastHours == 0) {
426 "Can't update channel group {} because forecastHours is set to '0'. Please adjust config accordingly",
430 OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
431 if (localWeatherData != null && localWeatherData.getHourly().size() > count) {
432 org.openhab.binding.openweathermap.internal.dto.onecall.Hourly forecastData = localWeatherData.getHourly()
434 State state = UnDefType.UNDEF;
436 case CHANNEL_TIME_STAMP:
437 state = getDateTimeTypeState(forecastData.getDt());
439 case CHANNEL_CONDITION:
440 if (!forecastData.getWeather().isEmpty()) {
441 state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
444 case CHANNEL_CONDITION_ID:
445 if (!forecastData.getWeather().isEmpty()) {
446 state = getStringTypeState(Integer.toString(forecastData.getWeather().get(0).getId()));
449 case CHANNEL_CONDITION_ICON:
450 if (!forecastData.getWeather().isEmpty()) {
451 state = getRawTypeState(
452 OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
455 case CHANNEL_CONDITION_ICON_ID:
456 if (!forecastData.getWeather().isEmpty()) {
457 state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
460 case CHANNEL_TEMPERATURE:
461 state = getQuantityTypeState(forecastData.getTemp(), CELSIUS);
463 case CHANNEL_APPARENT_TEMPERATURE:
464 state = getQuantityTypeState(forecastData.getFeelsLike(), CELSIUS);
466 case CHANNEL_PRESSURE:
467 state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
469 case CHANNEL_HUMIDITY:
470 state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
472 case CHANNEL_DEW_POINT:
473 state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
475 case CHANNEL_WIND_SPEED:
476 state = getQuantityTypeState(forecastData.getWindSpeed(), METRE_PER_SECOND);
478 case CHANNEL_WIND_DIRECTION:
479 state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
481 case CHANNEL_GUST_SPEED:
482 state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
484 case CHANNEL_CLOUDINESS:
485 state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
487 case CHANNEL_VISIBILITY:
488 State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
489 .toUnit(KILO(METRE));
490 state = (tempstate == null ? state : tempstate);
491 case CHANNEL_PRECIP_PROBABILITY:
492 state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
495 Precipitation rain = forecastData.getRain();
496 state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
499 Precipitation snow = forecastData.getSnow();
500 state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
503 // This should not happen
504 logger.warn("Unknown channel id {} in onecall hourly weather data", channelId);
507 logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
508 updateState(channelUID, state);
510 logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
515 * Update the channel from the last OpenWeatherMap data retrieved.
517 * @param channelUID the id identifying the channel to be updated
518 * @param count the index of the daily data referenced by the channel (today is count 0)
520 private void updateDailyForecastChannel(ChannelUID channelUID, int count) {
521 String channelId = channelUID.getIdWithoutGroup();
522 String channelGroupId = channelUID.getGroupId();
523 if (forecastDays == 0) {
525 "Can't update channel group {} because forecastDays is set to '0'. Please adjust config accordingly",
529 OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
530 if (localWeatherData != null && localWeatherData.getDaily().size() > count) {
531 org.openhab.binding.openweathermap.internal.dto.onecall.Daily forecastData = localWeatherData.getDaily()
533 State state = UnDefType.UNDEF;
535 FeelsLikeTemp feelsLike;
537 case CHANNEL_TIME_STAMP:
538 state = getDateTimeTypeState(forecastData.getDt());
540 case CHANNEL_SUNRISE:
541 state = getDateTimeTypeState(forecastData.getSunrise());
544 state = getDateTimeTypeState(forecastData.getSunset());
546 case CHANNEL_CONDITION:
547 if (!forecastData.getWeather().isEmpty()) {
548 state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
551 case CHANNEL_CONDITION_ID:
552 if (!forecastData.getWeather().isEmpty()) {
553 state = getStringTypeState(Integer.toString(forecastData.getWeather().get(0).getId()));
556 case CHANNEL_CONDITION_ICON:
557 if (!forecastData.getWeather().isEmpty()) {
558 state = getRawTypeState(
559 OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
562 case CHANNEL_CONDITION_ICON_ID:
563 if (!forecastData.getWeather().isEmpty()) {
564 state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
567 case CHANNEL_MIN_TEMPERATURE:
568 temp = forecastData.getTemp();
570 state = getQuantityTypeState(temp.getMin(), CELSIUS);
573 case CHANNEL_MAX_TEMPERATURE:
574 temp = forecastData.getTemp();
576 state = getQuantityTypeState(temp.getMax(), CELSIUS);
579 case CHANNEL_MORNING_TEMPERATURE:
580 temp = forecastData.getTemp();
582 state = getQuantityTypeState(temp.getMorn(), CELSIUS);
585 case CHANNEL_DAY_TEMPERATURE:
586 temp = forecastData.getTemp();
588 state = getQuantityTypeState(temp.getDay(), CELSIUS);
591 case CHANNEL_EVENING_TEMPERATURE:
592 temp = forecastData.getTemp();
594 state = getQuantityTypeState(temp.getEve(), CELSIUS);
597 case CHANNEL_NIGHT_TEMPERATURE:
598 temp = forecastData.getTemp();
600 state = getQuantityTypeState(temp.getNight(), CELSIUS);
604 case CHANNEL_APPARENT_DAY:
605 feelsLike = forecastData.getFeelsLike();
606 if (feelsLike != null) {
607 state = getQuantityTypeState(feelsLike.getDay(), CELSIUS);
610 case CHANNEL_APPARENT_MORNING:
611 feelsLike = forecastData.getFeelsLike();
612 if (feelsLike != null) {
613 state = getQuantityTypeState(feelsLike.getMorn(), CELSIUS);
616 case CHANNEL_APPARENT_EVENING:
617 feelsLike = forecastData.getFeelsLike();
618 if (feelsLike != null) {
619 state = getQuantityTypeState(feelsLike.getEve(), CELSIUS);
622 case CHANNEL_APPARENT_NIGHT:
623 feelsLike = forecastData.getFeelsLike();
624 if (feelsLike != null) {
625 state = getQuantityTypeState(feelsLike.getNight(), CELSIUS);
628 case CHANNEL_PRESSURE:
629 state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
631 case CHANNEL_HUMIDITY:
632 state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
634 case CHANNEL_WIND_SPEED:
635 state = getQuantityTypeState(forecastData.getWindSpeed(), METRE_PER_SECOND);
637 case CHANNEL_WIND_DIRECTION:
638 state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
640 case CHANNEL_GUST_SPEED:
641 state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
643 case CHANNEL_CLOUDINESS:
644 state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
646 case CHANNEL_DEW_POINT:
647 state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
649 case CHANNEL_UVINDEX:
650 state = getDecimalTypeState(forecastData.getUvi());
652 case CHANNEL_VISIBILITY:
653 State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
654 .toUnit(KILO(METRE));
655 state = (tempstate == null ? state : tempstate);
656 case CHANNEL_PRECIP_PROBABILITY:
657 state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
660 state = getQuantityTypeState(forecastData.getRain(), MILLI(METRE));
663 state = getQuantityTypeState(forecastData.getSnow(), MILLI(METRE));
666 // This should not happen
667 logger.warn("Unknown channel id {} in onecall daily weather data", channelId);
670 logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
671 updateState(channelUID, state);
673 logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
678 * Update the channel from the last OpenWeaterhMap data retrieved.
680 * @param channelUID the id identifying the channel to be updated
681 * @param count the index of the alert data referenced by the channel (alert 1 is count 0)
683 private void updateAlertsChannel(ChannelUID channelUID, int count) {
684 String channelId = channelUID.getIdWithoutGroup();
685 String channelGroupId = channelUID.getGroupId();
686 OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
687 List<Alert> alerts = localWeatherData != null ? localWeatherData.alerts : null;
688 State state = UnDefType.UNDEF;
689 if (alerts != null && alerts.size() > count) {
690 Alert alert = alerts.get(count);
692 case CHANNEL_ALERT_EVENT:
693 state = getStringTypeState(alert.event);
695 case CHANNEL_ALERT_DESCRIPTION:
696 state = getStringTypeState(alert.description);
698 case CHANNEL_ALERT_ONSET:
699 state = getDateTimeTypeState(alert.start);
701 case CHANNEL_ALERT_EXPIRES:
702 state = getDateTimeTypeState(alert.end);
704 case CHANNEL_ALERT_SOURCE:
705 state = getStringTypeState(alert.senderName);
708 logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
710 logger.debug("No data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
712 updateState(channelUID, state);