/* * 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.heating.schedule.configuration; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import li.klass.fhem.domain.GenericDevice; import li.klass.fhem.domain.heating.schedule.DayProfile; import li.klass.fhem.domain.heating.schedule.WeekProfile; import li.klass.fhem.domain.heating.schedule.interval.FilledTemperatureInterval; import li.klass.fhem.util.DayUtil; import li.klass.fhem.util.StateToSet; import static li.klass.fhem.util.ValueExtractUtil.extractLeadingDouble; public class MAXConfiguration extends HeatingConfiguration<FilledTemperatureInterval, GenericDevice, MAXConfiguration> { public static final int MAXIMUM_NUMBER_OF_HEATING_INTERVALS = 13; public static final Pattern WEEKPROFILE_KEY_PATTERN = Pattern.compile("weekprofile_[0-9]+_([^_]+)_(time|temp)"); public static final double MINIMUM_TEMPERATURE = 4.5; public MAXConfiguration() { super("", MAXIMUM_NUMBER_OF_HEATING_INTERVALS, NumberOfIntervalsType.DYNAMIC, 5); } @Override public void readNode(WeekProfile<FilledTemperatureInterval, MAXConfiguration, GenericDevice> weekProfile, String key, String value) { if (!key.startsWith("weekprofile") || (!key.endsWith("temp") && !key.endsWith("time"))) { return; } key = key.replaceAll("-", "_"); // B0 is a pretty strange fix. Sometimes it seems to be places instead of a degree (°) sign value = value.replaceAll("[^0-9. -:/]", "").replaceAll(" ", " "); Matcher matcher = WEEKPROFILE_KEY_PATTERN.matcher(key); if (!matcher.find()) { return; } String dayShortName = matcher.group(1); DayUtil.Day day = DayUtil.getDayForShortName(dayShortName); if (day == null) return; if (key.endsWith("temp")) { parseTemp(day, value, weekProfile); } else if (key.endsWith("time")) { parseTime(day, value, weekProfile); } } private void parseTemp(DayUtil.Day day, String value, WeekProfile<FilledTemperatureInterval, MAXConfiguration, GenericDevice> weekProfile) { String[] temperatures = value.split("/"); for (int i = 0; i < temperatures.length; i++) { String temperatureValue = temperatures[i].trim(); double temperature = extractLeadingDouble(temperatureValue); getOrCreateInterval(weekProfile, day, i).setTemperature(temperature); } } private void parseTime(DayUtil.Day day, String value, WeekProfile<FilledTemperatureInterval, MAXConfiguration, GenericDevice> weekProfile) { String[] timeIntervals = value.split("/"); for (int i = 0; i < timeIntervals.length; i++) { String switchTime = extractSwitchTime(timeIntervals[i]); boolean isTimeFixed = i == 0; FilledTemperatureInterval interval = getOrCreateInterval(weekProfile, day, i); interval.setSwitchTime(switchTime); interval.setTimeFixed(isTimeFixed); } } private String extractSwitchTime(String timeInterval) { timeInterval = timeInterval.trim(); int firstDash = timeInterval.indexOf("-"); return timeInterval.substring(0, firstDash); } @Override public FilledTemperatureInterval createHeatingInterval() { return new FilledTemperatureInterval(); } @Override public DayProfile<FilledTemperatureInterval, GenericDevice, MAXConfiguration> createDayProfileFor(DayUtil.Day day, MAXConfiguration configuration) { return new DayProfile<>(day, configuration); } @Override protected List<StateToSet> generateStateToSetFor(DayProfile<FilledTemperatureInterval, GenericDevice, MAXConfiguration> dayProfile) { StringBuilder builder = new StringBuilder(); List<FilledTemperatureInterval> heatingIntervals = new ArrayList<>(dayProfile.getHeatingIntervals()); Collections.sort(heatingIntervals); for (int i = 0; i < heatingIntervals.size(); i++) { FilledTemperatureInterval interval = heatingIntervals.get(i); if (i == 0) { builder.append(interval.getChangedTemperature()); } else { builder.append(","); builder.append(interval.getChangedSwitchTime()); builder.append(","); builder.append(interval.getChangedTemperature()); } } String shortName = DayUtil.getShortNameFor(dayProfile.getDay()); char firstChar = shortName.charAt(0); shortName = ((char) (firstChar - 'a' + 'A')) + shortName.substring(1); return ImmutableList.of(new StateToSet("weekProfile", shortName + " " + builder.toString())); } @Override public void afterXMLRead(WeekProfile<FilledTemperatureInterval, MAXConfiguration, GenericDevice> weekProfile) { super.afterXMLRead(weekProfile); List<DayProfile<FilledTemperatureInterval, GenericDevice, MAXConfiguration>> profiles = weekProfile.getSortedDayProfiles(); for (DayProfile<FilledTemperatureInterval, GenericDevice, MAXConfiguration> profile : profiles) { addMidnightIntervalIfNotAvailable(profile); } } private <D extends DayProfile<FilledTemperatureInterval, GenericDevice, MAXConfiguration>> void addMidnightIntervalIfNotAvailable(D profile) { boolean foundMidnightInterval = false; for (FilledTemperatureInterval interval : profile.getHeatingIntervals()) { if (interval.getChangedSwitchTime().equals("00:00")) { foundMidnightInterval = true; break; } } if (!foundMidnightInterval) { FilledTemperatureInterval interval = new FilledTemperatureInterval(); interval.setChangedSwitchTime("00:00"); interval.setChangedTemperature(MINIMUM_TEMPERATURE); interval.setTimeFixed(true); profile.addHeatingInterval(interval); } } @Override public IntervalType getIntervalType() { return IntervalType.FROM; } }