/* * 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.service.room.xmllist; import org.joda.time.DateTime; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Singleton; import li.klass.fhem.service.deviceConfiguration.DeviceConfigurationProvider; import li.klass.fhem.util.ValueDescriptionUtil; import static com.google.common.base.Strings.isNullOrEmpty; import static li.klass.fhem.service.room.xmllist.DeviceNode.DeviceNodeType.ATTR; import static li.klass.fhem.service.room.xmllist.DeviceNode.DeviceNodeType.STATE; import static li.klass.fhem.util.ValueExtractUtil.extractLeadingDouble; import static li.klass.fhem.util.ValueExtractUtil.extractLeadingInt; @Singleton public class Sanitiser { private static final Logger LOGGER = LoggerFactory.getLogger(Sanitiser.class); @Inject DeviceConfigurationProvider deviceConfigurationProvider; @Inject public Sanitiser() { } public DeviceNode sanitise(String deviceType, DeviceNode deviceNode) { try { JSONObject deviceOptions = optionsFor(deviceType); return sanitise(deviceNode, deviceOptions); } catch (Exception e) { LOGGER.error("cannot sanitise {}", deviceNode); return deviceNode; } } public void sanitise(String deviceType, XmlListDevice xmlListDevice) { try { JSONObject typeOptions = optionsFor(deviceType); if (typeOptions == null) return; JSONObject generalOptions = typeOptions.optJSONObject("__general__"); if (generalOptions == null) return; handleGeneral(xmlListDevice, generalOptions); } catch (JSONException e) { throw new RuntimeException(e); } } private void handleGeneral(XmlListDevice xmlListDevice, JSONObject generalOptions) throws JSONException { handleGeneralAttributesIfNotPresent(generalOptions, xmlListDevice); handleGeneralStatesIfNotPresent(generalOptions, xmlListDevice); handleGeneralAttributeAddIfModelDoesNotMatch(xmlListDevice, generalOptions); } private void handleGeneralAttributeAddIfModelDoesNotMatch(XmlListDevice xmlListDevice, JSONObject generalOptions) throws JSONException { JSONObject config = generalOptions.optJSONObject("addAttributeIfModelDoesNotMatch"); if (config == null) return; JSONArray models = config.getJSONArray("models"); DeviceNode modelNode = xmlListDevice.getAttributes().get("model"); String model = modelNode == null ? null : modelNode.getValue(); for (int i = 0; i < models.length(); i++) { if (models.getString(i).equalsIgnoreCase(model)) { return; } } xmlListDevice.setAttribute(config.getString("key"), config.getString("value")); } private void handleGeneralAttributesIfNotPresent(JSONObject generalOptions, XmlListDevice xmlListDevice) throws JSONException { JSONArray attributes = generalOptions.optJSONArray("addAttributesIfNotPresent"); if (attributes == null) return; for (int i = 0; i < attributes.length(); i++) { JSONObject object = attributes.getJSONObject(i); String key = object.getString("key"); String value = object.getString("value"); if (!xmlListDevice.getAttributes().containsKey(key)) { xmlListDevice.getAttributes().put(key, new DeviceNode(ATTR, key, value, (DateTime) null)); } } } private void handleGeneralStatesIfNotPresent(JSONObject generalOptions, XmlListDevice xmlListDevice) throws JSONException { JSONArray states = generalOptions.optJSONArray("addStatesIfNotPresent"); if (states == null) return; for (int i = 0; i < states.length(); i++) { JSONObject object = states.getJSONObject(i); String key = object.getString("key"); String value = object.getString("value"); if (!xmlListDevice.getStates().containsKey(key)) { xmlListDevice.getStates().put(key, new DeviceNode(STATE, key, value, (DateTime) null)); } } } private DeviceNode sanitise(DeviceNode deviceNode, JSONObject deviceOptions) { JSONObject attributeOptions = deviceOptions.optJSONObject(deviceNode.getKey()); if (attributeOptions == null) { return deviceNode; } String key = deviceNode.getKey(); String value = deviceNode.getValue(); DateTime measured = deviceNode.getMeasured(); DeviceNode.DeviceNodeType type = deviceNode.getType(); value = value.replaceAll("°", "°"); value = handleReplaceAll(attributeOptions, value); value = handleReplace(attributeOptions, value); value = handleExtract(attributeOptions, value); value = handleAppend(attributeOptions, value); return new DeviceNode(type, key, value, measured); } private String handleReplaceAll(JSONObject attributeOptions, String value) { JSONArray replaceAll = attributeOptions.optJSONArray("replaceAll"); if (replaceAll != null) { for (int i = 0; i < replaceAll.length(); i++) { JSONObject conf = replaceAll.optJSONObject(i); String toSearch = conf.optString("search"); String searchReplace = conf.optString("replace"); value = value.replaceAll(toSearch, searchReplace); } } return value.trim(); } private String handleReplace(JSONObject attributeOptions, String value) { String replace = attributeOptions.optString("replace"); String replaceBy = attributeOptions.optString("replaceBy"); replaceBy = replaceBy == null ? "" : replaceBy; if (!isNullOrEmpty(replace)) { value = value.replaceAll(replace, replaceBy); } return value.trim(); } private String handleAppend(JSONObject attributeOptions, String value) { String append = attributeOptions.optString("append"); if (!isNullOrEmpty(append)) { value = ValueDescriptionUtil.append(value, append); } return value; } private String handleExtract(JSONObject attributeOptions, String value) { String extract = attributeOptions.optString("extract"); if (!isNullOrEmpty(extract)) { switch (extract) { case "double": int extractDigits = attributeOptions.optInt("extractDigits", 0); double result = extractDigits != 0 ? extractLeadingDouble(value, extractDigits) : extractLeadingDouble(value); int divFactor = attributeOptions.optInt("extractDivideBy", 0); if (divFactor != 0) { result = Math.round(result / 1000d); } return String.valueOf(result); case "int": return String.valueOf(extractLeadingInt(value)); } } return value; } private JSONObject optionsFor(String type) { return deviceConfigurationProvider.sanitiseConfigurationFor(type).or(new JSONObject()); } }