/*
* AndFHEM - Open Source Android application to control a FHEM home automation
* server.
*
* Copyright (c) 2011, Matthias Klass or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GENERAL PUBLIC LICENSE
* for more details.
*
* You should have received a copy of the GNU GENERAL PUBLIC LICENSE
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package li.klass.fhem.domain;
import android.util.Log;
import org.jetbrains.annotations.NotNull;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import li.klass.fhem.appwidget.annotation.SupportsWidget;
import li.klass.fhem.appwidget.annotation.WidgetMediumLine1;
import li.klass.fhem.appwidget.annotation.WidgetMediumLine2;
import li.klass.fhem.appwidget.annotation.WidgetMediumLine3;
import li.klass.fhem.appwidget.annotation.WidgetTemperatureAdditionalField;
import li.klass.fhem.appwidget.annotation.WidgetTemperatureField;
import li.klass.fhem.appwidget.view.widget.medium.MediumInformationWidgetView;
import li.klass.fhem.appwidget.view.widget.medium.TemperatureWidgetView;
import li.klass.fhem.domain.core.DeviceFunctionality;
import li.klass.fhem.domain.core.FhemDevice;
import li.klass.fhem.domain.core.XmllistAttribute;
import li.klass.fhem.service.room.xmllist.DeviceNode;
import li.klass.fhem.util.ValueDescriptionUtil;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Sets.newTreeSet;
@SupportsWidget({TemperatureWidgetView.class, MediumInformationWidgetView.class})
public class WeatherDevice extends FhemDevice<WeatherDevice> {
public static final String IMAGE_URL_PREFIX = "http://andfhem.klass.li/images/weatherIcons/";
private static final DateTimeFormatter PARSE_DATE_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
@WidgetMediumLine3
private String condition;
@WidgetTemperatureAdditionalField
@WidgetMediumLine2
@XmllistAttribute("humidity")
private String humidity;
@XmllistAttribute("icon")
private String icon;
@WidgetTemperatureField
@WidgetMediumLine1
@XmllistAttribute("temp_c")
private String temperature;
@XmllistAttribute("wind_condition")
private String wind;
@XmllistAttribute("visibility")
private String visibilityConditions;
@XmllistAttribute("wind_chill")
private String windChill;
private Map<Integer, WeatherDeviceForecast> forecastMap = newHashMap();
@Override
public void onChildItemRead(DeviceNode.DeviceNodeType type, String key, String value, DeviceNode node) {
if (key.startsWith("fc")) {
parseForecast(key, value, node.getMeasured());
}
}
private void parseForecast(String keyValue, String nodeContent, DateTime measuredDate) {
try {
int underscorePosition = keyValue.indexOf("_");
String name = keyValue.substring(underscorePosition + 1);
int prefix = Integer.valueOf(keyValue.substring(2, underscorePosition));
if (((Integer) 1).equals(prefix)) return;
if (!forecastMap.containsKey(prefix)) {
DateTime forecastDate = measuredDate.plusDays(prefix - 1);
String forecastTimeString = WeatherDeviceForecast.FORECAST_DATE_FORMAT.print(forecastDate);
forecastMap.put(prefix, new WeatherDeviceForecast(forecastTimeString));
}
WeatherDeviceForecast forecast = forecastMap.get(prefix);
if (name.equalsIgnoreCase("CONDITION")) {
forecast.condition = nodeContent;
} else if (name.equalsIgnoreCase("DAY_OF_WEEK")) {
forecast.dayOfWeek = nodeContent;
} else if (name.equalsIgnoreCase("HIGH_C")) {
forecast.highTemperature = ValueDescriptionUtil.appendTemperature(nodeContent);
} else if (name.equalsIgnoreCase("LOW_C")) {
forecast.lowTemperature = ValueDescriptionUtil.appendTemperature(nodeContent);
} else if (name.equalsIgnoreCase("ICON")) {
forecast.icon = nodeContent;
}
} catch (Exception e) {
Log.e(WeatherDevice.class.getName(), "cannot parse forecast", e);
}
}
@XmllistAttribute("condition")
public void setCondition(String value, DeviceNode node) {
this.condition = value;
setMeasured(node.getMeasured());
}
public String getCondition() {
return condition;
}
public String getHumidity() {
return humidity;
}
public String getIcon() {
return parseIcon(icon);
}
public String getWindChill() {
return windChill;
}
public String getVisibilityConditions() {
return visibilityConditions;
}
public static String parseIcon(String icon) {
if (icon == null) return null;
if (!icon.endsWith(".png") && icon.lastIndexOf(".") != -1) {
icon = icon.substring(0, icon.lastIndexOf(".")) + ".png";
}
if (!icon.contains("/")) return icon;
int lastSlashIndex = icon.lastIndexOf("/");
return icon.substring(lastSlashIndex + 1);
}
public String getTemperature() {
return temperature;
}
public String getWind() {
return wind;
}
public List<WeatherDeviceForecast> getForecasts() {
TreeSet<Integer> keys = newTreeSet();
keys.addAll(forecastMap.keySet());
ArrayList<WeatherDeviceForecast> result = newArrayList();
for (Integer key : keys) {
result.add(forecastMap.get(key));
}
return result;
}
@Override
public DeviceFunctionality getDeviceGroup() {
return DeviceFunctionality.WEATHER;
}
@Override
public boolean isSensorDevice() {
return true;
}
public static class WeatherDeviceForecast implements Comparable<WeatherDeviceForecast>, Serializable {
private static final DateTimeFormatter FORECAST_DATE_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd");
private String date;
private String condition;
private String dayOfWeek;
private String highTemperature;
private String lowTemperature;
private String icon;
WeatherDeviceForecast(String date) {
this.date = date;
}
@Override
public int compareTo(@NotNull WeatherDeviceForecast weatherDeviceForecast) {
return date.compareTo(weatherDeviceForecast.date);
}
public String getDate() {
return date;
}
public String getCondition() {
return condition;
}
public String getDayOfWeek() {
return dayOfWeek;
}
public String getHighTemperature() {
return highTemperature;
}
public String getLowTemperature() {
return lowTemperature;
}
public String getUrl() {
return WeatherDevice.IMAGE_URL_PREFIX + getIcon() + ".png";
}
public String getIcon() {
return parseIcon(icon);
}
}
}